mirror of
https://github.com/YosysHQ/yosys
synced 2026-06-23 01:00:29 +00:00
Merge branch 'YosysHQ:main' into master
This commit is contained in:
commit
d563d3974f
97 changed files with 7962 additions and 4848 deletions
7
.github/actions/setup-build-env/action.yml
vendored
7
.github/actions/setup-build-env/action.yml
vendored
|
|
@ -8,14 +8,13 @@ runs:
|
|||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev
|
||||
sudo apt-get install gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev
|
||||
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: |
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew update
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash autoconf llvm lld || true
|
||||
brew bundle
|
||||
|
||||
- name: Linux runtime environment
|
||||
if: runner.os == 'Linux'
|
||||
|
|
@ -29,7 +28,7 @@ runs:
|
|||
shell: bash
|
||||
run: |
|
||||
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH
|
||||
echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV
|
||||
|
|
|
|||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install deps
|
||||
run: sudo apt-get install bison flex libreadline-dev tcl-dev libffi-dev
|
||||
run: sudo apt-get install bison flex libfl-dev libreadline-dev tcl-dev libffi-dev
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
|
|
|||
26
.github/workflows/extra-builds.yml
vendored
26
.github/workflows/extra-builds.yml
vendored
|
|
@ -27,19 +27,20 @@ jobs:
|
|||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
- run: sudo apt-get install libfl-dev
|
||||
- name: Build
|
||||
run: make vcxsrc YOSYS_VER=latest
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vcxsrc
|
||||
path: yosys-win32-vcxsrc-latest.zip
|
||||
|
||||
|
||||
vs-build:
|
||||
name: Visual Studio build
|
||||
runs-on: windows-latest
|
||||
needs: [vs-prep, pre_job]
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
steps:
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: vcxsrc
|
||||
|
|
@ -50,7 +51,7 @@ jobs:
|
|||
uses: microsoft/setup-msbuild@v2
|
||||
- name: MSBuild
|
||||
working-directory: yosys-win32-vcxsrc-latest
|
||||
run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.17763.0
|
||||
run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.26100.0
|
||||
|
||||
wasi-build:
|
||||
name: WASI build
|
||||
|
|
@ -68,9 +69,20 @@ jobs:
|
|||
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz
|
||||
if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi
|
||||
|
||||
FLEX_VER=2.6.4
|
||||
FLEX=flex-${FLEX_VER}
|
||||
FLEX_URL=https://github.com/westes/flex/releases/download/v${FLEX_VER}/${FLEX}.tar.gz
|
||||
if ! [ -d ${FLEX} ]; then curl -L ${FLEX_URL} | tar xzf -; fi
|
||||
|
||||
mkdir -p flex-build
|
||||
(cd flex-build &&
|
||||
../${FLEX}/configure --prefix=$(pwd)/../flex-prefix &&
|
||||
make &&
|
||||
make install)
|
||||
|
||||
mkdir -p build
|
||||
cat > build/Makefile.conf <<END
|
||||
export PATH := $(pwd)/${WASI_SDK}/bin:${PATH}
|
||||
export PATH := $(pwd)/${WASI_SDK}/bin:$(pwd)/flex-prefix/bin:${PATH}
|
||||
WASI_SYSROOT := $(pwd)/${WASI_SDK}/share/wasi-sysroot
|
||||
|
||||
CONFIG := wasi
|
||||
|
|
@ -80,6 +92,8 @@ jobs:
|
|||
ENABLE_READLINE := 0
|
||||
ENABLE_PLUGINS := 0
|
||||
ENABLE_ZLIB := 0
|
||||
|
||||
CXXFLAGS += -I$(pwd)/flex-prefix/include
|
||||
END
|
||||
|
||||
make -C build -f ../Makefile CXX=clang -j$(nproc)
|
||||
|
|
@ -98,7 +112,7 @@ jobs:
|
|||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
- uses: cachix/install-nix-action@v26
|
||||
- uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.18.1/install
|
||||
install_url: https://releases.nixos.org/nix/nix-2.30.0/install
|
||||
- run: nix build .?submodules=1 -L
|
||||
|
|
|
|||
38
.github/workflows/test-build.yml
vendored
38
.github/workflows/test-build.yml
vendored
|
|
@ -161,6 +161,44 @@ jobs:
|
|||
run: |
|
||||
find tests/**/*.err -print -exec cat {} \;
|
||||
|
||||
test-cells:
|
||||
name: Run test_cell
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [build-yosys, pre_job]
|
||||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
env:
|
||||
CC: clang
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
sanitizer: [undefined]
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup environment
|
||||
uses: ./.github/actions/setup-build-env
|
||||
|
||||
- name: Download build artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build-${{ matrix.os }}-${{ matrix.sanitizer }}
|
||||
|
||||
- name: Uncompress build
|
||||
shell: bash
|
||||
run:
|
||||
tar -xvf build.tar
|
||||
|
||||
- name: test_cell
|
||||
shell: bash
|
||||
run: |
|
||||
./yosys -p 'test_cell -n 20 -s 1 all'
|
||||
./yosys -p 'test_cell -n 20 -s 1 -nosat -aigmap $pow $pmux'
|
||||
./yosys -p 'test_cell -n 20 -s 1 -nosat -aigmap $eqx $nex $bweqx'
|
||||
./yosys -p 'test_cell -n 20 -s 1 -aigmap $buf'
|
||||
|
||||
test-docs:
|
||||
name: Run docs tests
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
|
|
|||
7
.github/workflows/test-compile.yml
vendored
7
.github/workflows/test-compile.yml
vendored
|
|
@ -36,9 +36,12 @@ jobs:
|
|||
- 'clang-19'
|
||||
- 'gcc-13'
|
||||
include:
|
||||
# macOS
|
||||
# macOS x86
|
||||
- os: macos-13
|
||||
compiler: 'clang'
|
||||
compiler: 'clang-19'
|
||||
# macOS arm
|
||||
- os: macos-latest
|
||||
compiler: 'clang-19'
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
|
|
|
|||
18
.github/workflows/wheels.yml
vendored
18
.github/workflows/wheels.yml
vendored
|
|
@ -4,7 +4,7 @@ name: Build Wheels for PyPI
|
|||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 10 * * 0'
|
||||
- cron: "0 10 * * 0"
|
||||
|
||||
jobs:
|
||||
build_wheels:
|
||||
|
|
@ -54,9 +54,6 @@ jobs:
|
|||
fetch-depth: 0
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
- if: ${{ matrix.os.family == 'linux' }}
|
||||
name: "[Linux] Set up QEMU"
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- uses: actions/setup-python@v5
|
||||
- name: Get Boost Source
|
||||
shell: bash
|
||||
|
|
@ -68,14 +65,19 @@ jobs:
|
|||
run: |
|
||||
mkdir -p ffi
|
||||
curl -L https://github.com/libffi/libffi/releases/download/v3.4.6/libffi-3.4.6.tar.gz | tar --strip-components=1 -xzC ffi
|
||||
- if: ${{ matrix.os.family == 'linux' }}
|
||||
name: "[Linux] Bison 3.8.2"
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p bison
|
||||
curl -L https://ftpmirror.gnu.org/gnu/bison/bison-3.8.2.tar.gz | tar --strip-components=1 -xzC bison
|
||||
## Software installed by default in GitHub Action Runner VMs:
|
||||
## https://github.com/actions/runner-images
|
||||
- if: ${{ matrix.os.family == 'macos' }}
|
||||
name: "[macOS] Flex/Bison"
|
||||
run: |
|
||||
brew install flex bison
|
||||
echo "PATH=$(brew --prefix flex)/bin:$PATH" >> $GITHUB_ENV
|
||||
echo "PATH=$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV
|
||||
echo "PATH=$(brew --prefix flex)/bin:$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV
|
||||
- if: ${{ matrix.os.family == 'windows' }}
|
||||
name: "[Windows] Flex/Bison"
|
||||
run: |
|
||||
|
|
@ -100,16 +102,20 @@ jobs:
|
|||
CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
|
||||
CIBW_BEFORE_ALL: bash ./.github/workflows/wheels/cibw_before_all.sh
|
||||
CIBW_ENVIRONMENT: >
|
||||
OPTFLAGS=-O3
|
||||
CXXFLAGS=-I./boost/pfx/include
|
||||
LINKFLAGS=-L./boost/pfx/lib
|
||||
PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig
|
||||
makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a'
|
||||
PATH="$PWD/bison/src:$PATH"
|
||||
CIBW_ENVIRONMENT_MACOS: >
|
||||
OPTFLAGS=-O3
|
||||
CXXFLAGS=-I./boost/pfx/include
|
||||
LINKFLAGS=-L./boost/pfx/lib
|
||||
PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig
|
||||
MACOSX_DEPLOYMENT_TARGET=11
|
||||
makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang'
|
||||
PATH="$PWD/bison/src:$PATH"
|
||||
CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh
|
||||
CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py
|
||||
- uses: actions/upload-artifact@v4
|
||||
|
|
|
|||
14
.github/workflows/wheels/_run_cibw_linux.py
vendored
14
.github/workflows/wheels/_run_cibw_linux.py
vendored
|
|
@ -20,11 +20,19 @@ import os
|
|||
import yaml
|
||||
import platform
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
__dir__ = os.path.dirname(os.path.abspath(__file__))
|
||||
__yosys_root__ = Path(__file__).absolute().parents[3]
|
||||
|
||||
for source in ["boost", "ffi", "bison"]:
|
||||
if not (__yosys_root__ / source).is_dir():
|
||||
print(
|
||||
"You need to download boost, ffi and bison in a similar manner to wheels.yml first."
|
||||
)
|
||||
exit(-1)
|
||||
|
||||
workflow = yaml.safe_load(open(os.path.join(os.path.dirname(__dir__), "wheels.yml")))
|
||||
with open(__yosys_root__ / ".github" / "workflows" / "wheels.yml") as f:
|
||||
workflow = yaml.safe_load(f)
|
||||
|
||||
env = os.environ.copy()
|
||||
|
||||
|
|
@ -40,5 +48,5 @@ for key, value in cibw_step["env"].items():
|
|||
continue
|
||||
env[key] = value
|
||||
|
||||
env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS") or platform.machine()
|
||||
env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS", platform.machine())
|
||||
subprocess.check_call(["cibuildwheel"], env=env)
|
||||
|
|
|
|||
36
.github/workflows/wheels/cibw_before_all.sh
vendored
36
.github/workflows/wheels/cibw_before_all.sh
vendored
|
|
@ -1,23 +1,37 @@
|
|||
set -e
|
||||
set -x
|
||||
#!/bin/bash
|
||||
set -e -x
|
||||
|
||||
# Build-time dependencies
|
||||
## Linux Docker Images
|
||||
if command -v yum &> /dev/null; then
|
||||
yum install -y flex bison
|
||||
yum install -y flex # manylinux's bison versions are hopelessly out of date
|
||||
fi
|
||||
|
||||
if command -v apk &> /dev/null; then
|
||||
apk add flex bison
|
||||
fi
|
||||
|
||||
if ! printf '%s\n' '%require "3.8"' '%%' 'start: ;' | bison -o /dev/null /dev/stdin ; then
|
||||
(
|
||||
set -e -x
|
||||
cd bison
|
||||
./configure
|
||||
make clean
|
||||
make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)
|
||||
)
|
||||
fi
|
||||
|
||||
## macOS/Windows -- installed in GitHub Action itself, not container
|
||||
|
||||
# Build Static FFI (platform-dependent but not Python version dependent)
|
||||
cd ffi
|
||||
## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries
|
||||
CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx
|
||||
## Without this, SHELL has a space in its path which breaks the makefile
|
||||
make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)
|
||||
## Forces static library to be used in all situations
|
||||
sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc
|
||||
# Runtime Dependencies
|
||||
## Build Static FFI (platform-dependent but not Python version dependent)
|
||||
(
|
||||
set -e -x
|
||||
cd ffi
|
||||
## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries
|
||||
CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx
|
||||
make clean
|
||||
make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)
|
||||
## Forces static library to be used in all situations
|
||||
sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc
|
||||
)
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -47,6 +47,7 @@
|
|||
/kernel/python_wrappers.cc
|
||||
/boost
|
||||
/ffi
|
||||
/bison
|
||||
/venv
|
||||
/*.whl
|
||||
/*.egg-info
|
||||
|
|
|
|||
3
Brewfile
3
Brewfile
|
|
@ -6,9 +6,8 @@ brew "git"
|
|||
brew "graphviz"
|
||||
brew "pkg-config"
|
||||
brew "python3"
|
||||
brew "tcl-tk"
|
||||
brew "xdot"
|
||||
brew "bash"
|
||||
brew "boost-python3"
|
||||
brew "llvm"
|
||||
brew "llvm@20"
|
||||
brew "lld"
|
||||
|
|
|
|||
17
CHANGELOG
17
CHANGELOG
|
|
@ -2,9 +2,24 @@
|
|||
List of major changes and improvements between releases
|
||||
=======================================================
|
||||
|
||||
Yosys 0.56 .. Yosys 0.57-dev
|
||||
Yosys 0.57 .. Yosys 0.58-dev
|
||||
--------------------------
|
||||
|
||||
Yosys 0.56 .. Yosys 0.57
|
||||
--------------------------
|
||||
* New commands and options
|
||||
- Added "-initstates" option to "abstract" pass.
|
||||
- Added "-set-assumes" option to "equiv_induct"
|
||||
and "equiv_simple" passes.
|
||||
- Added "-always" option to "raise_error" pass.
|
||||
- Added "-hierarchy" option to "stat" pass.
|
||||
- Added "-noflatten" option to "synth_quicklogic" pass.
|
||||
|
||||
* Various
|
||||
- smtbmc: Support skipping steps in cover mode.
|
||||
- write_btor: support $buf.
|
||||
- read_verilog: support package import.
|
||||
|
||||
Yosys 0.55 .. Yosys 0.56
|
||||
--------------------------
|
||||
* New commands and options
|
||||
|
|
|
|||
12
Makefile
12
Makefile
|
|
@ -132,8 +132,8 @@ ifeq ($(ENABLE_PYOSYS),1)
|
|||
CXXFLAGS += -I$(BREW_PREFIX)/boost/include
|
||||
LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib
|
||||
endif
|
||||
CXXFLAGS += -I$(BREW_PREFIX)/readline/include
|
||||
LINKFLAGS += -L$(BREW_PREFIX)/readline/lib
|
||||
CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include
|
||||
LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib
|
||||
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
|
||||
PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH)
|
||||
export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH)
|
||||
|
|
@ -159,7 +159,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.56+0
|
||||
YOSYS_VER := 0.57+0
|
||||
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
||||
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
|
||||
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
|
||||
|
|
@ -182,7 +182,7 @@ endif
|
|||
OBJS = kernel/version_$(GIT_REV).o
|
||||
|
||||
bumpversion:
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 9c447ad.. | wc -l`/;" Makefile
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 3aca860.. | wc -l`/;" Makefile
|
||||
|
||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
|
||||
|
||||
|
|
@ -745,9 +745,9 @@ $(PROGRAM_PREFIX)yosys$(EXE): $(OBJS)
|
|||
|
||||
libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
|
||||
ifeq ($(OS), Darwin)
|
||||
$(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
|
||||
$(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
|
||||
else
|
||||
$(P) $(CXX) -o libyosys.so -shared -Wl,-soname,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
|
||||
$(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
|
||||
endif
|
||||
|
||||
%.o: %.cc
|
||||
|
|
|
|||
|
|
@ -80,10 +80,10 @@ recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
|
|||
TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
|
||||
Xdot (graphviz) is used by the ``show`` command in yosys to display schematics.
|
||||
|
||||
For example on Ubuntu Linux 16.04 LTS the following commands will install all
|
||||
For example on Ubuntu Linux 22.04 LTS the following commands will install all
|
||||
prerequisites for building yosys:
|
||||
|
||||
$ sudo apt-get install build-essential clang lld bison flex \
|
||||
$ sudo apt-get install build-essential clang lld bison flex libfl-dev \
|
||||
libreadline-dev gawk tcl-dev libffi-dev git \
|
||||
graphviz xdot pkg-config python3 libboost-system-dev \
|
||||
libboost-python-dev libboost-filesystem-dev zlib1g-dev
|
||||
|
|
|
|||
2
abc
2
abc
|
|
@ -1 +1 @@
|
|||
Subproject commit fa7fa163dacdf81bdcb72b2d2713fbe9984b62bb
|
||||
Subproject commit 8827bafb7f288de6749dc6e30fa452f2040949c0
|
||||
|
|
@ -129,7 +129,7 @@ struct BtorWorker
|
|||
std::replace(src.begin(), src.end(), ' ', '_');
|
||||
if (srcsymbols.count(src) || module->count_id("\\" + src)) {
|
||||
for (int i = 1;; i++) {
|
||||
string s = stringf("%s-%d", src.c_str(), i);
|
||||
string s = stringf("%s-%d", src, i);
|
||||
if (!srcsymbols.count(s) && !module->count_id("\\" + s)) {
|
||||
src = s;
|
||||
break;
|
||||
|
|
@ -192,7 +192,7 @@ struct BtorWorker
|
|||
void btorf_push(const string &id)
|
||||
{
|
||||
if (verbose) {
|
||||
f << indent << stringf(" ; begin %s\n", id.c_str());
|
||||
f << indent << stringf(" ; begin %s\n", id);
|
||||
indent += " ";
|
||||
}
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ struct BtorWorker
|
|||
{
|
||||
if (verbose) {
|
||||
indent = indent.substr(4);
|
||||
f << indent << stringf(" ; end %s\n", id.c_str());
|
||||
f << indent << stringf(" ; end %s\n", id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -509,7 +509,7 @@ struct BtorWorker
|
|||
goto okay;
|
||||
}
|
||||
|
||||
if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos)))
|
||||
if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos), ID($buf), ID($_BUF_)))
|
||||
{
|
||||
string btor_op;
|
||||
if (cell->type.in(ID($not), ID($_NOT_))) btor_op = "not";
|
||||
|
|
@ -521,9 +521,9 @@ struct BtorWorker
|
|||
int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
|
||||
SigSpec sig = sigmap(cell->getPort(ID::Y));
|
||||
|
||||
// the $pos cell just passes through, all other cells need an actual operation applied
|
||||
// the $pos/$buf cells just pass through, all other cells need an actual operation applied
|
||||
int nid = nid_a;
|
||||
if (cell->type != ID($pos))
|
||||
if (!cell->type.in(ID($pos), ID($buf), ID($_BUF_)))
|
||||
{
|
||||
log_assert(!btor_op.empty());
|
||||
int sid = get_bv_sid(width);
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
|
|||
const std::string extmoduleFileinfo = getFileinfo(cell);
|
||||
|
||||
// Emit extmodule header.
|
||||
f << stringf(" extmodule %s: %s\n", exported_name.c_str(), extmoduleFileinfo.c_str());
|
||||
f << stringf(" extmodule %s: %s\n", exported_name, extmoduleFileinfo);
|
||||
|
||||
// Emit extmodule ports.
|
||||
for (auto wire : mod_instance->wires())
|
||||
|
|
@ -280,7 +280,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
|
|||
// Emit extmodule "defname" field. This is the name of the verilog blackbox
|
||||
// that is used when verilog is emitted, so we use the name of mod_instance
|
||||
// here.
|
||||
f << stringf("%sdefname = %s\n", indent.c_str(), blackbox_name.c_str());
|
||||
f << stringf("%sdefname = %s\n", indent, blackbox_name);
|
||||
|
||||
// Emit extmodule generic parameters.
|
||||
for (const auto &p : cell->parameters)
|
||||
|
|
@ -301,7 +301,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
|
|||
param_name.end()
|
||||
);
|
||||
|
||||
f << stringf("%sparameter %s = %s\n", indent.c_str(), param_name.c_str(), param_value.c_str());
|
||||
f << stringf("%sparameter %s = %s\n", indent, param_name, param_value);
|
||||
}
|
||||
|
||||
f << "\n";
|
||||
|
|
@ -417,7 +417,7 @@ struct FirrtlWorker
|
|||
else
|
||||
{
|
||||
string wire_id = make_id(chunk.wire->name);
|
||||
new_expr = stringf("bits(%s, %d, %d)", wire_id.c_str(), chunk.offset + chunk.width - 1, chunk.offset);
|
||||
new_expr = stringf("bits(%s, %d, %d)", wire_id, chunk.offset + chunk.width - 1, chunk.offset);
|
||||
}
|
||||
|
||||
if (expr.empty())
|
||||
|
|
@ -477,7 +477,7 @@ struct FirrtlWorker
|
|||
instanceOf;
|
||||
|
||||
std::string cellFileinfo = getFileinfo(cell);
|
||||
wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceName.c_str(), cellFileinfo.c_str()));
|
||||
wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent, cell_name, cell_name_comment, instanceName, cellFileinfo));
|
||||
|
||||
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
|
||||
if (it->second.size() > 0) {
|
||||
|
|
@ -518,7 +518,7 @@ struct FirrtlWorker
|
|||
// as part of the coalesced subfield assignments for this wire.
|
||||
register_reverse_wire_map(sourceExpr, *sinkSig);
|
||||
} else {
|
||||
wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str(), cellFileinfo.c_str()));
|
||||
wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent, sinkExpr, sourceExpr, cellFileinfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -535,7 +535,7 @@ struct FirrtlWorker
|
|||
int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
|
||||
string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
|
||||
// Deal with the difference in semantics between FIRRTL and verilog
|
||||
result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1);
|
||||
result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr, max_shift_string, max_shift_string, b_expr, max_shift_width_bits - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -543,7 +543,7 @@ struct FirrtlWorker
|
|||
void emit_module()
|
||||
{
|
||||
std::string moduleFileinfo = getFileinfo(module);
|
||||
f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo.c_str());
|
||||
f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo);
|
||||
vector<string> port_decls, wire_decls, mem_exprs, cell_exprs, wire_exprs;
|
||||
|
||||
std::vector<Mem> memories = Mem::get_all_memories(module);
|
||||
|
|
@ -602,7 +602,7 @@ struct FirrtlWorker
|
|||
if (cell->type.in(ID($not), ID($logic_not), ID($_NOT_), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor)))
|
||||
{
|
||||
string a_expr = make_expr(cell->getPort(ID::A));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str()));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo));
|
||||
|
||||
if (a_signed) {
|
||||
a_expr = "asSInt(" + a_expr + ")";
|
||||
|
|
@ -610,7 +610,7 @@ struct FirrtlWorker
|
|||
|
||||
// Don't use the results of logical operations (a single bit) to control padding
|
||||
if (!(cell->type.in(ID($eq), ID($eqx), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($reduce_bool), ID($logic_not)) && y_width == 1) ) {
|
||||
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
|
||||
a_expr = stringf("pad(%s, %d)", a_expr, y_width);
|
||||
}
|
||||
|
||||
// Assume the FIRRTL width is a single bit.
|
||||
|
|
@ -622,27 +622,27 @@ struct FirrtlWorker
|
|||
firrtl_width = a_width;
|
||||
} else if (cell->type == ID($logic_not)) {
|
||||
primop = "eq";
|
||||
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
|
||||
a_expr = stringf("%s, UInt(0)", a_expr);
|
||||
}
|
||||
else if (cell->type == ID($reduce_and)) primop = "andr";
|
||||
else if (cell->type == ID($reduce_or)) primop = "orr";
|
||||
else if (cell->type == ID($reduce_xor)) primop = "xorr";
|
||||
else if (cell->type == ID($reduce_xnor)) {
|
||||
primop = "not";
|
||||
a_expr = stringf("xorr(%s)", a_expr.c_str());
|
||||
a_expr = stringf("xorr(%s)", a_expr);
|
||||
}
|
||||
else if (cell->type == ID($reduce_bool)) {
|
||||
primop = "neq";
|
||||
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
|
||||
a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width);
|
||||
a_expr = stringf("%s, %cInt<%d>(0)", a_expr, a_signed ? 'S' : 'U', a_width);
|
||||
}
|
||||
|
||||
string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str());
|
||||
string expr = stringf("%s(%s)", primop, a_expr);
|
||||
|
||||
if ((firrtl_is_signed && !always_uint))
|
||||
expr = stringf("asUInt(%s)", expr.c_str());
|
||||
expr = stringf("asUInt(%s)", expr);
|
||||
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
|
||||
continue;
|
||||
|
|
@ -654,13 +654,13 @@ struct FirrtlWorker
|
|||
string a_expr = make_expr(cell->getPort(ID::A));
|
||||
string b_expr = make_expr(cell->getPort(ID::B));
|
||||
std::string cellFileinfo = getFileinfo(cell);
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str()));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo));
|
||||
|
||||
if (a_signed) {
|
||||
a_expr = "asSInt(" + a_expr + ")";
|
||||
// Expand the "A" operand to the result width
|
||||
if (a_width < y_width) {
|
||||
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
|
||||
a_expr = stringf("pad(%s, %d)", a_expr, y_width);
|
||||
a_width = y_width;
|
||||
}
|
||||
}
|
||||
|
|
@ -670,7 +670,7 @@ struct FirrtlWorker
|
|||
b_expr = "asSInt(" + b_expr + ")";
|
||||
// Expand the "B" operand to the result width
|
||||
if (b_width < y_width) {
|
||||
b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
|
||||
b_expr = stringf("pad(%s, %d)", b_expr, y_width);
|
||||
b_width = y_width;
|
||||
}
|
||||
}
|
||||
|
|
@ -680,11 +680,11 @@ struct FirrtlWorker
|
|||
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_)))
|
||||
{
|
||||
if (a_width < y_width) {
|
||||
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
|
||||
a_expr = stringf("pad(%s, %d)", a_expr, y_width);
|
||||
a_width = y_width;
|
||||
}
|
||||
if (b_width < y_width) {
|
||||
b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
|
||||
b_expr = stringf("pad(%s, %d)", b_expr, y_width);
|
||||
b_width = y_width;
|
||||
}
|
||||
}
|
||||
|
|
@ -856,23 +856,23 @@ struct FirrtlWorker
|
|||
string expr;
|
||||
// Deal with $xnor == ~^ (not xor)
|
||||
if (primop == "xnor") {
|
||||
expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str());
|
||||
expr = stringf("not(xor(%s, %s))", a_expr, b_expr);
|
||||
} else {
|
||||
expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
|
||||
expr = stringf("%s(%s, %s)", primop, a_expr, b_expr);
|
||||
}
|
||||
|
||||
// Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result.
|
||||
// If the operation is signed, the FIRRTL width will be 1 one bit larger.
|
||||
if (extract_y_bits) {
|
||||
expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
|
||||
expr = stringf("bits(%s, %d, 0)", expr, y_width - 1);
|
||||
} else if (firrtl_is_signed && (firrtl_width + 1) < y_width) {
|
||||
expr = stringf("pad(%s, %d)", expr.c_str(), y_width);
|
||||
expr = stringf("pad(%s, %d)", expr, y_width);
|
||||
}
|
||||
|
||||
if ((firrtl_is_signed && !always_uint))
|
||||
expr = stringf("asUInt(%s)", expr.c_str());
|
||||
expr = stringf("asUInt(%s)", expr);
|
||||
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
|
||||
continue;
|
||||
|
|
@ -887,9 +887,9 @@ struct FirrtlWorker
|
|||
string s_expr = make_expr(cell->getPort(ID::S));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), width, cellFileinfo.c_str()));
|
||||
|
||||
string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
|
||||
string expr = stringf("mux(%s, %s, %s)", s_expr, b_expr, a_expr);
|
||||
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
|
||||
continue;
|
||||
|
|
@ -911,9 +911,9 @@ struct FirrtlWorker
|
|||
string expr = make_expr(cell->getPort(ID::D));
|
||||
string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")";
|
||||
|
||||
wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent.c_str(), y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.c_str()));
|
||||
wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent, y_id, width, clk_expr, cellFileinfo));
|
||||
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Q));
|
||||
|
||||
continue;
|
||||
|
|
@ -934,7 +934,7 @@ struct FirrtlWorker
|
|||
int b_sign = cell->parameters.at(ID::B_WIDTH).as_int() - 1;
|
||||
b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string);
|
||||
}
|
||||
string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str());
|
||||
string expr = stringf("dshr(%s, %s)", a_expr, b_expr);
|
||||
|
||||
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str()));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
|
|
@ -973,7 +973,7 @@ struct FirrtlWorker
|
|||
// Verilog appears to treat the result as signed, so if the result is wider than "A",
|
||||
// we need to pad.
|
||||
if (a_width < y_width) {
|
||||
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
|
||||
a_expr = stringf("pad(%s, %d)", a_expr, y_width);
|
||||
}
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), a_expr.c_str()));
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ struct IntersynthBackend : public Backend {
|
|||
if (sig.size() != 0) {
|
||||
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size()));
|
||||
celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", log_id(port.first));
|
||||
node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig).c_str());
|
||||
node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig));
|
||||
}
|
||||
}
|
||||
for (auto ¶m : cell->parameters) {
|
||||
|
|
@ -199,13 +199,13 @@ struct IntersynthBackend : public Backend {
|
|||
if (!flag_notypes) {
|
||||
*f << stringf("### Connection Types\n");
|
||||
for (auto code : conntypes_code)
|
||||
*f << stringf("%s", code.c_str());
|
||||
*f << stringf("%s", code);
|
||||
*f << stringf("\n### Cell Types\n");
|
||||
for (auto code : celltypes_code)
|
||||
*f << stringf("%s", code.c_str());
|
||||
*f << stringf("%s", code);
|
||||
}
|
||||
*f << stringf("\n### Netlists\n");
|
||||
*f << stringf("%s", netlists_code.c_str());
|
||||
*f << stringf("%s", netlists_code);
|
||||
|
||||
for (auto lib : libs)
|
||||
delete lib;
|
||||
|
|
|
|||
|
|
@ -218,8 +218,8 @@ struct SimplecWorker
|
|||
s[i] -= 'a' - 'A';
|
||||
|
||||
util_declarations.push_back("");
|
||||
util_declarations.push_back(stringf("#ifndef %s", s.c_str()));
|
||||
util_declarations.push_back(stringf("#define %s", s.c_str()));
|
||||
util_declarations.push_back(stringf("#ifndef %s", s));
|
||||
util_declarations.push_back(stringf("#define %s", s));
|
||||
}
|
||||
|
||||
string util_get_bit(const string &signame, int n, int idx)
|
||||
|
|
@ -232,33 +232,33 @@ struct SimplecWorker
|
|||
if (generated_utils.count(util_name) == 0)
|
||||
{
|
||||
util_ifdef_guard(util_name);
|
||||
util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str()));
|
||||
util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name, sigtype(n)));
|
||||
util_declarations.push_back(stringf("{"));
|
||||
|
||||
int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
|
||||
string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize);
|
||||
|
||||
util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name.c_str(), word_offset));
|
||||
util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name, word_offset));
|
||||
|
||||
util_declarations.push_back(stringf("}"));
|
||||
util_declarations.push_back(stringf("#endif"));
|
||||
generated_utils.insert(util_name);
|
||||
}
|
||||
|
||||
return stringf("%s(&%s)", util_name.c_str(), signame.c_str());
|
||||
return stringf("%s(&%s)", util_name, signame);
|
||||
}
|
||||
|
||||
string util_set_bit(const string &signame, int n, int idx, const string &expr)
|
||||
{
|
||||
if (n == 1 && idx == 0)
|
||||
return stringf(" %s.value_0_0 = %s;", signame.c_str(), expr.c_str());
|
||||
return stringf(" %s.value_0_0 = %s;", signame, expr);
|
||||
|
||||
string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n);
|
||||
|
||||
if (generated_utils.count(util_name) == 0)
|
||||
{
|
||||
util_ifdef_guard(util_name);
|
||||
util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str()));
|
||||
util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name, sigtype(n)));
|
||||
util_declarations.push_back(stringf("{"));
|
||||
|
||||
int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
|
||||
|
|
@ -266,9 +266,9 @@ struct SimplecWorker
|
|||
|
||||
#if 0
|
||||
util_declarations.push_back(stringf(" if (value)"));
|
||||
util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name.c_str(), word_offset));
|
||||
util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name, word_offset));
|
||||
util_declarations.push_back(stringf(" else"));
|
||||
util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name.c_str(), word_offset));
|
||||
util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name, word_offset));
|
||||
#else
|
||||
util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);",
|
||||
value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset));
|
||||
|
|
@ -279,7 +279,7 @@ struct SimplecWorker
|
|||
generated_utils.insert(util_name);
|
||||
}
|
||||
|
||||
return stringf(" %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str());
|
||||
return stringf(" %s(&%s, %s);", util_name, signame, expr);
|
||||
}
|
||||
|
||||
void create_module_struct(Module *mod)
|
||||
|
|
@ -339,38 +339,38 @@ struct SimplecWorker
|
|||
for (int i = 0; i < GetSize(topo.sorted); i++)
|
||||
topoidx[mod->cell(topo.sorted[i])] = i;
|
||||
|
||||
string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name).c_str());
|
||||
string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name));
|
||||
|
||||
for (int i = 0; i < GetSize(ifdef_name); i++)
|
||||
if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z')
|
||||
ifdef_name[i] -= 'a' - 'A';
|
||||
|
||||
struct_declarations.push_back("");
|
||||
struct_declarations.push_back(stringf("#ifndef %s", ifdef_name.c_str()));
|
||||
struct_declarations.push_back(stringf("#define %s", ifdef_name.c_str()));
|
||||
struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name).c_str()));
|
||||
struct_declarations.push_back(stringf("#ifndef %s", ifdef_name));
|
||||
struct_declarations.push_back(stringf("#define %s", ifdef_name));
|
||||
struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name)));
|
||||
struct_declarations.push_back("{");
|
||||
|
||||
struct_declarations.push_back(" // Input Ports");
|
||||
for (Wire *w : mod->wires())
|
||||
if (w->port_input)
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
|
||||
|
||||
struct_declarations.push_back("");
|
||||
struct_declarations.push_back(" // Output Ports");
|
||||
for (Wire *w : mod->wires())
|
||||
if (!w->port_input && w->port_output)
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
|
||||
|
||||
struct_declarations.push_back("");
|
||||
struct_declarations.push_back(" // Internal Wires");
|
||||
for (Wire *w : mod->wires())
|
||||
if (!w->port_input && !w->port_output)
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
|
||||
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
|
||||
|
||||
for (Cell *c : mod->cells())
|
||||
if (design->module(c->type))
|
||||
struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type).c_str(), cid(c->name).c_str(), log_id(c)));
|
||||
struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type), cid(c->name), log_id(c)));
|
||||
|
||||
struct_declarations.push_back(stringf("};"));
|
||||
struct_declarations.push_back("#endif");
|
||||
|
|
@ -407,14 +407,14 @@ struct SimplecWorker
|
|||
string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
|
||||
string expr;
|
||||
|
||||
if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr.c_str(), b_expr.c_str());
|
||||
if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str());
|
||||
if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr.c_str(), b_expr.c_str());
|
||||
if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str());
|
||||
if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr.c_str(), b_expr.c_str());
|
||||
if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str());
|
||||
if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str());
|
||||
if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr.c_str(), b_expr.c_str());
|
||||
if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr, b_expr);
|
||||
if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr, b_expr);
|
||||
if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr, b_expr);
|
||||
if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr, b_expr);
|
||||
if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr, b_expr);
|
||||
if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr, b_expr);
|
||||
if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr, b_expr);
|
||||
if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr, b_expr);
|
||||
|
||||
log_assert(y.wire);
|
||||
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
|
||||
|
|
@ -436,8 +436,8 @@ struct SimplecWorker
|
|||
string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
|
||||
string expr;
|
||||
|
||||
if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
|
||||
if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
|
||||
if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr, b_expr, c_expr);
|
||||
if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr, b_expr, c_expr);
|
||||
|
||||
log_assert(y.wire);
|
||||
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
|
||||
|
|
@ -461,8 +461,8 @@ struct SimplecWorker
|
|||
string d_expr = d.wire ? util_get_bit(work->prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0";
|
||||
string expr;
|
||||
|
||||
if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
|
||||
if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
|
||||
if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr, b_expr, c_expr, d_expr);
|
||||
if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr, b_expr, c_expr, d_expr);
|
||||
|
||||
log_assert(y.wire);
|
||||
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
|
||||
|
|
@ -484,9 +484,9 @@ struct SimplecWorker
|
|||
string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0";
|
||||
|
||||
// casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933)
|
||||
string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(),
|
||||
cell->type == ID($_NMUX_) ? "!" : "", b_expr.c_str(),
|
||||
cell->type == ID($_NMUX_) ? "!" : "", a_expr.c_str());
|
||||
string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr,
|
||||
cell->type == ID($_NMUX_) ? "!" : "", b_expr,
|
||||
cell->type == ID($_NMUX_) ? "!" : "", a_expr);
|
||||
|
||||
log_assert(y.wire);
|
||||
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
|
||||
|
|
@ -518,7 +518,7 @@ struct SimplecWorker
|
|||
continue;
|
||||
if (verbose)
|
||||
log(" Propagating %s.%s[%d:%d].\n", work->log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset);
|
||||
funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix.c_str(), log_signal(chunk)));
|
||||
funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix, log_signal(chunk)));
|
||||
}
|
||||
|
||||
for (SigBit bit : dirtysig)
|
||||
|
|
@ -636,7 +636,7 @@ struct SimplecWorker
|
|||
reactivated_cells.clear();
|
||||
|
||||
funct_declarations.push_back("");
|
||||
funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str()));
|
||||
funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name, cid(work->module->name)));
|
||||
funct_declarations.push_back("{");
|
||||
for (auto &line : preamble)
|
||||
funct_declarations.push_back(line);
|
||||
|
|
|
|||
|
|
@ -1875,6 +1875,11 @@ elif covermode:
|
|||
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step-1, step))
|
||||
smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step))
|
||||
|
||||
if step < skip_steps:
|
||||
print_msg("Skipping step %d.." % (step))
|
||||
step += 1
|
||||
continue
|
||||
|
||||
while "1" in cover_mask:
|
||||
print_msg("Checking cover reachability in step %d.." % (step))
|
||||
smt_push()
|
||||
|
|
|
|||
|
|
@ -51,16 +51,16 @@ static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg,
|
|||
if (s.wire->port_id)
|
||||
use_inames = true;
|
||||
if (s.wire->width > 1)
|
||||
f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums).c_str(), s.offset);
|
||||
f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums), s.offset);
|
||||
else
|
||||
f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums).c_str());
|
||||
f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums));
|
||||
} else {
|
||||
if (s == RTLIL::State::S0)
|
||||
f << stringf(" %s", neg.c_str());
|
||||
f << stringf(" %s", neg);
|
||||
else if (s == RTLIL::State::S1)
|
||||
f << stringf(" %s", pos.c_str());
|
||||
f << stringf(" %s", pos);
|
||||
else
|
||||
f << stringf(" %s%d", ncpf.c_str(), nc_counter++);
|
||||
f << stringf(" %s%d", ncpf, nc_counter++);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
|
|||
}
|
||||
}
|
||||
|
||||
f << stringf(" %s\n", spice_id2str(cell->type).c_str());
|
||||
f << stringf(" %s\n", spice_id2str(cell->type));
|
||||
}
|
||||
|
||||
for (auto &conn : module->connections())
|
||||
|
|
@ -127,7 +127,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
|
|||
f << (buf == "DC" ? stringf("V%d", conn_counter++) : stringf("X%d", cell_counter++));
|
||||
print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
|
||||
print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
|
||||
f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf.c_str()));
|
||||
f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -242,18 +242,18 @@ struct SpiceBackend : public Backend {
|
|||
ports.at(wire->port_id-1) = wire;
|
||||
}
|
||||
|
||||
*f << stringf(".SUBCKT %s", spice_id2str(module->name).c_str());
|
||||
*f << stringf(".SUBCKT %s", spice_id2str(module->name));
|
||||
for (RTLIL::Wire *wire : ports) {
|
||||
log_assert(wire != NULL);
|
||||
if (wire->width > 1) {
|
||||
for (int i = 0; i < wire->width; i++)
|
||||
*f << stringf(" %s.%d", spice_id2str(wire->name).c_str(), big_endian ? wire->width - 1 - i : i);
|
||||
*f << stringf(" %s.%d", spice_id2str(wire->name), big_endian ? wire->width - 1 - i : i);
|
||||
} else
|
||||
*f << stringf(" %s", spice_id2str(wire->name).c_str());
|
||||
*f << stringf(" %s", spice_id2str(wire->name));
|
||||
}
|
||||
*f << stringf("\n");
|
||||
print_spice_module(*f, module, design, neg, pos, buf, ncpf, big_endian, use_inames);
|
||||
*f << stringf(".ENDS %s\n\n", spice_id2str(module->name).c_str());
|
||||
*f << stringf(".ENDS %s\n\n", spice_id2str(module->name));
|
||||
}
|
||||
|
||||
if (!top_module_name.empty()) {
|
||||
|
|
|
|||
|
|
@ -2374,8 +2374,16 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
f << indent + " " << "reg " << id(initial_id) << " = 0;\n";
|
||||
}
|
||||
|
||||
for (auto w : module->wires())
|
||||
// first dump input / output according to their order in module->ports
|
||||
for (auto port : module->ports)
|
||||
dump_wire(f, indent + " ", module->wire(port));
|
||||
|
||||
for (auto w : module->wires()) {
|
||||
// avoid duplication
|
||||
if (w->port_id)
|
||||
continue;
|
||||
dump_wire(f, indent + " ", w);
|
||||
}
|
||||
|
||||
for (auto &mem : Mem::get_all_memories(module))
|
||||
dump_memory(f, indent + " ", mem);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import os
|
|||
project = 'YosysHQ Yosys'
|
||||
author = 'YosysHQ GmbH'
|
||||
copyright ='2025 YosysHQ GmbH'
|
||||
yosys_ver = "0.56"
|
||||
yosys_ver = "0.57"
|
||||
|
||||
# select HTML theme
|
||||
html_theme = 'furo-ys'
|
||||
|
|
|
|||
|
|
@ -88,18 +88,18 @@ Build prerequisites
|
|||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A C++ compiler with C++17 support is required as well as some standard tools
|
||||
such as GNU Flex, GNU Bison, Make and Python. Some additional tools: readline,
|
||||
libffi, Tcl and zlib; are optional but enabled by default (see
|
||||
such as GNU Flex, GNU Bison (>=3.8), Make, and Python (>=3.11). Some additional
|
||||
tools: readline, libffi, Tcl and zlib; are optional but enabled by default (see
|
||||
:makevar:`ENABLE_*` settings in Makefile). Graphviz and Xdot are used by the
|
||||
`show` command to display schematics.
|
||||
|
||||
Installing all prerequisites for Ubuntu 20.04:
|
||||
Installing all prerequisites for Ubuntu 22.04:
|
||||
|
||||
.. code:: console
|
||||
|
||||
sudo apt-get install gperf build-essential bison flex \
|
||||
libreadline-dev gawk tcl-dev libffi-dev git graphviz \
|
||||
xdot pkg-config python3 libboost-system-dev \
|
||||
sudo apt-get install gperf build-essential clang lld bison flex libfl-dev \
|
||||
libreadline-dev gawk tcl-dev libffi-dev git \
|
||||
graphviz xdot pkg-config python3 libboost-system-dev \
|
||||
libboost-python-dev libboost-filesystem-dev zlib1g-dev
|
||||
|
||||
Installing all prerequisites for macOS 13 (with Homebrew):
|
||||
|
|
@ -137,8 +137,9 @@ For Cygwin use the following command to install all prerequisites, or select the
|
|||
minimum required version of Python is 3.11. This means that Cygwin is not
|
||||
compatible with many of the Python-based frontends. While this does not
|
||||
currently prevent Yosys itself from working, no guarantees are made for
|
||||
continued support. It is instead recommended to use Windows Subsystem for
|
||||
Linux (WSL) and follow the instructions for Ubuntu.
|
||||
continued support. You may also need to specify `CXXSTD=gnu++17` to resolve
|
||||
missing `strdup` function when using gcc. It is instead recommended to use
|
||||
Windows Subsystem for Linux (WSL) and follow the instructions for Ubuntu.
|
||||
|
||||
..
|
||||
For MSYS2 (MINGW64):
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@ be found in :file:`frontends/verilog/verilog_lexer.l` in the Yosys source tree.
|
|||
The lexer does little more than identifying all keywords and literals recognised
|
||||
by the Yosys Verilog frontend.
|
||||
|
||||
The lexer keeps track of the current location in the Verilog source code using
|
||||
some global variables. These variables are used by the constructor of AST nodes
|
||||
to annotate each node with the source code location it originated from.
|
||||
The lexer keeps track of the current location in the Verilog source code with
|
||||
a ``VerilogLexer::out_loc`` and uses it to construct parser-defined
|
||||
symbol objects.
|
||||
|
||||
Finally the lexer identifies and handles special comments such as "``// synopsys
|
||||
translate_off``" and "``// synopsys full_case``". (It is recommended to use
|
||||
|
|
@ -178,21 +178,22 @@ properties:
|
|||
|
||||
- | Source code location
|
||||
| Each ``AST::AstNode`` is automatically annotated with the current source
|
||||
code location by the ``AST::AstNode`` constructor. It is stored in the
|
||||
``std::string filename`` and ``int linenum`` member variables.
|
||||
code location by the ``AST::AstNode`` constructor. The ``location`` type
|
||||
is a manual reimplementation of the bison-provided location type. This
|
||||
type is defined at ``frontends/verilog/verilog_location.h``.
|
||||
|
||||
The ``AST::AstNode`` constructor can be called with up to two child nodes that
|
||||
are automatically added to the list of child nodes for the new object. This
|
||||
The ``AST::AstNode`` constructor can be called with up to 4 child nodes. This
|
||||
simplifies the creation of AST nodes for simple expressions a bit. For example
|
||||
the bison code for parsing multiplications:
|
||||
|
||||
.. code:: none
|
||||
:number-lines:
|
||||
:number-lines:
|
||||
|
||||
basic_expr '*' attr basic_expr {
|
||||
$$ = new AstNode(AST_MUL, $1, $4);
|
||||
append_attr($$, $3);
|
||||
} |
|
||||
basic_expr TOK_ASTER attr basic_expr {
|
||||
$$ = std::make_unique<AstNode>(AST_MUL, std::move($1), std::move($4));
|
||||
SET_AST_NODE_LOC($$.get(), @1, @4);
|
||||
append_attr($$.get(), $3);
|
||||
} |
|
||||
|
||||
The generated AST data structure is then passed directly to the AST frontend
|
||||
that performs the actual conversion to RTLIL.
|
||||
|
|
@ -204,7 +205,7 @@ tree respectively.
|
|||
Transforming AST to RTLIL
|
||||
-------------------------
|
||||
|
||||
The AST Frontend converts a set of modules in AST representation to modules in
|
||||
The AST frontend converts a set of modules in AST representation to modules in
|
||||
RTLIL representation and adds them to the current design. This is done in two
|
||||
steps: simplification and RTLIL generation.
|
||||
|
||||
|
|
|
|||
|
|
@ -38,9 +38,7 @@ using namespace AST_INTERNAL;
|
|||
|
||||
// instantiate global variables (public API)
|
||||
namespace AST {
|
||||
std::string current_filename;
|
||||
void (*set_line_num)(int) = NULL;
|
||||
int (*get_line_num)() = NULL;
|
||||
bool sv_mode_but_global_and_used_for_literally_one_condition;
|
||||
unsigned long long astnodes = 0;
|
||||
unsigned long long astnode_count() { return astnodes; }
|
||||
}
|
||||
|
|
@ -174,6 +172,7 @@ std::string AST::type2str(AstNodeType type)
|
|||
X(AST_MODPORT)
|
||||
X(AST_MODPORTMEMBER)
|
||||
X(AST_PACKAGE)
|
||||
X(AST_IMPORT)
|
||||
X(AST_WIRETYPE)
|
||||
X(AST_TYPEDEF)
|
||||
X(AST_STRUCT)
|
||||
|
|
@ -192,7 +191,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
|
|||
if (attributes.count(id) == 0)
|
||||
return false;
|
||||
|
||||
AstNode *attr = attributes.at(id);
|
||||
auto& attr = attributes.at(id);
|
||||
if (attr->type != AST_CONSTANT)
|
||||
attr->input_error("Attribute `%s' with non-constant value!\n", id.c_str());
|
||||
|
||||
|
|
@ -201,7 +200,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
|
|||
|
||||
// create new node (AstNode constructor)
|
||||
// (the optional child arguments make it easier to create AST trees)
|
||||
AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3, AstNode *child4)
|
||||
AstNode::AstNode(AstSrcLocType loc, AstNodeType type, std::unique_ptr<AstNode> child1, std::unique_ptr<AstNode> child2, std::unique_ptr<AstNode> child3, std::unique_ptr<AstNode> child4)
|
||||
{
|
||||
static unsigned int hashidx_count = 123456789;
|
||||
hashidx_count = mkhash_xorshift(hashidx_count);
|
||||
|
|
@ -209,7 +208,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
|
|||
astnodes++;
|
||||
|
||||
this->type = type;
|
||||
filename = current_filename;
|
||||
location = loc;
|
||||
is_input = false;
|
||||
is_output = false;
|
||||
is_reg = false;
|
||||
|
|
@ -239,56 +238,73 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
|
|||
in_param = false;
|
||||
|
||||
if (child1)
|
||||
children.push_back(child1);
|
||||
children.push_back(std::move(child1));
|
||||
if (child2)
|
||||
children.push_back(child2);
|
||||
children.push_back(std::move(child2));
|
||||
if (child3)
|
||||
children.push_back(child3);
|
||||
children.push_back(std::move(child3));
|
||||
if (child4)
|
||||
children.push_back(child4);
|
||||
children.push_back(std::move(child4));
|
||||
|
||||
fixup_hierarchy_flags();
|
||||
}
|
||||
|
||||
// create a (deep recursive) copy of a node
|
||||
AstNode *AstNode::clone() const
|
||||
std::unique_ptr<AstNode> AstNode::clone() const
|
||||
{
|
||||
AstNode *that = new AstNode;
|
||||
*that = *this;
|
||||
for (auto &it : that->children)
|
||||
it = it->clone();
|
||||
for (auto &it : that->attributes)
|
||||
it.second = it.second->clone();
|
||||
|
||||
that->set_in_lvalue_flag(false);
|
||||
that->set_in_param_flag(false);
|
||||
that->fixup_hierarchy_flags(); // fixup to set flags on cloned children
|
||||
auto that = std::make_unique<AstNode>(this->location, this->type);
|
||||
cloneInto(*that.get());
|
||||
return that;
|
||||
}
|
||||
|
||||
// create a (deep recursive) copy of a node use 'other' as target root node
|
||||
void AstNode::cloneInto(AstNode *other) const
|
||||
void AstNode::cloneInto(AstNode &other) const
|
||||
{
|
||||
AstNode *tmp = clone();
|
||||
tmp->in_lvalue_from_above = other->in_lvalue_from_above;
|
||||
tmp->in_param_from_above = other->in_param_from_above;
|
||||
other->delete_children();
|
||||
*other = *tmp;
|
||||
tmp->children.clear();
|
||||
tmp->attributes.clear();
|
||||
other->fixup_hierarchy_flags();
|
||||
delete tmp;
|
||||
other.type = type;
|
||||
other.str = str;
|
||||
other.bits = bits;
|
||||
other.is_input = is_input;
|
||||
other.is_output = is_output;
|
||||
other.is_reg = is_reg;
|
||||
other.is_logic = is_logic;
|
||||
other.is_signed = is_signed;
|
||||
other.is_string = is_string;
|
||||
other.is_wand = is_wand;
|
||||
other.is_wor = is_wor;
|
||||
other.range_valid = range_valid;
|
||||
other.range_swapped = range_swapped;
|
||||
other.was_checked = was_checked;
|
||||
other.is_unsized = is_unsized;
|
||||
other.is_custom_type = is_custom_type;
|
||||
other.port_id = port_id,
|
||||
other.range_left = range_left,
|
||||
other.range_right = range_right;
|
||||
other.integer = integer;
|
||||
other.realvalue = realvalue;
|
||||
other.is_enum = is_enum;
|
||||
other.dimensions = dimensions;
|
||||
other.unpacked_dimensions = unpacked_dimensions;
|
||||
other.id2ast = id2ast;
|
||||
other.basic_prep = basic_prep;
|
||||
other.lookahead = lookahead;
|
||||
other.location = location;
|
||||
other.in_lvalue = in_lvalue;
|
||||
other.in_param = in_param;
|
||||
// Keep in_lvalue_from_above and in_param_from_above untouched
|
||||
|
||||
other.delete_children();
|
||||
for (auto& child : this->children)
|
||||
other.children.push_back(child->clone());
|
||||
for (auto& [key, val] : this->attributes)
|
||||
other.attributes[key] = (val->clone());
|
||||
// fixup to set flags on cloned children
|
||||
other.fixup_hierarchy_flags();
|
||||
}
|
||||
|
||||
// delete all children in this node
|
||||
void AstNode::delete_children()
|
||||
{
|
||||
for (auto &it : children)
|
||||
delete it;
|
||||
children.clear();
|
||||
|
||||
for (auto &it : attributes)
|
||||
delete it.second;
|
||||
attributes.clear();
|
||||
}
|
||||
|
||||
|
|
@ -423,18 +439,18 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
{
|
||||
case AST_MODULE:
|
||||
fprintf(f, "%s" "module %s(", indent.c_str(), id2vl(str).c_str());
|
||||
for (auto child : children)
|
||||
for (const auto& child : children)
|
||||
if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
|
||||
fprintf(f, "%s%s", first ? "" : ", ", id2vl(child->str).c_str());
|
||||
first = false;
|
||||
}
|
||||
fprintf(f, ");\n");
|
||||
|
||||
for (auto child : children)
|
||||
for (const auto& child : children)
|
||||
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_DEFPARAM)
|
||||
child->dumpVlog(f, indent + " ");
|
||||
else
|
||||
rem_children1.push_back(child);
|
||||
rem_children1.push_back(child.get());
|
||||
|
||||
for (auto child : rem_children1)
|
||||
if (child->type == AST_WIRE || child->type == AST_AUTOWIRE || child->type == AST_MEMORY)
|
||||
|
|
@ -470,7 +486,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
fprintf(f, "%s" "reg", (is_input || is_output) ? " " : indent.c_str());
|
||||
if (is_signed)
|
||||
fprintf(f, " signed");
|
||||
for (auto child : children) {
|
||||
for (const auto& child : children) {
|
||||
fprintf(f, " ");
|
||||
child->dumpVlog(f, "");
|
||||
}
|
||||
|
|
@ -486,7 +502,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
fprintf(f, "%s" "memory", indent.c_str());
|
||||
if (is_signed)
|
||||
fprintf(f, " signed");
|
||||
for (auto child : children) {
|
||||
for (const auto& child : children) {
|
||||
fprintf(f, " ");
|
||||
child->dumpVlog(f, "");
|
||||
if (first)
|
||||
|
|
@ -500,7 +516,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
if (0) { case AST_MEMINIT: txt = "@meminit@"; }
|
||||
if (0) { case AST_MEMWR: txt = "@memwr@"; }
|
||||
fprintf(f, "%s%s", indent.c_str(), txt.c_str());
|
||||
for (auto child : children) {
|
||||
for (const auto& child : children) {
|
||||
fprintf(f, first ? "(" : ", ");
|
||||
child->dumpVlog(f, "");
|
||||
first = false;
|
||||
|
|
@ -517,7 +533,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
else
|
||||
fprintf(f, "[%d:%d]", range_left, range_right);
|
||||
} else {
|
||||
for (auto child : children) {
|
||||
for (const auto& child : children) {
|
||||
fprintf(f, "%c", first ? '[' : ':');
|
||||
child->dumpVlog(f, "");
|
||||
first = false;
|
||||
|
|
@ -527,13 +543,13 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
break;
|
||||
|
||||
case AST_MULTIRANGE:
|
||||
for (auto child : children)
|
||||
for (const auto& child : children)
|
||||
child->dumpVlog(f, "");
|
||||
break;
|
||||
|
||||
case AST_ALWAYS:
|
||||
fprintf(f, "%s" "always @", indent.c_str());
|
||||
for (auto child : children) {
|
||||
for (const auto& child : children) {
|
||||
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
|
||||
continue;
|
||||
fprintf(f, first ? "(" : ", ");
|
||||
|
|
@ -541,7 +557,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
first = false;
|
||||
}
|
||||
fprintf(f, first ? "*\n" : ")\n");
|
||||
for (auto child : children) {
|
||||
for (const auto& child : children) {
|
||||
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
|
||||
child->dumpVlog(f, indent + " ");
|
||||
}
|
||||
|
|
@ -549,7 +565,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
|
||||
case AST_INITIAL:
|
||||
fprintf(f, "%s" "initial\n", indent.c_str());
|
||||
for (auto child : children) {
|
||||
for (const auto& child : children) {
|
||||
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
|
||||
child->dumpVlog(f, indent + " ");
|
||||
}
|
||||
|
|
@ -562,7 +578,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
fprintf(f, "posedge ");
|
||||
if (type == AST_NEGEDGE)
|
||||
fprintf(f, "negedge ");
|
||||
for (auto child : children)
|
||||
for (const auto& child : children)
|
||||
child->dumpVlog(f, "");
|
||||
break;
|
||||
|
||||
|
|
@ -574,7 +590,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
else
|
||||
fprintf(f, "%s", id2vl(str).c_str());
|
||||
}
|
||||
for (auto child : children)
|
||||
for (const auto& child : children)
|
||||
child->dumpVlog(f, "");
|
||||
break;
|
||||
|
||||
|
|
@ -602,7 +618,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
children[0]->dumpVlog(f, indent);
|
||||
} else {
|
||||
fprintf(f, "%s" "begin\n", indent.c_str());
|
||||
for (auto child : children)
|
||||
for (const auto& child : children)
|
||||
child->dumpVlog(f, indent + " ");
|
||||
fprintf(f, "%s" "end\n", indent.c_str());
|
||||
}
|
||||
|
|
@ -618,7 +634,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
children[0]->dumpVlog(f, "");
|
||||
fprintf(f, ")\n");
|
||||
for (size_t i = 1; i < children.size(); i++) {
|
||||
AstNode *child = children[i];
|
||||
const auto& child = children[i];
|
||||
child->dumpVlog(f, indent + " ");
|
||||
}
|
||||
fprintf(f, "%s" "endcase\n", indent.c_str());
|
||||
|
|
@ -627,7 +643,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
case AST_COND:
|
||||
case AST_CONDX:
|
||||
case AST_CONDZ:
|
||||
for (auto child : children) {
|
||||
for (const auto& child : children) {
|
||||
if (child->type == AST_BLOCK) {
|
||||
fprintf(f, ":\n");
|
||||
child->dumpVlog(f, indent + " ");
|
||||
|
|
@ -663,7 +679,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
case AST_CONCAT:
|
||||
fprintf(f, "{");
|
||||
for (int i = GetSize(children)-1; i >= 0; i--) {
|
||||
auto child = children[i];
|
||||
const auto& child = children[i];
|
||||
if (!first)
|
||||
fprintf(f, ", ");
|
||||
child->dumpVlog(f, "");
|
||||
|
|
@ -818,16 +834,16 @@ bool AstNode::contains(const AstNode *other) const
|
|||
{
|
||||
if (this == other)
|
||||
return true;
|
||||
for (auto child : children)
|
||||
for (const auto& child : children)
|
||||
if (child->contains(other))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// create an AST node for a constant (using a 32 bit int as value)
|
||||
AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
|
||||
std::unique_ptr<AstNode> AstNode::mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width)
|
||||
{
|
||||
AstNode *node = new AstNode(AST_CONSTANT);
|
||||
auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
|
||||
node->integer = v;
|
||||
node->is_signed = is_signed;
|
||||
for (int i = 0; i < width; i++) {
|
||||
|
|
@ -841,9 +857,9 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
|
|||
}
|
||||
|
||||
// create an AST node for a constant (using a bit vector as value)
|
||||
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
|
||||
std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
|
||||
{
|
||||
AstNode *node = new AstNode(AST_CONSTANT);
|
||||
auto node = std::make_unique<AstNode>(loc, AST_CONSTANT);
|
||||
node->is_signed = is_signed;
|
||||
node->bits = v;
|
||||
for (size_t i = 0; i < 32; i++) {
|
||||
|
|
@ -859,15 +875,15 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
|
|||
return node;
|
||||
}
|
||||
|
||||
AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
|
||||
std::unique_ptr<AstNode> AstNode::mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed)
|
||||
{
|
||||
return mkconst_bits(v, is_signed, false);
|
||||
return mkconst_bits(loc, v, is_signed, false);
|
||||
}
|
||||
|
||||
// create an AST node for a constant (using a string in bit vector form as value)
|
||||
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
|
||||
std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v)
|
||||
{
|
||||
AstNode *node = mkconst_str(RTLIL::Const(v).decode_string());
|
||||
auto node = mkconst_str(loc, RTLIL::Const(v).decode_string());
|
||||
while (GetSize(node->bits) < GetSize(v))
|
||||
node->bits.push_back(RTLIL::State::S0);
|
||||
log_assert(node->bits == v);
|
||||
|
|
@ -875,14 +891,14 @@ AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
|
|||
}
|
||||
|
||||
// create an AST node for a constant (using a string as value)
|
||||
AstNode *AstNode::mkconst_str(const std::string &str)
|
||||
std::unique_ptr<AstNode> AstNode::mkconst_str(AstSrcLocType loc, const std::string &str)
|
||||
{
|
||||
AstNode *node;
|
||||
std::unique_ptr<AstNode> node;
|
||||
|
||||
// LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered
|
||||
// equivalent to the ASCII NUL ("\0")
|
||||
if (str.empty()) {
|
||||
node = AstNode::mkconst_int(0, false, 8);
|
||||
node = AstNode::mkconst_int(loc, 0, false, 8);
|
||||
} else {
|
||||
std::vector<RTLIL::State> data;
|
||||
data.reserve(str.size() * 8);
|
||||
|
|
@ -893,7 +909,7 @@ AstNode *AstNode::mkconst_str(const std::string &str)
|
|||
ch = ch >> 1;
|
||||
}
|
||||
}
|
||||
node = AstNode::mkconst_bits(data, false);
|
||||
node = AstNode::mkconst_bits(loc, data, false);
|
||||
}
|
||||
|
||||
node->is_string = true;
|
||||
|
|
@ -902,18 +918,19 @@ AstNode *AstNode::mkconst_str(const std::string &str)
|
|||
}
|
||||
|
||||
// create a temporary register
|
||||
AstNode *AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed)
|
||||
std::unique_ptr<AstNode> AstNode::mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed)
|
||||
{
|
||||
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true)));
|
||||
wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
|
||||
auto wire_owned = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, mkconst_int(loc, range_left, true), mkconst_int(loc, range_right, true)));
|
||||
auto* wire = wire_owned.get();
|
||||
wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++);
|
||||
if (nosync)
|
||||
wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
|
||||
wire->set_attribute(ID::nosync, AstNode::mkconst_int(loc, 1, false));
|
||||
wire->is_signed = is_signed;
|
||||
wire->is_logic = true;
|
||||
mod->children.push_back(wire);
|
||||
mod->children.push_back(std::move(wire_owned));
|
||||
while (wire->simplify(true, 1, -1, false)) { }
|
||||
|
||||
AstNode *ident = new AstNode(AST_IDENTIFIER);
|
||||
auto ident = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
|
||||
ident->str = wire->str;
|
||||
ident->id2ast = wire;
|
||||
|
||||
|
|
@ -967,10 +984,9 @@ RTLIL::Const AstNode::asParaConst() const
|
|||
{
|
||||
if (type == AST_REALVALUE)
|
||||
{
|
||||
AstNode *strnode = AstNode::mkconst_str(stringf("%f", realvalue));
|
||||
auto strnode = AstNode::mkconst_str(location, stringf("%f", realvalue));
|
||||
RTLIL::Const val = strnode->asAttrConst();
|
||||
val.flags |= RTLIL::CONST_FLAG_REAL;
|
||||
delete strnode;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
|
@ -1070,7 +1086,7 @@ RTLIL::Const AstNode::realAsConst(int width)
|
|||
|
||||
std::string AstNode::loc_string() const
|
||||
{
|
||||
return stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);
|
||||
return stringf("%s:%d.%d-%d.%d", location.begin.filename->c_str(), location.begin.line, location.begin.column, location.end.line, location.end.column);
|
||||
}
|
||||
|
||||
void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
|
||||
|
|
@ -1078,7 +1094,7 @@ void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
|
|||
obj->attributes[ID::src] = ast->loc_string();
|
||||
}
|
||||
|
||||
static bool param_has_no_default(const AstNode *param) {
|
||||
static bool param_has_no_default(const AstNode* param) {
|
||||
const auto &children = param->children;
|
||||
log_assert(param->type == AST_PARAMETER);
|
||||
log_assert(children.size() <= 2);
|
||||
|
|
@ -1086,7 +1102,7 @@ static bool param_has_no_default(const AstNode *param) {
|
|||
(children.size() == 1 && children[0]->type == AST_RANGE);
|
||||
}
|
||||
|
||||
static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false)
|
||||
static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, std::unique_ptr<AstNode> original_ast = NULL, bool quiet = false)
|
||||
{
|
||||
log_assert(current_scope.empty());
|
||||
log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
|
||||
|
|
@ -1100,15 +1116,15 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
|
|||
AstModule *module = new AstModule;
|
||||
current_module = module;
|
||||
|
||||
module->ast = NULL;
|
||||
module->ast = nullptr;
|
||||
module->name = ast->str;
|
||||
set_src_attr(module, ast);
|
||||
module->set_bool_attribute(ID::cells_not_processed);
|
||||
|
||||
current_ast_mod = ast;
|
||||
AstNode *ast_before_simplify;
|
||||
std::unique_ptr<AstNode> ast_before_simplify;
|
||||
if (original_ast != NULL)
|
||||
ast_before_simplify = original_ast;
|
||||
ast_before_simplify = std::move(original_ast);
|
||||
else
|
||||
ast_before_simplify = ast->clone();
|
||||
|
||||
|
|
@ -1125,15 +1141,15 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
|
|||
|
||||
if (!defer)
|
||||
{
|
||||
for (const AstNode *node : ast->children)
|
||||
if (node->type == AST_PARAMETER && param_has_no_default(node))
|
||||
for (auto& node : ast->children)
|
||||
if (node->type == AST_PARAMETER && param_has_no_default(node.get()))
|
||||
node->input_error("Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str());
|
||||
|
||||
bool blackbox_module = flag_lib;
|
||||
|
||||
if (!blackbox_module && !flag_noblackbox) {
|
||||
blackbox_module = true;
|
||||
for (auto child : ast->children) {
|
||||
for (const auto& child : ast->children) {
|
||||
if (child->type == AST_WIRE && (child->is_input || child->is_output))
|
||||
continue;
|
||||
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
|
||||
|
|
@ -1163,36 +1179,33 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
|
|||
ast->dumpVlog(NULL, " ");
|
||||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
|
||||
for (auto &attr: ast->attributes)
|
||||
log_assert((bool)attr.second.get());
|
||||
if (flag_nowb && ast->attributes.count(ID::whitebox)) {
|
||||
delete ast->attributes.at(ID::whitebox);
|
||||
ast->attributes.erase(ID::whitebox);
|
||||
}
|
||||
|
||||
for (auto &attr: ast->attributes)
|
||||
log_assert((bool)attr.second.get());
|
||||
if (ast->attributes.count(ID::lib_whitebox)) {
|
||||
if (!flag_lib || flag_nowb) {
|
||||
delete ast->attributes.at(ID::lib_whitebox);
|
||||
ast->attributes.erase(ID::lib_whitebox);
|
||||
} else {
|
||||
if (ast->attributes.count(ID::whitebox)) {
|
||||
delete ast->attributes.at(ID::whitebox);
|
||||
ast->attributes.erase(ID::whitebox);
|
||||
}
|
||||
AstNode *n = ast->attributes.at(ID::lib_whitebox);
|
||||
ast->set_attribute(ID::whitebox, n);
|
||||
ast->attributes.erase(ID::lib_whitebox);
|
||||
if (flag_lib && !flag_nowb) {
|
||||
ast->attributes[ID::whitebox] = std::move(
|
||||
ast->attributes[ID::lib_whitebox]
|
||||
);
|
||||
}
|
||||
ast->attributes.erase(ID::lib_whitebox);
|
||||
}
|
||||
for (auto &attr: ast->attributes)
|
||||
log_assert((bool)attr.second.get());
|
||||
|
||||
if (!blackbox_module && ast->attributes.count(ID::blackbox)) {
|
||||
AstNode *n = ast->attributes.at(ID::blackbox);
|
||||
auto& n = ast->attributes.at(ID::blackbox);
|
||||
if (n->type != AST_CONSTANT)
|
||||
ast->input_error("Got blackbox attribute with non-constant value!\n");
|
||||
blackbox_module = n->asBool();
|
||||
}
|
||||
|
||||
if (blackbox_module && ast->attributes.count(ID::whitebox)) {
|
||||
AstNode *n = ast->attributes.at(ID::whitebox);
|
||||
auto& n = ast->attributes.at(ID::whitebox);
|
||||
if (n->type != AST_CONSTANT)
|
||||
ast->input_error("Got whitebox attribute with non-constant value!\n");
|
||||
blackbox_module = !n->asBool();
|
||||
|
|
@ -1200,62 +1213,59 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
|
|||
|
||||
if (ast->attributes.count(ID::noblackbox)) {
|
||||
if (blackbox_module) {
|
||||
AstNode *n = ast->attributes.at(ID::noblackbox);
|
||||
auto& n = ast->attributes.at(ID::noblackbox);
|
||||
if (n->type != AST_CONSTANT)
|
||||
ast->input_error("Got noblackbox attribute with non-constant value!\n");
|
||||
blackbox_module = !n->asBool();
|
||||
}
|
||||
delete ast->attributes.at(ID::noblackbox);
|
||||
ast->attributes.erase(ID::noblackbox);
|
||||
}
|
||||
|
||||
for (auto &attr: ast->attributes)
|
||||
log_assert((bool)attr.second.get());
|
||||
if (blackbox_module)
|
||||
{
|
||||
if (ast->attributes.count(ID::whitebox)) {
|
||||
delete ast->attributes.at(ID::whitebox);
|
||||
ast->attributes.erase(ID::whitebox);
|
||||
}
|
||||
|
||||
if (ast->attributes.count(ID::lib_whitebox)) {
|
||||
delete ast->attributes.at(ID::lib_whitebox);
|
||||
ast->attributes.erase(ID::lib_whitebox);
|
||||
}
|
||||
|
||||
std::vector<AstNode*> new_children;
|
||||
for (auto child : ast->children) {
|
||||
std::vector<std::unique_ptr<AstNode>> new_children;
|
||||
for (auto& child : ast->children) {
|
||||
if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
|
||||
new_children.push_back(child);
|
||||
new_children.push_back(std::move(child));
|
||||
} else if (child->type == AST_PARAMETER) {
|
||||
new_children.push_back(child);
|
||||
new_children.push_back(std::move(child));
|
||||
} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
|
||||
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
|
||||
new_children.push_back(child);
|
||||
} else {
|
||||
delete child;
|
||||
new_children.push_back(std::move(child));
|
||||
}
|
||||
}
|
||||
|
||||
ast->children.swap(new_children);
|
||||
|
||||
if (ast->attributes.count(ID::blackbox) == 0) {
|
||||
ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false));
|
||||
ast->set_attribute(ID::blackbox, AstNode::mkconst_int(ast->location, 1, false));
|
||||
}
|
||||
}
|
||||
|
||||
ignoreThisSignalsInInitial = RTLIL::SigSpec();
|
||||
|
||||
for (auto &attr : ast->attributes) {
|
||||
log_assert((bool)attr.second.get());
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
ast->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
module->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
AstNode *node = ast->children[i];
|
||||
const auto& node = ast->children[i];
|
||||
if (node->type == AST_WIRE || node->type == AST_MEMORY)
|
||||
node->genRTLIL();
|
||||
}
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
AstNode *node = ast->children[i];
|
||||
const auto& node = ast->children[i];
|
||||
if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
|
||||
node->genRTLIL();
|
||||
}
|
||||
|
|
@ -1263,7 +1273,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
|
|||
ignoreThisSignalsInInitial.sort_and_unify();
|
||||
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
AstNode *node = ast->children[i];
|
||||
const auto& node = ast->children[i];
|
||||
if (node->type == AST_INITIAL)
|
||||
node->genRTLIL();
|
||||
}
|
||||
|
|
@ -1277,14 +1287,14 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
|
|||
continue;
|
||||
module->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
for (const AstNode *node : ast->children)
|
||||
for (const auto& node : ast->children)
|
||||
if (node->type == AST_PARAMETER)
|
||||
current_module->avail_parameters(node->str);
|
||||
}
|
||||
|
||||
if (ast->type == AST_INTERFACE)
|
||||
module->set_bool_attribute(ID::is_interface);
|
||||
module->ast = ast_before_simplify;
|
||||
module->ast = std::move(ast_before_simplify);
|
||||
module->nolatches = flag_nolatches;
|
||||
module->nomeminit = flag_nomeminit;
|
||||
module->nomem2reg = flag_nomem2reg;
|
||||
|
|
@ -1311,8 +1321,8 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
|
|||
RTLIL::Module *
|
||||
AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
|
||||
RTLIL::Module *old_module,
|
||||
AstNode *new_ast,
|
||||
AstNode *original_ast)
|
||||
AST::AstNode *new_ast,
|
||||
std::unique_ptr<AstNode> original_ast)
|
||||
{
|
||||
// The old module will be deleted. Rename and mark for deletion, using
|
||||
// a static counter to make sure we get a unique name.
|
||||
|
|
@ -1335,7 +1345,7 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
|
|||
}
|
||||
|
||||
// Generate RTLIL from AST for the new module and add to the design:
|
||||
RTLIL::Module* new_module = process_module(design, new_ast, false, original_ast);
|
||||
RTLIL::Module* new_module = process_module(design, new_ast, false, std::move(original_ast));
|
||||
|
||||
if (is_top)
|
||||
new_module->set_bool_attribute(ID::top);
|
||||
|
|
@ -1347,17 +1357,17 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design,
|
|||
static void rename_in_package_stmts(AstNode *pkg)
|
||||
{
|
||||
std::unordered_set<std::string> idents;
|
||||
for (AstNode *item : pkg->children)
|
||||
for (auto& item : pkg->children)
|
||||
idents.insert(item->str);
|
||||
std::function<void(AstNode*)> rename =
|
||||
[&rename, &idents, pkg](AstNode *node) {
|
||||
for (AstNode *child : node->children) {
|
||||
std::function<void(std::unique_ptr<AstNode>&)> rename =
|
||||
[&rename, &idents, pkg](std::unique_ptr<AstNode>& node) {
|
||||
for (auto& child : node->children) {
|
||||
if (idents.count(child->str))
|
||||
child->str = pkg->str + "::" + child->str.substr(1);
|
||||
rename(child);
|
||||
}
|
||||
};
|
||||
for (AstNode *item : pkg->children)
|
||||
for (auto& item : pkg->children)
|
||||
if (item->type == AST_FUNCTION || item->type == AST_TASK)
|
||||
rename(item);
|
||||
}
|
||||
|
|
@ -1390,17 +1400,17 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
|
|||
ast->fixup_hierarchy_flags(true);
|
||||
|
||||
log_assert(current_ast->type == AST_DESIGN);
|
||||
for (AstNode *child : current_ast->children)
|
||||
for (const auto& child : current_ast->children)
|
||||
{
|
||||
if (child->type == AST_MODULE || child->type == AST_INTERFACE)
|
||||
{
|
||||
for (auto n : design->verilog_globals)
|
||||
for (auto& n : design->verilog_globals)
|
||||
child->children.push_back(n->clone());
|
||||
|
||||
// append nodes from previous packages using package-qualified names
|
||||
for (auto &n : design->verilog_packages) {
|
||||
for (auto& n : design->verilog_packages) {
|
||||
for (auto &o : n->children) {
|
||||
AstNode *cloned_node = o->clone();
|
||||
auto cloned_node = o->clone();
|
||||
// log("cloned node %s\n", type2str(cloned_node->type).c_str());
|
||||
if (cloned_node->type == AST_ENUM) {
|
||||
for (auto &e : cloned_node->children) {
|
||||
|
|
@ -1410,7 +1420,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
|
|||
} else {
|
||||
cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1);
|
||||
}
|
||||
child->children.push_back(cloned_node);
|
||||
child->children.push_back(std::move(cloned_node));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1419,8 +1429,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
|
|||
|
||||
bool defer_local = defer;
|
||||
if (!defer_local)
|
||||
for (const AstNode *node : child->children)
|
||||
if (node->type == AST_PARAMETER && param_has_no_default(node))
|
||||
for (const auto& node : child->children)
|
||||
if (node->type == AST_PARAMETER && param_has_no_default(node.get()))
|
||||
{
|
||||
log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str());
|
||||
defer_local = true;
|
||||
|
|
@ -1434,7 +1444,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
|
|||
if (design->has(child->str)) {
|
||||
RTLIL::Module *existing_mod = design->module(child->str);
|
||||
if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) {
|
||||
log_file_error(child->filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str());
|
||||
log_file_error(*child->location.begin.filename, child->location.begin.line, "Re-definition of module `%s'!\n", child->str.c_str());
|
||||
} else if (nooverwrite) {
|
||||
log("Ignoring re-definition of module `%s' at %s.\n",
|
||||
child->str.c_str(), child->loc_string().c_str());
|
||||
|
|
@ -1447,13 +1457,13 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
|
|||
}
|
||||
}
|
||||
|
||||
process_module(design, child, defer_local);
|
||||
process_module(design, child.get(), defer_local);
|
||||
current_ast_mod = nullptr;
|
||||
}
|
||||
else if (child->type == AST_PACKAGE) {
|
||||
// process enum/other declarations
|
||||
child->simplify(true, 1, -1, false);
|
||||
rename_in_package_stmts(child);
|
||||
rename_in_package_stmts(child.get());
|
||||
design->verilog_packages.push_back(child->clone());
|
||||
current_scope.clear();
|
||||
}
|
||||
|
|
@ -1470,16 +1480,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump
|
|||
current_scope.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AstModule destructor
|
||||
AstModule::~AstModule()
|
||||
{
|
||||
if (ast != NULL)
|
||||
delete ast;
|
||||
}
|
||||
|
||||
|
||||
// An interface port with modport is specified like this:
|
||||
// <interface_name>.<modport_name>
|
||||
// This function splits the interface_name from the modport_name, and fails if it is not a valid combination
|
||||
|
|
@ -1516,7 +1519,7 @@ AstNode * AST::find_modport(AstNode *intf, std::string name)
|
|||
for (auto &ch : intf->children)
|
||||
if (ch->type == AST_MODPORT)
|
||||
if (ch->str == name) // Modport found
|
||||
return ch;
|
||||
return ch.get();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1524,7 +1527,8 @@ AstNode * AST::find_modport(AstNode *intf, std::string name)
|
|||
void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport)
|
||||
{
|
||||
for (auto w : intfmodule->wires()){
|
||||
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true)));
|
||||
auto loc = module_ast->location;
|
||||
auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
|
||||
std::string origname = log_id(w->name);
|
||||
std::string newname = intfname + "." + origname;
|
||||
wire->str = newname;
|
||||
|
|
@ -1543,16 +1547,13 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule
|
|||
}
|
||||
}
|
||||
if (found_in_modport) {
|
||||
module_ast->children.push_back(wire);
|
||||
}
|
||||
else { // If not found in modport, do not create port
|
||||
delete wire;
|
||||
module_ast->children.push_back(std::move(wire));
|
||||
}
|
||||
}
|
||||
else { // If no modport, set inout
|
||||
wire->is_input = true;
|
||||
wire->is_output = true;
|
||||
module_ast->children.push_back(wire);
|
||||
module_ast->children.push_back(std::move(wire));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1570,7 +1571,7 @@ bool AstModule::reprocess_if_necessary(RTLIL::Design *design)
|
|||
log("Reprocessing module %s because instantiated module %s has become available.\n",
|
||||
log_id(name), log_id(modname));
|
||||
loadconfig();
|
||||
process_and_replace_module(design, this, ast, NULL);
|
||||
process_and_replace_module(design, this, ast.get(), NULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1583,32 +1584,33 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
{
|
||||
loadconfig();
|
||||
|
||||
AstNode *new_ast = ast->clone();
|
||||
auto new_ast = ast->clone();
|
||||
auto loc = ast->location;
|
||||
for (auto &intf : local_interfaces) {
|
||||
std::string intfname = intf.first.str();
|
||||
RTLIL::Module *intfmodule = intf.second;
|
||||
for (auto w : intfmodule->wires()){
|
||||
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true)));
|
||||
auto wire = std::make_unique<AstNode>(loc, AST_WIRE, std::make_unique<AstNode>(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true)));
|
||||
std::string newname = log_id(w->name);
|
||||
newname = intfname + "." + newname;
|
||||
wire->str = newname;
|
||||
new_ast->children.push_back(wire);
|
||||
new_ast->children.push_back(std::move(wire));
|
||||
}
|
||||
}
|
||||
|
||||
AstNode *ast_before_replacing_interface_ports = new_ast->clone();
|
||||
auto ast_before_replacing_interface_ports = new_ast->clone();
|
||||
|
||||
// Explode all interface ports. Note this will only have an effect on 'top
|
||||
// level' modules. Other sub-modules will have their interface ports
|
||||
// exploded via the derive(..) function
|
||||
for (size_t i =0; i<new_ast->children.size(); i++)
|
||||
{
|
||||
AstNode *ch2 = new_ast->children[i];
|
||||
const auto& ch2 = new_ast->children[i];
|
||||
if (ch2->type == AST_INTERFACEPORT) { // Is an interface port
|
||||
std::string name_port = ch2->str; // Name of the interface port
|
||||
if (ch2->children.size() > 0) {
|
||||
for(size_t j=0; j<ch2->children.size();j++) {
|
||||
AstNode *ch = ch2->children[j];
|
||||
const auto& ch = ch2->children[j];
|
||||
if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface
|
||||
std::pair<std::string,std::string> res = split_modport_from_type(ch->str);
|
||||
std::string interface_type = res.first;
|
||||
|
|
@ -1616,11 +1618,11 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
if (design->module(interface_type) != nullptr) {
|
||||
// Add a cell to the module corresponding to the interface port such that
|
||||
// it can further propagated down if needed:
|
||||
AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE);
|
||||
auto celltype_for_intf = std::make_unique<AstNode>(loc, AST_CELLTYPE);
|
||||
celltype_for_intf->str = interface_type;
|
||||
AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf);
|
||||
auto cell_for_intf = std::make_unique<AstNode>(loc, AST_CELL, std::move(celltype_for_intf));
|
||||
cell_for_intf->str = name_port + "_inst_from_top_dummy";
|
||||
new_ast->children.push_back(cell_for_intf);
|
||||
new_ast->children.push_back(std::move(cell_for_intf));
|
||||
|
||||
// Get all members of this non-overridden dummy interface instance:
|
||||
RTLIL::Module *intfmodule = design->module(interface_type); // All interfaces should at this point in time (assuming
|
||||
|
|
@ -1628,9 +1630,9 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
// present in design->modules_
|
||||
AstModule *ast_module_of_interface = (AstModule*)intfmodule;
|
||||
std::string interface_modport_compare_str = "\\" + interface_modport;
|
||||
AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport
|
||||
AstNode *modport = find_modport(ast_module_of_interface->ast.get(), interface_modport_compare_str); // modport == NULL if no modport
|
||||
// Iterate over all wires in the interface and add them to the module:
|
||||
explode_interface_port(new_ast, intfmodule, name_port, modport);
|
||||
explode_interface_port(new_ast.get(), intfmodule, name_port, modport);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1642,9 +1644,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
// Generate RTLIL from AST for the new module and add to the design,
|
||||
// renaming this module to move it out of the way.
|
||||
RTLIL::Module* new_module =
|
||||
process_and_replace_module(design, this, new_ast, ast_before_replacing_interface_ports);
|
||||
|
||||
delete new_ast;
|
||||
process_and_replace_module(design, this, new_ast.get(), std::move(ast_before_replacing_interface_ports));
|
||||
|
||||
// Set the attribute "interfaces_replaced_in_module" so that it does not happen again.
|
||||
new_module->set_bool_attribute(ID::interfaces_replaced_in_module);
|
||||
|
|
@ -1654,7 +1654,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
// This method is used to explode the interface when the interface is a port of the module (not instantiated inside)
|
||||
RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool /*mayfail*/)
|
||||
{
|
||||
AstNode *new_ast = NULL;
|
||||
std::unique_ptr<AstNode> new_ast = NULL;
|
||||
std::string modname = derive_common(design, parameters, &new_ast);
|
||||
|
||||
// Since interfaces themselves may be instantiated with different parameters,
|
||||
|
|
@ -1690,14 +1690,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
if (modports.count(intfname) > 0) {
|
||||
std::string interface_modport = modports.at(intfname).str();
|
||||
AstModule *ast_module_of_interface = (AstModule*)intfmodule;
|
||||
AstNode *ast_node_of_interface = ast_module_of_interface->ast;
|
||||
AstNode *ast_node_of_interface = ast_module_of_interface->ast.get();
|
||||
modport = find_modport(ast_node_of_interface, interface_modport);
|
||||
}
|
||||
// Iterate over all wires in the interface and add them to the module:
|
||||
explode_interface_port(new_ast, intfmodule, intfname, modport);
|
||||
explode_interface_port(new_ast.get(), intfmodule, intfname, modport);
|
||||
}
|
||||
|
||||
process_module(design, new_ast, false);
|
||||
process_module(design, new_ast.get(), false);
|
||||
design->module(modname)->check();
|
||||
|
||||
RTLIL::Module* mod = design->module(modname);
|
||||
|
|
@ -1734,7 +1734,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
|
||||
}
|
||||
|
||||
delete new_ast;
|
||||
return modname;
|
||||
}
|
||||
|
||||
|
|
@ -1743,18 +1742,17 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
|
|||
{
|
||||
bool quiet = lib || attributes.count(ID::blackbox) || attributes.count(ID::whitebox);
|
||||
|
||||
AstNode *new_ast = NULL;
|
||||
std::unique_ptr<AstNode> new_ast = NULL;
|
||||
std::string modname = derive_common(design, parameters, &new_ast, quiet);
|
||||
|
||||
if (!design->has(modname) && new_ast) {
|
||||
new_ast->str = modname;
|
||||
process_module(design, new_ast, false, NULL, quiet);
|
||||
process_module(design, new_ast.get(), false, NULL, quiet);
|
||||
design->module(modname)->check();
|
||||
} else if (!quiet) {
|
||||
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
|
||||
}
|
||||
|
||||
delete new_ast;
|
||||
return modname;
|
||||
}
|
||||
|
||||
|
|
@ -1784,7 +1782,7 @@ std::string AST::derived_module_name(std::string stripped_name, const std::vecto
|
|||
}
|
||||
|
||||
// create a new parametric module (when needed) and return the name of the generated module
|
||||
std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, AstNode **new_ast_out, bool quiet)
|
||||
std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, std::unique_ptr<AstNode>* new_ast_out, bool quiet)
|
||||
{
|
||||
std::string stripped_name = name.str();
|
||||
(*new_ast_out) = nullptr;
|
||||
|
|
@ -1794,7 +1792,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
|
|||
|
||||
int para_counter = 0;
|
||||
std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> named_parameters;
|
||||
for (const auto child : ast->children) {
|
||||
for (const auto& child : ast->children) {
|
||||
if (child->type != AST_PARAMETER)
|
||||
continue;
|
||||
para_counter++;
|
||||
|
|
@ -1828,12 +1826,13 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
|
|||
pool<IdString> rewritten;
|
||||
rewritten.reserve(GetSize(parameters));
|
||||
|
||||
AstNode *new_ast = ast->clone();
|
||||
auto new_ast = ast->clone();
|
||||
auto loc = ast->location;
|
||||
if (!new_ast->attributes.count(ID::hdlname))
|
||||
new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name.substr(1)));
|
||||
new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(loc, stripped_name.substr(1)));
|
||||
|
||||
para_counter = 0;
|
||||
for (auto child : new_ast->children) {
|
||||
for (auto& child : new_ast->children) {
|
||||
if (child->type != AST_PARAMETER)
|
||||
continue;
|
||||
para_counter++;
|
||||
|
|
@ -1851,16 +1850,15 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
|
|||
}
|
||||
continue;
|
||||
rewrite_parameter:
|
||||
if (param_has_no_default(child))
|
||||
if (param_has_no_default(child.get()))
|
||||
child->children.insert(child->children.begin(), nullptr);
|
||||
delete child->children.at(0);
|
||||
if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) {
|
||||
child->children[0] = new AstNode(AST_REALVALUE);
|
||||
child->children[0] = std::make_unique<AstNode>(loc, AST_REALVALUE);
|
||||
child->children[0]->realvalue = std::stod(it->second.decode_string());
|
||||
} else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0)
|
||||
child->children[0] = AstNode::mkconst_str(it->second.decode_string());
|
||||
child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string());
|
||||
else
|
||||
child->children[0] = AstNode::mkconst_bits(it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0);
|
||||
child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0);
|
||||
rewritten.insert(it->first);
|
||||
}
|
||||
|
||||
|
|
@ -1868,17 +1866,17 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
|
|||
for (const auto ¶m : parameters) {
|
||||
if (rewritten.count(param.first))
|
||||
continue;
|
||||
AstNode *defparam = new AstNode(AST_DEFPARAM, new AstNode(AST_IDENTIFIER));
|
||||
auto defparam = std::make_unique<AstNode>(loc, AST_DEFPARAM, std::make_unique<AstNode>(loc, AST_IDENTIFIER));
|
||||
defparam->children[0]->str = param.first.str();
|
||||
if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0)
|
||||
defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string()));
|
||||
defparam->children.push_back(AstNode::mkconst_str(loc, param.second.decode_string()));
|
||||
else
|
||||
defparam->children.push_back(AstNode::mkconst_bits(param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0));
|
||||
new_ast->children.push_back(defparam);
|
||||
defparam->children.push_back(AstNode::mkconst_bits(loc, param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0));
|
||||
new_ast->children.push_back(std::move(defparam));
|
||||
}
|
||||
|
||||
new_ast->fixup_hierarchy_flags(true);
|
||||
(*new_ast_out) = new_ast;
|
||||
new_ast_out->reset(new_ast.release());
|
||||
return modname;
|
||||
}
|
||||
|
||||
|
|
@ -1928,7 +1926,7 @@ void AstNode::input_error(const char *format, ...) const
|
|||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
logv_file_error(filename, location.first_line, format, ap);
|
||||
logv_file_error(*location.begin.filename, location.begin.line, format, ap);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/fmt.h"
|
||||
#include "frontends/verilog/verilog_location.h"
|
||||
#include <stdint.h>
|
||||
#include <set>
|
||||
|
||||
|
|
@ -153,6 +154,7 @@ namespace AST
|
|||
AST_MODPORT,
|
||||
AST_MODPORTMEMBER,
|
||||
AST_PACKAGE,
|
||||
AST_IMPORT,
|
||||
|
||||
AST_WIRETYPE,
|
||||
AST_TYPEDEF,
|
||||
|
|
@ -162,12 +164,7 @@ namespace AST
|
|||
AST_BIND
|
||||
};
|
||||
|
||||
struct AstSrcLocType {
|
||||
unsigned int first_line, last_line;
|
||||
unsigned int first_column, last_column;
|
||||
AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {}
|
||||
AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {}
|
||||
};
|
||||
using AstSrcLocType = Location;
|
||||
|
||||
// convert an node type to a string (e.g. for debug output)
|
||||
std::string type2str(AstNodeType type);
|
||||
|
|
@ -183,10 +180,10 @@ namespace AST
|
|||
AstNodeType type;
|
||||
|
||||
// the list of child nodes for this node
|
||||
std::vector<AstNode*> children;
|
||||
std::vector<std::unique_ptr<AstNode>> children;
|
||||
|
||||
// the list of attributes assigned to this node
|
||||
std::map<RTLIL::IdString, AstNode*> attributes;
|
||||
std::map<RTLIL::IdString, std::unique_ptr<AstNode>> attributes;
|
||||
bool get_bool_attribute(RTLIL::IdString id);
|
||||
|
||||
// node content - most of it is unused in most node types
|
||||
|
|
@ -212,7 +209,7 @@ namespace AST
|
|||
int unpacked_dimensions;
|
||||
|
||||
// this is set by simplify and used during RTLIL generation
|
||||
AstNode *id2ast;
|
||||
AstNode* id2ast;
|
||||
|
||||
// this is used by simplify to detect if basic analysis has been performed already on the node
|
||||
bool basic_prep;
|
||||
|
|
@ -223,7 +220,6 @@ namespace AST
|
|||
// this is the original sourcecode location that resulted in this AST node
|
||||
// it is automatically set by the constructor using AST::current_filename and
|
||||
// the AST::get_line_num() callback function.
|
||||
std::string filename;
|
||||
AstSrcLocType location;
|
||||
|
||||
// are we embedded in an lvalue, param?
|
||||
|
|
@ -234,9 +230,9 @@ namespace AST
|
|||
bool in_param_from_above;
|
||||
|
||||
// creating and deleting nodes
|
||||
AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr);
|
||||
AstNode *clone() const;
|
||||
void cloneInto(AstNode *other) const;
|
||||
AstNode(AstSrcLocType loc, AstNodeType type = AST_NONE, std::unique_ptr<AstNode> child1 = nullptr, std::unique_ptr<AstNode> child2 = nullptr, std::unique_ptr<AstNode> child3 = nullptr, std::unique_ptr<AstNode> child4 = nullptr);
|
||||
std::unique_ptr<AstNode> clone() const;
|
||||
void cloneInto(AstNode &other) const;
|
||||
void delete_children();
|
||||
~AstNode();
|
||||
|
||||
|
|
@ -265,14 +261,14 @@ namespace AST
|
|||
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
|
||||
bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint);
|
||||
void replace_result_wire_name_in_function(const std::string &from, const std::string &to);
|
||||
AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
|
||||
std::unique_ptr<AstNode> readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
|
||||
void expand_genblock(const std::string &prefix);
|
||||
void label_genblks(std::set<std::string>& existing, int &counter);
|
||||
void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
|
||||
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
|
||||
bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block);
|
||||
bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block);
|
||||
bool mem2reg_check(pool<AstNode*> &mem2reg_set);
|
||||
void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);
|
||||
void mem2reg_remove(pool<AstNode*> &mem2reg_set);
|
||||
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
|
||||
bool detect_latch(const std::string &var);
|
||||
const RTLIL::Module* lookup_cell_module();
|
||||
|
|
@ -288,7 +284,7 @@ namespace AST
|
|||
};
|
||||
bool has_const_only_constructs();
|
||||
bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);
|
||||
AstNode *eval_const_function(AstNode *fcall, bool must_succeed);
|
||||
std::unique_ptr<AstNode> eval_const_function(AstNode *fcall, bool must_succeed);
|
||||
bool is_simple_const_expr();
|
||||
|
||||
// helper for parsing format strings
|
||||
|
|
@ -305,29 +301,30 @@ namespace AST
|
|||
std::vector<RTLIL::Binding *> genBindings() const;
|
||||
|
||||
// used by genRTLIL() for detecting expression width and sign
|
||||
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);
|
||||
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL);
|
||||
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
|
||||
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
|
||||
|
||||
// create RTLIL code for this AST node
|
||||
// for expressions the resulting signal vector is returned
|
||||
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
|
||||
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
|
||||
RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
|
||||
RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = nullptr);
|
||||
|
||||
// compare AST nodes
|
||||
bool operator==(const AstNode &other) const;
|
||||
bool operator!=(const AstNode &other) const;
|
||||
bool contains(const AstNode *other) const;
|
||||
AstNode operator=(AstNode) = delete;
|
||||
|
||||
// helper functions for creating AST nodes for constants
|
||||
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
|
||||
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
|
||||
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
|
||||
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
|
||||
static AstNode *mkconst_str(const std::string &str);
|
||||
static std::unique_ptr<AstNode> mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width = 32);
|
||||
static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
|
||||
static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed);
|
||||
static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v);
|
||||
static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::string &str);
|
||||
|
||||
// helper function to create an AST node for a temporary register
|
||||
AstNode *mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
|
||||
std::unique_ptr<AstNode> mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
|
||||
|
||||
// helper function for creating sign-extended const objects
|
||||
RTLIL::Const bitsAsConst(int width, bool is_signed);
|
||||
|
|
@ -356,12 +353,12 @@ namespace AST
|
|||
|
||||
// helper to clone the node with some of its subexpressions replaced with zero (this is used
|
||||
// to evaluate widths of dynamic ranges)
|
||||
AstNode *clone_at_zero();
|
||||
std::unique_ptr<AstNode> clone_at_zero();
|
||||
|
||||
void set_attribute(RTLIL::IdString key, AstNode *node)
|
||||
void set_attribute(RTLIL::IdString key, std::unique_ptr<AstNode> node)
|
||||
{
|
||||
attributes[key] = node;
|
||||
node->set_in_param_flag(true);
|
||||
attributes[key] = std::move(node);
|
||||
}
|
||||
|
||||
// helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag
|
||||
|
|
@ -377,7 +374,7 @@ namespace AST
|
|||
void fixup_hierarchy_flags(bool force_descend = false);
|
||||
|
||||
// helpers for indexing
|
||||
AstNode *make_index_range(AstNode *node, bool unpacked_range = false);
|
||||
std::unique_ptr<AstNode> make_index_range(AstNode *node, bool unpacked_range = false);
|
||||
AstNode *get_struct_member() const;
|
||||
|
||||
// helper to print errors from simplify/genrtlil code
|
||||
|
|
@ -391,12 +388,11 @@ namespace AST
|
|||
// parametric modules are supported directly by the AST library
|
||||
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
|
||||
struct AstModule : RTLIL::Module {
|
||||
AstNode *ast;
|
||||
std::unique_ptr<AstNode> ast;
|
||||
bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;
|
||||
~AstModule() override;
|
||||
RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail) override;
|
||||
RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override;
|
||||
std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, AstNode **new_ast_out, bool quiet = false);
|
||||
std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, std::unique_ptr<AstNode>* new_ast_out, bool quiet = false);
|
||||
void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;
|
||||
bool reprocess_if_necessary(RTLIL::Design *design) override;
|
||||
RTLIL::Module *clone() const override;
|
||||
|
|
@ -406,9 +402,9 @@ namespace AST
|
|||
// this must be set by the language frontend before parsing the sources
|
||||
// the AstNode constructor then uses current_filename and get_line_num()
|
||||
// to initialize the filename and linenum properties of new nodes
|
||||
extern std::string current_filename;
|
||||
extern void (*set_line_num)(int);
|
||||
extern int (*get_line_num)();
|
||||
// extern std::string current_filename;
|
||||
// also set by the language frontend to control some AST processing
|
||||
extern bool sv_mode_but_global_and_used_for_literally_one_condition;
|
||||
|
||||
// for stats
|
||||
unsigned long long astnode_count();
|
||||
|
|
@ -418,7 +414,7 @@ namespace AST
|
|||
void use_internal_line_num();
|
||||
|
||||
// call a DPI function
|
||||
AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args);
|
||||
std::unique_ptr<AstNode> dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AstNode>> &args);
|
||||
|
||||
// Helper functions related to handling SystemVerilog interfaces
|
||||
std::pair<std::string,std::string> split_modport_from_type(std::string name_type);
|
||||
|
|
@ -464,7 +460,7 @@ namespace AST_INTERNAL
|
|||
process_and_replace_module(RTLIL::Design *design,
|
||||
RTLIL::Module *old_module,
|
||||
AST::AstNode *new_ast,
|
||||
AST::AstNode *original_ast = nullptr);
|
||||
std::unique_ptr<AST::AstNode> original_ast = nullptr);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ static ffi_fptr resolve_fn (std::string symbol_name)
|
|||
log_error("unable to resolve '%s'.\n", symbol_name.c_str());
|
||||
}
|
||||
|
||||
AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args)
|
||||
std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AST::AstNode>> &args)
|
||||
{
|
||||
AST::AstNode *newNode = nullptr;
|
||||
std::unique_ptr<AST::AstNode> newNode = nullptr;
|
||||
union value { double f64; float f32; int32_t i32; void *ptr; };
|
||||
std::vector<value> value_store(args.size() + 1);
|
||||
std::vector<ffi_type *> types(args.size() + 1);
|
||||
|
|
@ -125,11 +125,11 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
|
|||
ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data());
|
||||
|
||||
if (rtype == "real") {
|
||||
newNode = new AstNode(AST_REALVALUE);
|
||||
newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
|
||||
newNode->realvalue = value_store[args.size()].f64;
|
||||
log(" return realvalue: %g\n", newNode->asReal(true));
|
||||
} else if (rtype == "shortreal") {
|
||||
newNode = new AstNode(AST_REALVALUE);
|
||||
newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
|
||||
newNode->realvalue = value_store[args.size()].f32;
|
||||
log(" return realvalue: %g\n", newNode->asReal(true));
|
||||
} else if (rtype == "chandle") {
|
||||
|
|
@ -137,10 +137,10 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
|
|||
std::vector<RTLIL::State> bits(64);
|
||||
for (int i = 0; i < 64; i++)
|
||||
bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
newNode = AstNode::mkconst_bits(bits, false);
|
||||
newNode = AstNode::mkconst_bits(loc, bits, false);
|
||||
log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false));
|
||||
} else {
|
||||
newNode = AstNode::mkconst_int(value_store[args.size()].i32, false);
|
||||
newNode = AstNode::mkconst_int(loc, value_store[args.size()].i32, false);
|
||||
log(" return integer: %lld\n", (long long)newNode->asInt(true));
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ YOSYS_NAMESPACE_END
|
|||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
|
||||
std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType, const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<std::unique_ptr<AST::AstNode>>&)
|
||||
{
|
||||
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ using namespace AST_INTERNAL;
|
|||
// helper function for creating RTLIL code for unary operations
|
||||
static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true)
|
||||
{
|
||||
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
|
||||
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
|
||||
RTLIL::Cell *cell = current_module->addCell(name, type);
|
||||
set_src_attr(cell, that);
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
|
|||
return;
|
||||
}
|
||||
|
||||
IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
|
||||
IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
|
||||
RTLIL::Cell *cell = current_module->addCell(name, ID($pos));
|
||||
set_src_attr(cell, that);
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
|
|||
set_src_attr(wire, that);
|
||||
wire->is_signed = that->is_signed;
|
||||
|
||||
if (that != NULL)
|
||||
if (that != nullptr)
|
||||
for (auto &attr : that->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
that->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
|
|
@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
|
|||
// helper function for creating RTLIL code for binary operations
|
||||
static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
|
||||
{
|
||||
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
|
||||
IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++);
|
||||
RTLIL::Cell *cell = current_module->addCell(name, type);
|
||||
set_src_attr(cell, that);
|
||||
|
||||
|
|
@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
|
|||
log_assert(cond.size() == 1);
|
||||
|
||||
std::stringstream sstr;
|
||||
sstr << "$ternary$" << RTLIL::encode_filename(that->filename) << ":" << that->location.first_line << "$" << (autoidx++);
|
||||
sstr << "$ternary$" << RTLIL::encode_filename(*that->location.begin.filename) << ":" << that->location.begin.line << "$" << (autoidx++);
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux));
|
||||
set_src_attr(cell, that);
|
||||
|
|
@ -195,22 +195,22 @@ struct AST_INTERNAL::LookaheadRewriter
|
|||
if (node->lookahead) {
|
||||
log_assert(node->type == AST_IDENTIFIER);
|
||||
if (!lookaheadids.count(node->str)) {
|
||||
AstNode *wire = new AstNode(AST_WIRE);
|
||||
for (auto c : node->id2ast->children)
|
||||
auto wire = std::make_unique<AstNode>(node->location, AST_WIRE);
|
||||
for (auto& c : node->id2ast->children)
|
||||
wire->children.push_back(c->clone());
|
||||
wire->fixup_hierarchy_flags();
|
||||
wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++);
|
||||
wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
|
||||
wire->set_attribute(ID::nosync, AstNode::mkconst_int(node->location, 1, false));
|
||||
wire->is_logic = true;
|
||||
while (wire->simplify(true, 1, -1, false)) { }
|
||||
current_ast_mod->children.push_back(wire);
|
||||
lookaheadids[node->str] = make_pair(node->id2ast, wire);
|
||||
lookaheadids[node->str] = make_pair(node->id2ast, wire.get());
|
||||
wire->genRTLIL();
|
||||
current_ast_mod->children.push_back(std::move(wire));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto child : node->children)
|
||||
collect_lookaheadids(child);
|
||||
for (auto& child : node->children)
|
||||
collect_lookaheadids(child.get());
|
||||
}
|
||||
|
||||
bool has_lookaheadids(AstNode *node)
|
||||
|
|
@ -218,8 +218,8 @@ struct AST_INTERNAL::LookaheadRewriter
|
|||
if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) != 0)
|
||||
return true;
|
||||
|
||||
for (auto child : node->children)
|
||||
if (has_lookaheadids(child))
|
||||
for (auto& child : node->children)
|
||||
if (has_lookaheadids(child.get()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -230,8 +230,8 @@ struct AST_INTERNAL::LookaheadRewriter
|
|||
if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) == 0)
|
||||
return true;
|
||||
|
||||
for (auto child : node->children)
|
||||
if (has_nonlookaheadids(child))
|
||||
for (auto& child : node->children)
|
||||
if (has_nonlookaheadids(child.get()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -241,16 +241,16 @@ struct AST_INTERNAL::LookaheadRewriter
|
|||
{
|
||||
if (node->type == AST_ASSIGN_LE)
|
||||
{
|
||||
if (has_lookaheadids(node->children[0]))
|
||||
if (has_lookaheadids(node->children[0].get()))
|
||||
{
|
||||
if (has_nonlookaheadids(node->children[0]))
|
||||
if (has_nonlookaheadids(node->children[0].get()))
|
||||
log_error("incompatible mix of lookahead and non-lookahead IDs in LHS expression.\n");
|
||||
|
||||
rewrite_lookaheadids(node->children[0], true);
|
||||
rewrite_lookaheadids(node->children[0].get(), true);
|
||||
node->type = AST_ASSIGN_EQ;
|
||||
}
|
||||
|
||||
rewrite_lookaheadids(node->children[1], lhs);
|
||||
rewrite_lookaheadids(node->children[1].get(), lhs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -261,21 +261,22 @@ struct AST_INTERNAL::LookaheadRewriter
|
|||
lhs = false;
|
||||
}
|
||||
|
||||
for (auto child : node->children)
|
||||
rewrite_lookaheadids(child, lhs);
|
||||
for (auto& child : node->children)
|
||||
rewrite_lookaheadids(child.get(), lhs);
|
||||
}
|
||||
|
||||
LookaheadRewriter(AstNode *top)
|
||||
{
|
||||
// top->dumpAst(NULL, "REWRITE-BEFORE> ");
|
||||
// top->dumpVlog(NULL, "REWRITE-BEFORE> ");
|
||||
// top->dumpAst(nullptr, "REWRITE-BEFORE> ");
|
||||
// top->dumpVlog(nullptr, "REWRITE-BEFORE> ");
|
||||
|
||||
AstNode *block = nullptr;
|
||||
auto loc = top->location;
|
||||
|
||||
for (auto c : top->children)
|
||||
for (auto& c : top->children)
|
||||
if (c->type == AST_BLOCK) {
|
||||
log_assert(block == nullptr);
|
||||
block = c;
|
||||
block = c.get();
|
||||
}
|
||||
log_assert(block != nullptr);
|
||||
|
||||
|
|
@ -284,25 +285,25 @@ struct AST_INTERNAL::LookaheadRewriter
|
|||
|
||||
for (auto it : lookaheadids)
|
||||
{
|
||||
AstNode *ref_orig = new AstNode(AST_IDENTIFIER);
|
||||
auto ref_orig = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
|
||||
ref_orig->str = it.second.first->str;
|
||||
ref_orig->id2ast = it.second.first;
|
||||
ref_orig->was_checked = true;
|
||||
|
||||
AstNode *ref_temp = new AstNode(AST_IDENTIFIER);
|
||||
auto ref_temp = std::make_unique<AstNode>(loc, AST_IDENTIFIER);
|
||||
ref_temp->str = it.second.second->str;
|
||||
ref_temp->id2ast = it.second.second;
|
||||
ref_temp->was_checked = true;
|
||||
|
||||
AstNode *init_assign = new AstNode(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone());
|
||||
AstNode *final_assign = new AstNode(AST_ASSIGN_LE, ref_orig, ref_temp);
|
||||
auto init_assign = std::make_unique<AstNode>(loc, AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone());
|
||||
auto final_assign = std::make_unique<AstNode>(loc, AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp));
|
||||
|
||||
block->children.insert(block->children.begin(), init_assign);
|
||||
block->children.push_back(final_assign);
|
||||
block->children.insert(block->children.begin(), std::move(init_assign));
|
||||
block->children.push_back(std::move(final_assign));
|
||||
}
|
||||
|
||||
// top->dumpAst(NULL, "REWRITE-AFTER> ");
|
||||
// top->dumpVlog(NULL, "REWRITE-AFTER> ");
|
||||
// top->dumpAst(nullptr, "REWRITE-AFTER> ");
|
||||
// top->dumpVlog(nullptr, "REWRITE-AFTER> ");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -310,7 +311,7 @@ struct AST_INTERNAL::LookaheadRewriter
|
|||
struct AST_INTERNAL::ProcessGenerator
|
||||
{
|
||||
// input and output structures
|
||||
AstNode *always;
|
||||
std::unique_ptr<AstNode> always;
|
||||
RTLIL::SigSpec initSyncSignals;
|
||||
RTLIL::Process *proc;
|
||||
RTLIL::SigSpec outputSignals;
|
||||
|
|
@ -341,14 +342,14 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
// The most recently assigned $print or $check cell \PRIORITY.
|
||||
int last_effect_priority;
|
||||
|
||||
ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg), last_effect_priority(0)
|
||||
ProcessGenerator(std::unique_ptr<AstNode> a, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(std::move(a)), initSyncSignals(initSyncSignalsArg), last_effect_priority(0)
|
||||
{
|
||||
// rewrite lookahead references
|
||||
LookaheadRewriter la_rewriter(always);
|
||||
LookaheadRewriter la_rewriter(always.get());
|
||||
|
||||
// generate process and simple root case
|
||||
proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++));
|
||||
set_src_attr(proc, always);
|
||||
proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(*always->location.begin.filename).c_str(), always->location.begin.line, autoidx++));
|
||||
set_src_attr(proc, always.get());
|
||||
for (auto &attr : always->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
always->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
|
|
@ -358,13 +359,13 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
|
||||
// create initial temporary signal for all output registers
|
||||
RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to;
|
||||
collect_lvalues(subst_lvalue_from, always, true, true);
|
||||
collect_lvalues(subst_lvalue_from, always.get(), true, true);
|
||||
subst_lvalue_to = new_temp_signal(subst_lvalue_from);
|
||||
subst_lvalue_map = subst_lvalue_from.to_sigbit_map(subst_lvalue_to);
|
||||
|
||||
bool found_global_syncs = false;
|
||||
bool found_anyedge_syncs = false;
|
||||
for (auto child : always->children)
|
||||
for (auto& child : always->children)
|
||||
{
|
||||
if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER &&
|
||||
child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) {
|
||||
|
|
@ -388,7 +389,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
|
||||
// create syncs for the process
|
||||
bool found_clocked_sync = false;
|
||||
for (auto child : always->children)
|
||||
for (auto& child : always->children)
|
||||
if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) {
|
||||
if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast &&
|
||||
child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk))
|
||||
|
|
@ -420,9 +421,9 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
}
|
||||
|
||||
// process the AST
|
||||
for (auto child : always->children)
|
||||
for (auto& child : always->children)
|
||||
if (child->type == AST_BLOCK)
|
||||
processAst(child);
|
||||
processAst(child.get());
|
||||
|
||||
for (auto sync: proc->syncs)
|
||||
processMemWrites(sync);
|
||||
|
|
@ -472,7 +473,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
for (int i = 0; i < GetSize(chunks); i++)
|
||||
{
|
||||
RTLIL::SigChunk &chunk = chunks[i];
|
||||
if (chunk.wire == NULL)
|
||||
if (chunk.wire == nullptr)
|
||||
continue;
|
||||
|
||||
std::string wire_name;
|
||||
|
|
@ -484,7 +485,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
} while (current_module->wires_.count(wire_name) > 0);
|
||||
|
||||
RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width);
|
||||
set_src_attr(wire, always);
|
||||
set_src_attr(wire, always.get());
|
||||
|
||||
chunk.wire = wire;
|
||||
chunk.offset = 0;
|
||||
|
|
@ -499,10 +500,10 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
switch (ast->type)
|
||||
{
|
||||
case AST_CASE:
|
||||
for (auto child : ast->children)
|
||||
for (auto& child : ast->children)
|
||||
if (child != ast->children[0]) {
|
||||
log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
|
||||
collect_lvalues(reg, child, type_eq, type_le, false);
|
||||
collect_lvalues(reg, child.get(), type_eq, type_le, false);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -511,19 +512,19 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
case AST_CONDZ:
|
||||
case AST_ALWAYS:
|
||||
case AST_INITIAL:
|
||||
for (auto child : ast->children)
|
||||
for (auto& child : ast->children)
|
||||
if (child->type == AST_BLOCK)
|
||||
collect_lvalues(reg, child, type_eq, type_le, false);
|
||||
collect_lvalues(reg, child.get(), type_eq, type_le, false);
|
||||
break;
|
||||
|
||||
case AST_BLOCK:
|
||||
for (auto child : ast->children) {
|
||||
for (auto& child : ast->children) {
|
||||
if (child->type == AST_ASSIGN_EQ && type_eq)
|
||||
reg.append(child->children[0]->genRTLIL());
|
||||
if (child->type == AST_ASSIGN_LE && type_le)
|
||||
reg.append(child->children[0]->genRTLIL());
|
||||
if (child->type == AST_CASE || child->type == AST_BLOCK)
|
||||
collect_lvalues(reg, child, type_eq, type_le, false);
|
||||
collect_lvalues(reg, child.get(), type_eq, type_le, false);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -583,8 +584,8 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
switch (ast->type)
|
||||
{
|
||||
case AST_BLOCK:
|
||||
for (auto child : ast->children)
|
||||
processAst(child);
|
||||
for (auto& child : ast->children)
|
||||
processAst(child.get());
|
||||
break;
|
||||
|
||||
case AST_ASSIGN_EQ:
|
||||
|
|
@ -641,9 +642,9 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
RTLIL::SigSpec this_case_eq_rvalue = this_case_eq_lvalue;
|
||||
this_case_eq_rvalue.replace(subst_rvalue_map.stdmap());
|
||||
|
||||
RTLIL::CaseRule *default_case = NULL;
|
||||
RTLIL::CaseRule *last_generated_case = NULL;
|
||||
for (auto child : ast->children)
|
||||
RTLIL::CaseRule *default_case = nullptr;
|
||||
RTLIL::CaseRule *last_generated_case = nullptr;
|
||||
for (auto& child : ast->children)
|
||||
{
|
||||
if (child == ast->children[0])
|
||||
continue;
|
||||
|
|
@ -657,14 +658,14 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
|
||||
RTLIL::CaseRule *backup_case = current_case;
|
||||
current_case = new RTLIL::CaseRule;
|
||||
set_src_attr(current_case, child);
|
||||
set_src_attr(current_case, child.get());
|
||||
last_generated_case = current_case;
|
||||
addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
|
||||
for (auto node : child->children) {
|
||||
for (auto& node : child->children) {
|
||||
if (node->type == AST_DEFAULT)
|
||||
default_case = current_case;
|
||||
else if (node->type == AST_BLOCK)
|
||||
processAst(node);
|
||||
processAst(node.get());
|
||||
else
|
||||
current_case->compare.push_back(node->genWidthRTLIL(width_hint, sign_hint, &subst_rvalue_map.stdmap()));
|
||||
}
|
||||
|
|
@ -678,7 +679,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
subst_rvalue_map.restore();
|
||||
}
|
||||
|
||||
if (last_generated_case != NULL && ast->get_bool_attribute(ID::full_case) && default_case == NULL) {
|
||||
if (last_generated_case != nullptr && ast->get_bool_attribute(ID::full_case) && default_case == nullptr) {
|
||||
#if 0
|
||||
// this is a valid transformation, but as optimization it is premature.
|
||||
// better: add a default case that assigns 'x' to everything, and let later
|
||||
|
|
@ -690,7 +691,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
sw->cases.push_back(default_case);
|
||||
#endif
|
||||
} else {
|
||||
if (default_case == NULL) {
|
||||
if (default_case == nullptr) {
|
||||
default_case = new RTLIL::CaseRule;
|
||||
addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
|
||||
}
|
||||
|
|
@ -723,7 +724,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" ||
|
||||
ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") {
|
||||
std::stringstream sstr;
|
||||
sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++);
|
||||
sstr << ast->str << "$" << ast->location.begin.filename << ":" << ast->location.begin.line << "$" << (autoidx++);
|
||||
|
||||
Wire *en = current_module->addWire(sstr.str() + "_EN", 1);
|
||||
set_src_attr(en, ast);
|
||||
|
|
@ -760,14 +761,14 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
default_base = 16;
|
||||
|
||||
std::vector<VerilogFmtArg> args;
|
||||
for (auto node : ast->children) {
|
||||
for (auto& node : ast->children) {
|
||||
int width;
|
||||
bool is_signed;
|
||||
node->detectSignWidth(width, is_signed, nullptr);
|
||||
|
||||
VerilogFmtArg arg = {};
|
||||
arg.filename = node->filename;
|
||||
arg.first_line = node->location.first_line;
|
||||
arg.filename = *node->location.begin.filename;
|
||||
arg.first_line = node->location.begin.line;
|
||||
if (node->type == AST_CONSTANT && node->is_string) {
|
||||
arg.type = VerilogFmtArg::STRING;
|
||||
arg.str = node->bitsAsConst().decode_string();
|
||||
|
|
@ -793,7 +794,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
fmt.append_literal("\n");
|
||||
fmt.emit_rtlil(cell);
|
||||
} else if (!ast->str.empty()) {
|
||||
log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
|
||||
log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -813,7 +814,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
|
||||
IdString cellname;
|
||||
if (ast->str.empty())
|
||||
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->filename).c_str(), ast->location.first_line, autoidx++);
|
||||
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*ast->location.begin.filename).c_str(), ast->location.begin.line, autoidx++);
|
||||
else
|
||||
cellname = ast->str;
|
||||
check_unique_id(current_module, cellname, ast, "procedural assertion");
|
||||
|
|
@ -843,7 +844,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
set_src_attr(cell, ast);
|
||||
for (auto &attr : ast->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_file_error(ast->filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
cell->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
cell->setParam(ID::FLAVOR, flavor);
|
||||
|
|
@ -866,8 +867,8 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
break;
|
||||
|
||||
default:
|
||||
// ast->dumpAst(NULL, "ast> ");
|
||||
// current_ast_mod->dumpAst(NULL, "mod> ");
|
||||
// ast->dumpAst(nullptr, "ast> ");
|
||||
// current_ast_mod->dumpAst(nullptr, "mod> ");
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
|
|
@ -876,14 +877,14 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
{
|
||||
// Maps per-memid AST_MEMWR IDs to indices in the mem_write_actions array.
|
||||
dict<std::pair<std::string, int>, int> port_map;
|
||||
for (auto child : always->children)
|
||||
for (auto& child : always->children)
|
||||
if (child->type == AST_MEMWR)
|
||||
{
|
||||
std::string memid = child->str;
|
||||
int portid = child->children[3]->asInt(false);
|
||||
int cur_idx = GetSize(sync->mem_write_actions);
|
||||
RTLIL::MemWriteAction action;
|
||||
set_src_attr(&action, child);
|
||||
set_src_attr(&action, child.get());
|
||||
action.memid = memid;
|
||||
action.address = child->children[0]->genWidthRTLIL(-1, true, &subst_rvalue_map.stdmap());
|
||||
action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, true, &subst_rvalue_map.stdmap());
|
||||
|
|
@ -971,11 +972,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
bool sub_sign_hint = true;
|
||||
int sub_width_hint = -1;
|
||||
int this_width = 0;
|
||||
AstNode *range = NULL;
|
||||
AstNode *id_ast = NULL;
|
||||
AstNode *range = nullptr;
|
||||
AstNode *id_ast = nullptr;
|
||||
|
||||
bool local_found_real = false;
|
||||
if (found_real == NULL)
|
||||
if (found_real == nullptr)
|
||||
found_real = &local_found_real;
|
||||
|
||||
switch (type)
|
||||
|
|
@ -1019,22 +1020,22 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
input_error("Failed to detect width for parameter %s!\n", str.c_str());
|
||||
}
|
||||
if (children.size() != 0)
|
||||
range = children[0];
|
||||
range = children[0].get();
|
||||
} else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) {
|
||||
if (!id_ast->range_valid) {
|
||||
if (id_ast->type == AST_AUTOWIRE)
|
||||
this_width = 1;
|
||||
else {
|
||||
// current_ast_mod->dumpAst(NULL, "mod> ");
|
||||
// current_ast_mod->dumpAst(nullptr, "mod> ");
|
||||
// log("---\n");
|
||||
// id_ast->dumpAst(NULL, "decl> ");
|
||||
// dumpAst(NULL, "ref> ");
|
||||
// id_ast->dumpAst(nullptr, "decl> ");
|
||||
// dumpAst(nullptr, "ref> ");
|
||||
input_error("Failed to detect width of signal access `%s'!\n", str.c_str());
|
||||
}
|
||||
} else {
|
||||
this_width = id_ast->range_left - id_ast->range_right + 1;
|
||||
if (children.size() != 0)
|
||||
range = children[0];
|
||||
range = children[0].get();
|
||||
}
|
||||
} else if (id_ast->type == AST_GENVAR) {
|
||||
this_width = 32;
|
||||
|
|
@ -1043,26 +1044,23 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
input_error("Failed to detect width of memory access `%s'!\n", str.c_str());
|
||||
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
|
||||
if (children.size() > 1)
|
||||
range = children[1];
|
||||
range = children[1].get();
|
||||
} else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT || id_ast->type == AST_UNION) {
|
||||
AstNode *tmp_range = make_index_range(id_ast);
|
||||
auto tmp_range = make_index_range(id_ast);
|
||||
this_width = tmp_range->range_left - tmp_range->range_right + 1;
|
||||
delete tmp_range;
|
||||
} else
|
||||
input_error("Failed to detect width for identifier %s!\n", str.c_str());
|
||||
if (range) {
|
||||
if (range->children.size() == 1)
|
||||
this_width = 1;
|
||||
else if (!range->range_valid) {
|
||||
AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero();
|
||||
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
|
||||
auto left_at_zero_ast = children[0]->children[0]->clone_at_zero();
|
||||
auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
|
||||
while (left_at_zero_ast->simplify(true, 1, -1, false)) { }
|
||||
while (right_at_zero_ast->simplify(true, 1, -1, false)) { }
|
||||
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
|
||||
input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
|
||||
this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
|
||||
delete left_at_zero_ast;
|
||||
delete right_at_zero_ast;
|
||||
} else
|
||||
this_width = range->range_left - range->range_right + 1;
|
||||
sign_hint = false;
|
||||
|
|
@ -1106,7 +1104,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
break;
|
||||
|
||||
case AST_CONCAT:
|
||||
for (auto child : children) {
|
||||
for (auto& child : children) {
|
||||
sub_width_hint = 0;
|
||||
sub_sign_hint = true;
|
||||
child->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
|
||||
|
|
@ -1135,7 +1133,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
case AST_BIT_OR:
|
||||
case AST_BIT_XOR:
|
||||
case AST_BIT_XNOR:
|
||||
for (auto child : children)
|
||||
for (auto& child : children)
|
||||
child->detectSignWidthWorker(width_hint, sign_hint, found_real);
|
||||
break;
|
||||
|
||||
|
|
@ -1175,7 +1173,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
case AST_MUL:
|
||||
case AST_DIV:
|
||||
case AST_MOD:
|
||||
for (auto child : children)
|
||||
for (auto& child : children)
|
||||
child->detectSignWidthWorker(width_hint, sign_hint, found_real);
|
||||
break;
|
||||
|
||||
|
|
@ -1216,12 +1214,13 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
width_hint = max(width_hint, sub_width_hint);
|
||||
sign_hint &= sub_sign_hint;
|
||||
};
|
||||
visit_case_expr(children[0]);
|
||||
visit_case_expr(children[0].get());
|
||||
for (size_t i = 1; i < children.size(); i++) {
|
||||
AstNode *child = children[i];
|
||||
for (AstNode *v : child->children)
|
||||
AstNode *child = children[i].get();
|
||||
for (auto& v : child->children) {
|
||||
if (v->type != AST_DEFAULT && v->type != AST_BLOCK)
|
||||
visit_case_expr(v);
|
||||
visit_case_expr(v.get());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1269,9 +1268,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (func->type != AST_FUNCTION)
|
||||
input_error("Function call to %s resolved to something that isn't a function!\n", RTLIL::unescape_id(str).c_str());
|
||||
const AstNode *wire = nullptr;
|
||||
for (const AstNode *child : func->children)
|
||||
for (const auto& child : func->children)
|
||||
if (child->str == func->str) {
|
||||
wire = child;
|
||||
wire = child.get();
|
||||
break;
|
||||
}
|
||||
log_assert(wire && wire->type == AST_WIRE);
|
||||
|
|
@ -1280,10 +1279,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (!wire->children.empty())
|
||||
{
|
||||
log_assert(wire->children.size() == 1);
|
||||
const AstNode *range = wire->children.at(0);
|
||||
const AstNode *range = wire->children.at(0).get();
|
||||
log_assert(range->type == AST_RANGE && range->children.size() == 2);
|
||||
AstNode *left = range->children.at(0)->clone();
|
||||
AstNode *right = range->children.at(1)->clone();
|
||||
auto left = range->children.at(0)->clone();
|
||||
auto right = range->children.at(1)->clone();
|
||||
left->set_in_param_flag(true);
|
||||
right->set_in_param_flag(true);
|
||||
while (left->simplify(true, 1, -1, false)) { }
|
||||
|
|
@ -1292,8 +1291,6 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
input_error("Function %s has non-constant width!",
|
||||
RTLIL::unescape_id(str).c_str());
|
||||
result_width = abs(int(left->asInt(true) - right->asInt(true)));
|
||||
delete left;
|
||||
delete right;
|
||||
}
|
||||
width_hint = max(width_hint, result_width);
|
||||
break;
|
||||
|
|
@ -1306,6 +1303,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
for (auto f : log_files)
|
||||
current_scope_ast->dumpAst(f, "verilog-ast> ");
|
||||
input_error("Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
|
||||
|
||||
}
|
||||
|
||||
if (*found_real)
|
||||
|
|
@ -1342,8 +1340,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
// be instantiated for this type of AST node.
|
||||
IdString type_name;
|
||||
|
||||
current_filename = filename;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
// simply ignore this nodes.
|
||||
|
|
@ -1361,6 +1357,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
case AST_GENIF:
|
||||
case AST_GENCASE:
|
||||
case AST_PACKAGE:
|
||||
case AST_IMPORT:
|
||||
case AST_ENUM:
|
||||
case AST_MODPORT:
|
||||
case AST_MODPORTMEMBER:
|
||||
|
|
@ -1508,7 +1505,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
}
|
||||
|
||||
RTLIL::SigSpec sig = realAsConst(width_hint);
|
||||
log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
|
||||
return sig;
|
||||
}
|
||||
|
||||
|
|
@ -1517,11 +1514,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
// shifter cell is created and the output signal of this cell is returned
|
||||
case AST_IDENTIFIER:
|
||||
{
|
||||
RTLIL::Wire *wire = NULL;
|
||||
RTLIL::Wire *wire = nullptr;
|
||||
RTLIL::SigChunk chunk;
|
||||
bool is_interface = false;
|
||||
|
||||
AST::AstNode *member_node = NULL;
|
||||
AST::AstNode *member_node = nullptr;
|
||||
int add_undef_bits_msb = 0;
|
||||
int add_undef_bits_lsb = 0;
|
||||
|
||||
|
|
@ -1540,7 +1537,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
if (dynamic_cast<RTLIL::Binding*>(current_module)) {
|
||||
/* nothing to do here */
|
||||
} else if (flag_autowire)
|
||||
log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str());
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "Identifier `%s' is implicitly declared.\n", str.c_str());
|
||||
else
|
||||
input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
|
||||
}
|
||||
|
|
@ -1608,14 +1605,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
}
|
||||
|
||||
if (!children[0]->range_valid) {
|
||||
AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero();
|
||||
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
|
||||
auto left_at_zero_ast = children[0]->children[0]->clone_at_zero();
|
||||
auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
|
||||
while (left_at_zero_ast->simplify(true, 1, -1, false)) { }
|
||||
while (right_at_zero_ast->simplify(true, 1, -1, false)) { }
|
||||
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
|
||||
input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
|
||||
int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
|
||||
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
|
||||
auto fake_ast = std::make_unique<AstNode>(children[0]->location, AST_NONE, clone(), children[0]->children.size() >= 2 ?
|
||||
children[0]->children[1]->clone() : children[0]->children[0]->clone());
|
||||
fake_ast->children[0]->delete_children();
|
||||
if (member_node)
|
||||
|
|
@ -1636,10 +1633,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
}
|
||||
if (GetSize(shift_val) >= 32)
|
||||
fake_ast->children[1]->is_signed = true;
|
||||
RTLIL::SigSpec sig = binop2rtlil(fake_ast, ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val);
|
||||
delete left_at_zero_ast;
|
||||
delete right_at_zero_ast;
|
||||
delete fake_ast;
|
||||
RTLIL::SigSpec sig = binop2rtlil(fake_ast.get(), ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val);
|
||||
return sig;
|
||||
} else {
|
||||
chunk.width = children[0]->range_left - children[0]->range_right + 1;
|
||||
|
|
@ -1648,10 +1642,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
chunk.offset = source_width - (chunk.offset + chunk.width);
|
||||
if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) {
|
||||
if (chunk.width == 1)
|
||||
log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
|
||||
str.c_str());
|
||||
else
|
||||
log_file_warning(filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
|
||||
children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
|
||||
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
|
||||
} else {
|
||||
|
|
@ -1665,10 +1659,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
chunk.offset += add_undef_bits_lsb;
|
||||
}
|
||||
if (add_undef_bits_lsb)
|
||||
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
|
||||
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
|
||||
if (add_undef_bits_msb)
|
||||
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
|
||||
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
|
||||
}
|
||||
}
|
||||
|
|
@ -1942,7 +1936,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
case AST_MEMRD:
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
|
||||
sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd));
|
||||
set_src_attr(cell, this);
|
||||
|
|
@ -1980,7 +1974,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
case AST_MEMINIT:
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
|
||||
sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
|
||||
|
||||
SigSpec en_sig = children[2]->genRTLIL();
|
||||
|
||||
|
|
@ -2025,7 +2019,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
|
||||
IdString cellname;
|
||||
if (str.empty())
|
||||
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
|
||||
cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++);
|
||||
else
|
||||
cellname = str;
|
||||
check_unique_id(current_module, cellname, this, "procedural assertion");
|
||||
|
|
@ -2068,7 +2062,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
new_left.append(left[i]);
|
||||
new_right.append(right[i]);
|
||||
}
|
||||
log_file_warning(filename, location.first_line, "Ignoring assignment to constant bits:\n"
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "Ignoring assignment to constant bits:\n"
|
||||
" old assignment: %s = %s\n new assignment: %s = %s.\n",
|
||||
log_signal(left), log_signal(right),
|
||||
log_signal(new_left), log_signal(new_right));
|
||||
|
|
@ -2092,7 +2086,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
cell->set_bool_attribute(ID::module_not_derived);
|
||||
|
||||
for (auto it = children.begin(); it != children.end(); it++) {
|
||||
AstNode *child = *it;
|
||||
auto* child = it->get();
|
||||
if (child->type == AST_CELLTYPE) {
|
||||
cell->type = child->str;
|
||||
if (flag_icells && cell->type.begins_with("\\$"))
|
||||
|
|
@ -2101,9 +2095,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
}
|
||||
if (child->type == AST_PARASET) {
|
||||
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
|
||||
const AstNode *value = child->children[0];
|
||||
const auto* value = child->children[0].get();
|
||||
if (value->type == AST_REALVALUE)
|
||||
log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n",
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "Replacing floating point parameter %s.%s = %f with string.\n",
|
||||
log_id(cell), log_id(paraname), value->realvalue);
|
||||
else if (value->type != AST_CONSTANT)
|
||||
input_error("Parameter %s.%s with non-constant value!\n",
|
||||
|
|
@ -2114,7 +2108,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
if (child->type == AST_ARGUMENT) {
|
||||
RTLIL::SigSpec sig;
|
||||
if (child->children.size() > 0) {
|
||||
AstNode *arg = child->children[0];
|
||||
auto* arg = child->children[0].get();
|
||||
int local_width_hint = -1;
|
||||
bool local_sign_hint = false;
|
||||
// don't inadvertently attempt to detect the width of interfaces
|
||||
|
|
@ -2186,30 +2180,27 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
|
||||
// use ProcessGenerator for always blocks
|
||||
case AST_ALWAYS: {
|
||||
AstNode *always = this->clone();
|
||||
ProcessGenerator generator(always);
|
||||
ProcessGenerator generator(this->clone());
|
||||
ignoreThisSignalsInInitial.append(generator.outputSignals);
|
||||
delete always;
|
||||
} break;
|
||||
|
||||
case AST_INITIAL: {
|
||||
AstNode *always = this->clone();
|
||||
ProcessGenerator generator(always, ignoreThisSignalsInInitial);
|
||||
delete always;
|
||||
auto always = this->clone();
|
||||
ProcessGenerator generator(this->clone(), ignoreThisSignalsInInitial);
|
||||
} break;
|
||||
|
||||
case AST_TECALL: {
|
||||
int sz = children.size();
|
||||
if (str == "$info") {
|
||||
if (sz > 0)
|
||||
log_file_info(filename, location.first_line, "%s.\n", children[0]->str.c_str());
|
||||
log_file_info(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str());
|
||||
else
|
||||
log_file_info(filename, location.first_line, "\n");
|
||||
log_file_info(*location.begin.filename, location.begin.line, "\n");
|
||||
} else if (str == "$warning") {
|
||||
if (sz > 0)
|
||||
log_file_warning(filename, location.first_line, "%s.\n", children[0]->str.c_str());
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str());
|
||||
else
|
||||
log_file_warning(filename, location.first_line, "\n");
|
||||
log_file_warning(*location.begin.filename, location.begin.line, "\n");
|
||||
} else if (str == "$error") {
|
||||
if (sz > 0)
|
||||
input_error("%s.\n", children[0]->str.c_str());
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -10,6 +10,10 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
|
|||
|
||||
frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc
|
||||
|
||||
frontends/verilog/verilog_frontend.o: frontends/verilog/verilog_parser.tab.hh
|
||||
frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh
|
||||
|
||||
frontends/verilog/verilog_lexer.h: frontends/verilog/verilog_parser.tab.hh
|
||||
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
|
||||
|
|
@ -20,5 +24,6 @@ OBJS += frontends/verilog/verilog_parser.tab.o
|
|||
OBJS += frontends/verilog/verilog_lexer.o
|
||||
OBJS += frontends/verilog/preproc.o
|
||||
OBJS += frontends/verilog/verilog_frontend.o
|
||||
OBJS += frontends/verilog/verilog_error.o
|
||||
OBJS += frontends/verilog/const2ast.o
|
||||
|
||||
|
|
|
|||
|
|
@ -42,14 +42,23 @@
|
|||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
using namespace AST;
|
||||
using namespace VERILOG_FRONTEND;
|
||||
|
||||
void ConstParser::log_maybe_loc_error(std::string msg) {
|
||||
log_file_error(*loc.begin.filename, loc.begin.line, "%s", msg.c_str());
|
||||
}
|
||||
|
||||
void ConstParser::log_maybe_loc_warn(std::string msg) {
|
||||
log_file_warning(*loc.begin.filename, loc.begin.line, "%s", msg.c_str());
|
||||
}
|
||||
|
||||
// divide an arbitrary length decimal number by two and return the rest
|
||||
static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
|
||||
int ConstParser::my_decimal_div_by_two(std::vector<uint8_t> &digits)
|
||||
{
|
||||
int carry = 0;
|
||||
for (size_t i = 0; i < digits.size(); i++) {
|
||||
if (digits[i] >= 10)
|
||||
log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n");
|
||||
log_maybe_loc_error("Invalid use of [a-fxz?] in decimal constant.\n");
|
||||
digits[i] += carry * 10;
|
||||
carry = digits[i] % 2;
|
||||
digits[i] /= 2;
|
||||
|
|
@ -60,7 +69,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
|
|||
}
|
||||
|
||||
// find the number of significant bits in a binary number (not including the sign bit)
|
||||
static int my_ilog2(int x)
|
||||
int ConstParser::my_ilog2(int x)
|
||||
{
|
||||
int ret = 0;
|
||||
while (x != 0 && x != -1) {
|
||||
|
|
@ -71,7 +80,7 @@ static int my_ilog2(int x)
|
|||
}
|
||||
|
||||
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
|
||||
static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
|
||||
void ConstParser::my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
|
||||
{
|
||||
// all digits in string (MSB at index 0)
|
||||
std::vector<uint8_t> digits;
|
||||
|
|
@ -102,8 +111,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
|
|||
int bits_per_digit = my_ilog2(base-1);
|
||||
for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
|
||||
if (*it > (base-1) && *it < 0xf0)
|
||||
log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n",
|
||||
base-1, base);
|
||||
log_maybe_loc_error(stringf("Digit larger than %d used in in base-%d constant.\n",
|
||||
base-1, base));
|
||||
for (int i = 0; i < bits_per_digit; i++) {
|
||||
int bitmask = 1 << i;
|
||||
if (*it == 0xf0)
|
||||
|
|
@ -126,7 +135,7 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
|
|||
}
|
||||
|
||||
if (is_unsized && (len > len_in_bits))
|
||||
log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
|
||||
log_maybe_loc_error(stringf("Unsized constant must have width of 1 bit, but have %d bits!\n", len));
|
||||
|
||||
for (len = len - 1; len >= 0; len--)
|
||||
if (data[len] == State::S1)
|
||||
|
|
@ -140,21 +149,19 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
|
|||
}
|
||||
|
||||
if (len_in_bits == 0)
|
||||
log_file_error(current_filename, get_line_num(), "Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n");
|
||||
log_maybe_loc_error("Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n");
|
||||
|
||||
if (len > len_in_bits)
|
||||
log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n",
|
||||
len_in_bits, len, current_filename.c_str(), get_line_num());
|
||||
log_maybe_loc_warn(stringf("Literal has a width of %d bit, but value requires %d bit.\n",
|
||||
len_in_bits, len));
|
||||
}
|
||||
|
||||
// convert the Verilog code for a constant to an AST node
|
||||
AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z)
|
||||
std::unique_ptr<AstNode> ConstParser::const2ast(std::string code, char case_type, bool warn_z)
|
||||
{
|
||||
if (warn_z) {
|
||||
AstNode *ret = const2ast(code, case_type);
|
||||
auto ret = const2ast(code, case_type);
|
||||
if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
|
||||
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
|
||||
current_filename.c_str(), get_line_num());
|
||||
log_maybe_loc_warn("Yosys has only limited support for tri-state logic at the moment.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +179,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
|||
ch = ch >> 1;
|
||||
}
|
||||
}
|
||||
AstNode *ast = AstNode::mkconst_bits(data, false);
|
||||
auto ast = AstNode::mkconst_bits(loc, data, false);
|
||||
ast->str = code;
|
||||
return ast;
|
||||
}
|
||||
|
|
@ -191,7 +198,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
|||
my_strtobin(data, str, -1, 10, case_type, false);
|
||||
if (data.back() == State::S1)
|
||||
data.push_back(State::S0);
|
||||
return AstNode::mkconst_bits(data, true);
|
||||
return AstNode::mkconst_bits(loc, data, true);
|
||||
}
|
||||
|
||||
// unsized constant
|
||||
|
|
@ -239,10 +246,11 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
|||
if (is_signed && data.back() == State::S1)
|
||||
data.push_back(State::S0);
|
||||
}
|
||||
return AstNode::mkconst_bits(data, is_signed, is_unsized);
|
||||
return AstNode::mkconst_bits(loc, data, is_signed, is_unsized);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "preproc.h"
|
||||
#include "verilog_frontend.h"
|
||||
#include "frontends/verilog/verilog_parser.tab.hh"
|
||||
#include "kernel/log.h"
|
||||
#include <assert.h>
|
||||
#include <stack>
|
||||
|
|
@ -749,7 +750,9 @@ frontend_verilog_preproc(std::istream &f,
|
|||
std::string filename,
|
||||
const define_map_t &pre_defines,
|
||||
define_map_t &global_defines_cache,
|
||||
const std::list<std::string> &include_dirs)
|
||||
const std::list<std::string> &include_dirs,
|
||||
ParseState &parse_state,
|
||||
ParseMode &parse_mode)
|
||||
{
|
||||
define_map_t defines;
|
||||
defines.merge(pre_defines);
|
||||
|
|
@ -961,11 +964,11 @@ frontend_verilog_preproc(std::istream &f,
|
|||
}
|
||||
|
||||
if (tok == "`resetall") {
|
||||
default_nettype_wire = true;
|
||||
parse_state.default_nettype_wire = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tok == "`undefineall" && sv_mode) {
|
||||
if (tok == "`undefineall" && parse_mode.sv) {
|
||||
defines.clear();
|
||||
global_defines_cache.clear();
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@ YOSYS_NAMESPACE_BEGIN
|
|||
struct define_body_t;
|
||||
struct arg_map_t;
|
||||
|
||||
namespace VERILOG_FRONTEND {
|
||||
struct ParseState;
|
||||
struct ParseMode;
|
||||
};
|
||||
|
||||
struct define_map_t
|
||||
{
|
||||
define_map_t();
|
||||
|
|
@ -71,7 +76,9 @@ frontend_verilog_preproc(std::istream &f,
|
|||
std::string filename,
|
||||
const define_map_t &pre_defines,
|
||||
define_map_t &global_defines_cache,
|
||||
const std::list<std::string> &include_dirs);
|
||||
const std::list<std::string> &include_dirs,
|
||||
VERILOG_FRONTEND::ParseState &parse_state,
|
||||
VERILOG_FRONTEND::ParseMode &parse_mode);
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
|
|
|||
68
frontends/verilog/verilog_error.cc
Normal file
68
frontends/verilog/verilog_error.cc
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/yosys_common.h"
|
||||
#include "frontends/verilog/verilog_error.h"
|
||||
#include "frontends/verilog/verilog_location.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
/**
|
||||
* Legacy behavior is to only track lines. Now we have columns too, but we don't
|
||||
* report them in errors.
|
||||
* TODO: report columns, too
|
||||
*/
|
||||
|
||||
[[noreturn]]
|
||||
static void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap)
|
||||
{
|
||||
char buffer[1024];
|
||||
char *p = buffer;
|
||||
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
|
||||
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
|
||||
YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void vwarn_at(std::string filename, int begin_line, char const *fmt, va_list ap)
|
||||
{
|
||||
char buffer[1024];
|
||||
char *p = buffer;
|
||||
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
|
||||
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
|
||||
YOSYS_NAMESPACE_PREFIX log_file_warning(filename, begin_line, "%s", buffer);
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
void VERILOG_FRONTEND::err_at_loc(Location loc, char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
verr_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args);
|
||||
}
|
||||
void VERILOG_FRONTEND::warn_at_loc(Location loc, char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vwarn_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
19
frontends/verilog/verilog_error.h
Normal file
19
frontends/verilog/verilog_error.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef VERILOG_ERROR_H
|
||||
#define VERILOG_ERROR_H
|
||||
|
||||
#include "kernel/yosys_common.h"
|
||||
#include "frontends/ast/ast.h"
|
||||
#include "frontends/verilog/verilog_location.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
namespace VERILOG_FRONTEND
|
||||
{
|
||||
[[noreturn]]
|
||||
void err_at_loc(Location loc, char const *fmt, ...);
|
||||
void warn_at_loc(Location loc, char const *fmt, ...);
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
@ -31,10 +31,14 @@
|
|||
#endif
|
||||
|
||||
#include "verilog_frontend.h"
|
||||
#include "verilog_lexer.h"
|
||||
#include "verilog_error.h"
|
||||
#include "verilog_location.h"
|
||||
#include "preproc.h"
|
||||
#include "kernel/yosys.h"
|
||||
#include "libs/sha1/sha1.h"
|
||||
#include <stdarg.h>
|
||||
#include <list>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
using namespace VERILOG_FRONTEND;
|
||||
|
|
@ -46,13 +50,13 @@ static std::list<std::vector<std::string>> verilog_defaults_stack;
|
|||
|
||||
static void error_on_dpi_function(AST::AstNode *node)
|
||||
{
|
||||
if (node->type == AST::AST_DPI_FUNCTION)
|
||||
log_file_error(node->filename, node->location.first_line, "Found DPI function %s.\n", node->str.c_str());
|
||||
for (auto child : node->children)
|
||||
error_on_dpi_function(child);
|
||||
if (node->type == AST::AST_DPI_FUNCTION)
|
||||
err_at_loc(node->location, "Found DPI function %s.\n", node->str.c_str());
|
||||
for (auto& child : node->children)
|
||||
error_on_dpi_function(child.get());
|
||||
}
|
||||
|
||||
static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list)
|
||||
static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<std::unique_ptr<AST::AstNode>> &package_list)
|
||||
{
|
||||
// prime the parser's user type lookup table with the package qualified names
|
||||
// of typedefed names in the packages seen so far.
|
||||
|
|
@ -61,7 +65,7 @@ static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std
|
|||
for (const auto &node: pkg->children) {
|
||||
if (node->type == AST::AST_TYPEDEF) {
|
||||
std::string s = pkg->str + "::" + node->str.substr(1);
|
||||
user_types[s] = node;
|
||||
user_types[s] = node.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -250,6 +254,8 @@ struct VerilogFrontend : public Frontend {
|
|||
bool flag_dump_vlog1 = false;
|
||||
bool flag_dump_vlog2 = false;
|
||||
bool flag_dump_rtlil = false;
|
||||
bool flag_debug_lexer = false;
|
||||
bool flag_debug_parser = false;
|
||||
bool flag_nolatches = false;
|
||||
bool flag_nomeminit = false;
|
||||
bool flag_nomem2reg = false;
|
||||
|
|
@ -266,22 +272,24 @@ struct VerilogFrontend : public Frontend {
|
|||
bool flag_noblackbox = false;
|
||||
bool flag_nowb = false;
|
||||
bool flag_nosynthesis = false;
|
||||
bool flag_yydebug = false;
|
||||
define_map_t defines_map;
|
||||
|
||||
std::list<std::string> include_dirs;
|
||||
std::list<std::string> attributes;
|
||||
|
||||
frontend_verilog_yydebug = false;
|
||||
sv_mode = false;
|
||||
formal_mode = false;
|
||||
noassert_mode = false;
|
||||
noassume_mode = false;
|
||||
norestrict_mode = false;
|
||||
assume_asserts_mode = false;
|
||||
assert_assumes_mode = false;
|
||||
lib_mode = false;
|
||||
specify_mode = false;
|
||||
default_nettype_wire = true;
|
||||
ParseMode parse_mode = {};
|
||||
ParseState parse_state = {};
|
||||
parse_mode.sv = false;
|
||||
parse_mode.formal = false;
|
||||
parse_mode.noassert = false;
|
||||
parse_mode.noassume = false;
|
||||
parse_mode.norestrict = false;
|
||||
parse_mode.assume_asserts = false;
|
||||
parse_mode.assert_assumes = false;
|
||||
parse_mode.lib = false;
|
||||
parse_mode.specify = false;
|
||||
parse_state.default_nettype_wire = true;
|
||||
|
||||
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
|
||||
|
||||
|
|
@ -289,11 +297,11 @@ struct VerilogFrontend : public Frontend {
|
|||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
std::string arg = args[argidx];
|
||||
if (arg == "-sv") {
|
||||
sv_mode = true;
|
||||
parse_mode.sv = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-formal") {
|
||||
formal_mode = true;
|
||||
parse_mode.formal = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-nosynthesis") {
|
||||
|
|
@ -301,23 +309,23 @@ struct VerilogFrontend : public Frontend {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-noassert") {
|
||||
noassert_mode = true;
|
||||
parse_mode.noassert = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-noassume") {
|
||||
noassume_mode = true;
|
||||
parse_mode.noassume = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-norestrict") {
|
||||
norestrict_mode = true;
|
||||
parse_mode.norestrict = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-assume-asserts") {
|
||||
assume_asserts_mode = true;
|
||||
parse_mode.assume_asserts = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-assert-assumes") {
|
||||
assert_assumes_mode = true;
|
||||
parse_mode.assert_assumes = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-nodisplay") {
|
||||
|
|
@ -329,7 +337,8 @@ struct VerilogFrontend : public Frontend {
|
|||
flag_dump_ast2 = true;
|
||||
flag_dump_vlog1 = true;
|
||||
flag_dump_vlog2 = true;
|
||||
frontend_verilog_yydebug = true;
|
||||
flag_debug_lexer = true;
|
||||
flag_debug_parser = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dump_ast1") {
|
||||
|
|
@ -357,7 +366,9 @@ struct VerilogFrontend : public Frontend {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-yydebug") {
|
||||
frontend_verilog_yydebug = true;
|
||||
flag_yydebug = true;
|
||||
flag_debug_lexer = true;
|
||||
flag_debug_parser = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-nolatches") {
|
||||
|
|
@ -393,7 +404,7 @@ struct VerilogFrontend : public Frontend {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-lib") {
|
||||
lib_mode = true;
|
||||
parse_mode.lib = true;
|
||||
defines_map.add("BLACKBOX", "");
|
||||
continue;
|
||||
}
|
||||
|
|
@ -402,7 +413,7 @@ struct VerilogFrontend : public Frontend {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-specify") {
|
||||
specify_mode = true;
|
||||
parse_mode.specify = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-noopt") {
|
||||
|
|
@ -432,7 +443,7 @@ struct VerilogFrontend : public Frontend {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-noautowire") {
|
||||
default_nettype_wire = false;
|
||||
parse_state.default_nettype_wire = false;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-setattr" && argidx+1 < args.size()) {
|
||||
|
|
@ -469,76 +480,82 @@ struct VerilogFrontend : public Frontend {
|
|||
break;
|
||||
}
|
||||
|
||||
if (formal_mode || !flag_nosynthesis)
|
||||
defines_map.add(formal_mode ? "FORMAL" : "SYNTHESIS", "1");
|
||||
if (parse_mode.formal || !flag_nosynthesis)
|
||||
defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1");
|
||||
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
|
||||
|
||||
log("Parsing %s%s input from `%s' to AST representation.\n",
|
||||
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
|
||||
parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str());
|
||||
|
||||
AST::current_filename = filename;
|
||||
AST::set_line_num = &frontend_verilog_yyset_lineno;
|
||||
AST::get_line_num = &frontend_verilog_yyget_lineno;
|
||||
|
||||
current_ast = new AST::AstNode(AST::AST_DESIGN);
|
||||
|
||||
lexin = f;
|
||||
AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv;
|
||||
std::string code_after_preproc;
|
||||
|
||||
parse_state.lexin = f;
|
||||
if (!flag_nopp) {
|
||||
code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs);
|
||||
code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs, parse_state, parse_mode);
|
||||
if (flag_ppdump)
|
||||
log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str());
|
||||
lexin = new std::istringstream(code_after_preproc);
|
||||
parse_state.lexin = new std::istringstream(code_after_preproc);
|
||||
}
|
||||
|
||||
auto filename_shared = std::make_shared<std::string>(filename);
|
||||
auto top_loc = Location();
|
||||
top_loc.begin.filename = filename_shared;
|
||||
parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN);
|
||||
VerilogLexer lexer(&parse_state, &parse_mode, filename_shared);
|
||||
frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode);
|
||||
lexer.set_debug(flag_debug_lexer);
|
||||
parser.set_debug_level(flag_debug_parser ? 1 : 0);
|
||||
|
||||
// make package typedefs available to parser
|
||||
add_package_types(pkg_user_types, design->verilog_packages);
|
||||
add_package_types(parse_state.pkg_user_types, design->verilog_packages);
|
||||
|
||||
UserTypeMap global_types_map;
|
||||
for (auto def : design->verilog_globals) {
|
||||
for (auto& def : design->verilog_globals) {
|
||||
if (def->type == AST::AST_TYPEDEF) {
|
||||
global_types_map[def->str] = def;
|
||||
global_types_map[def->str] = def.get();
|
||||
}
|
||||
}
|
||||
|
||||
log_assert(user_type_stack.empty());
|
||||
log_assert(parse_state.user_type_stack.empty());
|
||||
// use previous global typedefs as bottom level of user type stack
|
||||
user_type_stack.push_back(std::move(global_types_map));
|
||||
parse_state.user_type_stack.push_back(std::move(global_types_map));
|
||||
// add a new empty type map to allow overriding existing global definitions
|
||||
user_type_stack.push_back(UserTypeMap());
|
||||
parse_state.user_type_stack.push_back(UserTypeMap());
|
||||
|
||||
frontend_verilog_yyset_lineno(1);
|
||||
frontend_verilog_yyrestart(NULL);
|
||||
frontend_verilog_yyparse();
|
||||
frontend_verilog_yylex_destroy();
|
||||
if (flag_yydebug) {
|
||||
lexer.set_debug(true);
|
||||
parser.set_debug_level(1);
|
||||
}
|
||||
parser.parse();
|
||||
// frontend_verilog_yyset_lineno(1);
|
||||
|
||||
for (auto &child : current_ast->children) {
|
||||
for (auto &child : parse_state.current_ast->children) {
|
||||
if (child->type == AST::AST_MODULE)
|
||||
for (auto &attr : attributes)
|
||||
if (child->attributes.count(attr) == 0)
|
||||
child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
|
||||
child->attributes[attr] = AST::AstNode::mkconst_int(top_loc, 1, false);
|
||||
}
|
||||
|
||||
if (flag_nodpi)
|
||||
error_on_dpi_function(current_ast);
|
||||
error_on_dpi_function(parse_state.current_ast);
|
||||
|
||||
AST::process(design, current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
|
||||
flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
|
||||
AST::process(design, parse_state.current_ast, flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
|
||||
flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, parse_mode.lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, parse_state.default_nettype_wire);
|
||||
|
||||
|
||||
if (!flag_nopp)
|
||||
delete lexin;
|
||||
delete parse_state.lexin;
|
||||
|
||||
// only the previous and new global type maps remain
|
||||
log_assert(user_type_stack.size() == 2);
|
||||
user_type_stack.clear();
|
||||
log_assert(parse_state.user_type_stack.size() == 2);
|
||||
parse_state.user_type_stack.clear();
|
||||
|
||||
delete current_ast;
|
||||
current_ast = NULL;
|
||||
delete parse_state.current_ast;
|
||||
parse_state.current_ast = NULL;
|
||||
|
||||
log("Successfully finished Verilog frontend.\n");
|
||||
}
|
||||
|
|
@ -760,18 +777,3 @@ struct VerilogFileList : public Pass {
|
|||
#endif
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
// the yyerror function used by bison to report parser errors
|
||||
void frontend_verilog_yyerror(char const *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[1024];
|
||||
char *p = buffer;
|
||||
va_start(ap, fmt);
|
||||
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
|
||||
va_end(ap);
|
||||
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
|
||||
YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(),
|
||||
"%s", buffer);
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,70 +31,33 @@
|
|||
|
||||
#include "kernel/yosys.h"
|
||||
#include "frontends/ast/ast.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <list>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
namespace VERILOG_FRONTEND
|
||||
{
|
||||
// this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser
|
||||
extern struct AST::AstNode *current_ast;
|
||||
/* Ephemeral context class */
|
||||
struct ConstParser {
|
||||
AST::AstSrcLocType loc;
|
||||
private:
|
||||
void log_maybe_loc_error(std::string msg);
|
||||
void log_maybe_loc_warn(std::string msg);
|
||||
// divide an arbitrary length decimal number by two and return the rest
|
||||
int my_decimal_div_by_two(std::vector<uint8_t> &digits);
|
||||
// find the number of significant bits in a binary number (not including the sign bit)
|
||||
int my_ilog2(int x);
|
||||
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
|
||||
void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized);
|
||||
public:
|
||||
// convert the Verilog code for a constant to an AST node
|
||||
std::unique_ptr<AST::AstNode> const2ast(std::string code, char case_type = 0, bool warn_z = false);
|
||||
|
||||
// this function converts a Verilog constant to an AST_CONSTANT node
|
||||
AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
|
||||
|
||||
// names of locally typedef'ed types in a stack
|
||||
typedef std::map<std::string, AST::AstNode*> UserTypeMap;
|
||||
extern std::vector<UserTypeMap> user_type_stack;
|
||||
|
||||
// names of package typedef'ed types
|
||||
extern dict<std::string, AST::AstNode*> pkg_user_types;
|
||||
|
||||
// state of `default_nettype
|
||||
extern bool default_nettype_wire;
|
||||
|
||||
// running in SystemVerilog mode
|
||||
extern bool sv_mode;
|
||||
|
||||
// running in -formal mode
|
||||
extern bool formal_mode;
|
||||
|
||||
// running in -noassert mode
|
||||
extern bool noassert_mode;
|
||||
|
||||
// running in -noassume mode
|
||||
extern bool noassume_mode;
|
||||
|
||||
// running in -norestrict mode
|
||||
extern bool norestrict_mode;
|
||||
|
||||
// running in -assume-asserts mode
|
||||
extern bool assume_asserts_mode;
|
||||
|
||||
// running in -assert-assumes mode
|
||||
extern bool assert_assumes_mode;
|
||||
|
||||
// running in -lib mode
|
||||
extern bool lib_mode;
|
||||
|
||||
// running in -specify mode
|
||||
extern bool specify_mode;
|
||||
|
||||
// lexer input stream
|
||||
extern std::istream *lexin;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
// the usual bison/flex stuff
|
||||
extern int frontend_verilog_yydebug;
|
||||
void frontend_verilog_yyerror(char const *fmt, ...);
|
||||
void frontend_verilog_yyrestart(FILE *f);
|
||||
int frontend_verilog_yyparse(void);
|
||||
int frontend_verilog_yylex_destroy(void);
|
||||
int frontend_verilog_yyget_lineno(void);
|
||||
void frontend_verilog_yyset_lineno (int);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
48
frontends/verilog/verilog_lexer.h
Normal file
48
frontends/verilog/verilog_lexer.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef VERILOG_LEXER_H
|
||||
#define VERILOG_LEXER_H
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "frontends/ast/ast.h"
|
||||
#include "frontends/verilog/verilog_parser.tab.hh"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#if ! defined(yyFlexLexerOnce)
|
||||
#define yyFlexLexer frontend_verilog_yyFlexLexer
|
||||
#include <FlexLexer.h>
|
||||
#endif
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
namespace VERILOG_FRONTEND {
|
||||
using parser = frontend_verilog_yy::parser;
|
||||
class VerilogLexer : public frontend_verilog_yyFlexLexer {
|
||||
ParseState* extra;
|
||||
ParseMode* mode;
|
||||
parser::location_type out_loc;
|
||||
public:
|
||||
VerilogLexer(ParseState* e, ParseMode* m, std::shared_ptr<string> filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {
|
||||
out_loc.begin.filename = filename;
|
||||
}
|
||||
~VerilogLexer() override {}
|
||||
// autogenerated body due to YY_DECL
|
||||
parser::symbol_type nextToken();
|
||||
// get rid of override virtual function warning
|
||||
using FlexLexer::yylex;
|
||||
parser::symbol_type terminate() {
|
||||
return parser::make_FRONTEND_VERILOG_YYEOF(out_loc);
|
||||
}
|
||||
private:
|
||||
std::shared_ptr<std::string> current_filename;
|
||||
std::vector<std::shared_ptr<std::string>> fn_stack;
|
||||
std::vector<int> ln_stack;
|
||||
int LexerInput(char* buf, int max_size) override {
|
||||
return readsome(*extra->lexin, buf, max_size);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
@ -32,6 +32,13 @@
|
|||
*
|
||||
*/
|
||||
|
||||
%option c++
|
||||
%option yyclass="VerilogLexer"
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
%option yylineno
|
||||
%option prefix="frontend_verilog_yy"
|
||||
|
||||
%{
|
||||
|
||||
#ifdef __clang__
|
||||
|
|
@ -41,78 +48,109 @@
|
|||
#pragma clang diagnostic ignored "-Wmisleading-indentation"
|
||||
#endif
|
||||
|
||||
#include "kernel/log.h"
|
||||
#include "frontends/verilog/verilog_frontend.h"
|
||||
#include "frontends/verilog/verilog_lexer.h"
|
||||
#include "frontends/ast/ast.h"
|
||||
#include "verilog_parser.tab.hh"
|
||||
#include "frontends/verilog/verilog_location.h"
|
||||
#include "kernel/log.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
using namespace AST;
|
||||
using namespace VERILOG_FRONTEND;
|
||||
|
||||
#define YYSTYPE FRONTEND_VERILOG_YYSTYPE
|
||||
#define YYLTYPE FRONTEND_VERILOG_YYLTYPE
|
||||
using parser = frontend_verilog_yy::parser;
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
namespace VERILOG_FRONTEND {
|
||||
std::vector<std::string> fn_stack;
|
||||
std::vector<int> ln_stack;
|
||||
YYLTYPE real_location;
|
||||
YYLTYPE old_location;
|
||||
}
|
||||
#undef YY_DECL
|
||||
#define YY_DECL parser::symbol_type VerilogLexer::nextToken()
|
||||
|
||||
#undef yyterminate
|
||||
#define yyterminate() return terminate()
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#define SV_KEYWORD(_tok) \
|
||||
if (sv_mode) return _tok; \
|
||||
if (mode->sv) return _tok; \
|
||||
log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\
|
||||
"recognized unless read_verilog is called with -sv!\n", yytext, \
|
||||
AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \
|
||||
yylval->string = new std::string(std::string("\\") + yytext); \
|
||||
return TOK_ID;
|
||||
"recognized unless read_verilog is called with -sv!\n", YYText(), \
|
||||
current_filename->c_str(), yylineno); \
|
||||
string_t val = std::make_unique<std::string>(std::string("\\") + YYText()); \
|
||||
return parser::make_TOK_ID(std::move(val), out_loc);
|
||||
|
||||
#define NON_KEYWORD() \
|
||||
yylval->string = new std::string(std::string("\\") + yytext); \
|
||||
return TOK_ID;
|
||||
string_t val = std::make_unique<std::string>(std::string("\\") + YYText()); \
|
||||
return parser::make_TOK_ID(std::move(val), out_loc);
|
||||
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
|
||||
|
||||
#define YY_USER_ACTION \
|
||||
old_location = real_location; \
|
||||
real_location.first_line = real_location.last_line; \
|
||||
real_location.first_column = real_location.last_column; \
|
||||
for(int i = 0; yytext[i] != '\0'; ++i){ \
|
||||
if(yytext[i] == '\n') { \
|
||||
real_location.last_line++; \
|
||||
real_location.last_column = 1; \
|
||||
} \
|
||||
else { \
|
||||
real_location.last_column++; \
|
||||
} \
|
||||
} \
|
||||
(*yylloc) = real_location;
|
||||
out_loc.step(); \
|
||||
for(int i = 0; YYText()[i] != '\0'; ++i){ \
|
||||
if(YYText()[i] == '\n') { \
|
||||
out_loc.lines(); \
|
||||
} \
|
||||
else { \
|
||||
out_loc.columns(); \
|
||||
} \
|
||||
} \
|
||||
out_loc.begin.filename = current_filename; \
|
||||
out_loc.end.filename = current_filename;
|
||||
|
||||
#define YY_BREAK \
|
||||
(*yylloc) = old_location; \
|
||||
break;
|
||||
|
||||
#undef YY_BUF_SIZE
|
||||
#define YY_BUF_SIZE 65536
|
||||
|
||||
extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param);
|
||||
|
||||
static bool isUserType(std::string &s)
|
||||
static bool isUserType(ParseState* extra, std::string &s)
|
||||
{
|
||||
// check current scope then outer scopes for a name
|
||||
for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) {
|
||||
for (auto it = extra->user_type_stack.rbegin(); it != extra->user_type_stack.rend(); ++it) {
|
||||
if (it->count(s) > 0) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_hex_dig(char c, int *val)
|
||||
parser::symbol_type char_tok(char c, parser::location_type loc) {
|
||||
switch (c) {
|
||||
case '!': return parser::make_TOK_EXCL(loc);
|
||||
case '#': return parser::make_TOK_HASH(loc);
|
||||
case '%': return parser::make_TOK_PERC(loc);
|
||||
case '&': return parser::make_TOK_AMP(loc);
|
||||
case '(': return parser::make_TOK_LPAREN(loc);
|
||||
case ')': return parser::make_TOK_RPAREN(loc);
|
||||
case '*': return parser::make_TOK_ASTER(loc);
|
||||
case '+': return parser::make_TOK_PLUS(loc);
|
||||
case ',': return parser::make_TOK_COMMA(loc);
|
||||
case '-': return parser::make_TOK_MINUS(loc);
|
||||
case '.': return parser::make_TOK_DOT(loc);
|
||||
case '/': return parser::make_TOK_SLASH(loc);
|
||||
case ':': return parser::make_TOK_COL(loc);
|
||||
case ';': return parser::make_TOK_SEMICOL(loc);
|
||||
case '<': return parser::make_TOK_LT(loc);
|
||||
case '=': return parser::make_TOK_EQ(loc);
|
||||
case '>': return parser::make_TOK_GT(loc);
|
||||
case '?': return parser::make_TOK_QUE(loc);
|
||||
case '@': return parser::make_TOK_AT(loc);
|
||||
case '[': return parser::make_TOK_LBRA(loc);
|
||||
case ']': return parser::make_TOK_RBRA(loc);
|
||||
case '^': return parser::make_TOK_CARET(loc);
|
||||
case '_': return parser::make_TOK_UNDER(loc);
|
||||
case '{': return parser::make_TOK_LCURL(loc);
|
||||
case '|': return parser::make_TOK_PIPE(loc);
|
||||
case '}': return parser::make_TOK_RCURL(loc);
|
||||
case '~': return parser::make_TOK_TILDE(loc);
|
||||
case 'n': return parser::make_TOK_n(loc);
|
||||
case 'p': return parser::make_TOK_p(loc);
|
||||
case 'x': return parser::make_TOK_x(loc);
|
||||
case 'z': return parser::make_TOK_z(loc);
|
||||
case 0: return parser::make_FRONTEND_VERILOG_YYEOF(loc);
|
||||
default:
|
||||
return parser::make_ch_t(c, loc);
|
||||
}
|
||||
}
|
||||
static bool is_hex_dig(char c, int *val, parser::location_type loc)
|
||||
{
|
||||
if ('0' <= c && c <= '9') {
|
||||
*val = c - '0';
|
||||
|
|
@ -124,7 +162,7 @@ static bool is_hex_dig(char c, int *val)
|
|||
*val = c - 'A' + 0xA;
|
||||
return true;
|
||||
} else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') {
|
||||
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in hex escape sequence.\n", c);
|
||||
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in hex escape sequence.\n", c);
|
||||
*val = 0; // not semantically valid in hex escape...
|
||||
return true; // ...but still processed as part of hex token
|
||||
}
|
||||
|
|
@ -132,13 +170,13 @@ static bool is_hex_dig(char c, int *val)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool is_oct_dig(char c, int *val)
|
||||
static bool is_oct_dig(char c, int *val, parser::location_type loc)
|
||||
{
|
||||
if ('0' <= c && c <= '7') {
|
||||
*val = c - '0';
|
||||
return true;
|
||||
} else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') {
|
||||
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in octal escape sequence.\n", c);
|
||||
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in octal escape sequence.\n", c);
|
||||
*val = 0; // not semantically valid in octal escape...
|
||||
return true; // ...but still processed as part of octal token
|
||||
}
|
||||
|
|
@ -146,7 +184,7 @@ static bool is_oct_dig(char c, int *val)
|
|||
return false;
|
||||
}
|
||||
|
||||
static std::string *process_str(char *str, int len, bool triple)
|
||||
static parser::symbol_type process_str(char *str, int len, bool triple, parser::location_type loc)
|
||||
{
|
||||
char *in, *out; // Overwrite input buffer: flex manual states "Actions
|
||||
// are free to modify 'yytext' except for lengthening it".
|
||||
|
|
@ -158,7 +196,7 @@ static std::string *process_str(char *str, int len, bool triple)
|
|||
if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r'))
|
||||
in++;
|
||||
if (!triple)
|
||||
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "Multi-line string literals should be triple-quoted or escaped.\n");
|
||||
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "Multi-line string literals should be triple-quoted or escaped.\n");
|
||||
*out++ = '\n';
|
||||
break;
|
||||
case '\\':
|
||||
|
|
@ -186,16 +224,16 @@ static std::string *process_str(char *str, int len, bool triple)
|
|||
break;
|
||||
case 'x':
|
||||
int val;
|
||||
if (in + 1 < str + len && is_hex_dig(in[1], &val)) {
|
||||
if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) {
|
||||
*out = val;
|
||||
in++;
|
||||
if (in + 1 < str + len && is_hex_dig(in[1], &val)) {
|
||||
if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) {
|
||||
*out = *out * 0x10 + val;
|
||||
in++;
|
||||
}
|
||||
out++;
|
||||
} else
|
||||
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "ignoring invalid hex escape.\n");
|
||||
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "ignoring invalid hex escape.\n");
|
||||
break;
|
||||
case '\\':
|
||||
*out++ = '\\';
|
||||
|
|
@ -213,12 +251,12 @@ static std::string *process_str(char *str, int len, bool triple)
|
|||
int val;
|
||||
|
||||
*out = *in - '0';
|
||||
if (in + 1 < str + len && is_oct_dig(in[1], &val)) {
|
||||
if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) {
|
||||
*out = *out * 010 + val;
|
||||
in++;
|
||||
if (in + 1 < str + len && is_oct_dig(in[1], &val)) {
|
||||
if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) {
|
||||
if (*out >= 040)
|
||||
log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "octal escape exceeds \\377\n");
|
||||
log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "octal escape exceeds \\377\n");
|
||||
*out = *out * 010 + val;
|
||||
in++;
|
||||
}
|
||||
|
|
@ -232,18 +270,11 @@ static std::string *process_str(char *str, int len, bool triple)
|
|||
*out++ = *in;
|
||||
}
|
||||
|
||||
return new std::string(str, out - str);
|
||||
return parser::make_TOK_STRING(std::make_unique<std::string>(str, out - str), loc);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%option yylineno
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
%option bison-locations
|
||||
%option bison-bridge
|
||||
%option prefix="frontend_verilog_yy"
|
||||
|
||||
%x COMMENT
|
||||
%x SYNOPSYS_TRANSLATE_OFF
|
||||
%x SYNOPSYS_FLAGS
|
||||
|
|
@ -256,47 +287,46 @@ FIXED_POINT_NUMBER_NO_DEC [0-9][0-9_]*[eE][-+]?[0-9_]+
|
|||
TIME_SCALE_SUFFIX [munpf]?s
|
||||
|
||||
%%
|
||||
|
||||
// Initialise comment_caller to something to avoid a "maybe undefined"
|
||||
// warning from GCC.
|
||||
int comment_caller = INITIAL;
|
||||
|
||||
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* {
|
||||
fn_stack.push_back(current_filename);
|
||||
ln_stack.push_back(frontend_verilog_yyget_lineno());
|
||||
current_filename = yytext+11;
|
||||
if (!current_filename.empty() && current_filename.front() == '"')
|
||||
current_filename = current_filename.substr(1);
|
||||
if (!current_filename.empty() && current_filename.back() == '"')
|
||||
current_filename = current_filename.substr(0, current_filename.size()-1);
|
||||
frontend_verilog_yyset_lineno(0);
|
||||
yylloc->first_line = yylloc->last_line = 0;
|
||||
real_location.first_line = real_location.last_line = 0;
|
||||
ln_stack.push_back(yylineno);
|
||||
std::string filename = YYText()+11;
|
||||
if (!filename.empty() && filename.front() == '"')
|
||||
filename = filename.substr(1);
|
||||
if (!filename.empty() && filename.back() == '"')
|
||||
filename = filename.substr(0, filename.size()-1);
|
||||
current_filename = std::make_shared<std::string>(filename);
|
||||
yylineno = (0);
|
||||
out_loc.begin.line = out_loc.end.line = 0;
|
||||
}
|
||||
|
||||
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n {
|
||||
current_filename = fn_stack.back();
|
||||
fn_stack.pop_back();
|
||||
frontend_verilog_yyset_lineno(ln_stack.back());
|
||||
yylloc->first_line = yylloc->last_line = ln_stack.back();
|
||||
real_location.first_line = real_location.last_line = ln_stack.back();
|
||||
yylineno = (ln_stack.back());
|
||||
out_loc.begin.line = out_loc.end.line = ln_stack.back();
|
||||
ln_stack.pop_back();
|
||||
}
|
||||
|
||||
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n {
|
||||
char *p = yytext + 5;
|
||||
const char *p = YYText() + 5;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
frontend_verilog_yyset_lineno(atoi(p));
|
||||
yylloc->first_line = yylloc->last_line = atoi(p);
|
||||
real_location.first_line = real_location.last_line = atoi(p);
|
||||
yylineno = (atoi(p));
|
||||
out_loc.begin.line = out_loc.end.line = atoi(p);
|
||||
while (*p && *p != ' ' && *p != '\t') p++;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
char *q = *p ? p + 1 : p;
|
||||
const char *q = *p ? p + 1 : p;
|
||||
while (*q && *q != '"') q++;
|
||||
current_filename = std::string(p).substr(1, q-p-1);
|
||||
current_filename = std::make_shared<std::string>(std::string(p).substr(1, q-p-1));
|
||||
}
|
||||
|
||||
"`file_notfound "[^\n]* {
|
||||
log_error("Can't open include file `%s'!\n", yytext + 15);
|
||||
log_error("Can't open include file `%s'!\n", YYText() + 15);
|
||||
}
|
||||
|
||||
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
|
||||
|
|
@ -305,222 +335,223 @@ TIME_SCALE_SUFFIX [munpf]?s
|
|||
"`endcelldefine"[^\n]* /* ignore `endcelldefine */
|
||||
|
||||
"`default_nettype"[ \t]+[^ \t\r\n/]+ {
|
||||
char *p = yytext;
|
||||
const char *p = YYText();
|
||||
while (*p != 0 && *p != ' ' && *p != '\t') p++;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
if (!strcmp(p, "none"))
|
||||
VERILOG_FRONTEND::default_nettype_wire = false;
|
||||
extra->default_nettype_wire = false;
|
||||
else if (!strcmp(p, "wire"))
|
||||
VERILOG_FRONTEND::default_nettype_wire = true;
|
||||
extra->default_nettype_wire = true;
|
||||
else
|
||||
frontend_verilog_yyerror("Unsupported default nettype: %s", p);
|
||||
err_at_loc(out_loc, "Unsupported default nettype: %s", p);
|
||||
}
|
||||
|
||||
"`protect"[^\n]* /* ignore `protect*/
|
||||
"`endprotect"[^\n]* /* ignore `endprotect*/
|
||||
|
||||
"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
|
||||
frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
|
||||
err_at_loc(out_loc, "Unimplemented compiler directive or undefined macro %s.", YYText());
|
||||
}
|
||||
|
||||
"module" { return TOK_MODULE; }
|
||||
"endmodule" { return TOK_ENDMODULE; }
|
||||
"function" { return TOK_FUNCTION; }
|
||||
"endfunction" { return TOK_ENDFUNCTION; }
|
||||
"task" { return TOK_TASK; }
|
||||
"endtask" { return TOK_ENDTASK; }
|
||||
"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
|
||||
"endspecify" { return TOK_ENDSPECIFY; }
|
||||
"specparam" { return TOK_SPECPARAM; }
|
||||
"package" { SV_KEYWORD(TOK_PACKAGE); }
|
||||
"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
|
||||
"interface" { SV_KEYWORD(TOK_INTERFACE); }
|
||||
"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); }
|
||||
"modport" { SV_KEYWORD(TOK_MODPORT); }
|
||||
"parameter" { return TOK_PARAMETER; }
|
||||
"localparam" { return TOK_LOCALPARAM; }
|
||||
"defparam" { return TOK_DEFPARAM; }
|
||||
"assign" { return TOK_ASSIGN; }
|
||||
"always" { return TOK_ALWAYS; }
|
||||
"initial" { return TOK_INITIAL; }
|
||||
"begin" { return TOK_BEGIN; }
|
||||
"end" { return TOK_END; }
|
||||
"if" { return TOK_IF; }
|
||||
"else" { return TOK_ELSE; }
|
||||
"for" { return TOK_FOR; }
|
||||
"posedge" { return TOK_POSEDGE; }
|
||||
"negedge" { return TOK_NEGEDGE; }
|
||||
"or" { return TOK_OR; }
|
||||
"case" { return TOK_CASE; }
|
||||
"casex" { return TOK_CASEX; }
|
||||
"casez" { return TOK_CASEZ; }
|
||||
"endcase" { return TOK_ENDCASE; }
|
||||
"default" { return TOK_DEFAULT; }
|
||||
"generate" { return TOK_GENERATE; }
|
||||
"endgenerate" { return TOK_ENDGENERATE; }
|
||||
"while" { return TOK_WHILE; }
|
||||
"repeat" { return TOK_REPEAT; }
|
||||
"automatic" { return TOK_AUTOMATIC; }
|
||||
"module" { return parser::make_TOK_MODULE(out_loc); }
|
||||
"endmodule" { return parser::make_TOK_ENDMODULE(out_loc); }
|
||||
"function" { return parser::make_TOK_FUNCTION(out_loc); }
|
||||
"endfunction" { return parser::make_TOK_ENDFUNCTION(out_loc); }
|
||||
"task" { return parser::make_TOK_TASK(out_loc); }
|
||||
"endtask" { return parser::make_TOK_ENDTASK(out_loc); }
|
||||
"specify" { return mode->specify ? parser::make_TOK_SPECIFY(out_loc) : parser::make_TOK_IGNORED_SPECIFY(out_loc); }
|
||||
"endspecify" { return parser::make_TOK_ENDSPECIFY(out_loc); }
|
||||
"specparam" { return parser::make_TOK_SPECPARAM(out_loc); }
|
||||
"package" { SV_KEYWORD(parser::make_TOK_PACKAGE(out_loc)); }
|
||||
"endpackage" { SV_KEYWORD(parser::make_TOK_ENDPACKAGE(out_loc)); }
|
||||
"import" { SV_KEYWORD(parser::make_TOK_IMPORT(out_loc)); }
|
||||
"interface" { SV_KEYWORD(parser::make_TOK_INTERFACE(out_loc)); }
|
||||
"endinterface" { SV_KEYWORD(parser::make_TOK_ENDINTERFACE(out_loc)); }
|
||||
"modport" { SV_KEYWORD(parser::make_TOK_MODPORT(out_loc)); }
|
||||
"parameter" { return parser::make_TOK_PARAMETER(out_loc); }
|
||||
"localparam" { return parser::make_TOK_LOCALPARAM(out_loc); }
|
||||
"defparam" { return parser::make_TOK_DEFPARAM(out_loc); }
|
||||
"assign" { return parser::make_TOK_ASSIGN(out_loc); }
|
||||
"always" { return parser::make_TOK_ALWAYS(out_loc); }
|
||||
"initial" { return parser::make_TOK_INITIAL(out_loc); }
|
||||
"begin" { return parser::make_TOK_BEGIN(out_loc); }
|
||||
"end" { return parser::make_TOK_END(out_loc); }
|
||||
"if" { return parser::make_TOK_IF(out_loc); }
|
||||
"else" { return parser::make_TOK_ELSE(out_loc); }
|
||||
"for" { return parser::make_TOK_FOR(out_loc); }
|
||||
"posedge" { return parser::make_TOK_POSEDGE(out_loc); }
|
||||
"negedge" { return parser::make_TOK_NEGEDGE(out_loc); }
|
||||
"or" { return parser::make_TOK_OR(out_loc); }
|
||||
"case" { return parser::make_TOK_CASE(out_loc); }
|
||||
"casex" { return parser::make_TOK_CASEX(out_loc); }
|
||||
"casez" { return parser::make_TOK_CASEZ(out_loc); }
|
||||
"endcase" { return parser::make_TOK_ENDCASE(out_loc); }
|
||||
"default" { return parser::make_TOK_DEFAULT(out_loc); }
|
||||
"generate" { return parser::make_TOK_GENERATE(out_loc); }
|
||||
"endgenerate" { return parser::make_TOK_ENDGENERATE(out_loc); }
|
||||
"while" { return parser::make_TOK_WHILE(out_loc); }
|
||||
"repeat" { return parser::make_TOK_REPEAT(out_loc); }
|
||||
"automatic" { return parser::make_TOK_AUTOMATIC(out_loc); }
|
||||
|
||||
"unique" { SV_KEYWORD(TOK_UNIQUE); }
|
||||
"unique0" { SV_KEYWORD(TOK_UNIQUE0); }
|
||||
"priority" { SV_KEYWORD(TOK_PRIORITY); }
|
||||
"unique" { SV_KEYWORD(parser::make_TOK_UNIQUE(out_loc)); }
|
||||
"unique0" { SV_KEYWORD(parser::make_TOK_UNIQUE0(out_loc)); }
|
||||
"priority" { SV_KEYWORD(parser::make_TOK_PRIORITY(out_loc)); }
|
||||
|
||||
"always_comb" { SV_KEYWORD(TOK_ALWAYS_COMB); }
|
||||
"always_ff" { SV_KEYWORD(TOK_ALWAYS_FF); }
|
||||
"always_latch" { SV_KEYWORD(TOK_ALWAYS_LATCH); }
|
||||
"always_comb" { SV_KEYWORD(parser::make_TOK_ALWAYS_COMB(out_loc)); }
|
||||
"always_ff" { SV_KEYWORD(parser::make_TOK_ALWAYS_FF(out_loc)); }
|
||||
"always_latch" { SV_KEYWORD(parser::make_TOK_ALWAYS_LATCH(out_loc)); }
|
||||
|
||||
/* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
|
||||
to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
|
||||
global state.. its a mess) */
|
||||
[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
|
||||
if (!strcmp(yytext, "default"))
|
||||
return TOK_DEFAULT;
|
||||
yylval->string = new std::string(std::string("\\") + yytext);
|
||||
return TOK_SVA_LABEL;
|
||||
if (!strcmp(YYText(), "default"))
|
||||
return parser::make_TOK_DEFAULT(out_loc);
|
||||
string_t val = std::make_unique<std::string>(std::string("\\") + YYText());
|
||||
return parser::make_TOK_SVA_LABEL(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
|
||||
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
|
||||
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
|
||||
"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
|
||||
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
|
||||
"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); }
|
||||
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
|
||||
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
|
||||
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
|
||||
"bind" { if (formal_mode) return TOK_BIND; SV_KEYWORD(TOK_BIND); }
|
||||
"final" { SV_KEYWORD(TOK_FINAL); }
|
||||
"logic" { SV_KEYWORD(TOK_LOGIC); }
|
||||
"var" { SV_KEYWORD(TOK_VAR); }
|
||||
"bit" { SV_KEYWORD(TOK_LOGIC); }
|
||||
"int" { SV_KEYWORD(TOK_INT); }
|
||||
"byte" { SV_KEYWORD(TOK_BYTE); }
|
||||
"shortint" { SV_KEYWORD(TOK_SHORTINT); }
|
||||
"longint" { SV_KEYWORD(TOK_LONGINT); }
|
||||
"void" { SV_KEYWORD(TOK_VOID); }
|
||||
"assert" { if (mode->formal) return parser::make_TOK_ASSERT(out_loc); SV_KEYWORD(parser::make_TOK_ASSERT(out_loc)); }
|
||||
"assume" { if (mode->formal) return parser::make_TOK_ASSUME(out_loc); SV_KEYWORD(parser::make_TOK_ASSUME(out_loc)); }
|
||||
"cover" { if (mode->formal) return parser::make_TOK_COVER(out_loc); SV_KEYWORD(parser::make_TOK_COVER(out_loc)); }
|
||||
"restrict" { if (mode->formal) return parser::make_TOK_RESTRICT(out_loc); SV_KEYWORD(parser::make_TOK_RESTRICT(out_loc)); }
|
||||
"property" { if (mode->formal) return parser::make_TOK_PROPERTY(out_loc); SV_KEYWORD(parser::make_TOK_PROPERTY(out_loc)); }
|
||||
"rand" { if (mode->formal) return parser::make_TOK_RAND(out_loc); SV_KEYWORD(parser::make_TOK_RAND(out_loc)); }
|
||||
"const" { if (mode->formal) return parser::make_TOK_CONST(out_loc); SV_KEYWORD(parser::make_TOK_CONST(out_loc)); }
|
||||
"checker" { if (mode->formal) return parser::make_TOK_CHECKER(out_loc); SV_KEYWORD(parser::make_TOK_CHECKER(out_loc)); }
|
||||
"endchecker" { if (mode->formal) return parser::make_TOK_ENDCHECKER(out_loc); SV_KEYWORD(parser::make_TOK_ENDCHECKER(out_loc)); }
|
||||
"bind" { if (mode->formal) return parser::make_TOK_BIND(out_loc); SV_KEYWORD(parser::make_TOK_BIND(out_loc)); }
|
||||
"final" { SV_KEYWORD(parser::make_TOK_FINAL(out_loc)); }
|
||||
"logic" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); }
|
||||
"var" { SV_KEYWORD(parser::make_TOK_VAR(out_loc)); }
|
||||
"bit" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); }
|
||||
"int" { SV_KEYWORD(parser::make_TOK_INT(out_loc)); }
|
||||
"byte" { SV_KEYWORD(parser::make_TOK_BYTE(out_loc)); }
|
||||
"shortint" { SV_KEYWORD(parser::make_TOK_SHORTINT(out_loc)); }
|
||||
"longint" { SV_KEYWORD(parser::make_TOK_LONGINT(out_loc)); }
|
||||
"void" { SV_KEYWORD(parser::make_TOK_VOID(out_loc)); }
|
||||
|
||||
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||
"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||
"eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); }
|
||||
"s_eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); }
|
||||
|
||||
"input" { return TOK_INPUT; }
|
||||
"output" { return TOK_OUTPUT; }
|
||||
"inout" { return TOK_INOUT; }
|
||||
"wire" { return TOK_WIRE; }
|
||||
"tri" { return TOK_WIRE; }
|
||||
"wor" { return TOK_WOR; }
|
||||
"trior" { return TOK_WOR; }
|
||||
"wand" { return TOK_WAND; }
|
||||
"triand" { return TOK_WAND; }
|
||||
"reg" { return TOK_REG; }
|
||||
"integer" { return TOK_INTEGER; }
|
||||
"signed" { return TOK_SIGNED; }
|
||||
"unsigned" { SV_KEYWORD(TOK_UNSIGNED); }
|
||||
"genvar" { return TOK_GENVAR; }
|
||||
"real" { return TOK_REAL; }
|
||||
"input" { return parser::make_TOK_INPUT(out_loc); }
|
||||
"output" { return parser::make_TOK_OUTPUT(out_loc); }
|
||||
"inout" { return parser::make_TOK_INOUT(out_loc); }
|
||||
"wire" { return parser::make_TOK_WIRE(out_loc); }
|
||||
"tri" { return parser::make_TOK_WIRE(out_loc); }
|
||||
"wor" { return parser::make_TOK_WOR(out_loc); }
|
||||
"trior" { return parser::make_TOK_WOR(out_loc); }
|
||||
"wand" { return parser::make_TOK_WAND(out_loc); }
|
||||
"triand" { return parser::make_TOK_WAND(out_loc); }
|
||||
"reg" { return parser::make_TOK_REG(out_loc); }
|
||||
"integer" { return parser::make_TOK_INTEGER(out_loc); }
|
||||
"signed" { return parser::make_TOK_SIGNED(out_loc); }
|
||||
"unsigned" { SV_KEYWORD(parser::make_TOK_UNSIGNED(out_loc)); }
|
||||
"genvar" { return parser::make_TOK_GENVAR(out_loc); }
|
||||
"real" { return parser::make_TOK_REAL(out_loc); }
|
||||
|
||||
"enum" { SV_KEYWORD(TOK_ENUM); }
|
||||
"typedef" { SV_KEYWORD(TOK_TYPEDEF); }
|
||||
"struct" { SV_KEYWORD(TOK_STRUCT); }
|
||||
"union" { SV_KEYWORD(TOK_UNION); }
|
||||
"packed" { SV_KEYWORD(TOK_PACKED); }
|
||||
"enum" { SV_KEYWORD(parser::make_TOK_ENUM(out_loc)); }
|
||||
"typedef" { SV_KEYWORD(parser::make_TOK_TYPEDEF(out_loc)); }
|
||||
"struct" { SV_KEYWORD(parser::make_TOK_STRUCT(out_loc)); }
|
||||
"union" { SV_KEYWORD(parser::make_TOK_UNION(out_loc)); }
|
||||
"packed" { SV_KEYWORD(parser::make_TOK_PACKED(out_loc)); }
|
||||
|
||||
{UNSIGNED_NUMBER} {
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_CONSTVAL;
|
||||
string_t val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_CONSTVAL(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
\'[01zxZX] {
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_UNBASED_UNSIZED_CONSTVAL;
|
||||
string_t val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
\'[sS]?[bodhBODH] {
|
||||
BEGIN(BASED_CONST);
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_BASE;
|
||||
string_t val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_BASE(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
<BASED_CONST>[0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* {
|
||||
BEGIN(0);
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_BASED_CONSTVAL;
|
||||
string_t val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_BASED_CONSTVAL(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
{FIXED_POINT_NUMBER_DEC} {
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_REALVAL;
|
||||
string_t val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_REALVAL(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
{FIXED_POINT_NUMBER_NO_DEC} {
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_REALVAL;
|
||||
string_t val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_REALVAL(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
\"([^\\"]|\\.|\\\n)*\" { yylval->string = process_str(yytext + 1, yyleng - 2, false); return TOK_STRING; }
|
||||
\"([^\\"]|\\.|\\\n)*\" { return process_str(yytext + 1, yyleng - 2, false, out_loc); }
|
||||
|
||||
\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { yylval->string = process_str(yytext + 3, yyleng - 6, true); return TOK_STRING; }
|
||||
\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { return process_str(yytext + 3, yyleng - 6, true, out_loc); }
|
||||
|
||||
and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_PRIMITIVE;
|
||||
auto val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_PRIMITIVE(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
supply0 { return TOK_SUPPLY0; }
|
||||
supply1 { return TOK_SUPPLY1; }
|
||||
supply0 { return parser::make_TOK_SUPPLY0(out_loc); }
|
||||
supply1 { return parser::make_TOK_SUPPLY1(out_loc); }
|
||||
|
||||
"$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_ID;
|
||||
auto val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_ID(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
|
||||
if (!specify_mode) REJECT;
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_ID;
|
||||
if (!mode->specify) REJECT;
|
||||
auto val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_ID(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
"$"(info|warning|error|fatal) {
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_MSG_TASKS;
|
||||
auto val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_MSG_TASKS(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
"$signed" { return TOK_TO_SIGNED; }
|
||||
"$unsigned" { return TOK_TO_UNSIGNED; }
|
||||
"$signed" { return parser::make_TOK_TO_SIGNED(out_loc); }
|
||||
"$unsigned" { return parser::make_TOK_TO_UNSIGNED(out_loc); }
|
||||
|
||||
[a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_$][a-zA-Z0-9_$]* {
|
||||
// package qualifier
|
||||
auto s = std::string("\\") + yytext;
|
||||
if (pkg_user_types.count(s) > 0) {
|
||||
auto s = std::string("\\") + YYText();
|
||||
if (extra->pkg_user_types.count(s) > 0) {
|
||||
// package qualified typedefed name
|
||||
yylval->string = new std::string(s);
|
||||
return TOK_PKG_USER_TYPE;
|
||||
auto val = std::make_unique<std::string>(s);
|
||||
return parser::make_TOK_PKG_USER_TYPE(std::move(val), out_loc);
|
||||
}
|
||||
else {
|
||||
// backup before :: just return first part
|
||||
size_t len = strchr(yytext, ':') - yytext;
|
||||
size_t len = strchr(YYText(), ':') - YYText();
|
||||
yyless(len);
|
||||
yylval->string = new std::string(std::string("\\") + yytext);
|
||||
return TOK_ID;
|
||||
auto val = std::make_unique<std::string>(std::string("\\") + YYText());
|
||||
return parser::make_TOK_ID(std::move(val), out_loc);
|
||||
}
|
||||
}
|
||||
|
||||
[a-zA-Z_$][a-zA-Z0-9_$]* {
|
||||
auto s = std::string("\\") + yytext;
|
||||
if (isUserType(s)) {
|
||||
auto s = std::string("\\") + YYText();
|
||||
if (isUserType(extra, s)) {
|
||||
// previously typedefed name
|
||||
yylval->string = new std::string(s);
|
||||
return TOK_USER_TYPE;
|
||||
auto val = std::make_unique<std::string>(s);
|
||||
return parser::make_TOK_USER_TYPE(std::move(val), out_loc);
|
||||
}
|
||||
else {
|
||||
yylval->string = new std::string(std::string("\\") + yytext);
|
||||
return TOK_ID;
|
||||
auto val = std::make_unique<std::string>(std::string("\\") + YYText());
|
||||
return parser::make_TOK_ID(std::move(val), out_loc);
|
||||
}
|
||||
}
|
||||
|
||||
[a-zA-Z_$][a-zA-Z0-9_$\.]* {
|
||||
yylval->string = new std::string(std::string("\\") + yytext);
|
||||
return TOK_ID;
|
||||
auto val = std::make_unique<std::string>(std::string("\\") + YYText());
|
||||
return parser::make_TOK_ID(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
|
||||
|
|
@ -556,7 +587,7 @@ supply1 { return TOK_SUPPLY1; }
|
|||
);
|
||||
printed_warning = true;
|
||||
}
|
||||
return TOK_SYNOPSYS_FULL_CASE;
|
||||
return parser::make_TOK_SYNOPSYS_FULL_CASE(out_loc);
|
||||
}
|
||||
<SYNOPSYS_FLAGS>parallel_case {
|
||||
static bool printed_warning = false;
|
||||
|
|
@ -570,119 +601,115 @@ supply1 { return TOK_SUPPLY1; }
|
|||
);
|
||||
printed_warning = true;
|
||||
}
|
||||
return TOK_SYNOPSYS_PARALLEL_CASE;
|
||||
return parser::make_TOK_SYNOPSYS_PARALLEL_CASE(out_loc);
|
||||
}
|
||||
<SYNOPSYS_FLAGS>. /* ignore everything else */
|
||||
<SYNOPSYS_FLAGS>"*/" { BEGIN(0); }
|
||||
|
||||
import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
|
||||
BEGIN(IMPORT_DPI);
|
||||
return TOK_DPI_FUNCTION;
|
||||
return parser::make_TOK_DPI_FUNCTION(out_loc);
|
||||
}
|
||||
|
||||
<IMPORT_DPI>[a-zA-Z_$][a-zA-Z0-9_$]* {
|
||||
yylval->string = new std::string(std::string("\\") + yytext);
|
||||
return TOK_ID;
|
||||
auto val = std::make_unique<std::string>(std::string("\\") + YYText());
|
||||
return parser::make_TOK_ID(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
<IMPORT_DPI>[ \t\r\n] /* ignore whitespaces */
|
||||
|
||||
<IMPORT_DPI>";" {
|
||||
BEGIN(0);
|
||||
return *yytext;
|
||||
return char_tok(*YYText(), out_loc);
|
||||
}
|
||||
|
||||
<IMPORT_DPI>. {
|
||||
return *yytext;
|
||||
return char_tok(*YYText(), out_loc);
|
||||
}
|
||||
|
||||
"\\"[^ \t\r\n]+ {
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_ID;
|
||||
auto val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_ID(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
"(*" { return ATTR_BEGIN; }
|
||||
"*)" { return ATTR_END; }
|
||||
"(*" { return parser::make_ATTR_BEGIN(out_loc); }
|
||||
"*)" { return parser::make_ATTR_END(out_loc); }
|
||||
|
||||
"{*" { return DEFATTR_BEGIN; }
|
||||
"*}" { return DEFATTR_END; }
|
||||
"{*" { return parser::make_DEFATTR_BEGIN(out_loc); }
|
||||
"*}" { return parser::make_DEFATTR_END(out_loc); }
|
||||
|
||||
"**" { return OP_POW; }
|
||||
"||" { return OP_LOR; }
|
||||
"&&" { return OP_LAND; }
|
||||
"==" { return OP_EQ; }
|
||||
"!=" { return OP_NE; }
|
||||
"<=" { return OP_LE; }
|
||||
">=" { return OP_GE; }
|
||||
"**" { return parser::make_OP_POW(out_loc); }
|
||||
"||" { return parser::make_OP_LOR(out_loc); }
|
||||
"&&" { return parser::make_OP_LAND(out_loc); }
|
||||
"==" { return parser::make_OP_EQ(out_loc); }
|
||||
"!=" { return parser::make_OP_NE(out_loc); }
|
||||
"<=" { return parser::make_OP_LE(out_loc); }
|
||||
">=" { return parser::make_OP_GE(out_loc); }
|
||||
|
||||
"===" { return OP_EQX; }
|
||||
"!==" { return OP_NEX; }
|
||||
"===" { return parser::make_OP_EQX(out_loc); }
|
||||
"!==" { return parser::make_OP_NEX(out_loc); }
|
||||
|
||||
"~&" { return OP_NAND; }
|
||||
"~|" { return OP_NOR; }
|
||||
"~^" { return OP_XNOR; }
|
||||
"^~" { return OP_XNOR; }
|
||||
"~&" { return parser::make_OP_NAND(out_loc); }
|
||||
"~|" { return parser::make_OP_NOR(out_loc); }
|
||||
"~^" { return parser::make_OP_XNOR(out_loc); }
|
||||
"^~" { return parser::make_OP_XNOR(out_loc); }
|
||||
|
||||
"<<" { return OP_SHL; }
|
||||
">>" { return OP_SHR; }
|
||||
"<<<" { return OP_SSHL; }
|
||||
">>>" { return OP_SSHR; }
|
||||
"<<" { return parser::make_OP_SHL(out_loc); }
|
||||
">>" { return parser::make_OP_SHR(out_loc); }
|
||||
"<<<" { return parser::make_OP_SSHL(out_loc); }
|
||||
">>>" { return parser::make_OP_SSHR(out_loc); }
|
||||
|
||||
"'" { return OP_CAST; }
|
||||
"'" { return parser::make_OP_CAST(out_loc); }
|
||||
|
||||
"::" { return TOK_PACKAGESEP; }
|
||||
"++" { return TOK_INCREMENT; }
|
||||
"--" { return TOK_DECREMENT; }
|
||||
"::" { return parser::make_TOK_PACKAGESEP(out_loc); }
|
||||
"++" { return parser::make_TOK_INCREMENT(out_loc); }
|
||||
"--" { return parser::make_TOK_DECREMENT(out_loc); }
|
||||
|
||||
"+:" { return TOK_POS_INDEXED; }
|
||||
"-:" { return TOK_NEG_INDEXED; }
|
||||
"+:" { return parser::make_TOK_POS_INDEXED(out_loc); }
|
||||
"-:" { return parser::make_TOK_NEG_INDEXED(out_loc); }
|
||||
|
||||
".*" { return TOK_WILDCARD_CONNECT; }
|
||||
".*" { return parser::make_TOK_WILDCARD_CONNECT(out_loc); }
|
||||
|
||||
"|=" { SV_KEYWORD(TOK_BIT_OR_ASSIGN); }
|
||||
"&=" { SV_KEYWORD(TOK_BIT_AND_ASSIGN); }
|
||||
"+=" { SV_KEYWORD(TOK_ADD_ASSIGN); }
|
||||
"-=" { SV_KEYWORD(TOK_SUB_ASSIGN); }
|
||||
"^=" { SV_KEYWORD(TOK_BIT_XOR_ASSIGN); }
|
||||
"/=" { SV_KEYWORD(TOK_DIV_ASSIGN); }
|
||||
"%=" { SV_KEYWORD(TOK_MOD_ASSIGN); }
|
||||
"*=" { SV_KEYWORD(TOK_MUL_ASSIGN); }
|
||||
"<<=" { SV_KEYWORD(TOK_SHL_ASSIGN); }
|
||||
">>=" { SV_KEYWORD(TOK_SHR_ASSIGN); }
|
||||
"<<<=" { SV_KEYWORD(TOK_SSHL_ASSIGN); }
|
||||
">>>=" { SV_KEYWORD(TOK_SSHR_ASSIGN); }
|
||||
"|=" { SV_KEYWORD(parser::make_TOK_BIT_OR_ASSIGN(out_loc)); }
|
||||
"&=" { SV_KEYWORD(parser::make_TOK_BIT_AND_ASSIGN(out_loc)); }
|
||||
"+=" { SV_KEYWORD(parser::make_TOK_ADD_ASSIGN(out_loc)); }
|
||||
"-=" { SV_KEYWORD(parser::make_TOK_SUB_ASSIGN(out_loc)); }
|
||||
"^=" { SV_KEYWORD(parser::make_TOK_BIT_XOR_ASSIGN(out_loc)); }
|
||||
"/=" { SV_KEYWORD(parser::make_TOK_DIV_ASSIGN(out_loc)); }
|
||||
"%=" { SV_KEYWORD(parser::make_TOK_MOD_ASSIGN(out_loc)); }
|
||||
"*=" { SV_KEYWORD(parser::make_TOK_MUL_ASSIGN(out_loc)); }
|
||||
"<<=" { SV_KEYWORD(parser::make_TOK_SHL_ASSIGN(out_loc)); }
|
||||
">>=" { SV_KEYWORD(parser::make_TOK_SHR_ASSIGN(out_loc)); }
|
||||
"<<<=" { SV_KEYWORD(parser::make_TOK_SSHL_ASSIGN(out_loc)); }
|
||||
">>>=" { SV_KEYWORD(parser::make_TOK_SSHR_ASSIGN(out_loc)); }
|
||||
|
||||
[-+]?[=*]> {
|
||||
if (!specify_mode) REJECT;
|
||||
yylval->string = new std::string(yytext);
|
||||
return TOK_SPECIFY_OPER;
|
||||
if (!mode->specify) REJECT;
|
||||
auto val = std::make_unique<std::string>(YYText());
|
||||
return parser::make_TOK_SPECIFY_OPER(std::move(val), out_loc);
|
||||
}
|
||||
|
||||
"&&&" {
|
||||
if (!specify_mode) return TOK_IGNORED_SPECIFY_AND;
|
||||
return TOK_SPECIFY_AND;
|
||||
if (!mode->specify) return parser::make_TOK_IGNORED_SPECIFY_AND(out_loc);
|
||||
return parser::make_TOK_SPECIFY_AND(out_loc);
|
||||
}
|
||||
|
||||
{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
|
||||
{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
|
||||
{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; }
|
||||
{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
|
||||
{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
|
||||
{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); }
|
||||
|
||||
<INITIAL,BASED_CONST>"/*" { comment_caller=YY_START; BEGIN(COMMENT); }
|
||||
<COMMENT>. /* ignore comment body */
|
||||
<COMMENT>\n /* ignore comment body */
|
||||
<COMMENT>"*/" { BEGIN(comment_caller); }
|
||||
|
||||
|
||||
<INITIAL,BASED_CONST>[ \t\r\n] /* ignore whitespaces */
|
||||
<INITIAL,BASED_CONST>\\[\r\n] /* ignore continuation sequence */
|
||||
<INITIAL,BASED_CONST>"//"[^\r\n]* /* ignore one-line comments */
|
||||
|
||||
<INITIAL>. { return *yytext; }
|
||||
<*>. { BEGIN(0); return *yytext; }
|
||||
<INITIAL>. { return char_tok(*YYText(), out_loc); }
|
||||
<*>. { BEGIN(0); return char_tok(*YYText(), out_loc); }
|
||||
|
||||
%%
|
||||
|
||||
// this is a hack to avoid the 'yyinput defined but not used' error msgs
|
||||
void *frontend_verilog_avoid_input_warnings() {
|
||||
return (void*)&yyinput;
|
||||
}
|
||||
|
||||
|
|
|
|||
97
frontends/verilog/verilog_location.h
Normal file
97
frontends/verilog/verilog_location.h
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#ifndef VERILOG_LOCATION_H
|
||||
#define VERILOG_LOCATION_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
/**
|
||||
* Provide frontend-wide location tracking like what bison generates
|
||||
* but using shared_ptr for filename
|
||||
*/
|
||||
|
||||
struct Position {
|
||||
std::shared_ptr<std::string> filename;
|
||||
int line;
|
||||
int column;
|
||||
|
||||
Position(std::shared_ptr<std::string> filename, int line = 1, int column = 1)
|
||||
: filename(filename), line(line), column(column) {}
|
||||
Position() = default;
|
||||
Position(const Position& other) = default;
|
||||
Position& operator=(const Position& other) = default;
|
||||
|
||||
void advance() { ++column; }
|
||||
void columns(int count = 1) {
|
||||
column += count;
|
||||
}
|
||||
|
||||
void lines(int count = 1) {
|
||||
line += count;
|
||||
column = 1;
|
||||
}
|
||||
std::string to_string() const {
|
||||
std::ostringstream oss;
|
||||
if (filename && !filename->empty()) {
|
||||
oss << *filename << ":";
|
||||
}
|
||||
oss << line << ":" << column;
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct Location {
|
||||
Position begin;
|
||||
Position end;
|
||||
|
||||
Location() = default;
|
||||
Location(const Position& b, const Position& e)
|
||||
: begin(b), end(e) {}
|
||||
Location(const Location& other) = default;
|
||||
Location& operator=(const Location& other) = default;
|
||||
|
||||
void step() { begin = end; }
|
||||
|
||||
void columns(int count = 1) {
|
||||
end.columns(count);
|
||||
}
|
||||
|
||||
void lines(int count = 1) {
|
||||
end.lines(count);
|
||||
}
|
||||
std::string to_string() const {
|
||||
std::ostringstream oss;
|
||||
bool same_file = (!begin.filename && !end.filename) ||
|
||||
(begin.filename && end.filename &&
|
||||
*begin.filename == *end.filename);
|
||||
|
||||
if (same_file) {
|
||||
if (begin.filename && !begin.filename->empty())
|
||||
oss << *begin.filename << ":";
|
||||
|
||||
if (begin.line == end.line) {
|
||||
if (begin.column == end.column) {
|
||||
oss << begin.line << ":" << begin.column;
|
||||
} else {
|
||||
oss << begin.line << ":" << begin.column
|
||||
<< "-" << end.column;
|
||||
}
|
||||
} else {
|
||||
oss << begin.line << ":" << begin.column
|
||||
<< "-" << end.line << ":" << end.column;
|
||||
}
|
||||
} else {
|
||||
oss << begin.to_string() << "-" << end.to_string();
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& os, const Location& loc) {
|
||||
return os << loc.to_string();
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -25,6 +25,18 @@
|
|||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* This file implements BitPatternPool for efficiently storing and querying
|
||||
* sets of fixed-width 2-valued logic constants compressed as "bit patterns".
|
||||
* A bit pattern can have don't cares on one or more bit positions (State::Sa).
|
||||
*
|
||||
* In terms of logic synthesis:
|
||||
* A BitPatternPool is a sum of products (SOP).
|
||||
* BitPatternPool::bits_t is a cube.
|
||||
*
|
||||
* BitPatternPool does not permit adding new patterns, only removing.
|
||||
* Its intended use case is in analysing cases in case/match constructs in HDL.
|
||||
*/
|
||||
struct BitPatternPool
|
||||
{
|
||||
int width;
|
||||
|
|
@ -67,6 +79,9 @@ struct BitPatternPool
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pool of all possible patterns (all don't-care bits)
|
||||
*/
|
||||
BitPatternPool(int width)
|
||||
{
|
||||
this->width = width;
|
||||
|
|
@ -78,6 +93,10 @@ struct BitPatternPool
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a constant SigSpec to a pattern. Normalize Yosys many-valued
|
||||
* to three-valued logic.
|
||||
*/
|
||||
bits_t sig2bits(RTLIL::SigSpec sig)
|
||||
{
|
||||
bits_t bits;
|
||||
|
|
@ -88,6 +107,9 @@ struct BitPatternPool
|
|||
return bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Two cubes match if their intersection is non-empty.
|
||||
*/
|
||||
bool match(bits_t a, bits_t b)
|
||||
{
|
||||
log_assert(int(a.bitdata.size()) == width);
|
||||
|
|
@ -98,6 +120,15 @@ struct BitPatternPool
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does cube sig overlap any cube in the pool?
|
||||
* For example:
|
||||
* pool({aaa}).has_any(01a) == true
|
||||
* pool({01a}).has_any(01a) == true
|
||||
* pool({011}).has_any(01a) == true
|
||||
* pool({01a}).has_any(011) == true
|
||||
* pool({111}).has_any(01a) == false
|
||||
*/
|
||||
bool has_any(RTLIL::SigSpec sig)
|
||||
{
|
||||
bits_t bits = sig2bits(sig);
|
||||
|
|
@ -107,6 +138,15 @@ struct BitPatternPool
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is cube sig covered by a cube in the pool?
|
||||
* For example:
|
||||
* pool({aaa}).has_all(01a) == true
|
||||
* pool({01a}).has_any(01a) == true
|
||||
* pool({01a}).has_any(011) == true
|
||||
* pool({011}).has_all(01a) == false
|
||||
* pool({111}).has_all(01a) == false
|
||||
*/
|
||||
bool has_all(RTLIL::SigSpec sig)
|
||||
{
|
||||
bits_t bits = sig2bits(sig);
|
||||
|
|
@ -121,6 +161,12 @@ struct BitPatternPool
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove cube sig from the pool, splitting the remaining cubes. True if success.
|
||||
* For example:
|
||||
* Taking 011 out of pool({01a}) -> pool({010}), returns true.
|
||||
* Taking 011 out of pool({010}) does nothing, returns false.
|
||||
*/
|
||||
bool take(RTLIL::SigSpec sig)
|
||||
{
|
||||
bool status = false;
|
||||
|
|
@ -143,6 +189,9 @@ struct BitPatternPool
|
|||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all patterns. Returns false if already empty.
|
||||
*/
|
||||
bool take_all()
|
||||
{
|
||||
if (database.empty())
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ struct CellTypes
|
|||
return v;
|
||||
}
|
||||
|
||||
// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs
|
||||
static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr)
|
||||
{
|
||||
if (type == ID($sshr) && !signed1)
|
||||
|
|
@ -416,6 +417,7 @@ struct CellTypes
|
|||
log_abort();
|
||||
}
|
||||
|
||||
// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)
|
||||
{
|
||||
if (cell->type == ID($slice)) {
|
||||
|
|
@ -503,10 +505,13 @@ struct CellTypes
|
|||
return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp);
|
||||
}
|
||||
|
||||
// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)
|
||||
{
|
||||
if (cell->type.in(ID($mux), ID($_MUX_)))
|
||||
return const_mux(arg1, arg2, arg3);
|
||||
if (cell->type == ID($_NMUX_))
|
||||
return eval_not(const_mux(arg1, arg2, arg3));
|
||||
if (cell->type == ID($bwmux))
|
||||
return const_bwmux(arg1, arg2, arg3);
|
||||
if (cell->type == ID($pmux))
|
||||
|
|
@ -520,6 +525,7 @@ struct CellTypes
|
|||
return eval(cell, arg1, arg2, errp);
|
||||
}
|
||||
|
||||
// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr)
|
||||
{
|
||||
if (cell->type == ID($_AOI4_))
|
||||
|
|
|
|||
|
|
@ -349,7 +349,11 @@ struct ConstEval
|
|||
return false;
|
||||
|
||||
bool eval_err = false;
|
||||
RTLIL::Const eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err);
|
||||
RTLIL::Const eval_ret;
|
||||
if (sig_s.size() > 0 && eval(sig_s, undef, cell)) {
|
||||
eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_s.as_const(), &eval_err);
|
||||
} else
|
||||
eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err);
|
||||
|
||||
if (eval_err)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ YOSYS_NAMESPACE_BEGIN
|
|||
|
||||
struct FfInitVals
|
||||
{
|
||||
const SigMap *sigmap;
|
||||
const SigMapView *sigmap;
|
||||
dict<SigBit, std::pair<State,SigBit>> initbits;
|
||||
|
||||
void set(const SigMap *sigmap_, RTLIL::Module *module)
|
||||
void set(const SigMapView *sigmap_, RTLIL::Module *module)
|
||||
{
|
||||
sigmap = sigmap_;
|
||||
initbits.clear();
|
||||
|
|
@ -126,7 +126,7 @@ struct FfInitVals
|
|||
initbits.clear();
|
||||
}
|
||||
|
||||
FfInitVals (const SigMap *sigmap, RTLIL::Module *module)
|
||||
FfInitVals (const SigMapView *sigmap, RTLIL::Module *module)
|
||||
{
|
||||
set(sigmap, module);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
|
||||
struct FfMergeHelper
|
||||
{
|
||||
const SigMap *sigmap;
|
||||
const SigMapView *sigmap;
|
||||
RTLIL::Module *module;
|
||||
FfInitVals *initvals;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef HASHLIB_H
|
||||
#define HASHLIB_H
|
||||
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
|
|
@ -100,7 +101,7 @@ private:
|
|||
uint32_t hash = ((a << 5) + a) ^ b;
|
||||
return hash;
|
||||
}
|
||||
public:
|
||||
public:
|
||||
void hash32(uint32_t i) {
|
||||
state = djb2_xor(i, state);
|
||||
state = mkhash_xorshift(fudge ^ state);
|
||||
|
|
@ -127,6 +128,7 @@ private:
|
|||
*this = hash_ops<T>::hash_into(t, *this);
|
||||
}
|
||||
|
||||
[[deprecated]]
|
||||
void commutative_eat(hash_t t) {
|
||||
state ^= t;
|
||||
}
|
||||
|
|
@ -177,58 +179,58 @@ struct hash_ops {
|
|||
};
|
||||
|
||||
template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
|
||||
static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
|
||||
static inline bool cmp(const std::pair<P, Q> &a, const std::pair<P, Q> &b) {
|
||||
return a == b;
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(std::pair<P, Q> a, Hasher h) {
|
||||
[[nodiscard]] static inline Hasher hash_into(const std::pair<P, Q> &a, Hasher h) {
|
||||
h = hash_ops<P>::hash_into(a.first, h);
|
||||
h = hash_ops<Q>::hash_into(a.second, h);
|
||||
return h;
|
||||
}
|
||||
HASH_TOP_LOOP_FST (std::pair<P, Q> a) HASH_TOP_LOOP_SND
|
||||
HASH_TOP_LOOP_FST (const std::pair<P, Q> &a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
template<typename... T> struct hash_ops<std::tuple<T...>> {
|
||||
static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {
|
||||
static inline bool cmp(const std::tuple<T...> &a, const std::tuple<T...> &b) {
|
||||
return a == b;
|
||||
}
|
||||
template<size_t I = 0>
|
||||
static inline typename std::enable_if<I == sizeof...(T), Hasher>::type hash_into(std::tuple<T...>, Hasher h) {
|
||||
static inline typename std::enable_if<I == sizeof...(T), Hasher>::type hash_into(const std::tuple<T...> &, Hasher h) {
|
||||
return h;
|
||||
}
|
||||
template<size_t I = 0>
|
||||
static inline typename std::enable_if<I != sizeof...(T), Hasher>::type hash_into(std::tuple<T...> a, Hasher h) {
|
||||
static inline typename std::enable_if<I != sizeof...(T), Hasher>::type hash_into(const std::tuple<T...> &a, Hasher h) {
|
||||
typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
|
||||
h = hash_into<I+1>(a, h);
|
||||
h = element_ops_t::hash_into(std::get<I>(a), h);
|
||||
return h;
|
||||
}
|
||||
HASH_TOP_LOOP_FST (std::tuple<T...> a) HASH_TOP_LOOP_SND
|
||||
HASH_TOP_LOOP_FST (const std::tuple<T...> &a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
template<typename T> struct hash_ops<std::vector<T>> {
|
||||
static inline bool cmp(std::vector<T> a, std::vector<T> b) {
|
||||
static inline bool cmp(const std::vector<T> &a, const std::vector<T> &b) {
|
||||
return a == b;
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(std::vector<T> a, Hasher h) {
|
||||
[[nodiscard]] static inline Hasher hash_into(const std::vector<T> &a, Hasher h) {
|
||||
h.eat((uint32_t)a.size());
|
||||
for (auto k : a)
|
||||
h.eat(k);
|
||||
return h;
|
||||
}
|
||||
HASH_TOP_LOOP_FST (std::vector<T> a) HASH_TOP_LOOP_SND
|
||||
HASH_TOP_LOOP_FST (const std::vector<T> &a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
template<typename T, size_t N> struct hash_ops<std::array<T, N>> {
|
||||
static inline bool cmp(std::array<T, N> a, std::array<T, N> b) {
|
||||
static inline bool cmp(const std::array<T, N> &a, const std::array<T, N> &b) {
|
||||
return a == b;
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(std::array<T, N> a, Hasher h) {
|
||||
[[nodiscard]] static inline Hasher hash_into(const std::array<T, N> &a, Hasher h) {
|
||||
for (const auto& k : a)
|
||||
h = hash_ops<T>::hash_into(k, h);
|
||||
return h;
|
||||
}
|
||||
HASH_TOP_LOOP_FST (std::array<T, N> a) HASH_TOP_LOOP_SND
|
||||
HASH_TOP_LOOP_FST (const std::array<T, N> &a) HASH_TOP_LOOP_SND
|
||||
};
|
||||
|
||||
struct hash_cstr_ops {
|
||||
|
|
@ -300,10 +302,10 @@ template<> struct hash_ops<std::monostate> {
|
|||
};
|
||||
|
||||
template<typename... T> struct hash_ops<std::variant<T...>> {
|
||||
static inline bool cmp(std::variant<T...> a, std::variant<T...> b) {
|
||||
static inline bool cmp(const std::variant<T...> &a, const std::variant<T...> &b) {
|
||||
return a == b;
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(std::variant<T...> a, Hasher h) {
|
||||
[[nodiscard]] static inline Hasher hash_into(const std::variant<T...> &a, Hasher h) {
|
||||
std::visit([& h](const auto &v) { h.eat(v); }, a);
|
||||
h.eat(a.index());
|
||||
return h;
|
||||
|
|
@ -311,10 +313,10 @@ template<typename... T> struct hash_ops<std::variant<T...>> {
|
|||
};
|
||||
|
||||
template<typename T> struct hash_ops<std::optional<T>> {
|
||||
static inline bool cmp(std::optional<T> a, std::optional<T> b) {
|
||||
static inline bool cmp(const std::optional<T> &a, const std::optional<T> &b) {
|
||||
return a == b;
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(std::optional<T> a, Hasher h) {
|
||||
[[nodiscard]] static inline Hasher hash_into(const std::optional<T> &a, Hasher h) {
|
||||
if(a.has_value())
|
||||
h.eat(*a);
|
||||
else
|
||||
|
|
@ -356,6 +358,29 @@ template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
|
|||
template<typename K, typename OPS = hash_ops<K>> class pool;
|
||||
template<typename K, typename OPS = hash_ops<K>> class mfp;
|
||||
|
||||
// Computes the hash value of an unordered set of elements.
|
||||
// See https://www.preprints.org/manuscript/201710.0192/v1/download.
|
||||
// This is the Sum(4) algorithm from that paper, which has good collision resistance,
|
||||
// much better than Sum(1) or Xor(1) (and somewhat better than Xor(4)).
|
||||
class commutative_hash {
|
||||
public:
|
||||
commutative_hash() {
|
||||
buckets.fill(0);
|
||||
}
|
||||
void eat(Hasher h) {
|
||||
Hasher::hash_t v = h.yield();
|
||||
size_t index = v & (buckets.size() - 1);
|
||||
buckets[index] += v;
|
||||
}
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
for (auto b : buckets)
|
||||
h.eat(b);
|
||||
return h;
|
||||
}
|
||||
private:
|
||||
std::array<Hasher::hash_t, 4> buckets;
|
||||
};
|
||||
|
||||
template<typename K, typename T, typename OPS>
|
||||
class dict {
|
||||
struct entry_t
|
||||
|
|
@ -801,14 +826,14 @@ public:
|
|||
}
|
||||
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
commutative_hash comm;
|
||||
for (auto &it : entries) {
|
||||
Hasher entry_hash;
|
||||
entry_hash.eat(it.udata.first);
|
||||
entry_hash.eat(it.udata.second);
|
||||
h.commutative_eat(entry_hash.yield());
|
||||
comm.eat(entry_hash);
|
||||
}
|
||||
h.eat(entries.size());
|
||||
return h;
|
||||
return comm.hash_into(h);
|
||||
}
|
||||
|
||||
void reserve(size_t n) { entries.reserve(n); }
|
||||
|
|
@ -1184,11 +1209,11 @@ public:
|
|||
}
|
||||
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const {
|
||||
commutative_hash comm;
|
||||
for (auto &it : entries) {
|
||||
h.commutative_eat(ops.hash(it.udata).yield());
|
||||
comm.eat(ops.hash(it.udata));
|
||||
}
|
||||
h.eat(entries.size());
|
||||
return h;
|
||||
return comm.hash_into(h);
|
||||
}
|
||||
|
||||
void reserve(size_t n) { entries.reserve(n); }
|
||||
|
|
@ -1353,7 +1378,8 @@ public:
|
|||
return p;
|
||||
}
|
||||
|
||||
// Merge sets if the given indices belong to different sets
|
||||
// Merge sets if the given indices belong to different sets.
|
||||
// Makes ifind(j) the root of the merged set.
|
||||
void imerge(int i, int j)
|
||||
{
|
||||
i = ifind(i);
|
||||
|
|
|
|||
80
kernel/io.cc
80
kernel/io.cc
|
|
@ -412,6 +412,70 @@ static std::string string_view_stringf(std::string_view spec, ...)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int spec_parameter_size(std::string_view spec)
|
||||
{
|
||||
// Every valid spec starts with '%' which means the code below
|
||||
// won't look before the spec start.
|
||||
switch (spec[spec.size() - 1]) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
switch (spec[spec.size() - 2]) {
|
||||
case 'h':
|
||||
if (spec[spec.size() - 3] == 'h')
|
||||
return sizeof(char);
|
||||
return sizeof(short);
|
||||
case 'l':
|
||||
if (spec[spec.size() - 3] == 'l')
|
||||
return sizeof(long long);
|
||||
return sizeof(long);
|
||||
case 'L':
|
||||
case 'q':
|
||||
return sizeof(long long);
|
||||
case 'j':
|
||||
return sizeof(intmax_t);
|
||||
case 'z':
|
||||
case 'Z':
|
||||
return sizeof(size_t);
|
||||
case 't':
|
||||
return sizeof(ptrdiff_t);
|
||||
}
|
||||
return sizeof(int);
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'a':
|
||||
case 'A':
|
||||
if (spec[spec.size() - 2] == 'L')
|
||||
return sizeof(long double);
|
||||
if (spec[spec.size() - 2] == 'l' && spec[spec.size() - 3] == 'l')
|
||||
return sizeof(long double);
|
||||
return sizeof(double);
|
||||
case 'c':
|
||||
if (spec[spec.size() - 2] == 'l') {
|
||||
return sizeof(wchar_t);
|
||||
}
|
||||
return sizeof(unsigned char);
|
||||
case 'C':
|
||||
return sizeof(wchar_t);
|
||||
case 's':
|
||||
case 'p':
|
||||
case 'S':
|
||||
case 'n':
|
||||
return sizeof(void *);
|
||||
case 'm':
|
||||
return sizeof(int);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
static void format_emit_stringf(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
DynamicIntCount num_dynamic_ints, Arg arg)
|
||||
|
|
@ -439,7 +503,13 @@ void format_emit_long_long(std::string &result, std::string_view spec, int *dyna
|
|||
result += std::to_string(static_cast<int>(arg));
|
||||
return;
|
||||
}
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
if (spec_parameter_size(spec) <= 4) {
|
||||
// On some platforms (Wasm) we must ensure that the arg is properly aligned
|
||||
// after the dynamic `int` parameters.
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (int)arg);
|
||||
} else {
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void format_emit_unsigned_long_long(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
|
|
@ -454,7 +524,13 @@ void format_emit_unsigned_long_long(std::string &result, std::string_view spec,
|
|||
result += static_cast<char>(arg);
|
||||
return;
|
||||
}
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
if (spec_parameter_size(spec) <= 4) {
|
||||
// On some platforms (Wasm) we must ensure that the arg is properly aligned
|
||||
// after the dynamic `int` parameters.
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (unsigned int)arg);
|
||||
} else {
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void format_emit_double(std::string &result, std::string_view spec, int *dynamic_ints,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ std::vector<std::string> log_scratchpads;
|
|||
std::map<std::string, std::set<std::string>> log_hdump;
|
||||
std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
|
||||
dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;
|
||||
dict<std::string, LogExpectedItem> log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error;
|
||||
std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;
|
||||
int log_warnings_count = 0;
|
||||
int log_warnings_count_noexpect = 0;
|
||||
|
|
@ -178,7 +179,7 @@ void logv(const char *format, va_list ap)
|
|||
{
|
||||
log_warn_regex_recusion_guard = true;
|
||||
|
||||
if (log_warn_regexes.empty() && log_expect_log.empty())
|
||||
if (log_warn_regexes.empty() && log_expect_log.empty() && log_expect_prefix_log.empty())
|
||||
{
|
||||
linebuffer.clear();
|
||||
}
|
||||
|
|
@ -191,9 +192,9 @@ void logv(const char *format, va_list ap)
|
|||
if (std::regex_search(linebuffer, re))
|
||||
log_warning("Found log message matching -W regex:\n%s", str.c_str());
|
||||
|
||||
for (auto &item : log_expect_log)
|
||||
if (std::regex_search(linebuffer, item.second.pattern))
|
||||
item.second.current_count++;
|
||||
for (auto &[_, item] : log_expect_log)
|
||||
if (std::regex_search(linebuffer, item.pattern))
|
||||
item.current_count++;
|
||||
|
||||
linebuffer.clear();
|
||||
}
|
||||
|
|
@ -266,9 +267,15 @@ static void logv_warning_with_prefix(const char *prefix,
|
|||
log_error("%s", message.c_str());
|
||||
|
||||
bool warning_match = false;
|
||||
for (auto &item : log_expect_warning)
|
||||
if (std::regex_search(message, item.second.pattern)) {
|
||||
item.second.current_count++;
|
||||
for (auto &[_, item] : log_expect_warning)
|
||||
if (std::regex_search(message, item.pattern)) {
|
||||
item.current_count++;
|
||||
warning_match = true;
|
||||
}
|
||||
|
||||
for (auto &[_, item] : log_expect_prefix_warning)
|
||||
if (std::regex_search(string(prefix) + message, item.pattern)) {
|
||||
item.current_count++;
|
||||
warning_match = true;
|
||||
}
|
||||
|
||||
|
|
@ -355,9 +362,13 @@ static void logv_error_with_prefix(const char *prefix,
|
|||
|
||||
log_make_debug = bak_log_make_debug;
|
||||
|
||||
for (auto &item : log_expect_error)
|
||||
if (std::regex_search(log_last_error, item.second.pattern))
|
||||
item.second.current_count++;
|
||||
for (auto &[_, item] : log_expect_error)
|
||||
if (std::regex_search(log_last_error, item.pattern))
|
||||
item.current_count++;
|
||||
|
||||
for (auto &[_, item] : log_expect_prefix_error)
|
||||
if (std::regex_search(string(prefix) + string(log_last_error), item.pattern))
|
||||
item.current_count++;
|
||||
|
||||
log_check_expected();
|
||||
|
||||
|
|
@ -705,38 +716,39 @@ void log_check_expected()
|
|||
// copy out all of the expected logs so that they cannot be re-checked
|
||||
// or match against themselves
|
||||
dict<std::string, LogExpectedItem> expect_log, expect_warning, expect_error;
|
||||
dict<std::string, LogExpectedItem> expect_prefix_log, expect_prefix_warning, expect_prefix_error;
|
||||
std::swap(expect_warning, log_expect_warning);
|
||||
std::swap(expect_log, log_expect_log);
|
||||
std::swap(expect_error, log_expect_error);
|
||||
std::swap(expect_prefix_warning, log_expect_prefix_warning);
|
||||
std::swap(expect_prefix_log, log_expect_prefix_log);
|
||||
std::swap(expect_prefix_error, log_expect_prefix_error);
|
||||
|
||||
for (auto &item : expect_warning) {
|
||||
if (item.second.current_count == 0) {
|
||||
auto check = [&](const std::string kind, std::string pattern, LogExpectedItem item) {
|
||||
if (item.current_count == 0) {
|
||||
log_warn_regexes.clear();
|
||||
log_error("Expected warning pattern '%s' not found !\n", item.first.c_str());
|
||||
log_error("Expected %s pattern '%s' not found !\n", kind.c_str(), pattern.c_str());
|
||||
}
|
||||
if (item.second.current_count != item.second.expected_count) {
|
||||
if (item.current_count != item.expected_count) {
|
||||
log_warn_regexes.clear();
|
||||
log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n",
|
||||
item.first.c_str(), item.second.current_count, item.second.expected_count);
|
||||
log_error("Expected %s pattern '%s' found %d time(s), instead of %d time(s) !\n",
|
||||
kind.c_str(), pattern.c_str(), item.current_count, item.expected_count);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (auto &item : expect_log) {
|
||||
if (item.second.current_count == 0) {
|
||||
log_warn_regexes.clear();
|
||||
log_error("Expected log pattern '%s' not found !\n", item.first.c_str());
|
||||
}
|
||||
if (item.second.current_count != item.second.expected_count) {
|
||||
log_warn_regexes.clear();
|
||||
log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n",
|
||||
item.first.c_str(), item.second.current_count, item.second.expected_count);
|
||||
}
|
||||
}
|
||||
for (auto &[pattern, item] : expect_warning)
|
||||
check("warning", pattern, item);
|
||||
for (auto &[pattern, item] : expect_prefix_warning)
|
||||
check("prefixed warning", pattern, item);
|
||||
for (auto &[pattern, item] : expect_log)
|
||||
check("log", pattern, item);
|
||||
for (auto &[pattern, item] : expect_prefix_log)
|
||||
check("prefixed log", pattern, item);
|
||||
|
||||
for (auto &item : expect_error)
|
||||
if (item.second.current_count == item.second.expected_count) {
|
||||
auto check_err = [&](const std::string kind, std::string pattern, LogExpectedItem item) {
|
||||
if (item.current_count == item.expected_count) {
|
||||
log_warn_regexes.clear();
|
||||
log("Expected error pattern '%s' found !!!\n", item.first.c_str());
|
||||
log("Expected %s pattern '%s' found !!!\n", kind.c_str(), pattern.c_str());
|
||||
yosys_shutdown();
|
||||
#ifdef EMSCRIPTEN
|
||||
throw 0;
|
||||
|
|
@ -747,8 +759,13 @@ void log_check_expected()
|
|||
#endif
|
||||
} else {
|
||||
log_warn_regexes.clear();
|
||||
log_error("Expected error pattern '%s' not found !\n", item.first.c_str());
|
||||
log_error("Expected %s pattern '%s' not found !\n", kind.c_str(), pattern.c_str());
|
||||
}
|
||||
};
|
||||
for (auto &[pattern, item] : expect_error)
|
||||
check_err("error", pattern, item);
|
||||
for (auto &[pattern, item] : expect_prefix_error)
|
||||
check_err("prefixed error", pattern, item);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ struct LogExpectedItem
|
|||
};
|
||||
|
||||
extern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;
|
||||
extern dict<std::string, LogExpectedItem> log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error;
|
||||
void log_check_expected();
|
||||
|
||||
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
|
||||
|
|
|
|||
|
|
@ -952,10 +952,6 @@ RTLIL::Design::~Design()
|
|||
delete pr.second;
|
||||
for (auto n : bindings_)
|
||||
delete n;
|
||||
for (auto n : verilog_packages)
|
||||
delete n;
|
||||
for (auto n : verilog_globals)
|
||||
delete n;
|
||||
#ifdef WITH_PYTHON
|
||||
RTLIL::Design::get_all_designs()->erase(hashidx_);
|
||||
#endif
|
||||
|
|
@ -4287,9 +4283,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
|||
type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
|
||||
return;
|
||||
|
||||
if (type == ID($buf) || type == ID($mux) || type == ID($pmux) || type == ID($bmux)) {
|
||||
if (type == ID($buf) || type == ID($mux) || type == ID($pmux) || type == ID($bmux) || type == ID($bwmux) || type == ID($bweqx)) {
|
||||
parameters[ID::WIDTH] = GetSize(connections_[ID::Y]);
|
||||
if (type != ID($buf) && type != ID($mux))
|
||||
if (type.in(ID($pmux), ID($bmux)))
|
||||
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
|
||||
check();
|
||||
return;
|
||||
|
|
@ -4344,7 +4340,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
|||
parameters[ID::B_WIDTH] = GetSize(connections_[ID::B]);
|
||||
}
|
||||
|
||||
if (connections_.count(ID::Y))
|
||||
if (connections_.count(ID::Y) && type != ID($concat))
|
||||
parameters[ID::Y_WIDTH] = GetSize(connections_[ID::Y]);
|
||||
|
||||
if (connections_.count(ID::Q))
|
||||
|
|
@ -5710,16 +5706,10 @@ static void sigspec_parse_split(std::vector<std::string> &tokens, const std::str
|
|||
tokens.push_back(text.substr(start));
|
||||
}
|
||||
|
||||
static int sigspec_parse_get_dummy_line_num()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str)
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.parse");
|
||||
|
||||
AST::current_filename = "input";
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
sigspec_parse_split(tokens, str, ',');
|
||||
|
|
@ -5735,12 +5725,11 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
|
|||
|
||||
if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') {
|
||||
cover("kernel.rtlil.sigspec.parse.const");
|
||||
AST::get_line_num = sigspec_parse_get_dummy_line_num;
|
||||
AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname);
|
||||
if (ast == NULL)
|
||||
VERILOG_FRONTEND::ConstParser p{Location()};
|
||||
auto ast = p.const2ast(netname);
|
||||
if (ast == nullptr)
|
||||
return false;
|
||||
sig.append(RTLIL::Const(ast->bits));
|
||||
delete ast;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1334,7 +1334,7 @@ struct RTLIL::Design
|
|||
dict<RTLIL::IdString, RTLIL::Module*> modules_;
|
||||
std::vector<RTLIL::Binding*> bindings_;
|
||||
|
||||
std::vector<AST::AstNode*> verilog_packages, verilog_globals;
|
||||
std::vector<std::unique_ptr<AST::AstNode>> verilog_packages, verilog_globals;
|
||||
std::unique_ptr<define_map_t> verilog_defines;
|
||||
|
||||
std::vector<RTLIL::Selection> selection_stack;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ struct ezSatPtr : public std::unique_ptr<ezSAT> {
|
|||
struct SatGen
|
||||
{
|
||||
ezSAT *ez;
|
||||
SigMap *sigmap;
|
||||
const SigMap *sigmap;
|
||||
std::string prefix;
|
||||
SigPool initial_state;
|
||||
std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en;
|
||||
|
|
@ -75,12 +75,12 @@ struct SatGen
|
|||
bool model_undef;
|
||||
bool def_formal = false;
|
||||
|
||||
SatGen(ezSAT *ez, SigMap *sigmap, std::string prefix = std::string()) :
|
||||
SatGen(ezSAT *ez, const SigMap *sigmap, std::string prefix = std::string()) :
|
||||
ez(ez), sigmap(sigmap), prefix(prefix), ignore_div_by_zero(false), model_undef(false)
|
||||
{
|
||||
}
|
||||
|
||||
void setContext(SigMap *sigmap, std::string prefix = std::string())
|
||||
void setContext(const SigMap *sigmap, std::string prefix = std::string())
|
||||
{
|
||||
this->sigmap = sigmap;
|
||||
this->prefix = prefix;
|
||||
|
|
|
|||
|
|
@ -237,6 +237,42 @@ using sort_by_name_id_guard = typename std::enable_if<std::is_same<T,RTLIL::Cell
|
|||
template<typename T>
|
||||
class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name_id<typename std::remove_pointer<T>::type>> {};
|
||||
|
||||
struct SigMapView
|
||||
{
|
||||
mfp<SigBit> database;
|
||||
|
||||
// Modify bit to its representative
|
||||
void apply(RTLIL::SigBit &bit) const
|
||||
{
|
||||
bit = database.find(bit);
|
||||
}
|
||||
|
||||
void apply(RTLIL::SigSpec &sig) const
|
||||
{
|
||||
for (auto &bit : sig)
|
||||
apply(bit);
|
||||
}
|
||||
|
||||
RTLIL::SigBit operator()(RTLIL::SigBit bit) const
|
||||
{
|
||||
apply(bit);
|
||||
return bit;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const
|
||||
{
|
||||
apply(sig);
|
||||
return sig;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec operator()(RTLIL::Wire *wire) const
|
||||
{
|
||||
SigSpec sig(wire);
|
||||
apply(sig);
|
||||
return sig;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SigMap wraps a union-find "database"
|
||||
* to map SigBits of a module to canonical representative SigBits.
|
||||
|
|
@ -244,10 +280,8 @@ class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name
|
|||
* If a SigBit has a const state (impl: bit.wire is nullptr),
|
||||
* it's promoted to a representative.
|
||||
*/
|
||||
struct SigMap
|
||||
struct SigMap final : public SigMapView
|
||||
{
|
||||
mfp<SigBit> database;
|
||||
|
||||
SigMap(RTLIL::Module *module = NULL)
|
||||
{
|
||||
if (module != NULL)
|
||||
|
|
@ -320,37 +354,6 @@ struct SigMap
|
|||
|
||||
inline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); }
|
||||
|
||||
// Modify bit to its representative
|
||||
void apply(RTLIL::SigBit &bit) const
|
||||
{
|
||||
bit = database.find(bit);
|
||||
}
|
||||
|
||||
void apply(RTLIL::SigSpec &sig) const
|
||||
{
|
||||
for (auto &bit : sig)
|
||||
apply(bit);
|
||||
}
|
||||
|
||||
RTLIL::SigBit operator()(RTLIL::SigBit bit) const
|
||||
{
|
||||
apply(bit);
|
||||
return bit;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const
|
||||
{
|
||||
apply(sig);
|
||||
return sig;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec operator()(RTLIL::Wire *wire) const
|
||||
{
|
||||
SigSpec sig(wire);
|
||||
apply(sig);
|
||||
return sig;
|
||||
}
|
||||
|
||||
// All non-const bits
|
||||
RTLIL::SigSpec allbits() const
|
||||
{
|
||||
|
|
@ -362,6 +365,107 @@ struct SigMap
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SiValgMap wraps a union-find "database" to map SigBits of a module to
|
||||
* canonical representative SigBits plus some optional Val value associated with the bits.
|
||||
* Val has a commutative, associative, idempotent operator|=, a default constructor
|
||||
* which constructs an identity element, and a copy constructor.
|
||||
* SigBits that are connected share a set in the underlying database;
|
||||
* the associated value is the "sum" of all the values associated with the contributing bits.
|
||||
* If any of the SigBits in a set are a constant, the canonical SigBit is a constant.
|
||||
*/
|
||||
template <class Val>
|
||||
struct SigValMap final : public SigMapView
|
||||
{
|
||||
dict<SigBit, Val> values;
|
||||
|
||||
void swap(SigValMap<Val> &other)
|
||||
{
|
||||
database.swap(other.database);
|
||||
values.swap(other.values);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
database.clear();
|
||||
values.clear();
|
||||
}
|
||||
|
||||
// Rebuild SigMap for all connections in module
|
||||
void set(RTLIL::Module *module)
|
||||
{
|
||||
int bitcount = 0;
|
||||
for (auto &it : module->connections())
|
||||
bitcount += it.first.size();
|
||||
|
||||
database.clear();
|
||||
values.clear();
|
||||
database.reserve(bitcount);
|
||||
|
||||
for (auto &it : module->connections())
|
||||
add(it.first, it.second);
|
||||
}
|
||||
|
||||
// Add connections from "from" to "to", bit-by-bit.
|
||||
void add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to)
|
||||
{
|
||||
log_assert(GetSize(from) == GetSize(to));
|
||||
|
||||
for (int i = 0; i < GetSize(from); i++)
|
||||
{
|
||||
int bfi = database.lookup(from[i]);
|
||||
int bti = database.lookup(to[i]);
|
||||
if (bfi == bti) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const RTLIL::SigBit &bf = database[bfi];
|
||||
const RTLIL::SigBit &bt = database[bti];
|
||||
if (bf.wire == nullptr) {
|
||||
// bf is constant so make it the canonical representative.
|
||||
database.imerge(bti, bfi);
|
||||
merge_value(bt, bf);
|
||||
} else {
|
||||
// Make bt the canonical representative.
|
||||
database.imerge(bfi, bti);
|
||||
merge_value(bf, bt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addVal(const RTLIL::SigBit &bit, const Val &val)
|
||||
{
|
||||
values[database.find(bit)] |= val;
|
||||
}
|
||||
|
||||
void addVal(const RTLIL::SigSpec &sig, const Val &val)
|
||||
{
|
||||
for (const auto &bit : sig)
|
||||
addVal(bit, val);
|
||||
}
|
||||
|
||||
Val apply_and_get_value(RTLIL::SigBit &bit) const
|
||||
{
|
||||
bit = database.find(bit);
|
||||
auto it = values.find(bit);
|
||||
return it == values.end() ? Val() : it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
void merge_value(const RTLIL::SigBit &from, const RTLIL::SigBit &to)
|
||||
{
|
||||
auto it = values.find(from);
|
||||
if (it == values.end()) {
|
||||
return;
|
||||
}
|
||||
// values[to] could resize the underlying `entries` so
|
||||
// finish using `it` first.
|
||||
Val v = it->second;
|
||||
values.erase(it);
|
||||
values[to] |= v;
|
||||
}
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif /* SIGTOOLS_H */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#ifndef YOSYS_COMMON_H
|
||||
#define YOSYS_COMMON_H
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,13 @@ mv zlib-1.2.11/* "$vcxsrc"/yosys/libs/zlib/.
|
|||
rm -rf zlib-1.2.11
|
||||
pushd "$vcxsrc"/yosys
|
||||
ls libs/zlib/*.c | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' >> ../../srcfiles.txt
|
||||
|
||||
if [ -f "/usr/include/FlexLexer.h" ] ; then
|
||||
mkdir -p libs/flex
|
||||
cp /usr/include/FlexLexer.h libs/flex/FlexLexer.h
|
||||
ls libs/flex/*.h >> ../../srcfiles.txt
|
||||
fi
|
||||
|
||||
popd
|
||||
{
|
||||
n=$(grep -B999 '<ItemGroup>' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l)
|
||||
|
|
@ -31,6 +38,9 @@ popd
|
|||
} > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
||||
|
||||
sed -i 's,</AdditionalIncludeDirectories>,</AdditionalIncludeDirectories>\n <LanguageStandard>stdcpp17</LanguageStandard>\n <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
||||
if [ -f "/usr/include/FlexLexer.h" ] ; then
|
||||
sed -i 's,</AdditionalIncludeDirectories>,;..\\yosys\\libs\\flex</AdditionalIncludeDirectories>,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
|
||||
fi
|
||||
mv "$vcxsrc"/YosysVS/YosysVS.vcxproj.new "$vcxsrc"/YosysVS/YosysVS.vcxproj
|
||||
|
||||
mkdir -p "$vcxsrc"/yosys
|
||||
|
|
|
|||
|
|
@ -373,6 +373,12 @@ struct AbstractPass : public Pass {
|
|||
log(" abstractions performed by either mode. This option is not supported in\n");
|
||||
log(" the -init mode.\n");
|
||||
log("\n");
|
||||
log(" -initstates <n>\n");
|
||||
log(" Perform conditional abstraction for the first <n> time steps. See the\n");
|
||||
log(" description of the -state and -value modes for details on how the\n");
|
||||
log(" condition affects the abstractions performed by either mode. This option\n");
|
||||
log(" is not supported in the -init mode.\n");
|
||||
log("\n");
|
||||
log(" -slice <lhs>:<rhs>\n");
|
||||
log(" -slice <index>\n");
|
||||
log(" -rtlilslice <lhs>:<rhs>\n");
|
||||
|
|
@ -402,8 +408,10 @@ struct AbstractPass : public Pass {
|
|||
Always = -1,
|
||||
ActiveLow = false, // ensuring we can use bool(enable)
|
||||
ActiveHigh = true,
|
||||
Initstates = 2,
|
||||
};
|
||||
Enable enable = Enable::Always;
|
||||
int initstates = 0;
|
||||
std::string enable_name;
|
||||
std::vector<Slice> slices;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
|
@ -435,6 +443,13 @@ struct AbstractPass : public Pass {
|
|||
enable = Enable::ActiveLow;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-initstates" && argidx + 1 < args.size()) {
|
||||
if (enable != Enable::Always)
|
||||
log_cmd_error("Multiple enable condition are not supported\n");
|
||||
initstates = atoi(args[++argidx].c_str());
|
||||
enable = Enable::Initstates;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-slice" && argidx + 1 < args.size()) {
|
||||
slices.emplace_back(SliceIndices::HdlSlice, args[++argidx]);
|
||||
continue;
|
||||
|
|
@ -451,22 +466,50 @@ struct AbstractPass : public Pass {
|
|||
if (mode == Mode::Initial)
|
||||
log_cmd_error("Conditional initial value abstraction is not supported\n");
|
||||
|
||||
if (enable_name.empty())
|
||||
log_cmd_error("Unspecified enable wire\n");
|
||||
switch (enable) {
|
||||
case Enable::Always:
|
||||
log_assert(false);
|
||||
case Enable::ActiveLow:
|
||||
case Enable::ActiveHigh: {
|
||||
if (enable_name.empty())
|
||||
log_cmd_error("Unspecified enable wire\n");
|
||||
} break;
|
||||
case Enable::Initstates: {
|
||||
if (initstates <= 0)
|
||||
log_cmd_error("Number of initial time steps must be positive\n");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int changed = 0;
|
||||
if ((mode == State) || (mode == Value)) {
|
||||
for (auto mod : design->selected_modules()) {
|
||||
EnableLogic enable_logic = { State::S1, true };
|
||||
if (enable != Enable::Always) {
|
||||
Wire *enable_wire = mod->wire("\\" + enable_name);
|
||||
if (!enable_wire)
|
||||
log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str());
|
||||
if (GetSize(enable_wire) != 1)
|
||||
log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n",
|
||||
enable_name.c_str(), GetSize(enable_wire), mod->name.c_str());
|
||||
enable_logic = { enable_wire, enable == Enable::ActiveHigh };
|
||||
EnableLogic enable_logic;
|
||||
|
||||
switch (enable) {
|
||||
case Enable::Always: {
|
||||
enable_logic = { State::S1, true };
|
||||
} break;
|
||||
case Enable::ActiveLow:
|
||||
case Enable::ActiveHigh: {
|
||||
Wire *enable_wire = mod->wire("\\" + enable_name);
|
||||
if (!enable_wire)
|
||||
log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str());
|
||||
if (GetSize(enable_wire) != 1)
|
||||
log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n",
|
||||
enable_name.c_str(), GetSize(enable_wire), mod->name.c_str());
|
||||
enable_logic = { enable_wire, enable == Enable::ActiveHigh };
|
||||
} break;
|
||||
case Enable::Initstates: {
|
||||
SigBit in_init_states = mod->Initstate(NEW_ID);
|
||||
for (int i = 1; i < initstates; i++) {
|
||||
Wire *in_init_states_q = mod->addWire(NEW_ID);
|
||||
mod->addFf(NEW_ID, in_init_states, in_init_states_q);
|
||||
in_init_states_q->attributes[ID::init] = State::S1;
|
||||
in_init_states = in_init_states_q;
|
||||
}
|
||||
enable_logic = { in_init_states, true };
|
||||
} break;
|
||||
}
|
||||
if (mode == State)
|
||||
changed += abstract_state(mod, enable_logic, slices);
|
||||
|
|
|
|||
|
|
@ -195,16 +195,23 @@ struct CheckPass : public Pass {
|
|||
// in port widths are those for us to check.
|
||||
if (!cell->type.in(
|
||||
ID($add), ID($sub),
|
||||
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
|
||||
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
|
||||
ID($pmux), ID($bmux)))
|
||||
return false;
|
||||
|
||||
int in_widths = 0, out_widths = 0;
|
||||
|
||||
for (auto &conn : cell->connections()) {
|
||||
if (cell->input(conn.first))
|
||||
in_widths += conn.second.size();
|
||||
if (cell->output(conn.first))
|
||||
out_widths += conn.second.size();
|
||||
if (cell->type.in(ID($pmux), ID($bmux))) {
|
||||
// We're skipping inputs A and B, since each of their bits contributes only one edge
|
||||
in_widths = GetSize(cell->getPort(ID::S));
|
||||
out_widths = GetSize(cell->getPort(ID::Y));
|
||||
} else {
|
||||
for (auto &conn : cell->connections()) {
|
||||
if (cell->input(conn.first))
|
||||
in_widths += conn.second.size();
|
||||
if (cell->output(conn.first))
|
||||
out_widths += conn.second.size();
|
||||
}
|
||||
}
|
||||
|
||||
const int threshold = 1024;
|
||||
|
|
|
|||
|
|
@ -368,14 +368,8 @@ struct DesignPass : public Pass {
|
|||
|
||||
if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode)
|
||||
{
|
||||
for (auto node : design->verilog_packages)
|
||||
delete node;
|
||||
design->verilog_packages.clear();
|
||||
|
||||
for (auto node : design->verilog_globals)
|
||||
delete node;
|
||||
design->verilog_globals.clear();
|
||||
|
||||
design->verilog_defines->clear();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ struct LoggerPass : public Pass {
|
|||
log(" -expect <type> <regex> <expected_count>\n");
|
||||
log(" expect log, warning or error to appear. matched errors will terminate\n");
|
||||
log(" with exit code 0.\n");
|
||||
log(" Types prefix-log, prefix-warning and prefix-error match the entire\n");
|
||||
log(" logged string, including filename if present.\n");
|
||||
log("\n");
|
||||
log(" -expect-no-warnings\n");
|
||||
log(" gives error in case there is at least one warning that is not expected.\n");
|
||||
|
|
@ -156,26 +158,33 @@ struct LoggerPass : public Pass {
|
|||
}
|
||||
if (args[argidx] == "-expect" && argidx+3 < args.size()) {
|
||||
std::string type = args[++argidx];
|
||||
if (type!="error" && type!="warning" && type!="log")
|
||||
if (type!="error" && type!="warning" && type!="log"
|
||||
&& type!="prefix-error" && type!="prefix-warning" && type!="prefix-log")
|
||||
log_cmd_error("Expect command require type to be 'log', 'warning' or 'error' !\n");
|
||||
if (type=="error" && log_expect_error.size()>0)
|
||||
if ((type=="error" || type=="prefix-error") && log_expect_error.size()>0)
|
||||
log_cmd_error("Only single error message can be expected !\n");
|
||||
std::string pattern = args[++argidx];
|
||||
if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2);
|
||||
if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2);
|
||||
int count = atoi(args[++argidx].c_str());
|
||||
if (count<=0)
|
||||
log_cmd_error("Number of expected messages must be higher then 0 !\n");
|
||||
if (type=="error" && count!=1)
|
||||
if ((type=="error" || type=="prefix-error") && count!=1)
|
||||
log_cmd_error("Expected error message occurrences must be 1 !\n");
|
||||
log("Added regex '%s' to expected %s messages list.\n",
|
||||
pattern.c_str(), type.c_str());
|
||||
try {
|
||||
if (type == "error")
|
||||
log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
|
||||
else if (type == "prefix-error")
|
||||
log_expect_prefix_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
|
||||
else if (type == "warning")
|
||||
log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
|
||||
else if (type == "prefix-warning")
|
||||
log_expect_prefix_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
|
||||
else if (type == "log")
|
||||
log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
|
||||
else if (type == "prefix-log")
|
||||
log_expect_prefix_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
|
||||
else log_abort();
|
||||
}
|
||||
catch (const std::regex_error& e) {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ static std::string derive_name_from_src(const std::string &src, int counter)
|
|||
return stringf("\\%s$%d", src_base.c_str(), counter);
|
||||
}
|
||||
|
||||
static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, string suffix)
|
||||
static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, string suffix, bool move_to_cell)
|
||||
{
|
||||
// Find output
|
||||
const SigSpec *output = nullptr;
|
||||
|
|
@ -93,13 +93,21 @@ static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, strin
|
|||
|
||||
name += chunk.wire->name.str();
|
||||
if (chunk.wire->width != chunk.width) {
|
||||
name += "[";
|
||||
if (chunk.width != 1)
|
||||
name += std::to_string(chunk.offset + chunk.width) + ":";
|
||||
name += std::to_string(chunk.offset) + "]";
|
||||
int lhs = chunk.wire->to_hdl_index(chunk.offset + chunk.width - 1);
|
||||
int rhs = chunk.wire->to_hdl_index(chunk.offset);
|
||||
|
||||
if (lhs != rhs)
|
||||
name += stringf("[%d:%d]", lhs, rhs);
|
||||
else
|
||||
name += stringf("[%d]", lhs);
|
||||
}
|
||||
}
|
||||
|
||||
RTLIL::Wire *wire;
|
||||
|
||||
if (move_to_cell && (!(wire = cell->module->wire(name)) || !(wire->port_input || wire->port_output)))
|
||||
return name;
|
||||
|
||||
if (suffix.empty()) {
|
||||
suffix = cell->type.str();
|
||||
}
|
||||
|
|
@ -232,13 +240,17 @@ struct RenamePass : public Pass {
|
|||
log("cells with private names.\n");
|
||||
log("\n");
|
||||
log("\n");
|
||||
log(" rename -wire [selection] [-suffix <suffix>]\n");
|
||||
log(" rename -wire [selection] [-move-to-cell] [-suffix <suffix>]\n");
|
||||
log("\n");
|
||||
log("Assign auto-generated names based on the wires they drive to all selected\n");
|
||||
log("cells with private names. Ignores cells driving privatly named wires.\n");
|
||||
log("By default, the cell is named after the wire with the cell type as suffix.\n");
|
||||
log("The -suffix option can be used to set the suffix to the given string instead.\n");
|
||||
log("\n");
|
||||
log("The -move-to-cell option can be used to name the cell after the wire without\n");
|
||||
log("any suffix. If this would lead to conflicts, the suffix is added to the wire\n");
|
||||
log("instead. For cells driving ports, the -move-to-cell option is ignored.\n");
|
||||
log("\n");
|
||||
log("\n");
|
||||
log(" rename -enumerate [-pattern <pattern>] [selection]\n");
|
||||
log("\n");
|
||||
|
|
@ -286,6 +298,7 @@ struct RenamePass : public Pass {
|
|||
std::string cell_suffix = "";
|
||||
bool flag_src = false;
|
||||
bool flag_wire = false;
|
||||
bool flag_move_to_cell = false;
|
||||
bool flag_enumerate = false;
|
||||
bool flag_witness = false;
|
||||
bool flag_hide = false;
|
||||
|
|
@ -345,6 +358,10 @@ struct RenamePass : public Pass {
|
|||
got_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-move-to-cell" && flag_wire && !flag_move_to_cell) {
|
||||
flag_move_to_cell = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-pattern" && argidx+1 < args.size() && args[argidx+1].find('%') != std::string::npos) {
|
||||
int pos = args[++argidx].find('%');
|
||||
pattern_prefix = args[argidx].substr(0, pos);
|
||||
|
|
@ -396,9 +413,26 @@ struct RenamePass : public Pass {
|
|||
dict<RTLIL::Cell *, IdString> new_cell_names;
|
||||
for (auto cell : module->selected_cells())
|
||||
if (cell->name[0] == '$')
|
||||
new_cell_names[cell] = derive_name_from_cell_output_wire(cell, cell_suffix);
|
||||
for (auto &it : new_cell_names)
|
||||
module->rename(it.first, it.second);
|
||||
new_cell_names[cell] = derive_name_from_cell_output_wire(cell, cell_suffix, flag_move_to_cell);
|
||||
for (auto &[cell, new_name] : new_cell_names) {
|
||||
if (flag_move_to_cell) {
|
||||
RTLIL::Wire *found_wire = module->wire(new_name);
|
||||
if (found_wire) {
|
||||
std::string wire_suffix = cell_suffix;
|
||||
if (wire_suffix.empty()) {
|
||||
for (auto const &[port, _] : cell->connections()) {
|
||||
if (cell->output(port)) {
|
||||
wire_suffix += stringf("%s.%s", cell->type.c_str(), port.c_str() + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
IdString new_wire_name = found_wire->name.str() + wire_suffix;
|
||||
module->rename(found_wire, new_wire_name);
|
||||
}
|
||||
}
|
||||
module->rename(cell, new_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -564,6 +598,8 @@ struct RenamePass : public Pass {
|
|||
|
||||
for (auto &it : new_cell_names)
|
||||
module->rename(it.first, it.second);
|
||||
|
||||
module->fixup_ports();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -47,7 +47,7 @@ struct ContextData {
|
|||
std::string unused_outputs;
|
||||
};
|
||||
|
||||
std::optional<std::string> format(std::string fmt, const dict<IdString, Const> ¶meters,
|
||||
std::optional<std::string> format_with_params(std::string fmt, const dict<IdString, Const> ¶meters,
|
||||
const ContextData &context)
|
||||
{
|
||||
std::stringstream result;
|
||||
|
|
@ -230,7 +230,7 @@ struct WrapcellPass : Pass {
|
|||
context.unused_outputs += "_" + RTLIL::unescape_id(chunk.format(cell));
|
||||
}
|
||||
|
||||
std::optional<std::string> unescaped_name = format(name_fmt, cell->parameters, context);
|
||||
std::optional<std::string> unescaped_name = format_with_params(name_fmt, cell->parameters, context);
|
||||
if (!unescaped_name)
|
||||
log_error("Formatting error when processing cell '%s' in module '%s'\n",
|
||||
log_id(cell), log_id(module));
|
||||
|
|
@ -270,7 +270,7 @@ struct WrapcellPass : Pass {
|
|||
if (rule.value_fmt.empty()) {
|
||||
subm->set_bool_attribute(rule.name);
|
||||
} else {
|
||||
std::optional<std::string> value = format(rule.value_fmt, cell->parameters, context);
|
||||
std::optional<std::string> value = format_with_params(rule.value_fmt, cell->parameters, context);
|
||||
|
||||
if (!value)
|
||||
log_error("Formatting error when processing cell '%s' in module '%s'\n",
|
||||
|
|
|
|||
|
|
@ -37,14 +37,15 @@ struct EquivInductWorker
|
|||
|
||||
int max_seq;
|
||||
int success_counter;
|
||||
bool set_assumes;
|
||||
|
||||
dict<int, int> ez_step_is_consistent;
|
||||
pool<Cell*> cell_warn_cache;
|
||||
SigPool undriven_signals;
|
||||
|
||||
EquivInductWorker(Module *module, const pool<Cell*> &unproven_equiv_cells, bool model_undef, int max_seq) : module(module), sigmap(module),
|
||||
EquivInductWorker(Module *module, const pool<Cell*> &unproven_equiv_cells, bool model_undef, int max_seq, bool set_assumes) : module(module), sigmap(module),
|
||||
cells(module->selected_cells()), workset(unproven_equiv_cells),
|
||||
satgen(ez.get(), &sigmap), max_seq(max_seq), success_counter(0)
|
||||
satgen(ez.get(), &sigmap), max_seq(max_seq), success_counter(0), set_assumes(set_assumes)
|
||||
{
|
||||
satgen.model_undef = model_undef;
|
||||
}
|
||||
|
|
@ -77,6 +78,16 @@ struct EquivInductWorker
|
|||
}
|
||||
}
|
||||
|
||||
if (set_assumes) {
|
||||
if (step == 1) {
|
||||
RTLIL::SigSpec assumes_a, assumes_en;
|
||||
satgen.getAssumes(assumes_a, assumes_en, step);
|
||||
for (int i = 0; i < GetSize(assumes_a); i++)
|
||||
log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]));
|
||||
}
|
||||
ez->assume(satgen.importAssumes(step));
|
||||
}
|
||||
|
||||
if (satgen.model_undef) {
|
||||
for (auto bit : undriven_signals.export_all())
|
||||
ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step)));
|
||||
|
|
@ -184,6 +195,9 @@ struct EquivInductPass : public Pass {
|
|||
log(" -seq <N>\n");
|
||||
log(" the max. number of time steps to be considered (default = 4)\n");
|
||||
log("\n");
|
||||
log(" -set-assumes\n");
|
||||
log(" set all assumptions provided via $assume cells\n");
|
||||
log("\n");
|
||||
log("This command is very effective in proving complex sequential circuits, when\n");
|
||||
log("the internal state of the circuit quickly propagates to $equiv cells.\n");
|
||||
log("\n");
|
||||
|
|
@ -200,7 +214,7 @@ struct EquivInductPass : public Pass {
|
|||
void execute(std::vector<std::string> args, Design *design) override
|
||||
{
|
||||
int success_counter = 0;
|
||||
bool model_undef = false;
|
||||
bool model_undef = false, set_assumes = false;
|
||||
int max_seq = 4;
|
||||
|
||||
log_header(design, "Executing EQUIV_INDUCT pass.\n");
|
||||
|
|
@ -215,6 +229,10 @@ struct EquivInductPass : public Pass {
|
|||
max_seq = atoi(args[++argidx].c_str());
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-set-assumes") {
|
||||
set_assumes = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
|
@ -222,6 +240,7 @@ struct EquivInductPass : public Pass {
|
|||
for (auto module : design->selected_modules())
|
||||
{
|
||||
pool<Cell*> unproven_equiv_cells;
|
||||
vector<Cell*> assume_cells;
|
||||
|
||||
for (auto cell : module->selected_cells())
|
||||
if (cell->type == ID($equiv)) {
|
||||
|
|
@ -234,7 +253,7 @@ struct EquivInductPass : public Pass {
|
|||
continue;
|
||||
}
|
||||
|
||||
EquivInductWorker worker(module, unproven_equiv_cells, model_undef, max_seq);
|
||||
EquivInductWorker worker(module, unproven_equiv_cells, model_undef, max_seq, set_assumes);
|
||||
worker.run();
|
||||
success_counter += worker.success_counter;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,215 +27,345 @@ struct EquivSimpleWorker
|
|||
{
|
||||
Module *module;
|
||||
const vector<Cell*> &equiv_cells;
|
||||
Cell *equiv_cell;
|
||||
const vector<Cell*> &assume_cells;
|
||||
struct Cone {
|
||||
pool<Cell*> cells;
|
||||
pool<SigBit> bits;
|
||||
void clear() {
|
||||
cells.clear();
|
||||
bits.clear();
|
||||
}
|
||||
};
|
||||
|
||||
SigMap &sigmap;
|
||||
dict<SigBit, Cell*> &bit2driver;
|
||||
struct DesignModel {
|
||||
const SigMap &sigmap;
|
||||
dict<SigBit, Cell*> &bit2driver;
|
||||
};
|
||||
DesignModel model;
|
||||
|
||||
ezSatPtr ez;
|
||||
SatGen satgen;
|
||||
int max_seq;
|
||||
bool short_cones;
|
||||
bool verbose;
|
||||
|
||||
struct Config {
|
||||
bool verbose = false;
|
||||
bool short_cones = false;
|
||||
bool model_undef = false;
|
||||
bool nogroup = false;
|
||||
bool set_assumes = false;
|
||||
int max_seq = 1;
|
||||
};
|
||||
Config cfg;
|
||||
|
||||
pool<pair<Cell*, int>> imported_cells_cache;
|
||||
|
||||
EquivSimpleWorker(const vector<Cell*> &equiv_cells, SigMap &sigmap, dict<SigBit, Cell*> &bit2driver, int max_seq, bool short_cones, bool verbose, bool model_undef) :
|
||||
module(equiv_cells.front()->module), equiv_cells(equiv_cells), equiv_cell(nullptr),
|
||||
sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), short_cones(short_cones), verbose(verbose)
|
||||
EquivSimpleWorker(const vector<Cell*> &equiv_cells, const vector<Cell*> &assume_cells, DesignModel model, Config cfg) :
|
||||
module(equiv_cells.front()->module), equiv_cells(equiv_cells), assume_cells(assume_cells),
|
||||
model(model), satgen(ez.get(), &model.sigmap), cfg(cfg)
|
||||
{
|
||||
satgen.model_undef = model_undef;
|
||||
satgen.model_undef = cfg.model_undef;
|
||||
}
|
||||
|
||||
bool find_input_cone(pool<SigBit> &next_seed, pool<Cell*> &cells_cone, pool<SigBit> &bits_cone, const pool<Cell*> &cells_stop, const pool<SigBit> &bits_stop, pool<SigBit> *input_bits, Cell *cell)
|
||||
{
|
||||
if (cells_cone.count(cell))
|
||||
struct ConeFinder {
|
||||
DesignModel model;
|
||||
// Bits we should also analyze in a later iteration (flop inputs)
|
||||
pool<SigBit> &next_seed;
|
||||
// Cells and bits we've seen so far while traversing
|
||||
Cone& cone;
|
||||
// We're not allowed to traverse past cells and bits in `stop`
|
||||
const Cone& stop;
|
||||
// Input bits are bits that no longer can be traversed
|
||||
// Tracking these is optional
|
||||
pool<SigBit>* input_bits;
|
||||
|
||||
// Recursively traverses backwards from a cell to find all cells in its input cone
|
||||
// Adds cell to cone.cells, stops at cells in 'stop' set
|
||||
// Returns true if stopped on a stop cell
|
||||
bool find_input_cone(Cell *cell)
|
||||
{
|
||||
if (cone.cells.count(cell))
|
||||
return false;
|
||||
|
||||
cone.cells.insert(cell);
|
||||
|
||||
if (stop.cells.count(cell))
|
||||
return true;
|
||||
|
||||
for (auto &conn : cell->connections())
|
||||
if (yosys_celltypes.cell_input(cell->type, conn.first))
|
||||
for (auto bit : model.sigmap(conn.second)) {
|
||||
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
||||
if (!conn.first.in(ID::CLK, ID::C))
|
||||
next_seed.insert(bit);
|
||||
} else
|
||||
find_input_cone(bit);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void find_input_cone(SigBit bit)
|
||||
{
|
||||
if (cone.bits.count(bit))
|
||||
return;
|
||||
|
||||
cells_cone.insert(cell);
|
||||
cone.bits.insert(bit);
|
||||
|
||||
if (cells_stop.count(cell))
|
||||
return true;
|
||||
if (stop.bits.count(bit)) {
|
||||
if (input_bits != nullptr) input_bits->insert(bit);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &conn : cell->connections())
|
||||
if (yosys_celltypes.cell_input(cell->type, conn.first))
|
||||
for (auto bit : sigmap(conn.second)) {
|
||||
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
||||
if (!conn.first.in(ID::CLK, ID::C))
|
||||
next_seed.insert(bit);
|
||||
} else
|
||||
find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!model.bit2driver.count(bit))
|
||||
return;
|
||||
|
||||
void find_input_cone(pool<SigBit> &next_seed, pool<Cell*> &cells_cone, pool<SigBit> &bits_cone, const pool<Cell*> &cells_stop, const pool<SigBit> &bits_stop, pool<SigBit> *input_bits, SigBit bit)
|
||||
// If the input cone of the driver cell reaches a stop bit,
|
||||
// then `bit` is an "input bit"
|
||||
if (find_input_cone(model.bit2driver.at(bit)))
|
||||
if (input_bits != nullptr) input_bits->insert(bit);
|
||||
}
|
||||
void find_input_cone(pool<SigBit> bits)
|
||||
{
|
||||
for (auto bit : bits)
|
||||
find_input_cone(bit);
|
||||
}
|
||||
};
|
||||
|
||||
// Builds (full or short) input cones from the seeds
|
||||
// Creates full cones (no stops) and optionally short cones (stop at other side's cone)
|
||||
// Updates seed_a/seed_b with next iteration's FF inputs
|
||||
// Returns input bits and cone structures for SAT problem construction
|
||||
std::tuple<pool<SigBit>, Cone, Cone> init_iter(pool<SigBit>& seed_a, pool<SigBit>& seed_b) const
|
||||
{
|
||||
if (bits_cone.count(bit))
|
||||
return;
|
||||
// Empty, never inserted to, to traverse full cones
|
||||
const Cone no_stop;
|
||||
Cone full_cone_a, full_cone_b;
|
||||
|
||||
bits_cone.insert(bit);
|
||||
// Values of seed_* for the next iteration
|
||||
pool<SigBit> next_seed_a, next_seed_b;
|
||||
|
||||
if (bits_stop.count(bit)) {
|
||||
if (input_bits != nullptr) input_bits->insert(bit);
|
||||
return;
|
||||
{
|
||||
ConeFinder finder_a {model, next_seed_a, full_cone_a, no_stop, nullptr};
|
||||
finder_a.find_input_cone(seed_a);
|
||||
|
||||
ConeFinder finder_b {model, next_seed_b, full_cone_b, no_stop, nullptr};
|
||||
finder_b.find_input_cone(seed_b);
|
||||
}
|
||||
|
||||
if (!bit2driver.count(bit))
|
||||
return;
|
||||
Cone short_cone_a, short_cone_b;
|
||||
pool<SigBit> input_bits;
|
||||
|
||||
if (find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit2driver.at(bit)))
|
||||
if (input_bits != nullptr) input_bits->insert(bit);
|
||||
if (cfg.short_cones)
|
||||
{
|
||||
// Rebuild cones with the knowledge of the full cones.
|
||||
// Avoids stuffing overlaps in input cones into the solver
|
||||
// e.g. for A by using the full B cone as stops
|
||||
next_seed_a.clear();
|
||||
ConeFinder short_finder_a = {model, next_seed_a, short_cone_a, short_cone_b, &input_bits};
|
||||
short_finder_a.find_input_cone(seed_a);
|
||||
next_seed_a.swap(seed_a);
|
||||
|
||||
next_seed_b.clear();
|
||||
ConeFinder short_finder_b = {model, next_seed_b, short_cone_b, short_cone_a, &input_bits};
|
||||
short_finder_b.find_input_cone(seed_b);
|
||||
next_seed_b.swap(seed_b);
|
||||
}
|
||||
else
|
||||
{
|
||||
short_cone_a = full_cone_a;
|
||||
next_seed_a.swap(seed_a);
|
||||
|
||||
short_cone_b = full_cone_b;
|
||||
next_seed_b.swap(seed_b);
|
||||
}
|
||||
return std::make_tuple(input_bits, short_cone_a, short_cone_b);
|
||||
}
|
||||
|
||||
bool run_cell()
|
||||
void report_new_cells(const pool<Cell*>& cells, const Cone& cone_a, const Cone& cone_b) const
|
||||
{
|
||||
SigBit bit_a = sigmap(equiv_cell->getPort(ID::A)).as_bit();
|
||||
SigBit bit_b = sigmap(equiv_cell->getPort(ID::B)).as_bit();
|
||||
int ez_context = ez->frozen_literal();
|
||||
log(" Adding %d new cells to the problem (%d A, %d B, %d shared).\n",
|
||||
GetSize(cells), GetSize(cone_a.cells), GetSize(cone_b.cells),
|
||||
(GetSize(cone_a.cells) + GetSize(cone_b.cells)) - GetSize(cells));
|
||||
#if 0
|
||||
for (auto cell : short_cells_cone_a)
|
||||
log(" A-side cell: %s\n", log_id(cell));
|
||||
|
||||
for (auto cell : short_cells_cone_b)
|
||||
log(" B-side cell: %s\n", log_id(cell));
|
||||
#endif
|
||||
}
|
||||
void report_new_assume_cells(const pool<Cell*>& extra_problem_cells, int old_size, const pool<Cell*>& problem_cells) const
|
||||
{
|
||||
if (cfg.verbose) {
|
||||
log(" Adding %d new cells to check assumptions (and reusing %d).\n",
|
||||
GetSize(problem_cells) - old_size,
|
||||
old_size - (GetSize(problem_cells) - GetSize(extra_problem_cells)));
|
||||
#if 0
|
||||
for (auto cell : extra_problem_cells)
|
||||
log(" cell: %s\n", log_id(cell));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the input cones of $assume cells get modelled by the problem
|
||||
pool<Cell*> add_assumes_to_problem(const Cone& cone_a, const Cone& cone_b) const
|
||||
{
|
||||
pool<Cell*> extra_problem_cells;
|
||||
for (auto assume : assume_cells) {
|
||||
pool<SigBit> assume_seed, dummy_next_seed, overlap_bits;
|
||||
assume_seed.insert(model.sigmap(assume->getPort(ID::A)).as_bit());
|
||||
assume_seed.insert(model.sigmap(assume->getPort(ID::EN)).as_bit());
|
||||
|
||||
for (auto& cone : {cone_a, cone_b}) {
|
||||
Cone assume_cone;
|
||||
ConeFinder{model, dummy_next_seed, assume_cone, cone, &overlap_bits}
|
||||
.find_input_cone(assume_seed);
|
||||
if (GetSize(overlap_bits)) {
|
||||
extra_problem_cells.insert(assume);
|
||||
extra_problem_cells.insert(assume_cone.cells.begin(), assume_cone.cells.end());
|
||||
overlap_bits.clear();
|
||||
}
|
||||
assume_cone.clear();
|
||||
dummy_next_seed.clear();
|
||||
}
|
||||
}
|
||||
return extra_problem_cells;
|
||||
}
|
||||
|
||||
static void report_missing_model(Cell* cell)
|
||||
{
|
||||
if (RTLIL::builtin_ff_cell_types().count(cell->type))
|
||||
log_cmd_error("No SAT model available for async FF cell %s (%s). Consider running `async2sync` or `clk2fflogic` first.\n", log_id(cell), log_id(cell->type));
|
||||
else
|
||||
log_cmd_error("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
|
||||
}
|
||||
|
||||
void prepare_ezsat(int ez_context, SigBit bit_a, SigBit bit_b)
|
||||
{
|
||||
if (satgen.model_undef)
|
||||
{
|
||||
int ez_a = satgen.importSigBit(bit_a, max_seq+1);
|
||||
int ez_b = satgen.importDefSigBit(bit_b, max_seq+1);
|
||||
int ez_undef_a = satgen.importUndefSigBit(bit_a, max_seq+1);
|
||||
int ez_a = satgen.importSigBit(bit_a, cfg.max_seq+1);
|
||||
int ez_b = satgen.importDefSigBit(bit_b, cfg.max_seq+1);
|
||||
int ez_undef_a = satgen.importUndefSigBit(bit_a, cfg.max_seq+1);
|
||||
|
||||
ez->assume(ez->XOR(ez_a, ez_b), ez_context);
|
||||
ez->assume(ez->NOT(ez_undef_a), ez_context);
|
||||
}
|
||||
else
|
||||
{
|
||||
int ez_a = satgen.importSigBit(bit_a, max_seq+1);
|
||||
int ez_b = satgen.importSigBit(bit_b, max_seq+1);
|
||||
int ez_a = satgen.importSigBit(bit_a, cfg.max_seq+1);
|
||||
int ez_b = satgen.importSigBit(bit_b, cfg.max_seq+1);
|
||||
ez->assume(ez->XOR(ez_a, ez_b), ez_context);
|
||||
}
|
||||
}
|
||||
void construct_ezsat(const pool<SigBit>& input_bits, int step)
|
||||
{
|
||||
if (cfg.set_assumes) {
|
||||
if (cfg.verbose && step == cfg.max_seq) {
|
||||
RTLIL::SigSpec assumes_a, assumes_en;
|
||||
satgen.getAssumes(assumes_a, assumes_en, step+1);
|
||||
for (int i = 0; i < GetSize(assumes_a); i++)
|
||||
log(" Import constraint from assume cell: %s when %s (%d).\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]), step);
|
||||
}
|
||||
ez->assume(satgen.importAssumes(step+1));
|
||||
}
|
||||
|
||||
if (satgen.model_undef) {
|
||||
for (auto bit : input_bits)
|
||||
ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step+1)));
|
||||
}
|
||||
|
||||
if (cfg.verbose)
|
||||
log(" Problem size at t=%d: %d literals, %d clauses\n", step, ez->numCnfVariables(), ez->numCnfClauses());
|
||||
}
|
||||
|
||||
bool prove_equiv_cell(Cell* cell)
|
||||
{
|
||||
SigBit bit_a = model.sigmap(cell->getPort(ID::A)).as_bit();
|
||||
SigBit bit_b = model.sigmap(cell->getPort(ID::B)).as_bit();
|
||||
int ez_context = ez->frozen_literal();
|
||||
|
||||
prepare_ezsat(ez_context, bit_a, bit_b);
|
||||
|
||||
// Two bits, bit_a, and bit_b, have been marked equivalent in the design
|
||||
// We will be traversing the input cones for each of them
|
||||
// In the first iteration, we will using those as starting points
|
||||
pool<SigBit> seed_a = { bit_a };
|
||||
pool<SigBit> seed_b = { bit_b };
|
||||
|
||||
if (verbose) {
|
||||
log(" Trying to prove $equiv cell %s:\n", log_id(equiv_cell));
|
||||
log(" A = %s, B = %s, Y = %s\n", log_signal(bit_a), log_signal(bit_b), log_signal(equiv_cell->getPort(ID::Y)));
|
||||
if (cfg.verbose) {
|
||||
log(" Trying to prove $equiv cell %s:\n", log_id(cell));
|
||||
log(" A = %s, B = %s, Y = %s\n", log_signal(bit_a), log_signal(bit_b), log_signal(cell->getPort(ID::Y)));
|
||||
} else {
|
||||
log(" Trying to prove $equiv for %s:", log_signal(equiv_cell->getPort(ID::Y)));
|
||||
log(" Trying to prove $equiv for %s:", log_signal(cell->getPort(ID::Y)));
|
||||
}
|
||||
|
||||
int step = max_seq;
|
||||
int step = cfg.max_seq;
|
||||
while (1)
|
||||
{
|
||||
pool<Cell*> no_stop_cells;
|
||||
pool<SigBit> no_stop_bits;
|
||||
|
||||
pool<Cell*> full_cells_cone_a, full_cells_cone_b;
|
||||
pool<SigBit> full_bits_cone_a, full_bits_cone_b;
|
||||
|
||||
pool<SigBit> next_seed_a, next_seed_b;
|
||||
|
||||
for (auto bit_a : seed_a)
|
||||
find_input_cone(next_seed_a, full_cells_cone_a, full_bits_cone_a, no_stop_cells, no_stop_bits, nullptr, bit_a);
|
||||
|
||||
for (auto bit_b : seed_b)
|
||||
find_input_cone(next_seed_b, full_cells_cone_b, full_bits_cone_b, no_stop_cells, no_stop_bits, nullptr, bit_b);
|
||||
|
||||
pool<Cell*> short_cells_cone_a, short_cells_cone_b;
|
||||
pool<SigBit> short_bits_cone_a, short_bits_cone_b;
|
||||
pool<SigBit> input_bits;
|
||||
|
||||
if (short_cones)
|
||||
{
|
||||
next_seed_a.clear();
|
||||
for (auto bit_a : seed_a)
|
||||
find_input_cone(next_seed_a, short_cells_cone_a, short_bits_cone_a, full_cells_cone_b, full_bits_cone_b, &input_bits, bit_a);
|
||||
next_seed_a.swap(seed_a);
|
||||
|
||||
next_seed_b.clear();
|
||||
for (auto bit_b : seed_b)
|
||||
find_input_cone(next_seed_b, short_cells_cone_b, short_bits_cone_b, full_cells_cone_a, full_bits_cone_a, &input_bits, bit_b);
|
||||
next_seed_b.swap(seed_b);
|
||||
}
|
||||
else
|
||||
{
|
||||
short_cells_cone_a = full_cells_cone_a;
|
||||
short_bits_cone_a = full_bits_cone_a;
|
||||
next_seed_a.swap(seed_a);
|
||||
|
||||
short_cells_cone_b = full_cells_cone_b;
|
||||
short_bits_cone_b = full_bits_cone_b;
|
||||
next_seed_b.swap(seed_b);
|
||||
}
|
||||
// Traverse input cones of seed_a and seed_b, potentially finding new seeds
|
||||
auto [input_bits, cone_a, cone_b] = init_iter(seed_a, seed_b);
|
||||
|
||||
// Cells to model in SAT solver
|
||||
pool<Cell*> problem_cells;
|
||||
problem_cells.insert(short_cells_cone_a.begin(), short_cells_cone_a.end());
|
||||
problem_cells.insert(short_cells_cone_b.begin(), short_cells_cone_b.end());
|
||||
problem_cells.insert(cone_a.cells.begin(), cone_a.cells.end());
|
||||
problem_cells.insert(cone_b.cells.begin(), cone_b.cells.end());
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
log(" Adding %d new cells to the problem (%d A, %d B, %d shared).\n",
|
||||
GetSize(problem_cells), GetSize(short_cells_cone_a), GetSize(short_cells_cone_b),
|
||||
(GetSize(short_cells_cone_a) + GetSize(short_cells_cone_b)) - GetSize(problem_cells));
|
||||
#if 0
|
||||
for (auto cell : short_cells_cone_a)
|
||||
log(" A-side cell: %s\n", log_id(cell));
|
||||
if (cfg.verbose)
|
||||
report_new_cells(problem_cells, cone_a, cone_b);
|
||||
|
||||
for (auto cell : short_cells_cone_b)
|
||||
log(" B-side cell: %s\n", log_id(cell));
|
||||
#endif
|
||||
if (cfg.set_assumes) {
|
||||
auto extras = add_assumes_to_problem(cone_a, cone_b);
|
||||
if (GetSize(extras)) {
|
||||
auto old_size = GetSize(problem_cells);
|
||||
problem_cells.insert(extras.begin(), extras.end());
|
||||
report_new_assume_cells(extras, old_size, problem_cells);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto cell : problem_cells) {
|
||||
auto key = pair<Cell*, int>(cell, step+1);
|
||||
if (!imported_cells_cache.count(key) && !satgen.importCell(cell, step+1)) {
|
||||
if (RTLIL::builtin_ff_cell_types().count(cell->type))
|
||||
log_cmd_error("No SAT model available for async FF cell %s (%s). Consider running `async2sync` or `clk2fflogic` first.\n", log_id(cell), log_id(cell->type));
|
||||
else
|
||||
log_cmd_error("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
|
||||
report_missing_model(cell);
|
||||
}
|
||||
imported_cells_cache.insert(key);
|
||||
}
|
||||
|
||||
if (satgen.model_undef) {
|
||||
for (auto bit : input_bits)
|
||||
ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step+1)));
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
log(" Problem size at t=%d: %d literals, %d clauses\n", step, ez->numCnfVariables(), ez->numCnfClauses());
|
||||
construct_ezsat(input_bits, step);
|
||||
|
||||
if (!ez->solve(ez_context)) {
|
||||
log(verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n");
|
||||
equiv_cell->setPort(ID::B, equiv_cell->getPort(ID::A));
|
||||
log(cfg.verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n");
|
||||
// Replace $equiv cell with a short
|
||||
cell->setPort(ID::B, cell->getPort(ID::A));
|
||||
ez->assume(ez->NOT(ez_context));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
log(" Failed to prove equivalence with sequence length %d.\n", max_seq - step);
|
||||
if (cfg.verbose)
|
||||
log(" Failed to prove equivalence with sequence length %d.\n", cfg.max_seq - step);
|
||||
|
||||
if (--step < 0) {
|
||||
if (verbose)
|
||||
if (cfg.verbose)
|
||||
log(" Reached sequence limit.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (seed_a.empty() && seed_b.empty()) {
|
||||
if (verbose)
|
||||
if (cfg.verbose)
|
||||
log(" No nets to continue in previous time step.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (seed_a.empty()) {
|
||||
if (verbose)
|
||||
if (cfg.verbose)
|
||||
log(" No nets on A-side to continue in previous time step.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (seed_b.empty()) {
|
||||
if (verbose)
|
||||
if (cfg.verbose)
|
||||
log(" No nets on B-side to continue in previous time step.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (cfg.verbose) {
|
||||
#if 0
|
||||
log(" Continuing analysis in previous time step with the following nets:\n");
|
||||
for (auto bit : seed_a)
|
||||
|
|
@ -248,7 +378,7 @@ struct EquivSimpleWorker
|
|||
}
|
||||
}
|
||||
|
||||
if (!verbose)
|
||||
if (!cfg.verbose)
|
||||
log(" failed.\n");
|
||||
|
||||
ez->assume(ez->NOT(ez_context));
|
||||
|
|
@ -260,14 +390,13 @@ struct EquivSimpleWorker
|
|||
if (GetSize(equiv_cells) > 1) {
|
||||
SigSpec sig;
|
||||
for (auto c : equiv_cells)
|
||||
sig.append(sigmap(c->getPort(ID::Y)));
|
||||
sig.append(model.sigmap(c->getPort(ID::Y)));
|
||||
log(" Grouping SAT models for %s:\n", log_signal(sig));
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
for (auto c : equiv_cells) {
|
||||
equiv_cell = c;
|
||||
if (run_cell())
|
||||
if (prove_equiv_cell(c))
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
|
|
@ -301,35 +430,41 @@ struct EquivSimplePass : public Pass {
|
|||
log(" -seq <N>\n");
|
||||
log(" the max. number of time steps to be considered (default = 1)\n");
|
||||
log("\n");
|
||||
log(" -set-assumes\n");
|
||||
log(" set all assumptions provided via $assume cells\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, Design *design) override
|
||||
{
|
||||
bool verbose = false, short_cones = false, model_undef = false, nogroup = false;
|
||||
EquivSimpleWorker::Config cfg = {};
|
||||
int success_counter = 0;
|
||||
int max_seq = 1;
|
||||
|
||||
log_header(design, "Executing EQUIV_SIMPLE pass.\n");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-v") {
|
||||
verbose = true;
|
||||
cfg.verbose = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-short") {
|
||||
short_cones = true;
|
||||
cfg.short_cones = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-undef") {
|
||||
model_undef = true;
|
||||
cfg.model_undef = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nogroup") {
|
||||
nogroup = true;
|
||||
cfg.nogroup = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-seq" && argidx+1 < args.size()) {
|
||||
max_seq = atoi(args[++argidx].c_str());
|
||||
cfg.max_seq = atoi(args[++argidx].c_str());
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-set-assumes") {
|
||||
cfg.set_assumes = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
|
@ -347,17 +482,21 @@ struct EquivSimplePass : public Pass {
|
|||
SigMap sigmap(module);
|
||||
dict<SigBit, Cell*> bit2driver;
|
||||
dict<SigBit, dict<SigBit, Cell*>> unproven_equiv_cells;
|
||||
vector<Cell*> assumes;
|
||||
int unproven_cells_counter = 0;
|
||||
|
||||
for (auto cell : module->selected_cells())
|
||||
for (auto cell : module->selected_cells()) {
|
||||
if (cell->type == ID($equiv) && cell->getPort(ID::A) != cell->getPort(ID::B)) {
|
||||
auto bit = sigmap(cell->getPort(ID::Y).as_bit());
|
||||
auto bit_group = bit;
|
||||
if (!nogroup && bit_group.wire)
|
||||
if (!cfg.nogroup && bit_group.wire)
|
||||
bit_group.offset = 0;
|
||||
unproven_equiv_cells[bit_group][bit] = cell;
|
||||
unproven_cells_counter++;
|
||||
} else if (cell->type == ID($assume)) {
|
||||
assumes.push_back(cell);
|
||||
}
|
||||
}
|
||||
|
||||
if (unproven_equiv_cells.empty())
|
||||
continue;
|
||||
|
|
@ -375,15 +514,16 @@ struct EquivSimplePass : public Pass {
|
|||
}
|
||||
|
||||
unproven_equiv_cells.sort();
|
||||
for (auto it : unproven_equiv_cells)
|
||||
for (auto [_, d] : unproven_equiv_cells)
|
||||
{
|
||||
it.second.sort();
|
||||
d.sort();
|
||||
|
||||
vector<Cell*> cells;
|
||||
for (auto it2 : it.second)
|
||||
cells.push_back(it2.second);
|
||||
for (auto [_, cell] : d)
|
||||
cells.push_back(cell);
|
||||
|
||||
EquivSimpleWorker worker(cells, sigmap, bit2driver, max_seq, short_cones, verbose, model_undef);
|
||||
EquivSimpleWorker::DesignModel model {sigmap, bit2driver};
|
||||
EquivSimpleWorker worker(cells, assumes, model, cfg);
|
||||
success_counter += worker.run();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ enum class WrTransKind {
|
|||
|
||||
struct WrTransDef {
|
||||
WrTransTargetKind target_kind;
|
||||
int target_group;
|
||||
int target_group = 0;
|
||||
WrTransKind kind;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ struct OptDffWorker
|
|||
|
||||
const auto complimentary_var = find_comp(left, right);
|
||||
|
||||
if (complimentary_var) {
|
||||
if (complimentary_var && new_patterns.count(right)) {
|
||||
new_patterns.erase(right);
|
||||
right.erase(complimentary_var.value());
|
||||
new_patterns.insert(right);
|
||||
|
|
|
|||
|
|
@ -44,20 +44,16 @@ struct OptMergeWorker
|
|||
CellTypes ct;
|
||||
int total_count;
|
||||
|
||||
static vector<pair<SigBit, SigSpec>> sorted_pmux_in(const dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
|
||||
static Hasher hash_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b, Hasher h)
|
||||
{
|
||||
SigSpec sig_s = conn.at(ID::S);
|
||||
SigSpec sig_b = conn.at(ID::B);
|
||||
|
||||
int s_width = GetSize(sig_s);
|
||||
int width = GetSize(sig_b) / s_width;
|
||||
|
||||
vector<pair<SigBit, SigSpec>> sb_pairs;
|
||||
hashlib::commutative_hash comm;
|
||||
for (int i = 0; i < s_width; i++)
|
||||
sb_pairs.push_back(pair<SigBit, SigSpec>(sig_s[i], sig_b.extract(i*width, width)));
|
||||
comm.eat(hash_ops<std::pair<SigBit, SigSpec>>::hash({sig_s[i], sig_b.extract(i*width, width)}));
|
||||
|
||||
std::sort(sb_pairs.begin(), sb_pairs.end());
|
||||
return sb_pairs;
|
||||
return comm.hash_into(h);
|
||||
}
|
||||
|
||||
static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
|
||||
|
|
@ -89,12 +85,10 @@ struct OptMergeWorker
|
|||
// (builtin || stdcell) && (unary || binary) && symmetrical
|
||||
if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul),
|
||||
ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) {
|
||||
std::array<RTLIL::SigSpec, 2> inputs = {
|
||||
assign_map(cell->getPort(ID::A)),
|
||||
assign_map(cell->getPort(ID::B))
|
||||
};
|
||||
std::sort(inputs.begin(), inputs.end());
|
||||
h = hash_ops<std::array<RTLIL::SigSpec, 2>>::hash_into(inputs, h);
|
||||
hashlib::commutative_hash comm;
|
||||
comm.eat(hash_ops<RTLIL::SigSpec>::hash(assign_map(cell->getPort(ID::A))));
|
||||
comm.eat(hash_ops<RTLIL::SigSpec>::hash(assign_map(cell->getPort(ID::B))));
|
||||
h = comm.hash_into(h);
|
||||
} else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) {
|
||||
SigSpec a = assign_map(cell->getPort(ID::A));
|
||||
a.sort();
|
||||
|
|
@ -104,44 +98,31 @@ struct OptMergeWorker
|
|||
a.sort_and_unify();
|
||||
h = a.hash_into(h);
|
||||
} else if (cell->type == ID($pmux)) {
|
||||
dict<RTLIL::IdString, RTLIL::SigSpec> conn = cell->connections();
|
||||
assign_map.apply(conn.at(ID::A));
|
||||
assign_map.apply(conn.at(ID::B));
|
||||
assign_map.apply(conn.at(ID::S));
|
||||
for (const auto& [s_bit, b_chunk] : sorted_pmux_in(conn)) {
|
||||
h = s_bit.hash_into(h);
|
||||
h = b_chunk.hash_into(h);
|
||||
}
|
||||
SigSpec sig_s = assign_map(cell->getPort(ID::S));
|
||||
SigSpec sig_b = assign_map(cell->getPort(ID::B));
|
||||
h = hash_pmux_in(sig_s, sig_b, h);
|
||||
h = assign_map(cell->getPort(ID::A)).hash_into(h);
|
||||
} else {
|
||||
std::vector<std::pair<IdString, SigSpec>> conns;
|
||||
for (const auto& conn : cell->connections()) {
|
||||
conns.push_back(conn);
|
||||
hashlib::commutative_hash comm;
|
||||
for (const auto& [port, sig] : cell->connections()) {
|
||||
if (cell->output(port))
|
||||
continue;
|
||||
comm.eat(hash_ops<std::pair<IdString, SigSpec>>::hash({port, assign_map(sig)}));
|
||||
}
|
||||
std::sort(conns.begin(), conns.end());
|
||||
for (const auto& [port, sig] : conns) {
|
||||
if (!cell->output(port)) {
|
||||
h = port.hash_into(h);
|
||||
h = assign_map(sig).hash_into(h);
|
||||
}
|
||||
}
|
||||
|
||||
h = comm.hash_into(h);
|
||||
if (RTLIL::builtin_ff_cell_types().count(cell->type))
|
||||
h = initvals(cell->getPort(ID::Q)).hash_into(h);
|
||||
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static Hasher hash_cell_parameters(const RTLIL::Cell *cell, Hasher h)
|
||||
{
|
||||
using Paramvec = std::vector<std::pair<IdString, Const>>;
|
||||
Paramvec params;
|
||||
hashlib::commutative_hash comm;
|
||||
for (const auto& param : cell->parameters) {
|
||||
params.push_back(param);
|
||||
comm.eat(hash_ops<std::pair<IdString, Const>>::hash(param));
|
||||
}
|
||||
std::sort(params.begin(), params.end());
|
||||
return hash_ops<Paramvec>::hash_into(params, h);
|
||||
return comm.hash_into(h);
|
||||
}
|
||||
|
||||
Hasher hash_cell_function(const RTLIL::Cell *cell, Hasher h) const
|
||||
|
|
@ -227,7 +208,7 @@ struct OptMergeWorker
|
|||
}
|
||||
|
||||
OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all, bool mode_keepdc) :
|
||||
design(design), module(module), assign_map(module), mode_share_all(mode_share_all)
|
||||
design(design), module(module), mode_share_all(mode_share_all)
|
||||
{
|
||||
total_count = 0;
|
||||
ct.setup_internals();
|
||||
|
|
|
|||
|
|
@ -23,12 +23,40 @@
|
|||
#include "kernel/celltypes.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
using RTLIL::id2cstr;
|
||||
/**
|
||||
* TERMINOLOGY
|
||||
*
|
||||
* A multiplexer tree (mux tree) is a tree composed exclusively of muxes.
|
||||
* By mux, I mean $mux or $pmux. By port, I usually mean input port.
|
||||
* The children of a node are all the muxes driving its input ports (A, B).
|
||||
* It must be rooted in a "root mux", a mux which has multiple mux users
|
||||
* or any number of non-mux users. Only the root and leaf nodes can be
|
||||
* root muxes, not the internal nodes. Leaf nodes that are root muxes
|
||||
* are roots of "input trees".
|
||||
*
|
||||
* OPERATING PRINCIPLE
|
||||
*
|
||||
* This pass traverses mux trees, learning port activations and making
|
||||
* assumptions about them as it goes. When valid, ports are replaced
|
||||
* with constants, or removed if they can never be activated.
|
||||
* When valid, muxes are replaced with shorts from port to output,
|
||||
* or removed if their outputs are found to be no longer observable.
|
||||
*
|
||||
* Input trees can be recursed into if limits_t::recursions_left allows.
|
||||
* Otherwise, the input tree is queued for a re-run with a fresh knowledge_t.
|
||||
* At any point, if glob_evals_left goes to 0, the pass terminates.
|
||||
*
|
||||
* Unlike share, this pass doesn't use SAT to learn things about logic
|
||||
* driving the mux control signals, and traverses mux regions from users
|
||||
* to drivers.
|
||||
*/
|
||||
|
||||
struct OptMuxtreeWorker
|
||||
{
|
||||
|
|
@ -36,9 +64,10 @@ struct OptMuxtreeWorker
|
|||
RTLIL::Module *module;
|
||||
SigMap assign_map;
|
||||
int removed_count;
|
||||
int glob_abort_cnt = 100000;
|
||||
int glob_evals_left = 100000;
|
||||
|
||||
struct bitinfo_t {
|
||||
// Is bit directly used by non-mux cells or ports?
|
||||
bool seen_non_mux;
|
||||
pool<int> mux_users;
|
||||
pool<int> mux_drivers;
|
||||
|
|
@ -48,12 +77,13 @@ struct OptMuxtreeWorker
|
|||
vector<bitinfo_t> bit2info;
|
||||
|
||||
struct portinfo_t {
|
||||
int ctrl_sig;
|
||||
pool<int> input_sigs;
|
||||
pool<int> input_muxes;
|
||||
bool const_activated;
|
||||
bool const_deactivated;
|
||||
bool enabled;
|
||||
int ctrl_sig = -1; // No associated control signal by default
|
||||
pool<int> input_sigs = {};
|
||||
pool<int> input_muxes = {};
|
||||
bool const_activated = false;
|
||||
bool const_deactivated = false;
|
||||
// Is the port reachable from inputs of a mux tree?
|
||||
bool observable = false;
|
||||
};
|
||||
|
||||
struct muxinfo_t {
|
||||
|
|
@ -66,13 +96,16 @@ struct OptMuxtreeWorker
|
|||
vector<bool> root_enable_muxes;
|
||||
pool<int> root_mux_rerun;
|
||||
|
||||
OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) :
|
||||
design(design), module(module), assign_map(module), removed_count(0)
|
||||
{
|
||||
log("Running muxtree optimizer on module %s..\n", module->name.c_str());
|
||||
|
||||
log(" Creating internal representation of mux trees.\n");
|
||||
portinfo_t used_port_bit(RTLIL::SigSpec& sig, int mux_idx) {
|
||||
portinfo_t portinfo = {};
|
||||
for (int bit_idx : sig2bits(sig)) {
|
||||
bit2info[bit_idx].mux_users.insert(mux_idx);
|
||||
portinfo.input_sigs.insert(bit_idx);
|
||||
}
|
||||
return portinfo;
|
||||
}
|
||||
|
||||
void track_mux(Cell* cell) {
|
||||
// Populate bit2info[]:
|
||||
// .seen_non_mux
|
||||
// .mux_users
|
||||
|
|
@ -82,73 +115,59 @@ struct OptMuxtreeWorker
|
|||
// .input_sigs
|
||||
// .const_activated
|
||||
// .const_deactivated
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
if (cell->type.in(ID($mux), ID($pmux)))
|
||||
{
|
||||
RTLIL::SigSpec sig_a = cell->getPort(ID::A);
|
||||
RTLIL::SigSpec sig_b = cell->getPort(ID::B);
|
||||
RTLIL::SigSpec sig_s = cell->getPort(ID::S);
|
||||
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
|
||||
RTLIL::SigSpec sig_a = cell->getPort(ID::A);
|
||||
RTLIL::SigSpec sig_b = cell->getPort(ID::B);
|
||||
RTLIL::SigSpec sig_s = cell->getPort(ID::S);
|
||||
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
|
||||
|
||||
muxinfo_t muxinfo;
|
||||
muxinfo.cell = cell;
|
||||
muxinfo_t muxinfo;
|
||||
muxinfo.cell = cell;
|
||||
int this_mux_idx = GetSize(mux2info);
|
||||
|
||||
for (int i = 0; i < GetSize(sig_s); i++) {
|
||||
RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
|
||||
RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1));
|
||||
portinfo_t portinfo;
|
||||
portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front();
|
||||
for (int idx : sig2bits(sig)) {
|
||||
bit2info[idx].mux_users.insert(GetSize(mux2info));
|
||||
portinfo.input_sigs.insert(idx);
|
||||
}
|
||||
portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool();
|
||||
portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool();
|
||||
portinfo.enabled = false;
|
||||
muxinfo.ports.push_back(portinfo);
|
||||
}
|
||||
|
||||
portinfo_t portinfo;
|
||||
for (int idx : sig2bits(sig_a)) {
|
||||
bit2info[idx].mux_users.insert(GetSize(mux2info));
|
||||
portinfo.input_sigs.insert(idx);
|
||||
}
|
||||
portinfo.ctrl_sig = -1;
|
||||
portinfo.const_activated = false;
|
||||
portinfo.const_deactivated = false;
|
||||
portinfo.enabled = false;
|
||||
muxinfo.ports.push_back(portinfo);
|
||||
|
||||
for (int idx : sig2bits(sig_y))
|
||||
bit2info[idx].mux_drivers.insert(GetSize(mux2info));
|
||||
|
||||
for (int idx : sig2bits(sig_s))
|
||||
bit2info[idx].seen_non_mux = true;
|
||||
|
||||
mux2info.push_back(muxinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &it : cell->connections()) {
|
||||
for (int idx : sig2bits(it.second))
|
||||
bit2info[idx].seen_non_mux = true;
|
||||
}
|
||||
}
|
||||
// Analyze port B
|
||||
// In case of $pmux, port B is multiple slices, concatenated, one per bit of port S
|
||||
for (int i = 0; i < GetSize(sig_s); i++) {
|
||||
RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
|
||||
RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1));
|
||||
portinfo_t portinfo = used_port_bit(sig, this_mux_idx);
|
||||
portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front();
|
||||
portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool();
|
||||
portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool();
|
||||
muxinfo.ports.push_back(portinfo);
|
||||
}
|
||||
|
||||
// Analyze port A
|
||||
muxinfo.ports.push_back(used_port_bit(sig_a, this_mux_idx));
|
||||
|
||||
for (int idx : sig2bits(sig_y))
|
||||
bit2info[idx].mux_drivers.insert(this_mux_idx);
|
||||
|
||||
for (int idx : sig2bits(sig_s))
|
||||
bit2info[idx].seen_non_mux = true;
|
||||
|
||||
mux2info.push_back(muxinfo);
|
||||
}
|
||||
|
||||
void see_non_mux_cell(Cell* cell) {
|
||||
for (auto &it : cell->connections()) {
|
||||
for (int idx : sig2bits(it.second))
|
||||
bit2info[idx].seen_non_mux = true;
|
||||
}
|
||||
}
|
||||
|
||||
void see_non_mux_wires() {
|
||||
for (auto wire : module->wires()) {
|
||||
if (wire->port_output || wire->get_bool_attribute(ID::keep))
|
||||
for (int idx : sig2bits(RTLIL::SigSpec(wire)))
|
||||
bit2info[idx].seen_non_mux = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mux2info.empty()) {
|
||||
log(" No muxes found in this module.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Populate mux2info[].ports[]:
|
||||
// .input_muxes
|
||||
// Populate mux2info[].ports[]:
|
||||
// .input_muxes
|
||||
void fixup_input_muxes() {
|
||||
// bit2info knows the mux users and mux drivers of bits
|
||||
// use this to tell mux2info ports about what muxes are driven by it
|
||||
for (int i = 0; i < GetSize(bit2info); i++)
|
||||
for (int j : bit2info[i].mux_users)
|
||||
for (auto &p : mux2info[j].ports) {
|
||||
|
|
@ -156,12 +175,15 @@ struct OptMuxtreeWorker
|
|||
for (int k : bit2info[i].mux_drivers)
|
||||
p.input_muxes.insert(k);
|
||||
}
|
||||
}
|
||||
|
||||
log(" Evaluating internal representation of mux trees.\n");
|
||||
|
||||
void populate_roots() {
|
||||
// mux_to_users[i] means "set of muxes using output of mux i"
|
||||
dict<int, pool<int>> mux_to_users;
|
||||
root_muxes.resize(GetSize(mux2info));
|
||||
// Pure root muxes (outputs seen by non-muxes)
|
||||
root_enable_muxes.resize(GetSize(mux2info));
|
||||
// All root muxes (outputs seen by non-muxes or multiple muxes)
|
||||
root_muxes.resize(GetSize(mux2info));
|
||||
|
||||
for (auto &bi : bit2info) {
|
||||
for (int i : bi.mux_drivers)
|
||||
|
|
@ -175,16 +197,44 @@ struct OptMuxtreeWorker
|
|||
}
|
||||
}
|
||||
|
||||
for (auto &it : mux_to_users)
|
||||
if (GetSize(it.second) > 1)
|
||||
root_muxes.at(it.first) = true;
|
||||
for (auto &[driving_mux, user_muxes] : mux_to_users)
|
||||
if (GetSize(user_muxes) > 1)
|
||||
root_muxes.at(driving_mux) = true;
|
||||
}
|
||||
|
||||
OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) :
|
||||
design(design), module(module), assign_map(module), removed_count(0)
|
||||
{
|
||||
log("Running muxtree optimizer on module %s..\n", module->name.c_str());
|
||||
|
||||
log(" Creating internal representation of mux trees.\n");
|
||||
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
if (cell->type.in(ID($mux), ID($pmux)))
|
||||
track_mux(cell);
|
||||
else
|
||||
see_non_mux_cell(cell);
|
||||
}
|
||||
see_non_mux_wires();
|
||||
|
||||
if (mux2info.empty()) {
|
||||
log(" No muxes found in this module.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fixup_input_muxes();
|
||||
|
||||
log(" Evaluating internal representation of mux trees.\n");
|
||||
|
||||
populate_roots();
|
||||
|
||||
for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++)
|
||||
if (root_muxes.at(mux_idx)) {
|
||||
log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
|
||||
root_mux_rerun.erase(mux_idx);
|
||||
eval_root_mux(mux_idx);
|
||||
if (glob_abort_cnt == 0) {
|
||||
if (glob_evals_left == 0) {
|
||||
log(" Giving up (too many iterations)\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -196,21 +246,21 @@ struct OptMuxtreeWorker
|
|||
log_assert(root_enable_muxes.at(mux_idx));
|
||||
root_mux_rerun.erase(mux_idx);
|
||||
eval_root_mux(mux_idx);
|
||||
if (glob_abort_cnt == 0) {
|
||||
if (glob_evals_left == 0) {
|
||||
log(" Giving up (too many iterations)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log(" Analyzing evaluation results.\n");
|
||||
log_assert(glob_abort_cnt > 0);
|
||||
log_assert(glob_evals_left > 0);
|
||||
|
||||
for (auto &mi : mux2info)
|
||||
{
|
||||
vector<int> live_ports;
|
||||
for (int port_idx = 0; port_idx < GetSize(mi.ports); port_idx++) {
|
||||
portinfo_t &pi = mi.ports[port_idx];
|
||||
if (pi.enabled) {
|
||||
if (pi.observable) {
|
||||
live_ports.push_back(port_idx);
|
||||
} else {
|
||||
log(" dead port %d/%d on %s %s.\n", port_idx+1, GetSize(mi.ports),
|
||||
|
|
@ -288,73 +338,125 @@ struct OptMuxtreeWorker
|
|||
|
||||
struct knowledge_t
|
||||
{
|
||||
// database of known inactive signals
|
||||
// the payload is a reference counter used to manage the
|
||||
// list. when it is non-zero the signal in known to be inactive
|
||||
vector<int> known_inactive;
|
||||
// Known inactive signals
|
||||
// The payload is a reference counter used to manage the list
|
||||
// When it is non-zero, the signal in known to be inactive
|
||||
// When it reaches zero, the map element is removed
|
||||
std::unordered_map<int, int> known_inactive;
|
||||
|
||||
// database of known active signals
|
||||
vector<int> known_active;
|
||||
std::unordered_map<int, int> known_active;
|
||||
|
||||
// this is just used to keep track of visited muxes in order to prohibit
|
||||
// endless recursion in mux loops
|
||||
vector<bool> visited_muxes;
|
||||
std::unordered_set<int> visited_muxes;
|
||||
};
|
||||
|
||||
void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
|
||||
static void activate_port(knowledge_t &knowledge, int port_idx, const muxinfo_t &muxinfo) {
|
||||
// First, mark all other ports inactive
|
||||
for (int i = 0; i < GetSize(muxinfo.ports); i++) {
|
||||
if (i == port_idx)
|
||||
continue;
|
||||
if (muxinfo.ports[i].ctrl_sig >= 0)
|
||||
++knowledge.known_inactive[muxinfo.ports[i].ctrl_sig];
|
||||
}
|
||||
// Mark port active unless it's the last one
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
|
||||
++knowledge.known_active[muxinfo.ports[port_idx].ctrl_sig];
|
||||
}
|
||||
|
||||
static void deactivate_port(knowledge_t &knowledge, int port_idx, const muxinfo_t &muxinfo) {
|
||||
auto unlearn = [](std::unordered_map<int, int>& knowns, int i) {
|
||||
auto it = knowns.find(i);
|
||||
if (it != knowns.end())
|
||||
if (--it->second == 0)
|
||||
knowns.erase(it);
|
||||
};
|
||||
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
|
||||
unlearn(knowledge.known_active, muxinfo.ports[port_idx].ctrl_sig);
|
||||
|
||||
// Undo inactivity assumptions for other ports
|
||||
for (int i = 0; i < GetSize(muxinfo.ports); i++) {
|
||||
if (i == port_idx)
|
||||
continue;
|
||||
if (muxinfo.ports[i].ctrl_sig >= 0)
|
||||
unlearn(knowledge.known_inactive, muxinfo.ports[i].ctrl_sig);
|
||||
}
|
||||
}
|
||||
|
||||
struct limits_t {
|
||||
// Are we allowed to replace inputs with constants?
|
||||
// True if knowledge doesn't contain assumptions
|
||||
bool do_replace_known = true;
|
||||
// Are we allowed to mark ports as observable?
|
||||
// True if we're recursing from a pure root mux
|
||||
bool do_mark_ports_observable = true;
|
||||
// How many more subtree recursions into input trees can we take?
|
||||
// Then shalt thou count to three, no more, no less. Three shall be the number thou shalt count, and the number of the counting shall be three.
|
||||
int recursions_left = 3;
|
||||
limits_t subtree() const {
|
||||
limits_t ret = *this;
|
||||
log_assert(ret.recursions_left > 0);
|
||||
ret.recursions_left--;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, limits_t limits)
|
||||
{
|
||||
if (glob_abort_cnt == 0)
|
||||
if (glob_evals_left == 0)
|
||||
return;
|
||||
|
||||
muxinfo_t &muxinfo = mux2info[mux_idx];
|
||||
|
||||
if (do_enable_ports)
|
||||
muxinfo.ports[port_idx].enabled = true;
|
||||
if (limits.do_mark_ports_observable)
|
||||
muxinfo.ports[port_idx].observable = true;
|
||||
|
||||
for (int i = 0; i < GetSize(muxinfo.ports); i++) {
|
||||
if (i == port_idx)
|
||||
continue;
|
||||
if (muxinfo.ports[i].ctrl_sig >= 0)
|
||||
knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)++;
|
||||
}
|
||||
// For the purposes of recursion, we assume the port is active,
|
||||
// meaning all other ports are inactive
|
||||
activate_port(knowledge, port_idx, muxinfo);
|
||||
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
|
||||
knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)++;
|
||||
|
||||
vector<int> parent_muxes;
|
||||
vector<int> input_mux_queue;
|
||||
for (int m : muxinfo.ports[port_idx].input_muxes) {
|
||||
if (knowledge.visited_muxes[m])
|
||||
if (knowledge.visited_muxes.count(m))
|
||||
continue;
|
||||
knowledge.visited_muxes[m] = true;
|
||||
parent_muxes.push_back(m);
|
||||
knowledge.visited_muxes.insert(m);
|
||||
input_mux_queue.push_back(m);
|
||||
}
|
||||
for (int m : parent_muxes) {
|
||||
for (int m : input_mux_queue) {
|
||||
if (root_enable_muxes.at(m))
|
||||
continue;
|
||||
else if (root_muxes.at(m)) {
|
||||
if (abort_count == 0) {
|
||||
// This leaf node of the current tree
|
||||
// is the root of an input tree of the current tree
|
||||
if (limits.recursions_left == 0) {
|
||||
// Ran out of subtree depth, re-eval this input tree in the next re-run
|
||||
root_mux_rerun.insert(m);
|
||||
root_enable_muxes.at(m) = true;
|
||||
log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell));
|
||||
} else
|
||||
eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1);
|
||||
} else
|
||||
eval_mux(knowledge, m, do_replace_known, do_enable_ports, abort_count);
|
||||
if (glob_abort_cnt == 0)
|
||||
} else {
|
||||
auto new_limits = limits.subtree();
|
||||
// Since our knowledge includes assumption,
|
||||
// we can't generally allow replacing in an input tree based on it
|
||||
new_limits.do_replace_known = false;
|
||||
eval_mux(knowledge, m, new_limits);
|
||||
}
|
||||
} else {
|
||||
// This non-root input mux has only this mux as a user,
|
||||
// so here we are allowed to pass along do_replace_known
|
||||
eval_mux(knowledge, m, limits);
|
||||
}
|
||||
if (glob_evals_left == 0)
|
||||
return;
|
||||
}
|
||||
for (int m : parent_muxes)
|
||||
knowledge.visited_muxes[m] = false;
|
||||
|
||||
if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
|
||||
knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)--;
|
||||
// Allow revisiting input muxes, since evaluating other ports should
|
||||
// revisit these input muxes with different activation assumptions
|
||||
for (int m : input_mux_queue)
|
||||
knowledge.visited_muxes.erase(m);
|
||||
|
||||
for (int i = 0; i < GetSize(muxinfo.ports); i++) {
|
||||
if (i == port_idx)
|
||||
continue;
|
||||
if (muxinfo.ports[i].ctrl_sig >= 0)
|
||||
knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)--;
|
||||
}
|
||||
// Undo our assumptions that the port is active
|
||||
deactivate_port(knowledge, port_idx, muxinfo);
|
||||
}
|
||||
|
||||
void replace_known(knowledge_t &knowledge, muxinfo_t &muxinfo, IdString portname)
|
||||
|
|
@ -362,37 +464,51 @@ struct OptMuxtreeWorker
|
|||
SigSpec sig = muxinfo.cell->getPort(portname);
|
||||
bool did_something = false;
|
||||
|
||||
int width = 0;
|
||||
int width_if_b = 0;
|
||||
idict<int> ctrl_bits;
|
||||
if (portname == ID::B)
|
||||
width = GetSize(muxinfo.cell->getPort(ID::A));
|
||||
width_if_b = GetSize(muxinfo.cell->getPort(ID::A));
|
||||
for (int bit : sig2bits(muxinfo.cell->getPort(ID::S), false))
|
||||
ctrl_bits(bit);
|
||||
|
||||
int port_idx = 0, port_off = 0;
|
||||
int slice_idx = 0, slice_off = 0;
|
||||
vector<int> bits = sig2bits(sig, false);
|
||||
for (int i = 0; i < GetSize(bits); i++) {
|
||||
if (bits[i] >= 0) {
|
||||
if (knowledge.known_inactive.at(bits[i])) {
|
||||
if (knowledge.known_inactive.count(bits[i]) > 0) {
|
||||
sig[i] = State::S0;
|
||||
did_something = true;
|
||||
} else
|
||||
if (knowledge.known_active.at(bits[i])) {
|
||||
if (knowledge.known_active.count(bits[i]) > 0) {
|
||||
sig[i] = State::S1;
|
||||
did_something = true;
|
||||
}
|
||||
if (ctrl_bits.count(bits[i])) {
|
||||
if (width) {
|
||||
sig[i] = ctrl_bits.at(bits[i]) == port_idx ? State::S1 : State::S0;
|
||||
} else {
|
||||
if (!width_if_b) {
|
||||
// Single-bit $mux example
|
||||
// mux: S ? B : A = Y
|
||||
// A=S
|
||||
// 0 ? B : 0 = 0
|
||||
// 1 ? B : 1 = B
|
||||
// rewrite to A=0
|
||||
// 0 ? B : 0 = 0
|
||||
// 1 ? B : 0 = B
|
||||
// which is equivalent
|
||||
sig[i] = State::S0;
|
||||
} else {
|
||||
// "Sliced" $pmux example
|
||||
// B[i]=S[j]
|
||||
// i == j => B[i] activated only when B[i] is high, safe to rewrite to 1
|
||||
// i != j => B[i] activated only when B[i] is low, safe to rewrite to 0
|
||||
sig[i] = ctrl_bits.at(bits[i]) == slice_idx ? State::S1 : State::S0;
|
||||
}
|
||||
did_something = true;
|
||||
}
|
||||
}
|
||||
if (width) {
|
||||
if (++port_off == width)
|
||||
port_idx++, port_off=0;
|
||||
if (width_if_b) {
|
||||
// Roll over into next slice
|
||||
if (++slice_off == width_if_b)
|
||||
slice_idx++, slice_off=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -403,16 +519,17 @@ struct OptMuxtreeWorker
|
|||
}
|
||||
}
|
||||
|
||||
void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
|
||||
void eval_mux(knowledge_t &knowledge, int mux_idx, limits_t limits)
|
||||
{
|
||||
if (glob_abort_cnt == 0)
|
||||
if (glob_evals_left == 0)
|
||||
return;
|
||||
glob_abort_cnt--;
|
||||
glob_evals_left--;
|
||||
|
||||
muxinfo_t &muxinfo = mux2info[mux_idx];
|
||||
log_debug("\t\teval %s (replace %d enable %d)\n", log_id(muxinfo.cell), limits.do_replace_known, limits.do_mark_ports_observable);
|
||||
|
||||
// set input ports to constants if we find known active or inactive signals
|
||||
if (do_replace_known) {
|
||||
if (limits.do_replace_known) {
|
||||
replace_known(knowledge, muxinfo, ID::A);
|
||||
replace_known(knowledge, muxinfo, ID::B);
|
||||
}
|
||||
|
|
@ -422,21 +539,21 @@ struct OptMuxtreeWorker
|
|||
{
|
||||
portinfo_t &portinfo = muxinfo.ports[port_idx];
|
||||
if (portinfo.const_activated) {
|
||||
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
|
||||
eval_mux_port(knowledge, mux_idx, port_idx, limits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// compare ports with known_active signals. if we find a match, only this
|
||||
// port can be active. do not include the last port (its the default port
|
||||
// that has no control signals).
|
||||
// Compare ports with known active control signals. if we find a match,
|
||||
// only this port can be active. Do not include the last port,
|
||||
// it's the default port without an associated control signal
|
||||
for (int port_idx = 0; port_idx < GetSize(muxinfo.ports)-1; port_idx++)
|
||||
{
|
||||
portinfo_t &portinfo = muxinfo.ports[port_idx];
|
||||
if (portinfo.const_deactivated)
|
||||
continue;
|
||||
if (knowledge.known_active.at(portinfo.ctrl_sig)) {
|
||||
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
|
||||
if (knowledge.known_active.count(portinfo.ctrl_sig) > 0) {
|
||||
eval_mux_port(knowledge, mux_idx, port_idx, limits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -449,24 +566,23 @@ struct OptMuxtreeWorker
|
|||
if (portinfo.const_deactivated)
|
||||
continue;
|
||||
if (port_idx < GetSize(muxinfo.ports)-1)
|
||||
if (knowledge.known_inactive.at(portinfo.ctrl_sig))
|
||||
if (knowledge.known_inactive.count(portinfo.ctrl_sig) > 0)
|
||||
continue;
|
||||
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
|
||||
eval_mux_port(knowledge, mux_idx, port_idx, limits);
|
||||
|
||||
if (glob_abort_cnt == 0)
|
||||
if (glob_evals_left == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void eval_root_mux(int mux_idx)
|
||||
{
|
||||
log_assert(glob_abort_cnt > 0);
|
||||
log_assert(glob_evals_left > 0);
|
||||
knowledge_t knowledge;
|
||||
knowledge.known_inactive.resize(GetSize(bit2info));
|
||||
knowledge.known_active.resize(GetSize(bit2info));
|
||||
knowledge.visited_muxes.resize(GetSize(mux2info));
|
||||
knowledge.visited_muxes[mux_idx] = true;
|
||||
eval_mux(knowledge, mux_idx, true, root_enable_muxes.at(mux_idx), 3);
|
||||
knowledge.visited_muxes.insert(mux_idx);
|
||||
limits_t limits = {};
|
||||
limits.do_mark_ports_observable = root_enable_muxes.at(mux_idx);
|
||||
eval_mux(knowledge, mux_idx, limits);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -71,6 +71,29 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
|
|||
cell->setPort(ID::Y, wire);
|
||||
}
|
||||
|
||||
if (cell_type.in(ID($_MUX_), ID($_NMUX_)))
|
||||
{
|
||||
wire = module->addWire(ID::A);
|
||||
wire->width = 1;
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::A, wire);
|
||||
|
||||
wire = module->addWire(ID::B);
|
||||
wire->width = 1;
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::B, wire);
|
||||
|
||||
wire = module->addWire(ID::S);
|
||||
wire->width = 1;
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::S, wire);
|
||||
|
||||
wire = module->addWire(ID::Y);
|
||||
wire->width = 1;
|
||||
wire->port_output = true;
|
||||
cell->setPort(ID::Y, wire);
|
||||
}
|
||||
|
||||
if (cell_type == ID($bmux))
|
||||
{
|
||||
int width = 1 + xorshift32(8 * bloat_factor);
|
||||
|
|
@ -167,7 +190,7 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
|
|||
cell->setPort(ID::CO, wire);
|
||||
}
|
||||
|
||||
if (cell_type == ID($macc))
|
||||
if (cell_type == ID($macc_v2))
|
||||
{
|
||||
Macc macc;
|
||||
int width = 1 + xorshift32(8 * bloat_factor);
|
||||
|
|
@ -201,6 +224,7 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
|
|||
this_term.do_subtract = xorshift32(2) == 1;
|
||||
macc.terms.push_back(this_term);
|
||||
}
|
||||
|
||||
// Macc::to_cell sets the input ports
|
||||
macc.to_cell(cell);
|
||||
|
||||
|
|
@ -208,12 +232,6 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
|
|||
wire->width = width;
|
||||
wire->port_output = true;
|
||||
cell->setPort(ID::Y, wire);
|
||||
|
||||
// override the B input (macc helpers always sets an empty vector)
|
||||
wire = module->addWire(ID::B);
|
||||
wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1);
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::B, wire);
|
||||
}
|
||||
|
||||
if (cell_type == ID($lut))
|
||||
|
|
@ -273,14 +291,19 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
|
|||
|
||||
if (cell_type_flags.find('A') != std::string::npos) {
|
||||
wire = module->addWire(ID::A);
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
if (cell_type_flags.find('b') != std::string::npos)
|
||||
wire->width = 1;
|
||||
else
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::A, wire);
|
||||
}
|
||||
|
||||
if (cell_type_flags.find('B') != std::string::npos) {
|
||||
wire = module->addWire(ID::B);
|
||||
if (cell_type_flags.find('h') != std::string::npos)
|
||||
if (cell_type_flags.find('b') != std::string::npos)
|
||||
wire->width = 1;
|
||||
else if (cell_type_flags.find('h') != std::string::npos)
|
||||
wire->width = 1 + xorshift32(6 * bloat_factor);
|
||||
else
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
|
|
@ -288,6 +311,26 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
|
|||
cell->setPort(ID::B, wire);
|
||||
}
|
||||
|
||||
if (cell_type_flags.find('C') != std::string::npos) {
|
||||
wire = module->addWire(ID::C);
|
||||
if (cell_type_flags.find('b') != std::string::npos)
|
||||
wire->width = 1;
|
||||
else
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::C, wire);
|
||||
}
|
||||
|
||||
if (cell_type_flags.find('D') != std::string::npos) {
|
||||
wire = module->addWire(ID::D);
|
||||
if (cell_type_flags.find('b') != std::string::npos)
|
||||
wire->width = 1;
|
||||
else
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::D, wire);
|
||||
}
|
||||
|
||||
if (cell_type_flags.find('S') != std::string::npos && xorshift32(2)) {
|
||||
if (cell_type_flags.find('A') != std::string::npos)
|
||||
cell->parameters[ID::A_SIGNED] = true;
|
||||
|
|
@ -304,7 +347,10 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
|
|||
|
||||
if (cell_type_flags.find('Y') != std::string::npos) {
|
||||
wire = module->addWire(ID::Y);
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
if (cell_type_flags.find('b') != std::string::npos)
|
||||
wire->width = 1;
|
||||
else
|
||||
wire->width = 1 + xorshift32(8 * bloat_factor);
|
||||
wire->port_output = true;
|
||||
cell->setPort(ID::Y, wire);
|
||||
}
|
||||
|
|
@ -345,6 +391,58 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
|
|||
cell->setPort(ID::CO, wire);
|
||||
}
|
||||
|
||||
if (cell_type == ID($slice))
|
||||
{
|
||||
int a_size = GetSize(cell->getPort(ID::A));
|
||||
int y_size = 1;
|
||||
if (a_size > 1)
|
||||
y_size += (xorshift32(8 * bloat_factor) % (a_size - 1));
|
||||
wire = module->addWire(ID::Y);
|
||||
wire->width = y_size;
|
||||
wire->port_output = true;
|
||||
cell->setPort(ID::Y, wire);
|
||||
if (a_size > y_size)
|
||||
cell->setParam(ID::OFFSET, (xorshift32(8 * bloat_factor) % (a_size - y_size)));
|
||||
else
|
||||
cell->setParam(ID::OFFSET, 0);
|
||||
}
|
||||
|
||||
if (cell_type == ID($concat))
|
||||
{
|
||||
wire = module->addWire(ID::Y);
|
||||
wire->width = GetSize(cell->getPort(ID::A)) + GetSize(cell->getPort(ID::B));
|
||||
wire->port_output = true;
|
||||
cell->setPort(ID::Y, wire);
|
||||
}
|
||||
|
||||
if (cell_type == ID($buf))
|
||||
{
|
||||
wire = module->addWire(ID::Y);
|
||||
wire->width = GetSize(cell->getPort(ID::A));
|
||||
wire->port_output = true;
|
||||
cell->setPort(ID::Y, wire);
|
||||
}
|
||||
|
||||
if (cell_type.in(ID($bwmux), ID($bweqx)))
|
||||
{
|
||||
int a_size = GetSize(cell->getPort(ID::A));
|
||||
wire = module->addWire(ID::B);
|
||||
wire->width = a_size;
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::B, wire);
|
||||
if (cell_type == ID($bwmux))
|
||||
{
|
||||
wire = module->addWire(ID::S);
|
||||
wire->width = a_size;
|
||||
wire->port_input = true;
|
||||
cell->setPort(ID::S, wire);
|
||||
}
|
||||
wire = module->addWire(ID::Y);
|
||||
wire->width = a_size;
|
||||
wire->port_output = true;
|
||||
cell->setPort(ID::Y, wire);
|
||||
}
|
||||
|
||||
if (constmode)
|
||||
{
|
||||
auto conn_list = cell->connections();
|
||||
|
|
@ -884,6 +982,9 @@ struct TestCellPass : public Pass {
|
|||
cell_types[ID($not)] = "ASY";
|
||||
cell_types[ID($pos)] = "ASY";
|
||||
cell_types[ID($neg)] = "ASY";
|
||||
// $buf is unsupported with techmap -assert
|
||||
if (techmap_cmd.compare("techmap -assert") != 0)
|
||||
cell_types[ID($buf)] = "A";
|
||||
|
||||
cell_types[ID($and)] = "ABSY";
|
||||
cell_types[ID($or)] = "ABSY";
|
||||
|
|
@ -907,8 +1008,14 @@ struct TestCellPass : public Pass {
|
|||
cell_types[ID($le)] = "ABSY";
|
||||
cell_types[ID($eq)] = "ABSY";
|
||||
cell_types[ID($ne)] = "ABSY";
|
||||
// cell_types[ID($eqx)] = "ABSY";
|
||||
// cell_types[ID($nex)] = "ABSY";
|
||||
// $eqx, $nex, and $bweqx don't work in sat, and are unsupported with
|
||||
// 'techmap -assert'
|
||||
if (nosat && techmap_cmd.compare("techmap -assert") != 0)
|
||||
{
|
||||
cell_types[ID($eqx)] = "ABSY";
|
||||
cell_types[ID($nex)] = "ABSY";
|
||||
cell_types[ID($bweqx)] = "A";
|
||||
}
|
||||
cell_types[ID($ge)] = "ABSY";
|
||||
cell_types[ID($gt)] = "ABSY";
|
||||
|
||||
|
|
@ -919,7 +1026,10 @@ struct TestCellPass : public Pass {
|
|||
cell_types[ID($mod)] = "ABSY";
|
||||
cell_types[ID($divfloor)] = "ABSY";
|
||||
cell_types[ID($modfloor)] = "ABSY";
|
||||
// cell_types[ID($pow)] = "ABsY";
|
||||
// $pow doesnt work in sat, not supported with 'techmap -assert', and only
|
||||
// only partially supported with '-simlib'
|
||||
if (nosat && techmap_cmd.compare("aigmap") == 0)
|
||||
cell_types[ID($pow)] = "ABsY";
|
||||
|
||||
cell_types[ID($logic_not)] = "ASY";
|
||||
cell_types[ID($logic_and)] = "ABSY";
|
||||
|
|
@ -928,20 +1038,43 @@ struct TestCellPass : public Pass {
|
|||
cell_types[ID($mux)] = "*";
|
||||
cell_types[ID($bmux)] = "*";
|
||||
cell_types[ID($demux)] = "*";
|
||||
if (edges) {
|
||||
// $pmux doesn't work in sat, and is not supported with 'techmap -assert' or
|
||||
// '-simlib'
|
||||
if (nosat && techmap_cmd.compare("aigmap") == 0)
|
||||
cell_types[ID($pmux)] = "*";
|
||||
}
|
||||
cell_types[ID($bwmux)] = "A";
|
||||
|
||||
// cell_types[ID($slice)] = "A";
|
||||
// cell_types[ID($concat)] = "A";
|
||||
cell_types[ID($slice)] = "A";
|
||||
cell_types[ID($concat)] = "AB";
|
||||
|
||||
cell_types[ID($lut)] = "*";
|
||||
cell_types[ID($sop)] = "*";
|
||||
cell_types[ID($alu)] = "ABSY";
|
||||
cell_types[ID($lcu)] = "*";
|
||||
cell_types[ID($macc)] = "*";
|
||||
cell_types[ID($macc_v2)] = "*";
|
||||
cell_types[ID($fa)] = "*";
|
||||
|
||||
cell_types[ID($_BUF_)] = "AYb";
|
||||
cell_types[ID($_NOT_)] = "AYb";
|
||||
cell_types[ID($_AND_)] = "ABYb";
|
||||
cell_types[ID($_NAND_)] = "ABYb";
|
||||
cell_types[ID($_OR_)] = "ABYb";
|
||||
cell_types[ID($_NOR_)] = "ABYb";
|
||||
cell_types[ID($_XOR_)] = "ABYb";
|
||||
cell_types[ID($_XNOR_)] = "ABYb";
|
||||
cell_types[ID($_ANDNOT_)] = "ABYb";
|
||||
cell_types[ID($_ORNOT_)] = "ABYb";
|
||||
cell_types[ID($_MUX_)] = "*";
|
||||
cell_types[ID($_NMUX_)] = "*";
|
||||
// wide $_MUX_ cells are not yet implemented
|
||||
// cell_types[ID($_MUX4_)] = "*";
|
||||
// cell_types[ID($_MUX8_)] = "*";
|
||||
// cell_types[ID($_MUX16_)] = "*";
|
||||
cell_types[ID($_AOI3_)] = "ABCYb";
|
||||
cell_types[ID($_OAI3_)] = "ABCYb";
|
||||
cell_types[ID($_AOI4_)] = "ABCDYb";
|
||||
cell_types[ID($_OAI4_)] = "ABCDYb";
|
||||
|
||||
for (; argidx < GetSize(args); argidx++)
|
||||
{
|
||||
if (args[argidx].rfind("-", 0) == 0)
|
||||
|
|
|
|||
20
setup.py
20
setup.py
|
|
@ -51,16 +51,27 @@ class libyosys_so_ext(Extension):
|
|||
]
|
||||
|
||||
def custom_build(self, bext: build_ext):
|
||||
make_flags_split = shlex.split(os.getenv("makeFlags", ""))
|
||||
# abc linking takes a lot of memory, best get it out of the way first
|
||||
bext.spawn(
|
||||
[
|
||||
"make",
|
||||
f"-j{os.cpu_count() or 1}",
|
||||
"yosys-abc",
|
||||
*make_flags_split,
|
||||
*self.args,
|
||||
]
|
||||
)
|
||||
# build libyosys and share with abc out of the way
|
||||
bext.spawn(
|
||||
[
|
||||
"make",
|
||||
f"-j{os.cpu_count() or 1}",
|
||||
self.name,
|
||||
"yosys-abc",
|
||||
"share",
|
||||
*make_flags_split,
|
||||
*self.args,
|
||||
]
|
||||
+ shlex.split(os.getenv("makeFlags", ""))
|
||||
+ self.args
|
||||
)
|
||||
build_path = os.path.dirname(os.path.dirname(bext.get_ext_fullpath(self.name)))
|
||||
pyosys_path = os.path.join(build_path, "pyosys")
|
||||
|
|
@ -85,6 +96,7 @@ class libyosys_so_ext(Extension):
|
|||
|
||||
shutil.copytree("share", share_target)
|
||||
|
||||
|
||||
class custom_build_ext(build_ext):
|
||||
def build_extension(self, ext) -> None:
|
||||
if not hasattr(ext, "custom_build"):
|
||||
|
|
@ -100,8 +112,8 @@ setup(
|
|||
long_description=open(os.path.join(__dir__, "README.md")).read(),
|
||||
long_description_content_type="text/markdown",
|
||||
install_requires=["wheel", "setuptools"],
|
||||
license="MIT",
|
||||
classifiers=[
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Intended Audience :: Developers",
|
||||
"Operating System :: POSIX :: Linux",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ endmodule
|
|||
|
||||
(* blackbox *)
|
||||
module DP16KD (...);
|
||||
parameter CLKAMUX = "CLKA";
|
||||
parameter CLKBMUX = "CLKB";
|
||||
parameter DATA_WIDTH_A = 18;
|
||||
parameter DATA_WIDTH_B = 18;
|
||||
parameter REGMODE_A = "NOREG";
|
||||
|
|
@ -215,6 +217,8 @@ endmodule
|
|||
|
||||
(* blackbox *)
|
||||
module PDPW16KD (...);
|
||||
parameter CLKRMUX = "CLKR";
|
||||
parameter CLKWMUX = "CLKW";
|
||||
parameter DATA_WIDTH_W = 36;
|
||||
parameter DATA_WIDTH_R = 36;
|
||||
parameter GSR = "ENABLED";
|
||||
|
|
|
|||
|
|
@ -11,10 +11,11 @@ import re
|
|||
|
||||
|
||||
class Cell:
|
||||
def __init__(self, name, keep=False, port_attrs={}):
|
||||
def __init__(self, name, keep=False, port_attrs={}, extra_params={}):
|
||||
self.name = name
|
||||
self.keep = keep
|
||||
self.port_attrs = port_attrs
|
||||
self.extra_params = extra_params
|
||||
self.found = False
|
||||
|
||||
class State(Enum):
|
||||
|
|
@ -120,8 +121,18 @@ devices = [
|
|||
#Cell("XOR3"),
|
||||
#Cell("XOR4"),
|
||||
#Cell("XOR5"),
|
||||
Cell("DP16KD"),
|
||||
Cell("PDPW16KD"),
|
||||
Cell("DP16KD", extra_params={
|
||||
# Optional clock inverters, present in prjtrellis data but
|
||||
# not in Diamond bb models.
|
||||
"CLKAMUX": "CLKA",
|
||||
"CLKBMUX": "CLKB",
|
||||
}),
|
||||
Cell("PDPW16KD", extra_params={
|
||||
# Optional clock inverters, present in prjtrellis data but
|
||||
# not in Diamond bb models.
|
||||
"CLKWMUX": "CLKW",
|
||||
"CLKRMUX": "CLKR",
|
||||
}),
|
||||
#Cell("DPR16X4C"),
|
||||
#Cell("SPR16X4C"),
|
||||
#Cell("LVDSOB"),
|
||||
|
|
@ -795,6 +806,10 @@ def xtract_cells_decl(device, cells, dirs, outf):
|
|||
rng = None
|
||||
module_ports.append((kind, rng, port))
|
||||
elif l.startswith('parameter ') and state == State.IN_MODULE:
|
||||
if cell.extra_params:
|
||||
for name, default in sorted(cell.extra_params.items()):
|
||||
outf.write(' parameter {} = "{}";\n'.format(name, default))
|
||||
cell.extra_params = None
|
||||
l = l.strip()
|
||||
if l.endswith((';', ',')):
|
||||
l = l[:-1]
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
}
|
||||
|
||||
string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path;
|
||||
bool abc9, inferAdder, nobram, bramTypes, dsp, ioff;
|
||||
bool abc9, inferAdder, nobram, bramTypes, dsp, ioff, flatten;
|
||||
|
||||
void clear_flags() override
|
||||
{
|
||||
|
|
@ -95,6 +95,7 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
lib_path = "+/quicklogic/";
|
||||
dsp = true;
|
||||
ioff = true;
|
||||
flatten = true;
|
||||
}
|
||||
|
||||
void set_scratchpad_defaults(RTLIL::Design *design) {
|
||||
|
|
@ -163,6 +164,10 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
ioff = false;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noflatten") {
|
||||
flatten = false;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
|
@ -207,7 +212,8 @@ struct SynthQuickLogicPass : public ScriptPass {
|
|||
|
||||
if (check_label("prepare")) {
|
||||
run("proc");
|
||||
run("flatten");
|
||||
if (flatten)
|
||||
run("flatten", "(unless -noflatten)");
|
||||
if (help_mode || family == "pp3") {
|
||||
run("tribuf -logic", " (for pp3)");
|
||||
}
|
||||
|
|
|
|||
648
tests/opt/opt_dff-simplify.il
Normal file
648
tests/opt/opt_dff-simplify.il
Normal file
|
|
@ -0,0 +1,648 @@
|
|||
# Generated by Yosys 0.53+24 (git sha1 ab636979e, sccache clang++ 19.1.7 -fPIC -O3 -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address,undefined)
|
||||
autoidx 171528
|
||||
attribute \hdlname "csr_regfile_0000000000000000_1"
|
||||
module \csr_regfile_0000000000000000_1
|
||||
wire $delete_wire$169641
|
||||
wire $delete_wire$169642
|
||||
wire $delete_wire$169643
|
||||
wire $delete_wire$169644
|
||||
wire $delete_wire$169645
|
||||
wire $delete_wire$169646
|
||||
wire $delete_wire$169647
|
||||
wire $delete_wire$169648
|
||||
wire $delete_wire$169649
|
||||
wire $delete_wire$169650
|
||||
wire $delete_wire$169651
|
||||
wire $delete_wire$169652
|
||||
wire $delete_wire$169653
|
||||
wire $delete_wire$169654
|
||||
wire $delete_wire$169655
|
||||
wire $delete_wire$169656
|
||||
wire $delete_wire$169657
|
||||
wire $delete_wire$169658
|
||||
wire $delete_wire$169659
|
||||
wire $delete_wire$169660
|
||||
wire $delete_wire$169661
|
||||
wire $delete_wire$169662
|
||||
wire $delete_wire$169663
|
||||
wire $delete_wire$169664
|
||||
wire $delete_wire$169665
|
||||
wire $delete_wire$169666
|
||||
wire $delete_wire$169667
|
||||
wire $delete_wire$169668
|
||||
wire $delete_wire$169669
|
||||
wire $delete_wire$169670
|
||||
wire $delete_wire$169671
|
||||
wire $delete_wire$169672
|
||||
wire $delete_wire$169673
|
||||
wire $delete_wire$169674
|
||||
wire $delete_wire$169675
|
||||
wire $delete_wire$169676
|
||||
wire $delete_wire$169677
|
||||
wire $delete_wire$169678
|
||||
wire $delete_wire$169679
|
||||
wire $delete_wire$169680
|
||||
wire $delete_wire$169681
|
||||
wire $delete_wire$169682
|
||||
wire $delete_wire$169683
|
||||
wire $delete_wire$169684
|
||||
wire $delete_wire$169685
|
||||
wire $delete_wire$169686
|
||||
wire $delete_wire$169687
|
||||
wire $delete_wire$169688
|
||||
wire $delete_wire$169689
|
||||
wire $delete_wire$169690
|
||||
wire $delete_wire$169691
|
||||
wire $delete_wire$169692
|
||||
wire $delete_wire$169693
|
||||
wire $delete_wire$169694
|
||||
wire $delete_wire$169695
|
||||
wire $delete_wire$169696
|
||||
wire $delete_wire$169697
|
||||
wire $delete_wire$169698
|
||||
wire $delete_wire$169699
|
||||
wire $delete_wire$169700
|
||||
wire $delete_wire$169701
|
||||
wire $delete_wire$169702
|
||||
wire $delete_wire$169703
|
||||
wire $delete_wire$169704
|
||||
wire $delete_wire$169705
|
||||
wire $delete_wire$169706
|
||||
wire $delete_wire$169707
|
||||
wire $delete_wire$169708
|
||||
wire $delete_wire$169709
|
||||
wire $delete_wire$169710
|
||||
wire $delete_wire$169711
|
||||
wire $delete_wire$169712
|
||||
wire width 32 $delete_wire$169713
|
||||
wire $delete_wire$169714
|
||||
wire $delete_wire$169715
|
||||
wire $delete_wire$169716
|
||||
wire $delete_wire$169717
|
||||
wire $delete_wire$169718
|
||||
wire $delete_wire$169719
|
||||
wire $delete_wire$169720
|
||||
wire $delete_wire$169721
|
||||
wire $delete_wire$169722
|
||||
wire $delete_wire$169723
|
||||
wire $delete_wire$169724
|
||||
wire $delete_wire$169725
|
||||
wire $delete_wire$169726
|
||||
wire $delete_wire$169727
|
||||
wire $delete_wire$169728
|
||||
wire $delete_wire$169729
|
||||
wire $delete_wire$169730
|
||||
wire $delete_wire$169731
|
||||
wire $delete_wire$169732
|
||||
wire $delete_wire$169733
|
||||
wire $delete_wire$169734
|
||||
wire $delete_wire$169735
|
||||
wire $delete_wire$169736
|
||||
wire $delete_wire$169737
|
||||
wire $delete_wire$169738
|
||||
wire $delete_wire$169739
|
||||
wire $delete_wire$169740
|
||||
wire $delete_wire$169741
|
||||
wire $delete_wire$169742
|
||||
wire $delete_wire$169743
|
||||
wire $delete_wire$169744
|
||||
wire $delete_wire$169745
|
||||
wire $delete_wire$169746
|
||||
wire $delete_wire$169747
|
||||
wire $delete_wire$169748
|
||||
wire $delete_wire$169749
|
||||
wire $delete_wire$169750
|
||||
wire $delete_wire$169751
|
||||
wire $delete_wire$169752
|
||||
wire $delete_wire$169753
|
||||
wire $delete_wire$169754
|
||||
wire $delete_wire$169755
|
||||
wire $delete_wire$169756
|
||||
wire $delete_wire$169757
|
||||
wire $delete_wire$169758
|
||||
wire $delete_wire$169759
|
||||
wire $delete_wire$169760
|
||||
wire $delete_wire$169761
|
||||
wire $delete_wire$169762
|
||||
wire $delete_wire$169763
|
||||
wire $delete_wire$169764
|
||||
wire $delete_wire$169765
|
||||
wire $delete_wire$169766
|
||||
wire $delete_wire$169767
|
||||
wire $delete_wire$169768
|
||||
wire $delete_wire$169769
|
||||
wire $delete_wire$169770
|
||||
wire $delete_wire$169771
|
||||
wire $delete_wire$169772
|
||||
wire $delete_wire$169773
|
||||
wire $delete_wire$169774
|
||||
wire $delete_wire$169775
|
||||
wire $delete_wire$169776
|
||||
wire $delete_wire$169777
|
||||
wire $delete_wire$169778
|
||||
wire $delete_wire$169779
|
||||
wire $delete_wire$169780
|
||||
wire $delete_wire$169781
|
||||
wire $delete_wire$169782
|
||||
wire $delete_wire$169783
|
||||
wire $delete_wire$169784
|
||||
wire $delete_wire$169785
|
||||
wire $delete_wire$169786
|
||||
wire $delete_wire$169787
|
||||
wire $delete_wire$169788
|
||||
wire $delete_wire$169789
|
||||
wire $delete_wire$169790
|
||||
wire $delete_wire$169791
|
||||
wire $delete_wire$169792
|
||||
wire $delete_wire$169793
|
||||
wire $delete_wire$169794
|
||||
wire $delete_wire$169795
|
||||
wire $delete_wire$169796
|
||||
wire $delete_wire$169797
|
||||
wire $delete_wire$169798
|
||||
wire $delete_wire$169799
|
||||
wire $delete_wire$169800
|
||||
wire $delete_wire$169801
|
||||
wire $delete_wire$169802
|
||||
wire $delete_wire$169803
|
||||
wire $delete_wire$169804
|
||||
wire $delete_wire$169805
|
||||
wire $delete_wire$169806
|
||||
wire $delete_wire$169807
|
||||
wire $delete_wire$169808
|
||||
wire $delete_wire$169809
|
||||
wire $delete_wire$169810
|
||||
wire $delete_wire$169811
|
||||
wire $delete_wire$169812
|
||||
wire $delete_wire$169813
|
||||
wire $delete_wire$169814
|
||||
wire $delete_wire$169815
|
||||
wire $delete_wire$169816
|
||||
wire $delete_wire$169817
|
||||
wire $delete_wire$169818
|
||||
wire $delete_wire$169819
|
||||
wire $delete_wire$169820
|
||||
wire $delete_wire$169821
|
||||
wire width 5 $delete_wire$169822
|
||||
wire width 17 $delete_wire$169823
|
||||
wire $delete_wire$169824
|
||||
wire $delete_wire$169825
|
||||
wire $delete_wire$169826
|
||||
wire $delete_wire$169827
|
||||
wire $delete_wire$169828
|
||||
wire $delete_wire$169829
|
||||
wire $delete_wire$169830
|
||||
wire $delete_wire$169831
|
||||
wire $delete_wire$169832
|
||||
wire $delete_wire$169833
|
||||
wire $delete_wire$169834
|
||||
wire $delete_wire$169835
|
||||
wire $delete_wire$169836
|
||||
wire $delete_wire$169837
|
||||
wire $delete_wire$169838
|
||||
wire $delete_wire$169839
|
||||
wire $delete_wire$169840
|
||||
wire $delete_wire$169960
|
||||
wire $delete_wire$169961
|
||||
wire $delete_wire$169962
|
||||
wire $delete_wire$169963
|
||||
wire $delete_wire$169964
|
||||
wire $delete_wire$169965
|
||||
wire $delete_wire$169966
|
||||
wire $delete_wire$169967
|
||||
wire $delete_wire$169968
|
||||
wire $delete_wire$169969
|
||||
wire $delete_wire$169970
|
||||
wire $delete_wire$169971
|
||||
wire $delete_wire$169972
|
||||
wire $delete_wire$169973
|
||||
wire $delete_wire$169974
|
||||
wire $delete_wire$169975
|
||||
wire $delete_wire$169976
|
||||
wire $delete_wire$169977
|
||||
wire $delete_wire$169978
|
||||
wire $delete_wire$169979
|
||||
wire $delete_wire$169980
|
||||
wire $delete_wire$169981
|
||||
wire $delete_wire$169982
|
||||
wire $delete_wire$169983
|
||||
wire $delete_wire$169984
|
||||
wire $delete_wire$169985
|
||||
wire $delete_wire$169986
|
||||
wire $delete_wire$169987
|
||||
wire $delete_wire$169988
|
||||
wire $delete_wire$169989
|
||||
wire $delete_wire$169990
|
||||
wire $delete_wire$169991
|
||||
wire $delete_wire$169992
|
||||
wire $delete_wire$169993
|
||||
wire $delete_wire$169994
|
||||
wire $delete_wire$169995
|
||||
wire $delete_wire$169996
|
||||
wire $delete_wire$169997
|
||||
wire $delete_wire$169998
|
||||
wire $delete_wire$169999
|
||||
wire $delete_wire$170000
|
||||
wire $delete_wire$170001
|
||||
wire $delete_wire$170002
|
||||
wire $delete_wire$170003
|
||||
wire $delete_wire$170004
|
||||
wire $delete_wire$170005
|
||||
wire $delete_wire$170006
|
||||
wire $delete_wire$170007
|
||||
wire $delete_wire$170008
|
||||
wire $delete_wire$170009
|
||||
wire $delete_wire$170010
|
||||
wire $delete_wire$170011
|
||||
wire $delete_wire$170012
|
||||
wire $delete_wire$170013
|
||||
wire $delete_wire$170014
|
||||
wire $delete_wire$170015
|
||||
wire $delete_wire$170016
|
||||
wire $delete_wire$170017
|
||||
wire $delete_wire$170018
|
||||
wire $delete_wire$170019
|
||||
wire $delete_wire$170020
|
||||
wire $delete_wire$170021
|
||||
wire $delete_wire$170022
|
||||
wire $delete_wire$170023
|
||||
wire $delete_wire$170024
|
||||
wire $delete_wire$170025
|
||||
wire $delete_wire$170026
|
||||
wire $delete_wire$170027
|
||||
wire $delete_wire$170028
|
||||
wire $delete_wire$170029
|
||||
wire $delete_wire$170030
|
||||
wire $delete_wire$170031
|
||||
wire $delete_wire$170032
|
||||
wire $delete_wire$170033
|
||||
wire $delete_wire$170034
|
||||
wire $delete_wire$170035
|
||||
wire $delete_wire$170036
|
||||
wire $delete_wire$170037
|
||||
wire $delete_wire$170038
|
||||
wire $delete_wire$170039
|
||||
wire $delete_wire$170040
|
||||
wire $delete_wire$170041
|
||||
wire $delete_wire$170042
|
||||
wire $delete_wire$170043
|
||||
wire $delete_wire$170044
|
||||
wire $delete_wire$170045
|
||||
wire $delete_wire$170046
|
||||
wire $delete_wire$170047
|
||||
wire $delete_wire$170048
|
||||
wire $delete_wire$170049
|
||||
wire $delete_wire$170050
|
||||
wire $delete_wire$170051
|
||||
wire $delete_wire$170052
|
||||
wire $delete_wire$170053
|
||||
wire $delete_wire$170054
|
||||
wire $delete_wire$170055
|
||||
wire $delete_wire$170056
|
||||
wire $delete_wire$170057
|
||||
wire $delete_wire$170058
|
||||
wire $delete_wire$170059
|
||||
wire $delete_wire$170635
|
||||
wire $delete_wire$170636
|
||||
wire $delete_wire$170637
|
||||
wire $delete_wire$170638
|
||||
wire $delete_wire$170639
|
||||
wire $delete_wire$170640
|
||||
wire $delete_wire$170641
|
||||
wire $delete_wire$170642
|
||||
wire $delete_wire$170643
|
||||
wire $delete_wire$170644
|
||||
wire $delete_wire$170645
|
||||
wire $delete_wire$170646
|
||||
wire $delete_wire$170647
|
||||
wire $delete_wire$170648
|
||||
wire $delete_wire$170649
|
||||
wire $delete_wire$170650
|
||||
wire $delete_wire$170651
|
||||
wire $delete_wire$170652
|
||||
wire $delete_wire$170653
|
||||
wire $delete_wire$170654
|
||||
wire $delete_wire$170655
|
||||
wire $delete_wire$170656
|
||||
wire $delete_wire$170657
|
||||
wire $delete_wire$170658
|
||||
wire $delete_wire$170659
|
||||
wire $delete_wire$170660
|
||||
wire $delete_wire$170661
|
||||
wire $delete_wire$170662
|
||||
wire $delete_wire$170663
|
||||
wire $delete_wire$170664
|
||||
wire $delete_wire$170665
|
||||
wire $delete_wire$170666
|
||||
wire $delete_wire$170667
|
||||
wire $delete_wire$170668
|
||||
wire $delete_wire$170669
|
||||
wire $delete_wire$170670
|
||||
wire $delete_wire$170749
|
||||
wire $delete_wire$170750
|
||||
wire $delete_wire$170751
|
||||
wire $delete_wire$170752
|
||||
wire $delete_wire$170753
|
||||
wire $delete_wire$170754
|
||||
wire $delete_wire$170755
|
||||
wire width 2 $delete_wire$170756
|
||||
wire width 2 $delete_wire$170757
|
||||
wire $delete_wire$170758
|
||||
wire $delete_wire$170759
|
||||
wire $delete_wire$170760
|
||||
wire $delete_wire$170761
|
||||
wire $delete_wire$170762
|
||||
wire $delete_wire$170763
|
||||
wire $delete_wire$170764
|
||||
wire $delete_wire$170765
|
||||
wire $delete_wire$170766
|
||||
wire $delete_wire$170767
|
||||
wire $delete_wire$170768
|
||||
wire $delete_wire$170769
|
||||
wire $delete_wire$170770
|
||||
wire $delete_wire$170771
|
||||
wire $delete_wire$170772
|
||||
wire $delete_wire$170773
|
||||
wire $delete_wire$170774
|
||||
wire $delete_wire$170775
|
||||
wire $delete_wire$170859
|
||||
wire $delete_wire$170860
|
||||
wire $delete_wire$170861
|
||||
wire $delete_wire$170862
|
||||
wire $delete_wire$170863
|
||||
wire $delete_wire$170864
|
||||
wire $delete_wire$170865
|
||||
wire $delete_wire$170866
|
||||
wire $delete_wire$170867
|
||||
wire $delete_wire$170868
|
||||
wire $delete_wire$170869
|
||||
wire $delete_wire$170870
|
||||
wire $delete_wire$170871
|
||||
wire $delete_wire$170872
|
||||
wire $delete_wire$170873
|
||||
wire $delete_wire$170874
|
||||
wire $delete_wire$170875
|
||||
wire $delete_wire$170876
|
||||
wire $delete_wire$170877
|
||||
wire $delete_wire$170878
|
||||
wire $delete_wire$170879
|
||||
wire $delete_wire$170880
|
||||
wire $delete_wire$170881
|
||||
wire $delete_wire$170882
|
||||
wire $delete_wire$170996
|
||||
wire $delete_wire$170997
|
||||
wire $delete_wire$170998
|
||||
wire $delete_wire$170999
|
||||
wire $delete_wire$171000
|
||||
wire $delete_wire$171001
|
||||
wire $delete_wire$171002
|
||||
wire $delete_wire$171003
|
||||
wire $delete_wire$171004
|
||||
wire $delete_wire$171005
|
||||
wire $delete_wire$171006
|
||||
wire $delete_wire$171007
|
||||
wire $delete_wire$171008
|
||||
wire $delete_wire$171009
|
||||
wire $delete_wire$171010
|
||||
wire $delete_wire$171011
|
||||
wire $delete_wire$171035
|
||||
wire $delete_wire$171036
|
||||
wire $delete_wire$171037
|
||||
wire $delete_wire$171038
|
||||
wire $delete_wire$171039
|
||||
wire $delete_wire$171040
|
||||
wire $delete_wire$171041
|
||||
wire $delete_wire$171042
|
||||
wire $delete_wire$171043
|
||||
wire $delete_wire$171044
|
||||
wire $delete_wire$171045
|
||||
wire $delete_wire$171046
|
||||
wire $delete_wire$171047
|
||||
wire $delete_wire$171048
|
||||
wire $delete_wire$171049
|
||||
wire $delete_wire$171172
|
||||
wire $delete_wire$171173
|
||||
wire $delete_wire$171174
|
||||
wire $delete_wire$171175
|
||||
wire $delete_wire$171176
|
||||
wire $delete_wire$171177
|
||||
wire $delete_wire$171178
|
||||
wire $delete_wire$171179
|
||||
wire $delete_wire$171180
|
||||
wire $delete_wire$171181
|
||||
wire $delete_wire$171182
|
||||
wire $delete_wire$171183
|
||||
wire $delete_wire$171184
|
||||
wire $delete_wire$171185
|
||||
wire $delete_wire$171186
|
||||
wire $delete_wire$171187
|
||||
wire $delete_wire$171188
|
||||
wire $delete_wire$171189
|
||||
wire $delete_wire$171190
|
||||
wire width 2 $delete_wire$171200
|
||||
wire width 2 $delete_wire$171201
|
||||
wire $delete_wire$171202
|
||||
wire $delete_wire$171203
|
||||
wire $delete_wire$171204
|
||||
wire $delete_wire$171205
|
||||
wire $delete_wire$171206
|
||||
wire $delete_wire$171207
|
||||
wire $delete_wire$171226
|
||||
wire $delete_wire$171227
|
||||
wire $delete_wire$171228
|
||||
wire $delete_wire$171229
|
||||
wire $delete_wire$171230
|
||||
wire $delete_wire$171231
|
||||
wire $delete_wire$171232
|
||||
wire $delete_wire$171254
|
||||
wire $delete_wire$171255
|
||||
wire $delete_wire$171256
|
||||
wire $delete_wire$171257
|
||||
wire $delete_wire$171258
|
||||
wire $delete_wire$171259
|
||||
wire $delete_wire$171267
|
||||
wire $delete_wire$171268
|
||||
wire $delete_wire$171269
|
||||
wire $delete_wire$171270
|
||||
wire $delete_wire$171271
|
||||
wire $delete_wire$171272
|
||||
wire $delete_wire$171314
|
||||
wire $delete_wire$171315
|
||||
wire $delete_wire$171316
|
||||
wire $delete_wire$171317
|
||||
wire $delete_wire$171318
|
||||
wire $delete_wire$171338
|
||||
wire $delete_wire$171339
|
||||
wire $delete_wire$171340
|
||||
wire $delete_wire$171341
|
||||
wire $delete_wire$171350
|
||||
wire $delete_wire$171351
|
||||
wire $delete_wire$171352
|
||||
wire $delete_wire$171353
|
||||
wire $delete_wire$171354
|
||||
wire $delete_wire$171355
|
||||
wire $delete_wire$171356
|
||||
wire $delete_wire$171357
|
||||
wire $delete_wire$171358
|
||||
wire $delete_wire$171359
|
||||
wire $delete_wire$171360
|
||||
wire width 2 $delete_wire$171361
|
||||
wire $delete_wire$171362
|
||||
wire $delete_wire$171371
|
||||
wire $delete_wire$171372
|
||||
wire $delete_wire$171373
|
||||
wire $delete_wire$171374
|
||||
wire $delete_wire$171387
|
||||
wire $delete_wire$171388
|
||||
wire $delete_wire$171389
|
||||
wire $delete_wire$171390
|
||||
wire $delete_wire$171408
|
||||
wire $delete_wire$171409
|
||||
wire $delete_wire$171441
|
||||
wire $delete_wire$171442
|
||||
wire $delete_wire$171449
|
||||
wire $delete_wire$171450
|
||||
wire $delete_wire$171454
|
||||
wire $delete_wire$171455
|
||||
wire $delete_wire$171471
|
||||
wire $delete_wire$171472
|
||||
wire $delete_wire$171477
|
||||
wire $delete_wire$171501
|
||||
wire $delete_wire$171502
|
||||
wire $delete_wire$171507
|
||||
wire $delete_wire$171512
|
||||
wire $delete_wire$171513
|
||||
wire $delete_wire$171514
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323_Y
|
||||
wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322_Y
|
||||
wire \N2231
|
||||
wire \N3558
|
||||
attribute \unused_bits "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31"
|
||||
wire width 32 \dcsr_d
|
||||
wire \dcsr_q_prv__0_
|
||||
cell $adff $procdff$137332
|
||||
parameter \ARST_POLARITY 0
|
||||
parameter \ARST_VALUE 1'1
|
||||
parameter \CLK_POLARITY 1'1
|
||||
parameter \WIDTH 1
|
||||
connect \ARST $delete_wire$170004
|
||||
connect \CLK $delete_wire$171206
|
||||
connect \D \dcsr_d [0]
|
||||
connect \Q \dcsr_q_prv__0_
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216087$6334
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$170875 $delete_wire$171472 $delete_wire$171181 $delete_wire$169735 $delete_wire$169994 $delete_wire$169963 $delete_wire$170670 $delete_wire$169702 $delete_wire$169975 $delete_wire$170002 $delete_wire$169641 $delete_wire$171011 $delete_wire$171006 $delete_wire$171173 $delete_wire$171387 $delete_wire$170769 $delete_wire$170881 $delete_wire$169743 $delete_wire$169731 $delete_wire$169710 $delete_wire$169756 $delete_wire$170018 $delete_wire$169779 $delete_wire$170037 $delete_wire$169794 $delete_wire$171339 $delete_wire$171256 $delete_wire$171205 $delete_wire$169670 $delete_wire$171352 $delete_wire$171315 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333_Y
|
||||
connect \S $delete_wire$169809
|
||||
connect \Y { $delete_wire$169830 $delete_wire$171390 $delete_wire$169837 $delete_wire$169679 $delete_wire$169677 $delete_wire$169767 $delete_wire$169828 $delete_wire$170038 $delete_wire$169704 $delete_wire$169653 $delete_wire$169707 $delete_wire$169684 $delete_wire$169986 $delete_wire$169712 $delete_wire$170033 $delete_wire$169759 $delete_wire$171513 $delete_wire$170012 $delete_wire$170876 $delete_wire$170007 $delete_wire$169965 $delete_wire$169825 $delete_wire$169655 $delete_wire$169839 $delete_wire$170034 $delete_wire$170042 $delete_wire$171338 $delete_wire$169833 $delete_wire$169762 $delete_wire$169835 $delete_wire$169764 \N2231 }
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$170014 $delete_wire$171257 $delete_wire$170770 $delete_wire$169725 $delete_wire$170873 $delete_wire$171514 $delete_wire$170870 $delete_wire$169692 $delete_wire$171184 $delete_wire$170045 $delete_wire$169649 $delete_wire$170859 $delete_wire$171455 $delete_wire$170053 $delete_wire$170044 $delete_wire$170768 $delete_wire$170659 $delete_wire$169742 $delete_wire$169730 $delete_wire$169718 $delete_wire$169741 $delete_wire$170019 $delete_wire$169778 $delete_wire$170024 $delete_wire$169807 $delete_wire$171046 $delete_wire$171374 $delete_wire$170861 $delete_wire$169669 $delete_wire$171182 $delete_wire$171388 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332_Y
|
||||
connect \S $delete_wire$169810
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169820 $delete_wire$171507 $delete_wire$171441 $delete_wire$169724 $delete_wire$169992 $delete_wire$169691 $delete_wire$171356 $delete_wire$169700 $delete_wire$169977 $delete_wire$170046 $delete_wire$169648 $delete_wire$170774 $delete_wire$171038 $delete_wire$171005 $delete_wire$170057 $delete_wire$171226 $delete_wire$170874 $delete_wire$169755 $delete_wire$169729 $delete_wire$171450 $delete_wire$169754 $delete_wire$170020 $delete_wire$169777 $delete_wire$170025 $delete_wire$169806 $delete_wire$170643 $delete_wire$171177 $delete_wire$171449 $delete_wire$169668 $delete_wire$171512 $delete_wire$171501 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331_Y
|
||||
connect \S $delete_wire$169997
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169819 $delete_wire$170772 $delete_wire$170773 $delete_wire$169723 $delete_wire$169990 $delete_wire$169690 $delete_wire$170669 $delete_wire$169699 $delete_wire$169978 $delete_wire$170047 $delete_wire$169647 $delete_wire$171049 $delete_wire$171007 $delete_wire$170872 $delete_wire$170056 $delete_wire$171004 $delete_wire$171202 $delete_wire$169793 $delete_wire$169728 $delete_wire$170664 $delete_wire$169753 $delete_wire$170021 $delete_wire$169776 $delete_wire$170026 $delete_wire$169805 $delete_wire$170644 $delete_wire$171008 $delete_wire$170657 $delete_wire$169658 $delete_wire$171003 $delete_wire$170749 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330_Y
|
||||
connect \S $delete_wire$169826
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330
|
||||
parameter \WIDTH 32
|
||||
connect \A { 4'0100 $delete_wire$169823 2'00 $delete_wire$169822 1'0 $delete_wire$169781 $delete_wire$170757 }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329_Y
|
||||
connect \S $delete_wire$170006
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169818 $delete_wire$170762 $delete_wire$170868 $delete_wire$169722 $delete_wire$169991 $delete_wire$169689 $delete_wire$170642 $delete_wire$169698 $delete_wire$169979 $delete_wire$170048 $delete_wire$169646 $delete_wire$171409 $delete_wire$171259 $delete_wire$170043 $delete_wire$170055 $delete_wire$171471 $delete_wire$170646 $delete_wire$169792 $delete_wire$169727 $delete_wire$169740 $delete_wire$169752 $delete_wire$170022 $delete_wire$169775 $delete_wire$170027 $delete_wire$169804 $delete_wire$170666 $delete_wire$170663 $delete_wire$171179 $delete_wire$169666 $delete_wire$171186 $delete_wire$170655 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328_Y
|
||||
connect \S $delete_wire$169972
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169817 $delete_wire$171190 $delete_wire$171408 $delete_wire$169721 $delete_wire$171002 $delete_wire$169688 $delete_wire$171270 $delete_wire$169697 $delete_wire$169980 $delete_wire$169982 $delete_wire$169645 $delete_wire$171180 $delete_wire$169771 $delete_wire$170860 $delete_wire$170054 $delete_wire$171009 $delete_wire$170639 $delete_wire$169791 $delete_wire$170879 $delete_wire$169739 $delete_wire$169751 $delete_wire$170049 $delete_wire$169774 $delete_wire$170028 $delete_wire$169803 $delete_wire$170645 $delete_wire$169989 $delete_wire$171272 $delete_wire$169665 $delete_wire$171174 $delete_wire$170653 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327_Y
|
||||
connect \S $delete_wire$170036
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169816 $delete_wire$171228 $delete_wire$171454 $delete_wire$169720 $delete_wire$170997 $delete_wire$169687 $delete_wire$170649 $delete_wire$169696 $delete_wire$169981 $delete_wire$170050 $delete_wire$169644 $delete_wire$170760 $delete_wire$169786 $delete_wire$170862 $delete_wire$170032 $delete_wire$171389 $delete_wire$171043 $delete_wire$169790 $delete_wire$169749 $delete_wire$169738 $delete_wire$169750 $delete_wire$169983 $delete_wire$169773 $delete_wire$170029 $delete_wire$169802 $delete_wire$170660 $delete_wire$169962 $delete_wire$170658 $delete_wire$169664 $delete_wire$170751 $delete_wire$170640 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326_Y
|
||||
connect \S $delete_wire$169705
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169815 $delete_wire$171372 $delete_wire$171175 $delete_wire$169719 $delete_wire$171044 $delete_wire$169686 $delete_wire$171231 $delete_wire$169695 $delete_wire$170008 $delete_wire$170052 $delete_wire$169643 $delete_wire$170996 $delete_wire$169785 $delete_wire$170865 $delete_wire$170636 $delete_wire$171185 $delete_wire$171188 $delete_wire$169789 $delete_wire$171045 $delete_wire$169737 $delete_wire$169765 $delete_wire$171268 $delete_wire$169772 $delete_wire$170016 $delete_wire$169801 $delete_wire$170665 $delete_wire$170058 $delete_wire$169961 $delete_wire$169663 $delete_wire$171502 $delete_wire$170652 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325_Y
|
||||
connect \S $delete_wire$170650
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169814 $delete_wire$170753 $delete_wire$171176 $delete_wire$169709 $delete_wire$170999 $delete_wire$169685 $delete_wire$170647 $delete_wire$169694 $delete_wire$169999 $delete_wire$170051 $delete_wire$169642 $delete_wire$170863 $delete_wire$169784 $delete_wire$170755 $delete_wire$170754 $delete_wire$171204 $delete_wire$171373 $delete_wire$169788 $delete_wire$170059 $delete_wire$169736 $delete_wire$169748 $delete_wire$171351 $delete_wire$169787 $delete_wire$171340 $delete_wire$169800 $delete_wire$170638 $delete_wire$169970 $delete_wire$169974 $delete_wire$169662 $delete_wire$170764 $delete_wire$170651 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324_Y
|
||||
connect \S $delete_wire$169996
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169813 $delete_wire$171229 $delete_wire$170765 $delete_wire$169717 $delete_wire$171035 $delete_wire$169675 $delete_wire$170637 $delete_wire$169693 $delete_wire$170000 $delete_wire$171000 $delete_wire$169650 $delete_wire$171442 $delete_wire$169783 $delete_wire$170882 $delete_wire$171318 $delete_wire$171010 $delete_wire$171357 $delete_wire$169821 $delete_wire$170880 $delete_wire$169726 $delete_wire$169747 $delete_wire$169984 $delete_wire$169770 $delete_wire$170031 $delete_wire$169799 $delete_wire$171048 $delete_wire$169969 $delete_wire$170656 $delete_wire$169661 $delete_wire$171354 $delete_wire$170661 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323_Y
|
||||
connect \S $delete_wire$169671
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169998 $delete_wire$171350 $delete_wire$170759 $delete_wire$169716 $delete_wire$169993 $delete_wire$169683 $delete_wire$170654 $delete_wire$169667 $delete_wire$170001 $delete_wire$171371 $delete_wire$169674 $delete_wire$170667 $delete_wire$169782 $delete_wire$171187 $delete_wire$170878 $delete_wire$170766 $delete_wire$171254 $delete_wire$169796 $delete_wire$170877 $delete_wire$169734 $delete_wire$169746 $delete_wire$171207 $delete_wire$169769 $delete_wire$170009 $delete_wire$169798 $delete_wire$171172 $delete_wire$169968 $delete_wire$171271 $delete_wire$169660 $delete_wire$171232 $delete_wire$170662 \dcsr_q_prv__0_ }
|
||||
connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322_Y
|
||||
connect \S $delete_wire$169831
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$169811 $delete_wire$171355 $delete_wire$170763 $delete_wire$169715 $delete_wire$171039 $delete_wire$169682 $delete_wire$169988 $delete_wire$169657 $delete_wire$170015 $delete_wire$171317 $delete_wire$169673 $delete_wire$170866 $delete_wire$169768 $delete_wire$170998 $delete_wire$170752 $delete_wire$170023 $delete_wire$170767 $delete_wire$169795 $delete_wire$170030 $delete_wire$169733 $delete_wire$169745 $delete_wire$171360 $delete_wire$169834 $delete_wire$170010 $delete_wire$169976 $delete_wire$171203 $delete_wire$169967 $delete_wire$171477 $delete_wire$169659 $delete_wire$171230 $delete_wire$170641 \dcsr_q_prv__0_ }
|
||||
connect \B $delete_wire$169713
|
||||
connect \S $delete_wire$171001
|
||||
connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322_Y
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:217099$7332
|
||||
parameter \WIDTH 32
|
||||
connect \A { $delete_wire$170013 $delete_wire$171353 $delete_wire$171037 $delete_wire$169714 $delete_wire$171269 $delete_wire$169681 $delete_wire$170668 $delete_wire$169656 $delete_wire$170003 $delete_wire$171189 $delete_wire$169672 $delete_wire$169960 $delete_wire$169780 $delete_wire$170775 $delete_wire$170871 $delete_wire$170864 $delete_wire$171183 $delete_wire$169808 $delete_wire$170017 $delete_wire$169732 $delete_wire$169744 $delete_wire$171359 $delete_wire$171041 $delete_wire$171040 $delete_wire$170761 $delete_wire$170635 $delete_wire$169966 $delete_wire$169971 $delete_wire$169701 $delete_wire$170648 $delete_wire$171255 \dcsr_q_prv__0_ }
|
||||
connect \B { $delete_wire$169829 $delete_wire$171316 $delete_wire$169836 $delete_wire$169678 $delete_wire$169676 $delete_wire$169766 $delete_wire$169827 $delete_wire$170039 $delete_wire$169703 $delete_wire$169652 $delete_wire$169706 $delete_wire$169708 $delete_wire$169987 $delete_wire$169711 $delete_wire$169985 $delete_wire$169758 $delete_wire$169973 $delete_wire$170011 $delete_wire$170869 $delete_wire$169812 $delete_wire$169964 $delete_wire$169824 $delete_wire$169654 $delete_wire$169838 $delete_wire$170035 $delete_wire$169840 $delete_wire$171341 $delete_wire$169832 $delete_wire$169761 $delete_wire$169797 $delete_wire$169763 \N2231 }
|
||||
connect \S $delete_wire$169760
|
||||
connect \Y { \dcsr_d [31:9] $delete_wire$171047 $delete_wire$170040 $delete_wire$170750 \dcsr_d [5:2] $delete_wire$171227 \N3558 }
|
||||
end
|
||||
cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:217233$7498
|
||||
parameter \WIDTH 5
|
||||
connect \A { $delete_wire$169995 $delete_wire$169651 $delete_wire$171042 $delete_wire$171201 }
|
||||
connect \B { $delete_wire$170867 $delete_wire$170041 $delete_wire$171178 $delete_wire$171358 \N3558 }
|
||||
connect \S $delete_wire$170771
|
||||
connect \Y { \dcsr_d [8:6] \dcsr_d [1:0] }
|
||||
end
|
||||
end
|
||||
58
tests/opt/opt_dff-simplify.ys
Normal file
58
tests/opt/opt_dff-simplify.ys
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# 5279 issue
|
||||
# Check only for complimentary patterns elimination
|
||||
|
||||
read_rtlil opt_dff-simplify.il
|
||||
|
||||
select -assert-count 0 t:$adffe
|
||||
select -assert-count 1 t:$adff
|
||||
select -assert-count 0 t:$ne
|
||||
|
||||
opt_dff
|
||||
|
||||
select -assert-count 1 t:$adffe
|
||||
select -assert-count 0 t:$adff
|
||||
|
||||
select -assert-count 8 t:$ne r:A_WIDTH=3 %i
|
||||
select -assert-count 5 t:$ne r:A_WIDTH=2 %i
|
||||
|
||||
select -assert-none t:$ne r:A_WIDTH=13 %i
|
||||
select -assert-none t:$ne r:A_WIDTH=14 %i
|
||||
select -assert-none t:$ne r:A_WIDTH=15 %i
|
||||
select -assert-none t:$ne r:A_WIDTH=10 %i
|
||||
select -assert-none t:$ne r:A_WIDTH=12 %i
|
||||
select -assert-none t:$ne r:A_WIDTH=11 %i
|
||||
|
||||
# Check for both complimentary and redundancy elimination
|
||||
|
||||
read_verilog << EOT
|
||||
module test(input clk, input h, input i, input m, output reg p);
|
||||
wire D;
|
||||
wire a;
|
||||
wire j;
|
||||
wire c;
|
||||
wire mux_test;
|
||||
wire n;
|
||||
|
||||
always @(posedge clk)
|
||||
p <= D;
|
||||
assign j = n ? 1'hx : a;
|
||||
assign a = i ? mux_test : p;
|
||||
assign D = m ? h : j;
|
||||
assign c = n ? 1'hx : p;
|
||||
assign mux_test = m ? 1'hx : c;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
cd test
|
||||
proc
|
||||
|
||||
select -assert-count 0 t:$dffe
|
||||
select -assert-count 1 t:$dff
|
||||
select -assert-count 0 t:$ne
|
||||
|
||||
opt_dff
|
||||
|
||||
select -assert-count 1 t:$dffe
|
||||
select -assert-count 0 t:$dff
|
||||
select -assert-count 1 t:$ne r:A_WIDTH=2 %i
|
||||
select -assert-none t:$ne r:A_WIDTH=3 %i
|
||||
32
tests/unit/kernel/bitpatternTest.cc
Normal file
32
tests/unit/kernel/bitpatternTest.cc
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "kernel/bitpattern.h"
|
||||
#include "kernel/rtlil.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
TEST(BitpatternTest, has)
|
||||
{
|
||||
SigSpec _aaa = {RTLIL::Sa, RTLIL::Sa, RTLIL::Sa};
|
||||
SigSpec _01a = {RTLIL::S0, RTLIL::S1, RTLIL::Sa};
|
||||
SigSpec _011 = {RTLIL::S0, RTLIL::S1, RTLIL::S1};
|
||||
SigSpec _111 = {RTLIL::S1, RTLIL::S1, RTLIL::S1};
|
||||
|
||||
EXPECT_TRUE(BitPatternPool(_aaa).has_any(_01a));
|
||||
EXPECT_TRUE(BitPatternPool(_01a).has_any(_01a));
|
||||
// 011 overlaps with 01a
|
||||
EXPECT_TRUE(BitPatternPool(_011).has_any(_01a));
|
||||
// overlap is symmetric
|
||||
EXPECT_TRUE(BitPatternPool(_01a).has_any(_011));
|
||||
EXPECT_FALSE(BitPatternPool(_111).has_any(_01a));
|
||||
|
||||
EXPECT_TRUE(BitPatternPool(_aaa).has_all(_01a));
|
||||
EXPECT_TRUE(BitPatternPool(_01a).has_all(_01a));
|
||||
// 011 is covered by 01a
|
||||
EXPECT_TRUE(BitPatternPool(_01a).has_all(_011));
|
||||
// 01a is not covered by 011
|
||||
EXPECT_FALSE(BitPatternPool(_011).has_all(_01a));
|
||||
EXPECT_FALSE(BitPatternPool(_111).has_all(_01a));
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
67
tests/unit/kernel/hashTest.cc
Normal file
67
tests/unit/kernel/hashTest.cc
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "kernel/yosys_common.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
static Hasher hash(int x)
|
||||
{
|
||||
Hasher h;
|
||||
h.eat(x);
|
||||
return h;
|
||||
}
|
||||
|
||||
TEST(CommutativeTest, basic)
|
||||
{
|
||||
hashlib::commutative_hash comm1;
|
||||
comm1.eat(hash(1));
|
||||
comm1.eat(hash(2));
|
||||
hashlib::commutative_hash comm2;
|
||||
comm2.eat(hash(2));
|
||||
comm2.eat(hash(1));
|
||||
EXPECT_EQ(comm1.hash_into(Hasher()).yield(), comm2.hash_into(Hasher()).yield());
|
||||
}
|
||||
|
||||
TEST(PoolHashTest, collisions)
|
||||
{
|
||||
uint64_t collisions = 0;
|
||||
std::unordered_set<Hasher::hash_t> hashes;
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
for (int j = i + 1; j < 1000; ++j) {
|
||||
pool<int> p1;
|
||||
p1.insert(i);
|
||||
p1.insert(j);
|
||||
auto h = p1.hash_into(Hasher()).yield();
|
||||
if (!hashes.insert(h).second) {
|
||||
++collisions;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "pool<int> collisions: " << collisions << std::endl;
|
||||
EXPECT_LT(collisions, 10'000);
|
||||
}
|
||||
|
||||
TEST(PoolHashTest, subset_collisions)
|
||||
{
|
||||
uint64_t collisions = 0;
|
||||
std::unordered_set<Hasher::hash_t> hashes;
|
||||
for (int i = 0; i < 1000 * 1000; ++i) {
|
||||
|
||||
pool<int> p1;
|
||||
for (int b = 0; i >> b; ++b) {
|
||||
if ((i >> b) & 1) {
|
||||
p1.insert(b);
|
||||
}
|
||||
}
|
||||
auto h = p1.hash_into(Hasher()).yield();
|
||||
if (!hashes.insert(h).second) {
|
||||
++collisions;
|
||||
}
|
||||
|
||||
}
|
||||
std::cout << "pool<int> subset collisions: " << collisions << std::endl;
|
||||
EXPECT_LT(collisions, 100);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
@ -69,4 +69,14 @@ TEST(KernelStringfTest, dynamicWidthAndPrecision)
|
|||
EXPECT_EQ(stringf("%*.*f", 8, 4, 1.0), " 1.0000");
|
||||
}
|
||||
|
||||
TEST(KernelStringfTest, dynamicPrecisionInt)
|
||||
{
|
||||
EXPECT_EQ(stringf("%.*d", 4, 7), "0007");
|
||||
}
|
||||
|
||||
TEST(KernelStringfTest, dynamicWidthAndPrecisionInt)
|
||||
{
|
||||
EXPECT_EQ(stringf("%*.*d", 8, 4, 7), " 0007");
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
|||
30
tests/various/abstract_initstates.ys
Normal file
30
tests/various/abstract_initstates.ys
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
read_verilog <<EOT
|
||||
|
||||
module half_clock (CLK, Q, magic);
|
||||
input CLK;
|
||||
output reg Q = 0;
|
||||
input magic;
|
||||
always @(posedge CLK)
|
||||
Q <= ~Q;
|
||||
endmodule
|
||||
|
||||
EOT
|
||||
proc
|
||||
design -save half_clock
|
||||
|
||||
sat -set-init-undef -enable_undef -verify -seq 5 -set-at 1 Q 0
|
||||
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0
|
||||
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 2 Q 0 -set-at 3 Q 0
|
||||
abstract -state -initstates 1 */Q
|
||||
sat -set-init-undef -enable_undef -verify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0
|
||||
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 2 Q 0 -set-at 3 Q 0
|
||||
|
||||
design -load half_clock
|
||||
|
||||
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0
|
||||
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 2 Q 0 -set-at 3 Q 0
|
||||
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 3 Q 0 -set-at 4 Q 0
|
||||
abstract -state -initstates 2 */Q
|
||||
sat -set-init-undef -enable_undef -verify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0
|
||||
sat -set-init-undef -enable_undef -verify -seq 5 -set-at 1 Q 0 -set-at 2 Q 0 -set-at 3 Q 0
|
||||
sat -set-init-undef -enable_undef -falsify -seq 5 -set-at 3 Q 0 -set-at 4 Q 0
|
||||
141
tests/various/equiv_assume.ys
Normal file
141
tests/various/equiv_assume.ys
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
read_verilog -sv <<EOT
|
||||
module gold (input D, output Q);
|
||||
assign Q = '0;
|
||||
endmodule
|
||||
|
||||
module gate (input D, output Q);
|
||||
assume property (D == '0);
|
||||
assign Q = D;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
chformal -lower
|
||||
async2sync
|
||||
design -stash input
|
||||
|
||||
# using $assert cells in sat verifies
|
||||
design -load input
|
||||
equiv_make -make_assert gold gate equiv
|
||||
prep -top equiv
|
||||
sat -set-assumes -prove-asserts -verify
|
||||
# this fails
|
||||
# sat -prove-asserts -verify
|
||||
|
||||
# so should $equiv
|
||||
## in equiv_simple
|
||||
design -load input
|
||||
equiv_make gold gate equiv
|
||||
equiv_simple -set-assumes equiv
|
||||
equiv_status -assert equiv
|
||||
|
||||
## and equiv_induct
|
||||
delete equiv
|
||||
equiv_make gold gate equiv
|
||||
equiv_induct -set-assumes equiv
|
||||
equiv_status -assert equiv
|
||||
|
||||
# and it works through cells
|
||||
design -reset
|
||||
read_verilog -sv <<EOT
|
||||
module gold (input [1:0] D, output [1:0] Q);
|
||||
assign Q = !D;
|
||||
endmodule
|
||||
|
||||
module gate (input [1:0] D, output [1:0] Q);
|
||||
assume property (D == 2'b11);
|
||||
wire [1:0] G = ~D;
|
||||
assign Q = G;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
chformal -lower
|
||||
async2sync
|
||||
design -stash input2
|
||||
|
||||
design -load input2
|
||||
equiv_make -make_assert gold gate equiv
|
||||
prep -top equiv
|
||||
sat -set-assumes -prove-asserts -verify
|
||||
|
||||
design -load input2
|
||||
equiv_make gold gate equiv
|
||||
equiv_simple -set-assumes equiv
|
||||
equiv_status -assert equiv
|
||||
|
||||
delete equiv
|
||||
equiv_make gold gate equiv
|
||||
equiv_induct -set-assumes equiv
|
||||
equiv_status -assert equiv
|
||||
|
||||
# and registers
|
||||
design -reset
|
||||
read_verilog -sv <<EOT
|
||||
module gold (input clk, input [1:0] D, output [1:0] Q);
|
||||
assign Q = '0;
|
||||
endmodule
|
||||
|
||||
module gate (input clk, input [1:0] D, output [1:0] Q);
|
||||
reg [1:0] Dreg;
|
||||
assume property (Dreg == 2'b11);
|
||||
always @(clk) begin
|
||||
Dreg <= D;
|
||||
end
|
||||
assign Q = ~Dreg;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
proc
|
||||
chformal -lower
|
||||
async2sync
|
||||
design -stash input3
|
||||
|
||||
design -load input3
|
||||
equiv_make -make_assert gold gate equiv
|
||||
prep -top equiv
|
||||
sat -set-assumes -prove-asserts -verify
|
||||
|
||||
design -load input3
|
||||
equiv_make gold gate equiv
|
||||
equiv_simple -set-assumes equiv
|
||||
equiv_status -assert equiv
|
||||
|
||||
delete equiv
|
||||
equiv_make gold gate equiv
|
||||
equiv_induct -set-assumes equiv
|
||||
equiv_status -assert equiv
|
||||
|
||||
# so long as the assumption doesn't end up after the equiv
|
||||
design -reset
|
||||
read_verilog -sv <<EOT
|
||||
module gold (input [1:0] D, output [1:0] Q);
|
||||
assign Q = !D;
|
||||
endmodule
|
||||
|
||||
module gate (input [1:0] D, output [1:0] Q);
|
||||
assume property (G == 2'b00);
|
||||
wire [1:0] G = ~D;
|
||||
assign Q = G;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
chformal -lower
|
||||
async2sync
|
||||
design -stash input4
|
||||
|
||||
logger -expect log "model found: FAIL!" 1
|
||||
logger -expect log "Found a total of 2 unproven .equiv cells." 2
|
||||
|
||||
design -load input4
|
||||
equiv_make -make_assert gold gate equiv
|
||||
prep -top equiv
|
||||
sat -set-assumes -prove-asserts
|
||||
|
||||
design -load input4
|
||||
equiv_make gold gate equiv
|
||||
equiv_simple -set-assumes equiv
|
||||
equiv_status equiv
|
||||
|
||||
delete equiv
|
||||
equiv_make gold gate equiv
|
||||
equiv_induct -set-assumes equiv
|
||||
equiv_status equiv
|
||||
|
|
@ -39,3 +39,18 @@ select -assert-count 1 w:d__1
|
|||
select -assert-count 1 w:_e
|
||||
select -assert-count 1 w:wire_
|
||||
select -assert-count 1 w:$add$<<EOF:*$1_Y
|
||||
|
||||
# Ports are updated during rename
|
||||
design -reset
|
||||
read_verilog << EOT
|
||||
module top(output \$e );
|
||||
submod \a$ (\$e );
|
||||
endmodule
|
||||
|
||||
module submod(output \a[0] );
|
||||
assign \a[0] = 0;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
rename -unescape
|
||||
check
|
||||
|
|
|
|||
35
tests/various/rename_wire_move_to_cell.ys
Normal file
35
tests/various/rename_wire_move_to_cell.ys
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
read_verilog <<EOF
|
||||
module top(input clk, rst, input [7:0] din, output [7:0] dout, input bin, output bout);
|
||||
reg [7:0] dq;
|
||||
reg bq;
|
||||
|
||||
always @(posedge clk, posedge rst) begin
|
||||
if (rst) dq <= '0;
|
||||
else dq <= din;
|
||||
end
|
||||
|
||||
always @(posedge clk) bq <= bin;
|
||||
|
||||
assign dout = dq;
|
||||
assign bout = bq;
|
||||
endmodule
|
||||
EOF
|
||||
|
||||
proc
|
||||
hierarchy -top top
|
||||
|
||||
select -assert-count 1 t:$dff
|
||||
select -assert-count 1 t:$adff
|
||||
select -assert-count 0 t:$dff n:bq %i
|
||||
select -assert-count 0 t:$adff n:dq %i
|
||||
select -assert-count 1 w:bq
|
||||
select -assert-count 1 w:dq
|
||||
|
||||
rename -wire -move-to-cell
|
||||
|
||||
select -assert-count 1 t:$dff
|
||||
select -assert-count 1 t:$adff
|
||||
select -assert-count 1 t:$dff n:bq %i
|
||||
select -assert-count 1 t:$adff n:dq %i
|
||||
select -assert-count 0 w:bq
|
||||
select -assert-count 0 w:dq
|
||||
|
|
@ -11,6 +11,8 @@ end
|
|||
EOT
|
||||
logger -expect log "Chip area for module '\\top': 9.072000" 1
|
||||
logger -expect-no-warnings
|
||||
logger -expect log " 1 9.072 cells" 1
|
||||
logger -expect log " 1 9.072 sg13g2_and2_1" 1
|
||||
stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz
|
||||
|
||||
|
||||
|
|
@ -70,5 +72,8 @@ end
|
|||
EOT
|
||||
logger -expect log "Chip area for top module '\\top': 112.492800" 1
|
||||
logger -expect log "of which used for sequential elements: 94.348800" 1
|
||||
logger -expect log "2 18.144 cells" 1
|
||||
logger -expect log "4 112.493 cells" 1
|
||||
logger -expect log "2 94.349 sg13g2_dfrbp_1" 1
|
||||
logger -expect-no-warnings
|
||||
stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top
|
||||
|
|
|
|||
25
tests/various/stat_area_by_width.lib
Normal file
25
tests/various/stat_area_by_width.lib
Normal file
File diff suppressed because one or more lines are too long
62
tests/various/stat_hierarchy.ys
Normal file
62
tests/various/stat_hierarchy.ys
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
read_rtlil << EOT
|
||||
module \top
|
||||
wire input 1 \A
|
||||
wire output 2 \Y
|
||||
wire output 3 \N
|
||||
|
||||
cell \sg13g2_and2_1 \sub1
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \Y \Y
|
||||
end
|
||||
|
||||
cell \child \sequential
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \R 1'0
|
||||
connect \Y \Y
|
||||
connect \N \N
|
||||
end
|
||||
|
||||
cell \child \sequential1
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \R 1'0
|
||||
connect \Y \Y
|
||||
connect \N \N
|
||||
end
|
||||
|
||||
cell \sg13g2_and2_1 \sub2
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \Y \Y
|
||||
end
|
||||
end
|
||||
|
||||
module \child
|
||||
wire input 1 \A
|
||||
wire input 2 \B
|
||||
wire input 3 \R
|
||||
|
||||
wire output 4 \Y
|
||||
wire output 5 \N
|
||||
|
||||
cell \sg13g2_dfrbp_1 \sequential_ff
|
||||
connect \CLK \A
|
||||
connect \D \B
|
||||
connect \Q \Y
|
||||
connect \Q_N \N
|
||||
connect \RESET_B \R
|
||||
end
|
||||
|
||||
end
|
||||
EOT
|
||||
logger -expect log "4 112.493 2 18.144 cells" 2
|
||||
logger -expect log "2 18.144 2 18.144 sg13g2_and2_1" 2
|
||||
logger -expect log "2 94.349 - - sg13g2_dfrbp_1" 2
|
||||
logger -expect log "2 94.349 2 - submodules" 2
|
||||
logger -expect-no-warnings
|
||||
stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top -hierarchy
|
||||
|
||||
|
||||
92
tests/various/stat_high_level.ys
Normal file
92
tests/various/stat_high_level.ys
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
read_rtlil << EOT
|
||||
module \top
|
||||
wire input 1 \A
|
||||
wire output 2 \Y
|
||||
wire output 3 \N
|
||||
|
||||
cell $and \sub1
|
||||
parameter \A_SIGNED 0
|
||||
parameter \A_WIDTH 1
|
||||
parameter \B_SIGNED 0
|
||||
parameter \B_WIDTH 1
|
||||
parameter \Y_WIDTH 1
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \Y \Y
|
||||
end
|
||||
|
||||
cell \child \sequential
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \R 1'0
|
||||
connect \Y \Y
|
||||
connect \N \N
|
||||
end
|
||||
|
||||
cell \child \sequential1
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \R 1'0
|
||||
connect \Y \Y
|
||||
connect \N \N
|
||||
end
|
||||
|
||||
cell $xor \sub2
|
||||
parameter \A_SIGNED 0
|
||||
parameter \A_WIDTH 1
|
||||
parameter \B_SIGNED 0
|
||||
parameter \B_WIDTH 1
|
||||
parameter \Y_WIDTH 1
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \Y \Y
|
||||
end
|
||||
end
|
||||
|
||||
module \child
|
||||
wire input 1 \A
|
||||
wire input 2 \B
|
||||
wire input 3 \R
|
||||
|
||||
wire output 4 \Y
|
||||
wire output 5 \N
|
||||
wire \Y1
|
||||
wire \Y2
|
||||
cell \sg13g2_dfrbp_1 \sequential_ff
|
||||
connect \CLK \A
|
||||
connect \D \Y2
|
||||
connect \Q \Y
|
||||
connect \Q_N \N
|
||||
connect \RESET_B \R
|
||||
end
|
||||
|
||||
cell $xor \sub2
|
||||
parameter \A_SIGNED 0
|
||||
parameter \A_WIDTH 1
|
||||
parameter \B_SIGNED 0
|
||||
parameter \B_WIDTH 1
|
||||
parameter \Y_WIDTH 1
|
||||
connect \A \B
|
||||
connect \B 1'0
|
||||
connect \Y \Y1
|
||||
end
|
||||
|
||||
cell $reduce_xor \sub3
|
||||
parameter \A_SIGNED 0
|
||||
parameter \A_WIDTH 10
|
||||
parameter \Y_WIDTH 1
|
||||
connect \A 10'0000000000
|
||||
connect \Y \Y2
|
||||
end
|
||||
|
||||
end
|
||||
EOT
|
||||
logger -expect log "Chip area for top module '\\top': 66.000000" 1
|
||||
logger -expect log "3 30.5 3 30.5 cells" 1
|
||||
logger -expect log "2 51 - - \$reduce_xor" 2
|
||||
logger -expect log "8 66 2 5 cells" 2
|
||||
logger -expect-no-warnings
|
||||
stat -liberty ./stat_area_by_width.lib -top \top -hierarchy
|
||||
|
||||
|
||||
91
tests/various/stat_high_level2.ys
Normal file
91
tests/various/stat_high_level2.ys
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
read_rtlil << EOT
|
||||
module \top
|
||||
wire input 1 \A
|
||||
wire output 2 \Y
|
||||
wire output 3 \N
|
||||
|
||||
cell $and \sub1
|
||||
parameter \A_SIGNED 0
|
||||
parameter \A_WIDTH 1
|
||||
parameter \B_SIGNED 0
|
||||
parameter \B_WIDTH 1
|
||||
parameter \Y_WIDTH 1
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \Y \Y
|
||||
end
|
||||
|
||||
cell \child \sequential
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \R 1'0
|
||||
connect \Y \Y
|
||||
connect \N \N
|
||||
end
|
||||
|
||||
cell \child \sequential1
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \R 1'0
|
||||
connect \Y \Y
|
||||
connect \N \N
|
||||
end
|
||||
|
||||
cell $xor \sub2
|
||||
parameter \A_SIGNED 0
|
||||
parameter \A_WIDTH 1
|
||||
parameter \B_SIGNED 0
|
||||
parameter \B_WIDTH 1
|
||||
parameter \Y_WIDTH 1
|
||||
connect \A \A
|
||||
connect \B 1'0
|
||||
connect \Y \Y
|
||||
end
|
||||
end
|
||||
|
||||
module \child
|
||||
wire input 1 \A
|
||||
wire input 2 \B
|
||||
wire input 3 \R
|
||||
|
||||
wire output 4 \Y
|
||||
wire output 5 \N
|
||||
wire \Y1
|
||||
wire \Y2
|
||||
wire width 2 \A2
|
||||
cell \sg13g2_dfrbp_1 \sequential_ff
|
||||
connect \CLK \A
|
||||
connect \D \Y2
|
||||
connect \Q \Y
|
||||
connect \Q_N \N
|
||||
connect \RESET_B \R
|
||||
end
|
||||
|
||||
cell $bmux \bmux1
|
||||
parameter \WIDTH 2
|
||||
parameter \S_WIDTH 2
|
||||
connect \A 8'00000000
|
||||
connect \S 2'00
|
||||
connect \Y \A2
|
||||
end
|
||||
|
||||
cell $reduce_xor \sub3
|
||||
parameter \A_SIGNED 0
|
||||
parameter \A_WIDTH 10
|
||||
parameter \Y_WIDTH 1
|
||||
connect \A 10'0000000000
|
||||
connect \Y \Y2
|
||||
end
|
||||
|
||||
end
|
||||
EOT
|
||||
|
||||
logger -expect log "Chip area for top module '\\top': 80.000000" 1
|
||||
logger -expect log "1 12 1 12 \$bmux" 1
|
||||
logger -expect log "3 37.5 3 37.5 cells" 1
|
||||
logger -expect log "8 80 2 5 cells" 2
|
||||
logger -expect-no-warnings
|
||||
stat -liberty ./stat_area_by_width.lib -top \top -hierarchy
|
||||
|
||||
|
||||
7
tests/verilog/constparser_f.ys
Normal file
7
tests/verilog/constparser_f.ys
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
logger -expect prefix-error "<<EOT:2: ERROR: Digit larger than 1 used in in base-2 constant." 1
|
||||
read_verilog <<EOT
|
||||
module test (y);
|
||||
output signed [2:0] y = 1'bf;
|
||||
endmodule
|
||||
EOT
|
||||
dump
|
||||
3
tests/verilog/constparser_f_file.sv
Normal file
3
tests/verilog/constparser_f_file.sv
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module test (y);
|
||||
output signed [2:0] y = 1'bf;
|
||||
endmodule
|
||||
2
tests/verilog/constparser_f_file.ys
Normal file
2
tests/verilog/constparser_f_file.ys
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
logger -expect prefix-error "./constparser_f_file.sv:2: ERROR: Digit larger than 1 used in in base-2 constant." 1
|
||||
read_verilog -sv ./constparser_f_file.sv
|
||||
6
tests/verilog/constparser_g.ys
Normal file
6
tests/verilog/constparser_g.ys
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
logger -expect prefix-error "<<EOT:2: ERROR: syntax error, unexpected invalid token, expecting TOK_BASED_CONSTVAL" 1
|
||||
read_verilog <<EOT
|
||||
module test (y);
|
||||
output signed [2:0] y = 1'bg;
|
||||
endmodule
|
||||
EOT
|
||||
15
tests/verilog/fcall_smoke.ys
Normal file
15
tests/verilog/fcall_smoke.ys
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
read_verilog -sv <<EOT
|
||||
module smoke_initstate (
|
||||
input resetn,
|
||||
input clk,
|
||||
input a
|
||||
);
|
||||
always @(posedge clk) begin
|
||||
assert property ($stable(a));
|
||||
assert property ($changed(a));
|
||||
assert property ($rose(a));
|
||||
assert property ($fell(a));
|
||||
assume(resetn == !$initstate);
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
14
tests/verilog/package_import_separate.sv
Normal file
14
tests/verilog/package_import_separate.sv
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package package_import_separate;
|
||||
|
||||
localparam integer
|
||||
DATAWIDTH = 8,
|
||||
ADDRWIDTH = 4;
|
||||
|
||||
localparam logic [2:0]
|
||||
IDLE = 3'b000,
|
||||
START = 3'b001,
|
||||
DATA = 3'b010,
|
||||
STOP = 3'b100,
|
||||
DONE = 3'b101;
|
||||
|
||||
endpackage
|
||||
5
tests/verilog/package_import_separate.ys
Normal file
5
tests/verilog/package_import_separate.ys
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
read_verilog -sv package_import_separate.sv
|
||||
read_verilog -sv package_import_separate_module.sv
|
||||
hierarchy -check
|
||||
proc
|
||||
opt -full
|
||||
19
tests/verilog/package_import_separate_module.sv
Normal file
19
tests/verilog/package_import_separate_module.sv
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import package_import_separate::*;
|
||||
|
||||
module package_import_separate_module;
|
||||
logic [DATAWIDTH-1:0] data;
|
||||
logic [ADDRWIDTH-1:0] addr;
|
||||
logic [2:0] state;
|
||||
|
||||
always_comb begin
|
||||
case (state)
|
||||
IDLE: data = 8'h00;
|
||||
START: data = 8'h01;
|
||||
DATA: data = 8'h02;
|
||||
STOP: data = 8'h04;
|
||||
DONE: data = 8'h05;
|
||||
default: data = 8'hFF;
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Add table
Add a link
Reference in a new issue