aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArchie <ac11018@ic.ac.uk>2022-08-21 17:18:20 -0500
committerArchie <ac11018@ic.ac.uk>2022-08-21 17:18:20 -0500
commitdb73f3c26b2768f93c7573b7c7d74b1cc7a0756d (patch)
tree81696fd98770e519aea96fe3a6e40bcc3b3a4360
parente7e8e3b0f65ea1ebfcf04bffd0d9ba90f8e0d7fe (diff)
parent029c2785e810fda0ccc5abbb6057af760f2fc6f3 (diff)
downloadyosys-db73f3c26b2768f93c7573b7c7d74b1cc7a0756d.tar.gz
yosys-db73f3c26b2768f93c7573b7c7d74b1cc7a0756d.tar.bz2
yosys-db73f3c26b2768f93c7573b7c7d74b1cc7a0756d.zip
Merge branch 'master' of https://github.com/ALGCDG/yosys
-rw-r--r--.github/workflows/test-macos.yml54
-rw-r--r--.gitignore3
-rw-r--r--CHANGELOG55
-rw-r--r--CODEOWNERS4
-rw-r--r--Makefile48
-rw-r--r--README.md12
-rw-r--r--backends/aiger/aiger.cc180
-rw-r--r--backends/btor/btor.cc31
-rw-r--r--backends/cxxrtl/cxxrtl.h21
-rw-r--r--backends/cxxrtl/cxxrtl_backend.cc2
-rw-r--r--backends/jny/jny.cc43
-rw-r--r--backends/rtlil/rtlil_backend.cc2
-rw-r--r--backends/smt2/Makefile.inc16
-rw-r--r--backends/smt2/smt2.cc160
-rw-r--r--backends/smt2/smtbmc.py439
-rw-r--r--backends/smt2/smtio.py67
-rw-r--r--backends/smt2/witness.py254
-rw-r--r--backends/smt2/ywio.py392
-rw-r--r--frontends/ast/genrtlil.cc16
-rw-r--r--frontends/ast/simplify.cc36
-rw-r--r--frontends/liberty/liberty.cc14
-rw-r--r--frontends/verific/README2
-rw-r--r--frontends/verific/verific.cc86
-rw-r--r--frontends/verilog/preproc.cc5
-rw-r--r--kernel/celltypes.h6
-rw-r--r--kernel/constids.inc1
-rw-r--r--kernel/driver.cc13
-rw-r--r--kernel/ff.cc19
-rw-r--r--kernel/ff.h8
-rw-r--r--kernel/log.cc2
-rw-r--r--kernel/log.h2
-rw-r--r--kernel/rtlil.cc198
-rw-r--r--kernel/rtlil.h137
-rw-r--r--kernel/satgen.cc2
-rw-r--r--kernel/yosys.cc38
-rw-r--r--kernel/yosys.h2
-rw-r--r--libs/fst/config.h2
-rw-r--r--manual/CHAPTER_CellLib.tex2
-rw-r--r--manual/command-reference-manual.tex93
-rw-r--r--misc/jny.schema.json193
-rw-r--r--passes/cmds/rename.cc137
-rw-r--r--passes/cmds/setundef.cc24
-rw-r--r--passes/cmds/show.cc1
-rw-r--r--passes/cmds/stat.cc147
-rw-r--r--passes/fsm/fsm_detect.cc1
-rw-r--r--passes/hierarchy/hierarchy.cc23
-rw-r--r--passes/hierarchy/submod.cc1
-rw-r--r--passes/memory/memory_libmap.cc7
-rw-r--r--passes/memory/memory_map.cc225
-rw-r--r--passes/opt/opt_clean.cc2
-rw-r--r--passes/opt/opt_dff.cc22
-rw-r--r--passes/opt/opt_reduce.cc6
-rw-r--r--passes/opt/wreduce.cc8
-rw-r--r--passes/sat/Makefile.inc1
-rw-r--r--passes/sat/async2sync.cc3
-rw-r--r--passes/sat/clk2fflogic.cc5
-rw-r--r--passes/sat/formalff.cc549
-rw-r--r--passes/sat/qbfsat.cc2
-rw-r--r--passes/sat/sim.cc84
-rw-r--r--passes/techmap/abc.cc16
-rw-r--r--passes/techmap/abc9_exe.cc12
-rw-r--r--techlibs/common/simlib.v17
-rw-r--r--techlibs/gatemate/.gitignore4
-rw-r--r--techlibs/gatemate/Makefile.inc16
-rw-r--r--techlibs/gatemate/cells_sim.v44
-rw-r--r--techlibs/gatemate/gatemate_foldinv.cc219
-rw-r--r--techlibs/gatemate/inv_map.v4
-rw-r--r--techlibs/gatemate/make_lut_tree_lib.py323
-rw-r--r--techlibs/gatemate/synth_gatemate.cc32
-rw-r--r--techlibs/gowin/synth_gowin.cc1
-rw-r--r--techlibs/ice40/cells_sim.v48
-rw-r--r--techlibs/nexus/brams_map.v74
-rw-r--r--tests/arch/gatemate/gen_luttrees.py48
-rw-r--r--tests/arch/gatemate/luttrees.v752
-rw-r--r--tests/arch/gatemate/luttrees.ys13
-rw-r--r--tests/arch/ice40/.gitignore1
-rwxr-xr-xtests/gen-tests-makefile.sh2
-rwxr-xr-xtests/tools/autotest.sh16
-rw-r--r--tests/various/aiger_dff.ys7
-rw-r--r--tests/various/rename_scramble_name.ys31
-rw-r--r--tests/various/smtlib2_module-expected.smt28
81 files changed, 4859 insertions, 737 deletions
diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml
index b14ce8633..22cf5e658 100644
--- a/.github/workflows/test-macos.yml
+++ b/.github/workflows/test-macos.yml
@@ -71,57 +71,3 @@ jobs:
shell: bash
run: |
make -j${{ env.procs }} test CXXSTD=${{ matrix.cpp_std }} CC=cc CXX=cc LD=cc
-
-
- test-macos-homebrew:
- runs-on: ${{ matrix.os.id }}
- strategy:
- matrix:
- os:
- - { id: macos-10.15, name: Catalina }
- cpp_std:
- - 'c++17'
- compiler:
- - gcc
- fail-fast: false
- steps:
- - name: Install Dependencies
- run: |
- brew install bison flex gawk libffi pkg-config bash
-
- - name: Runtime environment
- shell: bash
- env:
- WORKSPACE: ${{ github.workspace }}
- run: |
- echo "GITHUB_WORKSPACE=`pwd`" >> $GITHUB_ENV
- echo "$GITHUB_WORKSPACE/.local/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
-
- - name: Setup compiler
- shell: bash
- run: |
- brew install ${{ matrix.compiler }}
- CC=${COMPILER/@/-}
- CXX=${CC/#gcc/g++}
- echo "CC=$CC" >> $GITHUB_ENV
- echo "CXX=$CXX" >> $GITHUB_ENV
- env:
- COMPILER: ${{ matrix.compiler }}
-
- - name: Tool versions
- shell: bash
- run: |
- $CC --version
- $CXX --version
-
- - name: Checkout Yosys
- uses: actions/checkout@v2
-
- - name: Build yosys
- shell: bash
- run: |
- make config-gcc
- make -j${{ env.procs }} CXXSTD=${{ matrix.cpp_std }} CC=$CC CXX=$CC LD=$CC
diff --git a/.gitignore b/.gitignore
index 0460c7c13..49b886e7e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,9 @@ __pycache__
/yosys-smtbmc
/yosys-smtbmc.exe
/yosys-smtbmc-script.py
+/yosys-witness
+/yosys-witness.exe
+/yosys-witness-script.py
/yosys-filterlib
/yosys-filterlib.exe
/kernel/*.pyh
diff --git a/CHANGELOG b/CHANGELOG
index e32d9d053..a1f4624ee 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,8 +2,61 @@
List of major changes and improvements between releases
=======================================================
-Yosys 0.18 .. Yosys 0.18-dev
+Yosys 0.20 .. Yosys 0.20-dev
--------------------------
+ * New commands and options
+ - Added "formalff" pass - transforms FFs for formal verification
+ - Added option "-formal" to "memory_map" pass
+ - Added option "-witness" to "rename" - give public names to all signals
+ present in yosys witness traces
+ - Added option "-hdlname" to "sim" pass - preserves hiearachy when writing
+ simulation output for a flattened design
+
+ * Formal Verification
+ - Added $anyinit cell to directly represent FFs with an unconstrained
+ initialization value. These can be generated by the new formalff pass.
+ - New JSON based yosys witness format for formal verification traces.
+ - yosys-smtbmc: Reading and writing of yosys witness traces.
+ - write_smt2: Emit inline metadata to support yosys witness trace.
+ - yosys-witness is a new tool to inspect and convert yosys witness traces.
+ - write_aiger: Option to write a map file for yosys witness trace
+ conversion.
+ - yosys-witness: Conversion from and to AIGER witness traces.
+
+Yosys 0.19 .. Yosys 0.20
+--------------------------
+ * New commands and options
+ - Added option "-wb" to "read_liberty" pass
+
+ * Various
+ - Added support for $modfloor operator to cxxrtl backend
+ - Support build on OpenBSD
+ - Fixed smt2 backend use of $shift/$shiftx with negative shift amounts,
+ which affects bit/part-select assignments with a dynamic index. Shift
+ operators were not affected.
+
+ * Verific support
+ - Proper import of port ranges into Yosys, may result in reversed
+ bit-order of top-level ports for some synthesis flows.
+
+Yosys 0.18 .. Yosys 0.19
+--------------------------
+ * New commands and options
+ - Added option "-rom-only" to "memory_libmap" pass
+ - Added option "-smtcheck" to "hierarchy" pass
+ - Added option "-keepdc" to "memory_libmap" pass
+ - Added option "-suffix" to "rename" pass
+ - Added "gatemate_foldinv" pass
+
+ * Formal Verification
+ - Added support for $pos cell in btor backend
+ - Added the "smtlib2_module" and "smtlib2_comb_expr" attributes
+
+ * GateMate support
+ - Added LUT tree mapping
+
+ * Verific support
+ - Added option "-pp" to "verific -import"
Yosys 0.17 .. Yosys 0.18
--------------------------
diff --git a/CODEOWNERS b/CODEOWNERS
index 11a8cc026..a33a9a68c 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -16,7 +16,7 @@ backends/cxxrtl/ @whitequark
passes/cmds/bugpoint.cc @whitequark
passes/techmap/flowmap.cc @whitequark
passes/opt/opt_lut.cc @whitequark
-passes/techmap/abc9*.cc @eddiehung
+passes/techmap/abc9*.cc @eddiehung @Ravenslofty
backends/aiger/xaiger.cc @eddiehung
@@ -30,7 +30,7 @@ backends/aiger/xaiger.cc @eddiehung
frontends/verilog/ @zachjs
frontends/ast/ @zachjs
-techlibs/intel_alm/ @ZirconiumX
+techlibs/intel_alm/ @Ravenslofty
techlibs/gowin/ @pepijndevos
techlibs/gatemate/ @pu-cc
diff --git a/Makefile b/Makefile
index f85ea0b53..d4573cd47 100644
--- a/Makefile
+++ b/Makefile
@@ -126,10 +126,12 @@ endif
else
LDFLAGS += -rdynamic
+ifneq ($(OS), OpenBSD)
LDLIBS += -lrt
endif
+endif
-YOSYS_VER := 0.18+10
+YOSYS_VER := 0.20+45
# Note: We arrange for .gitcommit to contain the (short) commit hash in
# tarballs generated with git-archive(1) using .gitattributes. The git repo
@@ -145,7 +147,7 @@ endif
OBJS = kernel/version_$(GIT_REV).o
bumpversion:
- sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 19ce3b4.. | wc -l`/;" Makefile
+ sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 4fcb95e.. | wc -l`/;" Makefile
# set 'ABCREV = default' to use abc/ as it is
#
@@ -153,10 +155,10 @@ bumpversion:
# is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC..
-ABCREV = 09a7e6d
+ABCREV = 20f970f
ABCPULL = 1
ABCURL ?= https://github.com/YosysHQ/abc
-ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 VERBOSE=$(Q)
+ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
# set ABCEXTERNAL = <abc-command> to use an external ABC instance
# Note: The in-tree ABC (yosys-abc) will not be installed when ABCEXTERNAL is set.
@@ -197,11 +199,16 @@ endif
endif
+ABC_ARCHFLAGS = ""
+ifeq ($(OS), OpenBSD)
+ABC_ARCHFLAGS += "-DABC_NO_RLIMIT"
+endif
+
ifeq ($(CONFIG),clang)
CXX = clang
LD = clang++
CXXFLAGS += -std=$(CXXSTD) -Os
-ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -Wno-c++11-narrowing $(ABC_ARCHFLAGS)"
ifneq ($(SANITIZER),)
$(info [Clang Sanitizer] $(SANITIZER))
@@ -224,7 +231,7 @@ else ifeq ($(CONFIG),gcc)
CXX = gcc
LD = gcc
CXXFLAGS += -std=$(CXXSTD) -Os
-ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
else ifeq ($(CONFIG),gcc-static)
LD = $(CXX)
@@ -260,7 +267,7 @@ else ifeq ($(CONFIG),emcc)
CXX = emcc
LD = emcc
CXXFLAGS := -std=$(CXXSTD) $(filter-out -fPIC -ggdb,$(CXXFLAGS))
-ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8"
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8 -Wno-c++11-narrowing"
EMCC_CXXFLAGS := -Os -Wno-warn-absolute-paths
EMCC_LDFLAGS := --memory-init-file 0 --embed-file share
EMCC_LDFLAGS += -s NO_EXIT_RUNTIME=1
@@ -314,7 +321,7 @@ CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) -Os $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LDFLAGS))
LDLIBS := $(filter-out -lrt,$(LDLIBS))
ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)"
-ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING"
+ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -DABC_NO_RLIMIT -Wno-c++11-narrowing"
ABCMKARGS += OPTFLAGS="-Os"
EXE = .wasm
@@ -395,7 +402,7 @@ endif # ENABLE_PYOSYS
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
-ifeq ($(OS), FreeBSD)
+ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD))
CXXFLAGS += -I/usr/local/include
endif
LDLIBS += -lreadline
@@ -430,7 +437,7 @@ endif
ifeq ($(ENABLE_PLUGINS),1)
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS
LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi)
-ifneq ($(OS), FreeBSD)
+ifneq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD))
LDLIBS += -ldl
endif
endif
@@ -447,10 +454,13 @@ endif
ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
-ifeq ($(OS), FreeBSD)
+ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD))
+# BSDs usually use tcl8.6, but the lib is named "libtcl86"
TCL_INCLUDE ?= /usr/local/include/$(TCL_VERSION)
+TCL_LIBS ?= -l$(subst .,,$(TCL_VERSION))
else
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
+TCL_LIBS ?= -l$(TCL_VERSION)
endif
ifeq ($(CONFIG),mxe)
@@ -458,12 +468,7 @@ CXXFLAGS += -DYOSYS_ENABLE_TCL
LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv
else
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
-ifeq ($(OS), FreeBSD)
-# FreeBSD uses tcl8.6, but lib is named "libtcl86"
-LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION) | tr -d '.')
-else
-LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION))
-endif
+LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo $(TCL_LIBS))
endif
endif
@@ -772,11 +777,16 @@ ifneq ($(ABCREV),default)
$(Q) if test -d abc/.hg; then \
echo 'REEBE: NOP qverpgbel vf n ut jbexvat pbcl! Erzbir nop/ naq er-eha "znxr".' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi
- $(Q) if test -d abc && ! git -C abc diff-index --quiet HEAD; then \
+ $(Q) if test -d abc && test -d abc/.git && ! git -C abc diff-index --quiet HEAD; then \
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi
+ $(Q) if test -d abc && ! test -d abc/.git && ! test "`cat abc/.gitcommit | cut -c1-7`" == "$(ABCREV)"; then \
+ echo 'REEBE: Qbjaybnqrq NOP irefvbaf qbrf abg zngpu! Qbjaybnq sebz:' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; echo $(ABCURL)/archive/$(ABCREV).tar.gz; false; \
+ fi
# set a variable so the test fails if git fails to run - when comparing outputs directly, empty string would match empty string
- $(Q) if ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \
+ $(Q) if test -d abc && ! test -d abc/.git && test "`cat abc/.gitcommit | cut -c1-7`" == "$(ABCREV)"; then \
+ echo "Compiling local copy of ABC"; \
+ elif ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
echo "Pulling ABC from $(ABCURL):"; set -x; \
test -d abc || git clone $(ABCURL) abc; \
diff --git a/README.md b/README.md
index 0232a5ed0..f916b38ad 100644
--- a/README.md
+++ b/README.md
@@ -505,6 +505,18 @@ Verilog Attributes and non-standard features
module. Modules with such cells will be reprocessed during the ``hierarchy``
pass once the referenced module definition(s) become available.
+- The ``smtlib2_module`` attribute can be set on a blackbox module to specify a
+ formal model directly using SMT-LIB 2. For such a module, the
+ ``smtlib2_comb_expr`` attribute can be used on output ports to define their
+ value using an SMT-LIB 2 expression. For example:
+
+ (* blackbox *)
+ (* smtlib2_module *)
+ module submod(a, b);
+ input [7:0] a;
+ (* smtlib2_comb_expr = "(bvnot a)" *)
+ output [7:0] b;
+ endmodule
Non-standard or SystemVerilog features for formal verification
==============================================================
diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc
index 547d131ee..513f9d95a 100644
--- a/backends/aiger/aiger.cc
+++ b/backends/aiger/aiger.cc
@@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "libs/json11/json11.hpp"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -61,6 +62,8 @@ struct AigerWriter
dict<SigBit, int> init_inputs;
int initstate_ff = 0;
+ dict<SigBit, int> ywmap_clocks;
+
int mkgate(int a0, int a1)
{
aig_m++, aig_a++;
@@ -159,6 +162,17 @@ struct AigerWriter
output_bits.insert(wirebit);
}
}
+
+ if (wire->width == 1) {
+ auto gclk_attr = wire->attributes.find(ID::replaced_by_gclk);
+ if (gclk_attr != wire->attributes.end()) {
+ SigBit bit = sigmap(wire);
+ if (gclk_attr->second == State::S1)
+ ywmap_clocks[bit] |= 1;
+ else if (gclk_attr->second == State::S0)
+ ywmap_clocks[bit] |= 2;
+ }
+ }
}
for (auto bit : input_bits)
@@ -186,6 +200,22 @@ struct AigerWriter
unused_bits.erase(D);
undriven_bits.erase(Q);
ff_map[Q] = D;
+
+ if (cell->type != ID($_FF_)) {
+ auto sig_clk = sigmap(cell->getPort(ID::C).as_bit());
+ ywmap_clocks[sig_clk] |= cell->type == ID($_DFF_N_) ? 2 : 1;
+ }
+ continue;
+ }
+
+ if (cell->type == ID($anyinit))
+ {
+ auto sig_d = sigmap(cell->getPort(ID::D));
+ auto sig_q = sigmap(cell->getPort(ID::Q));
+ for (int i = 0; i < sig_d.size(); i++) {
+ undriven_bits.erase(sig_q[i]);
+ ff_map[sig_q[i]] = sig_d[i];
+ }
continue;
}
@@ -678,6 +708,137 @@ struct AigerWriter
for (auto &it : wire_lines)
f << it.second;
}
+
+ template<class T> static std::vector<std::string> witness_path(T *obj) {
+ std::vector<std::string> path;
+ if (obj->name.isPublic()) {
+ auto hdlname = obj->get_string_attribute(ID::hdlname);
+ for (auto token : split_tokens(hdlname))
+ path.push_back("\\" + token);
+ }
+ if (path.empty())
+ path.push_back(obj->name.str());
+ return path;
+ }
+
+ void write_ywmap(std::ostream &f)
+ {
+ f << "{\n";
+ f << " \"version\": \"Yosys Witness Aiger Map\",\n";
+ f << stringf(" \"generator\": %s,\n", json11::Json(yosys_version_str).dump().c_str());
+ f << stringf(" \"latch_count\": %d,\n", aig_l);
+ f << stringf(" \"input_count\": %d,\n", aig_i);
+
+ dict<int, string> clock_lines;
+ dict<int, string> input_lines;
+ dict<int, string> init_lines;
+ dict<int, string> seq_lines;
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type.in(ID($_FF_), ID($_DFF_N_), ID($_DFF_P_), ID($anyinit), ID($anyconst), ID($anyseq)))
+ {
+ // Use sig_q to get the FF output name, but sig to lookup aiger bits
+ auto sig_qy = cell->getPort(cell->type.in(ID($anyconst), ID($anyseq)) ? ID::Y : ID::Q);
+ SigSpec sig = sigmap(sig_qy);
+
+ for (int i = 0; i < GetSize(sig_qy); i++) {
+ if (sig_qy[i].wire == nullptr || sig[i].wire == nullptr)
+ continue;
+
+ auto wire = sig_qy[i].wire;
+
+ if (init_inputs.count(sig[i])) {
+ int a = init_inputs.at(sig[i]);
+ log_assert((a & 1) == 0);
+ init_lines[a] += json11::Json(json11::Json::object {
+ { "path", witness_path(wire) },
+ { "input", (a >> 1) - 1 },
+ { "offset", sig_qy[i].offset },
+ }).dump();
+ }
+
+ if (input_bits.count(sig[i])) {
+ int a = aig_map.at(sig[i]);
+ log_assert((a & 1) == 0);
+ seq_lines[a] += json11::Json(json11::Json::object {
+ { "path", witness_path(wire) },
+ { "input", (a >> 1) - 1 },
+ { "offset", sig_qy[i].offset },
+ }).dump();
+ }
+ }
+ }
+ }
+
+ for (auto wire : module->wires())
+ {
+ SigSpec sig = sigmap(wire);
+ if (wire->port_input)
+ {
+ auto path = witness_path(wire);
+ for (int i = 0; i < GetSize(wire); i++) {
+ if (aig_map.count(sig[i]) == 0 || sig[i].wire == nullptr)
+ continue;
+
+ int a = aig_map.at(sig[i]);
+ log_assert((a & 1) == 0);
+ input_lines[a] += json11::Json(json11::Json::object {
+ { "path", path },
+ { "input", (a >> 1) - 1 },
+ { "offset", i },
+ }).dump();
+
+ if (ywmap_clocks.count(sig[i])) {
+ int clock_mode = ywmap_clocks[sig[i]];
+ if (clock_mode != 3) {
+ clock_lines[a] += json11::Json(json11::Json::object {
+ { "path", path },
+ { "input", (a >> 1) - 1 },
+ { "offset", i },
+ { "edge", clock_mode == 1 ? "posedge" : "negedge" },
+ }).dump();
+ }
+ }
+ }
+ }
+ }
+
+ f << " \"clocks\": [";
+ clock_lines.sort();
+ const char *sep = "\n ";
+ for (auto &it : clock_lines) {
+ f << sep << it.second;
+ sep = ",\n ";
+ }
+ f << "\n ],\n";
+
+ f << " \"inputs\": [";
+ input_lines.sort();
+ sep = "\n ";
+ for (auto &it : input_lines) {
+ f << sep << it.second;
+ sep = ",\n ";
+ }
+ f << "\n ],\n";
+
+ f << " \"seqs\": [";
+ sep = "\n ";
+ for (auto &it : seq_lines) {
+ f << sep << it.second;
+ sep = ",\n ";
+ }
+ f << "\n ],\n";
+
+ f << " \"inits\": [";
+ sep = "\n ";
+ for (auto &it : init_lines) {
+ f << sep << it.second;
+ sep = ",\n ";
+ }
+ f << "\n ]\n}\n";
+ }
+
};
struct AigerBackend : public Backend {
@@ -717,6 +878,9 @@ struct AigerBackend : public Backend {
log(" -no-startoffset\n");
log(" make indexes zero based, enable using map files with smt solvers.\n");
log("\n");
+ log(" -ywmap <filename>\n");
+ log(" write a map file for conversion to and from yosys witness traces.\n");
+ log("\n");
log(" -I, -O, -B, -L\n");
log(" If the design contains no input/output/assert/flip-flop then create one\n");
log(" dummy input/output/bad_state-pin or latch to make the tools reading the\n");
@@ -736,6 +900,7 @@ struct AigerBackend : public Backend {
bool lmode = false;
bool no_startoffset = false;
std::string map_filename;
+ std::string yw_map_filename;
log_header(design, "Executing AIGER backend.\n");
@@ -767,6 +932,10 @@ struct AigerBackend : public Backend {
verbose_map = true;
continue;
}
+ if (yw_map_filename.empty() && args[argidx] == "-ywmap" && argidx+1 < args.size()) {
+ yw_map_filename = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-no-startoffset") {
no_startoffset = true;
continue;
@@ -791,6 +960,9 @@ struct AigerBackend : public Backend {
}
extra_args(f, filename, args, argidx, !ascii_mode);
+ if (!yw_map_filename.empty() && !zinit_mode)
+ log_error("Currently -ywmap requires -zinit.\n");
+
Module *top_module = design->top_module();
if (top_module == nullptr)
@@ -815,6 +987,14 @@ struct AigerBackend : public Backend {
log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno));
writer.write_map(mapf, verbose_map, no_startoffset);
}
+
+ if (!yw_map_filename.empty()) {
+ std::ofstream mapf;
+ mapf.open(yw_map_filename.c_str(), std::ofstream::trunc);
+ if (mapf.fail())
+ log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno));
+ writer.write_ywmap(mapf);
+ }
}
} AigerBackend;
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 7de5deadd..06de71018 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -446,25 +446,28 @@ struct BtorWorker
goto okay;
}
- if (cell->type.in(ID($not), ID($neg), ID($_NOT_)))
+ if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos)))
{
string btor_op;
if (cell->type.in(ID($not), ID($_NOT_))) btor_op = "not";
if (cell->type == ID($neg)) btor_op = "neg";
- log_assert(!btor_op.empty());
int width = std::max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::Y)));
bool a_signed = cell->hasParam(ID::A_SIGNED) ? cell->getParam(ID::A_SIGNED).as_bool() : false;
-
- int sid = get_bv_sid(width);
int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
-
- int nid = next_nid++;
- btorf("%d %s %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, getinfo(cell).c_str());
-
SigSpec sig = sigmap(cell->getPort(ID::Y));
+ // the $pos cell just passes through, all other cells need an actual operation applied
+ int nid = nid_a;
+ if (cell->type != ID($pos))
+ {
+ log_assert(!btor_op.empty());
+ int sid = get_bv_sid(width);
+ nid = next_nid++;
+ btorf("%d %s %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, getinfo(cell).c_str());
+ }
+
if (GetSize(sig) < width) {
int sid = get_bv_sid(GetSize(sig));
int nid2 = next_nid++;
@@ -609,7 +612,7 @@ struct BtorWorker
goto okay;
}
- if (cell->type.in(ID($dff), ID($ff), ID($_DFF_P_), ID($_DFF_N), ID($_FF_)))
+ if (cell->type.in(ID($dff), ID($ff), ID($anyinit), ID($_DFF_P_), ID($_DFF_N), ID($_FF_)))
{
SigSpec sig_d = sigmap(cell->getPort(ID::D));
SigSpec sig_q = sigmap(cell->getPort(ID::Q));
@@ -1109,6 +1112,16 @@ struct BtorWorker
btorf("%d input %d%s\n", nid, sid, getinfo(wire).c_str());
add_nid_sig(nid, sig);
+
+ if (!info_filename.empty()) {
+ auto gclk_attr = wire->attributes.find(ID::replaced_by_gclk);
+ if (gclk_attr != wire->attributes.end()) {
+ if (gclk_attr->second == State::S1)
+ info_clocks[nid] |= 1;
+ else if (gclk_attr->second == State::S0)
+ info_clocks[nid] |= 2;
+ }
+ }
}
btorf_pop("inputs");
diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h
index b4ffa87cd..073921cc4 100644
--- a/backends/cxxrtl/cxxrtl.h
+++ b/backends/cxxrtl/cxxrtl.h
@@ -1575,6 +1575,27 @@ value<BitsY> mod_ss(const value<BitsA> &a, const value<BitsB> &b) {
return divmod_ss<BitsY>(a, b).second;
}
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+CXXRTL_ALWAYS_INLINE
+value<BitsY> modfloor_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return divmod_uu<BitsY>(a, b).second;
+}
+
+// GHDL Modfloor operator. Returns r=a mod b, such that r has the same sign as b and
+// a=b*N+r where N is some integer
+// In practical terms, when a and b have different signs and the remainder returned by divmod_ss is not 0
+// then return the remainder + b
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+CXXRTL_ALWAYS_INLINE
+value<BitsY> modfloor_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ value<BitsY> r;
+ r = divmod_ss<BitsY>(a, b).second;
+ if((b.is_neg() != a.is_neg()) && !r.is_zero())
+ return add_ss<BitsY>(b, r);
+ return r;
+}
+
+
// Memory helper
struct memory_index {
bool valid;
diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc
index 404755b1e..62768bd33 100644
--- a/backends/cxxrtl/cxxrtl_backend.cc
+++ b/backends/cxxrtl/cxxrtl_backend.cc
@@ -185,7 +185,7 @@ bool is_binary_cell(RTLIL::IdString type)
ID($and), ID($or), ID($xor), ID($xnor), ID($logic_and), ID($logic_or),
ID($shl), ID($sshl), ID($shr), ID($sshr), ID($shift), ID($shiftx),
ID($eq), ID($ne), ID($eqx), ID($nex), ID($gt), ID($ge), ID($lt), ID($le),
- ID($add), ID($sub), ID($mul), ID($div), ID($mod));
+ ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor));
}
bool is_extending_cell(RTLIL::IdString type)
diff --git a/backends/jny/jny.cc b/backends/jny/jny.cc
index d801b144c..2b8d51b76 100644
--- a/backends/jny/jny.cc
+++ b/backends/jny/jny.cc
@@ -27,6 +27,8 @@
#include <algorithm>
#include <unordered_map>
#include <vector>
+#include <sstream>
+#include <iterator>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -116,17 +118,17 @@ struct JnyWriter
_include_connections(connections), _include_attributes(attributes), _include_properties(properties)
{ }
- void write_metadata(Design *design, uint16_t indent_level = 0)
+ void write_metadata(Design *design, uint16_t indent_level = 0, std::string invk = "")
{
log_assert(design != nullptr);
design->sort();
f << "{\n";
+ f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json\",\n";
f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_version_str).c_str());
- // XXX(aki): Replace this with a proper version info eventually:tm:
- f << " \"version\": \"0.0.0\",\n";
-
+ f << " \"version\": \"0.0.1\",\n";
+ f << " \"invocation\": \"" << escape_string(invk) << "\",\n";
f << " \"features\": [";
size_t fnum{0};
@@ -409,11 +411,12 @@ struct JnyWriter
struct JnyBackend : public Backend {
JnyBackend() : Backend("jny", "generate design metadata") { }
void help() override {
- // XXX(aki): TODO: explicitly document the JSON schema
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" jny [options] [selection]\n");
log("\n");
+ log("Write JSON netlist metadata for the current design\n");
+ log("\n");
log(" -no-connections\n");
log(" Don't include connection information in the netlist output.\n");
log("\n");
@@ -423,8 +426,8 @@ struct JnyBackend : public Backend {
log(" -no-properties\n");
log(" Don't include property information in the netlist output.\n");
log("\n");
- log("Write a JSON metadata for the current design\n");
- log("\n");
+ log("The JSON schema for JNY output files is located in the \"jny.schema.json\" file\n");
+ log("which is located at \"https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json\"\n");
log("\n");
}
@@ -453,12 +456,22 @@ struct JnyBackend : public Backend {
break;
}
+
+ // Compose invocation line
+ std::ostringstream invk;
+ if (!args.empty()) {
+ std::copy(args.begin(), args.end(),
+ std::ostream_iterator<std::string>(invk, " ")
+ );
+ }
+ invk << filename;
+
extra_args(f, filename, args, argidx);
log_header(design, "Executing jny backend.\n");
JnyWriter jny_writer(*f, false, connections, attributes, properties);
- jny_writer.write_metadata(design);
+ jny_writer.write_metadata(design, 0, invk.str());
}
} JnyBackend;
@@ -472,7 +485,7 @@ struct JnyPass : public Pass {
log("\n");
log(" jny [options] [selection]\n");
log("\n");
- log("Write a JSON netlist metadata for the current design\n");
+ log("Write JSON netlist metadata for the current design\n");
log("\n");
log(" -o <filename>\n");
log(" write to the specified file.\n");
@@ -520,6 +533,15 @@ struct JnyPass : public Pass {
break;
}
+
+ // Compose invocation line
+ std::ostringstream invk;
+ if (!args.empty()) {
+ std::copy(args.begin(), args.end(),
+ std::ostream_iterator<std::string>(invk, " ")
+ );
+ }
+
extra_args(args, argidx, design);
std::ostream *f;
@@ -534,13 +556,14 @@ struct JnyPass : public Pass {
log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
}
f = ff;
+ invk << filename;
} else {
f = &buf;
}
JnyWriter jny_writer(*f, false, connections, attributes, properties);
- jny_writer.write_metadata(design);
+ jny_writer.write_metadata(design, 0, invk.str());
if (!filename.empty()) {
delete f;
diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc
index 1b11de5ec..b5163aefe 100644
--- a/backends/rtlil/rtlil_backend.cc
+++ b/backends/rtlil/rtlil_backend.cc
@@ -75,7 +75,7 @@ void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi
else if (str[i] == '\t')
f << stringf("\\t");
else if (str[i] < 32)
- f << stringf("\\%03o", str[i]);
+ f << stringf("\\%03o", (unsigned char)str[i]);
else if (str[i] == '"')
f << stringf("\\\"");
else if (str[i] == '\\')
diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc
index fb01308bd..3afe990e7 100644
--- a/backends/smt2/Makefile.inc
+++ b/backends/smt2/Makefile.inc
@@ -7,6 +7,7 @@ ifneq ($(CONFIG),emcc)
# MSYS targets support yosys-smtbmc, but require a launcher script
ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc.exe $(PROGRAM_PREFIX)yosys-smtbmc-script.py
+TARGETS += $(PROGRAM_PREFIX)yosys-witness.exe $(PROGRAM_PREFIX)yosys-witness-script.py
# Needed to find the Python interpreter for yosys-smtbmc scripts.
# Override if necessary, it is only used for msys2 targets.
PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
@@ -15,18 +16,31 @@ $(PROGRAM_PREFIX)yosys-smtbmc-script.py: backends/smt2/smtbmc.py
$(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' \
-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
+$(PROGRAM_PREFIX)yosys-witness-script.py: backends/smt2/witness.py
+ $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' \
+ -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
+
$(PROGRAM_PREFIX)yosys-smtbmc.exe: misc/launcher.c $(PROGRAM_PREFIX)yosys-smtbmc-script.py
$(P) $(CXX) -DGUI=0 -O -s -o $@ $<
+
+$(PROGRAM_PREFIX)yosys-witness.exe: misc/launcher.c $(PROGRAM_PREFIX)yosys-witness-script.py
+ $(P) $(CXX) -DGUI=0 -O -s -o $@ $<
# Other targets
else
-TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc
+TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc $(PROGRAM_PREFIX)yosys-witness
$(PROGRAM_PREFIX)yosys-smtbmc: backends/smt2/smtbmc.py
$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' < $< > $@.new
$(Q) chmod +x $@.new
$(Q) mv $@.new $@
+
+$(PROGRAM_PREFIX)yosys-witness: backends/smt2/witness.py
+ $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' < $< > $@.new
+ $(Q) chmod +x $@.new
+ $(Q) mv $@.new $@
endif
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
+$(eval $(call add_share_file,share/python3,backends/smt2/ywio.py))
endif
endif
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index 7481e0510..54783cf1b 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -23,6 +23,7 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include "kernel/mem.h"
+#include "libs/json11/json11.hpp"
#include <string>
USING_YOSYS_NAMESPACE
@@ -241,6 +242,17 @@ struct Smt2Worker
for (auto wire : module->wires())
{
+ auto gclk_attr = wire->attributes.find(ID::replaced_by_gclk);
+ if (gclk_attr != wire->attributes.end()) {
+ if (gclk_attr->second == State::S1)
+ clock_posedge.insert(sigmap(wire));
+ else if (gclk_attr->second == State::S0)
+ clock_negedge.insert(sigmap(wire));
+ }
+ }
+
+ for (auto wire : module->wires())
+ {
if (!wire->port_input || GetSize(wire) != 1)
continue;
SigBit bit = sigmap(wire);
@@ -449,7 +461,7 @@ struct Smt2Worker
bool is_signed = cell->getParam(ID::A_SIGNED).as_bool();
int width = GetSize(sig_y);
- if (type == 's' || type == 'd' || type == 'b') {
+ if (type == 's' || type == 'S' || type == 'd' || type == 'b') {
width = max(width, GetSize(cell->getPort(ID::A)));
if (cell->hasPort(ID::B))
width = max(width, GetSize(cell->getPort(ID::B)));
@@ -462,7 +474,7 @@ struct Smt2Worker
if (cell->hasPort(ID::B)) {
sig_b = cell->getPort(ID::B);
- sig_b.extend_u0(width, is_signed && !(type == 's'));
+ sig_b.extend_u0(width, (type == 'S') || (is_signed && !(type == 's')));
}
std::string processed_expr;
@@ -577,31 +589,41 @@ struct Smt2Worker
if (cell->type.in(ID($ff), ID($dff)))
{
registers.insert(cell);
+ for (auto chunk : cell->getPort(ID::Q).chunks())
+ if (chunk.is_wire())
+ decls.push_back(witness_signal("reg", chunk.width, chunk.offset, "", idcounter, chunk.wire));
makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(ID::Q)), log_signal(cell->getPort(ID::Q)));
register_bv(cell->getPort(ID::Q), idcounter++);
recursive_cells.erase(cell);
return;
}
- if (cell->type.in(ID($anyconst), ID($anyseq), ID($allconst), ID($allseq)))
+ if (cell->type.in(ID($anyconst), ID($anyseq), ID($anyinit), ID($allconst), ID($allseq)))
{
+ auto QY = cell->type == ID($anyinit) ? ID::Q : ID::Y;
registers.insert(cell);
string infostr = cell->attributes.count(ID::src) ? cell->attributes.at(ID::src).decode_string().c_str() : get_id(cell);
if (cell->attributes.count(ID::reg))
infostr += " " + cell->attributes.at(ID::reg).decode_string();
- decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort(ID::Y)), infostr.c_str()));
- if (cell->getPort(ID::Y).is_wire() && cell->getPort(ID::Y).as_wire()->get_bool_attribute(ID::maximize)){
+ decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort(QY)), infostr.c_str()));
+ if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::maximize)){
decls.push_back(stringf("; yosys-smt2-maximize %s#%d\n", get_id(module), idcounter));
- log("Wire %s is maximized\n", cell->getPort(ID::Y).as_wire()->name.str().c_str());
+ log("Wire %s is maximized\n", cell->getPort(QY).as_wire()->name.str().c_str());
}
- else if (cell->getPort(ID::Y).is_wire() && cell->getPort(ID::Y).as_wire()->get_bool_attribute(ID::minimize)){
+ else if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::minimize)){
decls.push_back(stringf("; yosys-smt2-minimize %s#%d\n", get_id(module), idcounter));
- log("Wire %s is minimized\n", cell->getPort(ID::Y).as_wire()->name.str().c_str());
+ log("Wire %s is minimized\n", cell->getPort(QY).as_wire()->name.str().c_str());
}
- makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(ID::Y)), log_signal(cell->getPort(ID::Y)));
+
+ bool init_only = cell->type.in(ID($anyconst), ID($anyinit), ID($allconst));
+ for (auto chunk : cell->getPort(QY).chunks())
+ if (chunk.is_wire())
+ decls.push_back(witness_signal(init_only ? "init" : "seq", chunk.width, chunk.offset, "", idcounter, chunk.wire));
+
+ makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(QY)), log_signal(cell->getPort(QY)));
if (cell->type == ID($anyseq))
ex_input_eq.push_back(stringf(" (= (|%s#%d| state) (|%s#%d| other_state))", get_id(module), idcounter, get_id(module), idcounter));
- register_bv(cell->getPort(ID::Y), idcounter++);
+ register_bv(cell->getPort(QY), idcounter++);
recursive_cells.erase(cell);
return;
}
@@ -619,8 +641,8 @@ struct Smt2Worker
if (cell->type.in(ID($shift), ID($shiftx))) {
if (cell->getParam(ID::B_SIGNED).as_bool()) {
return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) "
- "(bvlshr A B) (bvlshr A (bvneg B)))",
- GetSize(cell->getPort(ID::B)), 0), 's');
+ "(bvlshr A B) (bvshl A (bvneg B)))",
+ GetSize(cell->getPort(ID::B)), 0), 'S'); // type 'S' sign extends B
} else {
return export_bvop(cell, "(bvlshr A B)", 's');
}
@@ -748,6 +770,7 @@ struct Smt2Worker
log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", log_id(cell), log_id(module));
decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", get_id(mem->memid), abits, mem->width, GetSize(mem->rd_ports), GetSize(mem->wr_ports), has_async_wr ? "async" : "sync"));
+ decls.push_back(witness_memory(get_id(mem->memid), cell, mem));
string memstate;
if (has_async_wr) {
@@ -840,6 +863,7 @@ struct Smt2Worker
if (m != nullptr)
{
decls.push_back(stringf("; yosys-smt2-cell %s %s\n", get_id(cell->type), get_id(cell->name)));
+ decls.push_back(witness_cell(get_id(cell->name), cell));
string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name));
for (auto &conn : cell->connections())
@@ -920,7 +944,7 @@ struct Smt2Worker
pool<SigBit> reg_bits;
for (auto cell : module->cells())
- if (cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_P_), ID($_DFF_N_))) {
+ if (cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_P_), ID($_DFF_N_), ID($anyinit))) {
// not using sigmap -- we want the net directly at the dff output
for (auto bit : cell->getPort(ID::Q))
reg_bits.insert(bit);
@@ -938,14 +962,19 @@ struct Smt2Worker
for (auto wire : module->wires()) {
bool is_register = false;
- for (auto bit : SigSpec(wire))
+ bool contains_clock = false;
+ for (auto bit : SigSpec(wire)) {
if (reg_bits.count(bit))
is_register = true;
+ auto sig_bit = sigmap(bit);
+ if (clock_posedge.count(sig_bit) || clock_negedge.count(sig_bit))
+ contains_clock = true;
+ }
bool is_smtlib2_comb_expr = wire->has_attribute(ID::smtlib2_comb_expr);
if (is_smtlib2_comb_expr && !is_smtlib2_module)
log_error("smtlib2_comb_expr is only valid in a module with the smtlib2_module attribute: wire %s.%s", log_id(module),
log_id(wire));
- if (wire->port_id || is_register || wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic())) {
+ if (wire->port_id || is_register || contains_clock || wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic())) {
RTLIL::SigSpec sig = sigmap(wire);
std::vector<std::string> comments;
if (wire->port_input)
@@ -956,9 +985,20 @@ struct Smt2Worker
comments.push_back(stringf("; yosys-smt2-register %s %d\n", get_id(wire), wire->width));
if (wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic()))
comments.push_back(stringf("; yosys-smt2-wire %s %d\n", get_id(wire), wire->width));
- if (GetSize(wire) == 1 && (clock_posedge.count(sig) || clock_negedge.count(sig)))
+ if (contains_clock && GetSize(wire) == 1 && (clock_posedge.count(sig) || clock_negedge.count(sig)))
comments.push_back(stringf("; yosys-smt2-clock %s%s%s\n", get_id(wire),
clock_posedge.count(sig) ? " posedge" : "", clock_negedge.count(sig) ? " negedge" : ""));
+ if (contains_clock) {
+ for (int i = 0; i < GetSize(sig); i++) {
+ bool is_posedge = clock_posedge.count(sig[i]);
+ bool is_negedge = clock_negedge.count(sig[i]);
+ if (is_posedge != is_negedge)
+ comments.push_back(witness_signal(
+ is_posedge ? "posedge" : "negedge", 1, i, get_id(wire), -1, wire));
+ }
+ }
+ if (wire->port_input)
+ comments.push_back(witness_signal("input", wire->width, 0, get_id(wire), -1, wire));
std::string smtlib2_comb_expr;
if (is_smtlib2_comb_expr) {
smtlib2_comb_expr =
@@ -968,6 +1008,8 @@ struct Smt2Worker
if (!bvmode && GetSize(sig) > 1)
log_error("smtlib2_comb_expr is unsupported on multi-bit wires when -nobv is specified: wire %s.%s",
log_id(module), log_id(wire));
+
+ comments.push_back(witness_signal("blackbox", wire->width, 0, get_id(wire), -1, wire));
}
auto &out_decls = is_smtlib2_comb_expr ? smtlib2_decls : decls;
if (bvmode && GetSize(sig) > 1) {
@@ -1136,7 +1178,7 @@ struct Smt2Worker
ex_state_eq.push_back(stringf("(= %s %s)", get_bool(cell->getPort(ID::Q)).c_str(), get_bool(cell->getPort(ID::Q), "other_state").c_str()));
}
- if (cell->type.in(ID($ff), ID($dff)))
+ if (cell->type.in(ID($ff), ID($dff), ID($anyinit)))
{
std::string expr_d = get_bv(cell->getPort(ID::D));
std::string expr_q = get_bv(cell->getPort(ID::Q), "next_state");
@@ -1435,6 +1477,90 @@ struct Smt2Worker
f << "true)";
f << stringf(" ; end of module %s\n", get_id(module));
}
+
+ template<class T> static std::vector<std::string> witness_path(T *obj) {
+ std::vector<std::string> path;
+ if (obj->name.isPublic()) {
+ auto hdlname = obj->get_string_attribute(ID::hdlname);
+ for (auto token : split_tokens(hdlname))
+ path.push_back("\\" + token);
+ }
+ if (path.empty())
+ path.push_back(obj->name.str());
+ return path;
+ }
+
+ std::string witness_signal(const char *type, int width, int offset, const std::string &smtname, int smtid, RTLIL::Wire *wire)
+ {
+ std::vector<std::string> hiername;
+ const char *wire_name = wire->name.c_str();
+ if (wire_name[0] == '\\') {
+ auto hdlname = wire->get_string_attribute(ID::hdlname);
+ for (auto token : split_tokens(hdlname))
+ hiername.push_back("\\" + token);
+ }
+ if (hiername.empty())
+ hiername.push_back(wire->name.str());
+
+ std::string line = "; yosys-smt2-witness ";
+ (json11::Json { json11::Json::object {
+ { "type", type },
+ { "offset", offset },
+ { "width", width },
+ { "smtname", smtname.empty() ? json11::Json(smtid) : json11::Json(smtname) },
+ { "path", witness_path(wire) },
+ }}).dump(line);
+ line += "\n";
+ return line;
+ }
+
+ std::string witness_cell(const char *smtname, RTLIL::Cell *cell)
+ {
+ std::string line = "; yosys-smt2-witness ";
+ (json11::Json {json11::Json::object {
+ { "type", "cell" },
+ { "smtname", smtname },
+ { "path", witness_path(cell) },
+ }}).dump(line);
+ line += "\n";
+ return line;
+ }
+
+ std::string witness_memory(const char *smtname, RTLIL::Cell *cell, Mem *mem)
+ {
+ json11::Json::array uninitialized;
+ auto init_data = mem->get_init_data();
+
+ int cursor = 0;
+
+ while (cursor < init_data.size()) {
+ while (cursor < init_data.size() && init_data[cursor] != State::Sx)
+ cursor++;
+ int offset = cursor;
+ while (cursor < init_data.size() && init_data[cursor] == State::Sx)
+ cursor++;
+ int width = cursor - offset;
+ if (width)
+ uninitialized.push_back(json11::Json::object {
+ {"width", width},
+ {"offset", offset},
+ });
+ }
+
+ std::string line = "; yosys-smt2-witness ";
+ (json11::Json { json11::Json::object {
+ { "type", "mem" },
+ { "width", mem->width },
+ { "size", mem->size },
+ { "rom", mem->wr_ports.empty() },
+ { "statebv", statebv },
+ { "smtname", smtname },
+ { "uninitialized", uninitialized },
+ { "path", witness_path(cell) },
+ }}).dump(line);
+ line += "\n";
+ return line;
+ }
};
struct Smt2Backend : public Backend {
diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py
index 137182f33..5f05287de 100644
--- a/backends/smt2/smtbmc.py
+++ b/backends/smt2/smtbmc.py
@@ -17,9 +17,10 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
-import os, sys, getopt, re
+import os, sys, getopt, re, bisect
##yosys-sys-path##
from smtio import SmtIo, SmtOpts, MkVcd
+from ywio import ReadWitness, WriteWitness, WitnessValues
from collections import defaultdict
got_topt = False
@@ -28,6 +29,8 @@ step_size = 1
num_steps = 20
append_steps = 0
vcdfile = None
+inywfile = None
+outywfile = None
cexfile = None
aimfile = None
aiwfile = None
@@ -51,6 +54,7 @@ smtctop = None
noinit = False
binarymode = False
keep_going = False
+check_witness = False
so = SmtOpts()
@@ -94,6 +98,9 @@ def usage():
the AIGER witness file does not include the status and
properties lines.
+ --yw <yosys_witness_filename>
+ read a Yosys witness.
+
--btorwit <btor_witness_filename>
read a BTOR witness.
@@ -121,6 +128,9 @@ def usage():
(hint: use 'write_smt2 -wires' for maximum
coverage of signals in generated VCD file)
+ --dump-yw <yw_filename>
+ write trace as a Yosys witness trace
+
--dump-vlogtb <verilog_filename>
write trace as Verilog test bench
@@ -161,15 +171,19 @@ def usage():
covering all found failed assertions, the character '%' is
replaced in all dump filenames with an increasing number.
+ --check-witness
+ check that the used witness file contains sufficient
+ constraints to force an assertion failure.
+
""" + so.helpmsg())
sys.exit(1)
try:
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts +
- ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat",
- "dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=",
- "smtc-init", "smtc-top=", "noinit", "binary", "keep-going"])
+ ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "yw=", "btorwit=", "presat",
+ "dump-vcd=", "dump-yw=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=",
+ "smtc-init", "smtc-top=", "noinit", "binary", "keep-going", "check-witness"])
except:
usage()
@@ -204,10 +218,14 @@ for o, a in opts:
aiwfile = a + ".aiw"
elif o == "--aig-noheader":
aigheader = False
+ elif o == "--yw":
+ inywfile = a
elif o == "--btorwit":
btorwitfile = a
elif o == "--dump-vcd":
vcdfile = a
+ elif o == "--dump-yw":
+ outywfile = a
elif o == "--dump-vlogtb":
vlogtbfile = a
elif o == "--vlogtb-top":
@@ -244,6 +262,8 @@ for o, a in opts:
binarymode = True
elif o == "--keep-going":
keep_going = True
+ elif o == "--check-witness":
+ check_witness = True
elif so.handle(o, a):
pass
else:
@@ -462,7 +482,8 @@ if cexfile is not None:
constr_assumes[step].append((cexfile, smtexpr))
if not got_topt:
- skip_steps = max(skip_steps, step)
+ if not check_witness:
+ skip_steps = max(skip_steps, step)
num_steps = max(num_steps, step+1)
if aimfile is not None:
@@ -595,13 +616,119 @@ if aimfile is not None:
constr_assumes[step].append((cexfile, smtexpr))
if not got_topt:
- skip_steps = max(skip_steps, step)
+ if not check_witness:
+ skip_steps = max(skip_steps, step)
# some solvers optimize the properties so that they fail one cycle early,
# thus we check the properties in the cycle the aiger witness ends, and
# if that doesn't work, we check the cycle after that as well.
num_steps = max(num_steps, step+2)
step += 1
+if inywfile is not None:
+ if not got_topt:
+ assume_skipped = 0
+ skip_steps = 0
+ num_steps = 0
+
+ with open(inywfile, "r") as f:
+ inyw = ReadWitness(f)
+
+ inits, seqs, clocks, mems = smt.hierwitness(topmod, allregs=True, blackbox=True)
+
+ smt_wires = defaultdict(list)
+ smt_mems = defaultdict(list)
+
+ for wire in inits + seqs:
+ smt_wires[wire["path"]].append(wire)
+
+ for mem in mems:
+ smt_mems[mem["path"]].append(mem)
+
+ addr_re = re.compile(r'\\\[[0-9]+\]$')
+ bits_re = re.compile(r'[01?]*$')
+
+ for t, step in inyw.steps():
+ present_signals, missing = step.present_signals(inyw.sigmap)
+ for sig in present_signals:
+ bits = step[sig]
+ if not bits_re.match(bits):
+ raise ValueError("unsupported bit value in Yosys witness file")
+
+ sig_end = sig.offset + len(bits)
+ if sig.path in smt_wires:
+ for wire in smt_wires[sig.path]:
+ width, offset = wire["width"], wire["offset"]
+
+ smt_bool = smt.net_width(topmod, wire["smtpath"]) == 1
+
+ offset = max(offset, 0)
+
+ end = width + offset
+ common_offset = max(sig.offset, offset)
+ common_end = min(sig_end, end)
+ if common_end <= common_offset:
+ continue
+
+ smt_expr = smt.net_expr(topmod, f"s{t}", wire["smtpath"])
+
+ if not smt_bool:
+ slice_high = common_end - offset - 1
+ slice_low = common_offset - offset
+ smt_expr = "((_ extract %d %d) %s)" % (slice_high, slice_low, smt_expr)
+
+ bit_slice = bits[len(bits) - (common_end - sig.offset):len(bits) - (common_offset - sig.offset)]
+
+ if bit_slice.count("?") == len(bit_slice):
+ continue
+
+ if smt_bool:
+ assert width == 1
+ smt_constr = "(= %s %s)" % (smt_expr, "true" if bit_slice == "1" else "false")
+ else:
+ if "?" in bit_slice:
+ mask = bit_slice.replace("0", "1").replace("?", "0")
+ bit_slice = bit_slice.replace("?", "0")
+ smt_expr = "(bvand %s #b%s)" % (smt_expr, mask)
+
+ smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice)
+
+ constr_assumes[t].append((inywfile, smt_constr))
+
+ if sig.memory_path:
+ if sig.memory_path in smt_mems:
+ for mem in smt_mems[sig.memory_path]:
+ width, size, bv = mem["width"], mem["size"], mem["statebv"]
+
+ smt_expr = smt.net_expr(topmod, f"s{t}", mem["smtpath"])
+
+ if bv:
+ word_low = sig.memory_addr * width
+ word_high = word_low + width - 1
+ smt_expr = "((_ extract %d %d) %s)" % (word_high, word_low, smt_expr)
+ else:
+ addr_width = (size - 1).bit_length()
+ addr_bits = f"{sig.memory_addr:0{addr_width}b}"
+ smt_expr = "(select %s #b%s )" % (smt_expr, addr_bits)
+
+ if len(bits) < width:
+ slice_high = sig.offset + len(bits) - 1
+ smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr)
+
+ bit_slice = bits
+
+ if "?" in bit_slice:
+ mask = bit_slice.replace("0", "1").replace("?", "0")
+ bit_slice = bit_slice.replace("?", "0")
+ smt_expr = "(bvand %s #b%s)" % (smt_expr, mask)
+
+ smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice)
+ constr_assumes[t].append((inywfile, smt_constr))
+
+ if not got_topt:
+ if not check_witness:
+ skip_steps = max(skip_steps, t)
+ num_steps = max(num_steps, t+1)
+
if btorwitfile is not None:
with open(btorwitfile, "r") as f:
step = None
@@ -699,128 +826,137 @@ if btorwitfile is not None:
skip_steps = step
num_steps = step+1
-def write_vcd_trace(steps_start, steps_stop, index):
- filename = vcdfile.replace("%", index)
- print_msg("Writing trace to VCD file: %s" % (filename))
+def collect_mem_trace_data(steps_start, steps_stop, vcd=None):
+ mem_trace_data = dict()
- with open(filename, "w") as vcd_file:
- vcd = MkVcd(vcd_file)
- path_list = list()
+ for mempath in sorted(smt.hiermems(topmod)):
+ abits, width, rports, wports, asyncwr = smt.mem_info(topmod, mempath)
- for netpath in sorted(smt.hiernets(topmod)):
- hidden_net = False
- for n in netpath:
- if n.startswith("$"):
- hidden_net = True
- if not hidden_net:
- edge = smt.net_clock(topmod, netpath)
- if edge is None:
- vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath))
- else:
- vcd.add_clock([topmod] + netpath, edge)
- path_list.append(netpath)
-
- mem_trace_data = dict()
- for mempath in sorted(smt.hiermems(topmod)):
- abits, width, rports, wports, asyncwr = smt.mem_info(topmod, mempath)
+ expr_id = list()
+ expr_list = list()
+ for i in range(steps_start, steps_stop):
+ for j in range(rports):
+ expr_id.append(('R', i-steps_start, j, 'A'))
+ expr_id.append(('R', i-steps_start, j, 'D'))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dA" % j))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dD" % j))
+ for j in range(wports):
+ expr_id.append(('W', i-steps_start, j, 'A'))
+ expr_id.append(('W', i-steps_start, j, 'D'))
+ expr_id.append(('W', i-steps_start, j, 'M'))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dA" % j))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dD" % j))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dM" % j))
+
+ rdata = list()
+ wdata = list()
+ addrs = set()
+
+ for eid, edat in zip(expr_id, smt.get_list(expr_list)):
+ t, i, j, f = eid
+
+ if t == 'R':
+ c = rdata
+ elif t == 'W':
+ c = wdata
+ else:
+ assert False
- expr_id = list()
- expr_list = list()
- for i in range(steps_start, steps_stop):
- for j in range(rports):
- expr_id.append(('R', i-steps_start, j, 'A'))
- expr_id.append(('R', i-steps_start, j, 'D'))
- expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dA" % j))
- expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dD" % j))
- for j in range(wports):
- expr_id.append(('W', i-steps_start, j, 'A'))
- expr_id.append(('W', i-steps_start, j, 'D'))
- expr_id.append(('W', i-steps_start, j, 'M'))
- expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dA" % j))
- expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dD" % j))
- expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dM" % j))
-
- rdata = list()
- wdata = list()
- addrs = set()
-
- for eid, edat in zip(expr_id, smt.get_list(expr_list)):
- t, i, j, f = eid
-
- if t == 'R':
- c = rdata
- elif t == 'W':
- c = wdata
- else:
- assert False
+ while len(c) <= i:
+ c.append(list())
+ c = c[i]
- while len(c) <= i:
- c.append(list())
- c = c[i]
+ while len(c) <= j:
+ c.append(dict())
+ c = c[j]
- while len(c) <= j:
- c.append(dict())
- c = c[j]
+ c[f] = smt.bv2bin(edat)
- c[f] = smt.bv2bin(edat)
+ if f == 'A':
+ addrs.add(c[f])
- if f == 'A':
- addrs.add(c[f])
+ for addr in addrs:
+ tdata = list()
+ data = ["x"] * width
+ gotread = False
- for addr in addrs:
- tdata = list()
- data = ["x"] * width
- gotread = False
+ if len(wdata) == 0 and len(rdata) != 0:
+ wdata = [[]] * len(rdata)
- if len(wdata) == 0 and len(rdata) != 0:
- wdata = [[]] * len(rdata)
+ assert len(rdata) == len(wdata)
- assert len(rdata) == len(wdata)
+ for i in range(len(wdata)):
+ if not gotread:
+ for j_data in rdata[i]:
+ if j_data["A"] == addr:
+ data = list(j_data["D"])
+ gotread = True
+ break
- for i in range(len(wdata)):
- if not gotread:
- for j_data in rdata[i]:
- if j_data["A"] == addr:
- data = list(j_data["D"])
- gotread = True
- break
+ if gotread:
+ buf = data[:]
+ for ii in reversed(range(len(tdata))):
+ for k in range(width):
+ if tdata[ii][k] == "x":
+ tdata[ii][k] = buf[k]
+ else:
+ buf[k] = tdata[ii][k]
- if gotread:
- buf = data[:]
- for ii in reversed(range(len(tdata))):
- for k in range(width):
- if tdata[ii][k] == "x":
- tdata[ii][k] = buf[k]
- else:
- buf[k] = tdata[ii][k]
+ if not asyncwr:
+ tdata.append(data[:])
- if not asyncwr:
- tdata.append(data[:])
+ for j_data in wdata[i]:
+ if j_data["A"] != addr:
+ continue
- for j_data in wdata[i]:
- if j_data["A"] != addr:
- continue
+ D = j_data["D"]
+ M = j_data["M"]
- D = j_data["D"]
- M = j_data["M"]
+ for k in range(width):
+ if M[k] == "1":
+ data[k] = D[k]
- for k in range(width):
- if M[k] == "1":
- data[k] = D[k]
+ if asyncwr:
+ tdata.append(data[:])
- if asyncwr:
- tdata.append(data[:])
+ assert len(tdata) == len(rdata)
- assert len(tdata) == len(rdata)
+ int_addr = int(addr, 2)
- netpath = mempath[:]
- netpath[-1] += "<%0*x>" % ((len(addr)+3) // 4, int(addr, 2))
+ netpath = mempath[:]
+ if vcd:
+ netpath[-1] += "<%0*x>" % ((len(addr)+3) // 4, int_addr)
vcd.add_net([topmod] + netpath, width)
- for i in range(steps_start, steps_stop):
- if i not in mem_trace_data:
- mem_trace_data[i] = list()
- mem_trace_data[i].append((netpath, "".join(tdata[i-steps_start])))
+ for i in range(steps_start, steps_stop):
+ if i not in mem_trace_data:
+ mem_trace_data[i] = list()
+ mem_trace_data[i].append((netpath, int_addr, "".join(tdata[i-steps_start])))
+
+ return mem_trace_data
+
+def write_vcd_trace(steps_start, steps_stop, index):
+ filename = vcdfile.replace("%", index)
+ print_msg("Writing trace to VCD file: %s" % (filename))
+
+ with open(filename, "w") as vcd_file:
+ vcd = MkVcd(vcd_file)
+ path_list = list()
+
+ for netpath in sorted(smt.hiernets(topmod)):
+ hidden_net = False
+ for n in netpath:
+ if n.startswith("$"):
+ hidden_net = True
+ if not hidden_net:
+ edge = smt.net_clock(topmod, netpath)
+ if edge is None:
+ vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath))
+ else:
+ vcd.add_clock([topmod] + netpath, edge)
+ path_list.append(netpath)
+
+ mem_trace_data = collect_mem_trace_data(steps_start, steps_stop, vcd)
for i in range(steps_start, steps_stop):
vcd.set_time(i)
@@ -828,7 +964,7 @@ def write_vcd_trace(steps_start, steps_stop, index):
for path, value in zip(path_list, value_list):
vcd.set_net([topmod] + path, value)
if i in mem_trace_data:
- for path, value in mem_trace_data[i]:
+ for path, addr, value in mem_trace_data[i]:
vcd.set_net([topmod] + path, value)
vcd.set_time(steps_stop)
@@ -1072,8 +1208,72 @@ def write_constr_trace(steps_start, steps_stop, index):
for name, val in zip(pi_names, pi_values):
print("assume (= [%s%s] %s)" % (constr_prefix, ".".join(name), val), file=f)
+def write_yw_trace(steps_start, steps_stop, index, allregs=False):
+ filename = outywfile.replace("%", index)
+ print_msg("Writing trace to Yosys witness file: %s" % (filename))
+
+ mem_trace_data = collect_mem_trace_data(steps_start, steps_stop)
+
+ with open(filename, "w") as f:
+ inits, seqs, clocks, mems = smt.hierwitness(topmod, allregs)
+
+ yw = WriteWitness(f, "smtbmc")
+
+ for clock in clocks:
+ yw.add_clock(clock["path"], clock["offset"], clock["type"])
+
+ for seq in seqs:
+ seq["sig"] = yw.add_sig(seq["path"], seq["offset"], seq["width"])
-def write_trace(steps_start, steps_stop, index):
+ for init in inits:
+ init["sig"] = yw.add_sig(init["path"], init["offset"], init["width"], True)
+
+ inits = seqs + inits
+
+ mem_dict = {tuple(mem["smtpath"]): mem for mem in mems}
+ mem_init_values = []
+
+ for path, addr, value in mem_trace_data.get(0, ()):
+ json_mem = mem_dict.get(tuple(path))
+ if not json_mem:
+ continue
+
+ bit_addr = addr * json_mem["width"]
+ uninit_chunks = [(chunk["width"] + chunk["offset"], chunk["offset"]) for chunk in json_mem["uninitialized"]]
+ first_chunk_nr = bisect.bisect_left(uninit_chunks, (bit_addr + 1,))
+
+ for uninit_end, uninit_offset in uninit_chunks[first_chunk_nr:]:
+ assert uninit_end > bit_addr
+ if uninit_offset > bit_addr + json_mem["width"]:
+ break
+
+ word_path = (*json_mem["path"], f"\\[{addr}]")
+
+ overlap_start = max(uninit_offset - bit_addr, 0)
+ overlap_end = min(uninit_end - bit_addr, json_mem["width"])
+ overlap_bits = value[len(value)-overlap_end:len(value)-overlap_start]
+
+ sig = yw.add_sig(word_path, overlap_start, overlap_end - overlap_start, True)
+ mem_init_values.append((sig, overlap_bits.replace("x", "?")))
+
+ for k in range(steps_start, steps_stop):
+ step_values = WitnessValues()
+
+ if k == steps_start:
+ for sig, value in mem_init_values:
+ step_values[sig] = value
+ sigs = inits + seqs
+ else:
+ sigs = seqs
+
+ for sig in sigs:
+ step_values[sig["sig"]] = smt.bv2bin(smt.get(smt.net_expr(topmod, f"s{k}", sig["smtpath"])))
+ yw.step(step_values)
+
+ yw.end_trace()
+
+
+def write_trace(steps_start, steps_stop, index, allregs=False):
if vcdfile is not None:
write_vcd_trace(steps_start, steps_stop, index)
@@ -1083,6 +1283,9 @@ def write_trace(steps_start, steps_stop, index):
if outconstr is not None:
write_constr_trace(steps_start, steps_stop, index)
+ if outywfile is not None:
+ write_yw_trace(steps_start, steps_stop, index, allregs)
+
def print_failed_asserts_worker(mod, state, path, extrainfo, infomap, infokey=()):
assert mod in smt.modinfo
@@ -1392,12 +1595,12 @@ if tempind:
print_msg("Temporal induction failed!")
print_anyconsts(num_steps)
print_failed_asserts(num_steps)
- write_trace(step, num_steps+1, '%')
+ write_trace(step, num_steps+1, '%', allregs=True)
elif dumpall:
print_anyconsts(num_steps)
print_failed_asserts(num_steps)
- write_trace(step, num_steps+1, "%d" % step)
+ write_trace(step, num_steps+1, "%d" % step, allregs=True)
else:
print_msg("Temporal induction successful.")
@@ -1590,6 +1793,7 @@ else: # not tempind, covermode
smt_assert("(not %s)" % active_assert_expr)
else:
+ active_assert_expr = "true"
smt_assert("false")
@@ -1597,6 +1801,17 @@ else: # not tempind, covermode
if retstatus != "FAILED":
print("%s BMC failed!" % smt.timestamp())
+ if check_witness:
+ print_msg("Checking witness constraints...")
+ smt_pop()
+ smt_push()
+ smt_assert(active_assert_expr)
+ if smt_check_sat() != "sat":
+ retstatus = "PASSED"
+ check_witness = False
+ num_steps = -1
+ break
+
if append_steps > 0:
for i in range(last_check_step+1, last_check_step+1+append_steps):
print_msg("Appending additional step %d." % i)
@@ -1689,6 +1904,8 @@ else: # not tempind, covermode
print_anyconsts(0)
write_trace(0, num_steps, '%')
+ if check_witness:
+ retstatus = "FAILED"
smt.write("(exit)")
smt.wait()
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
index 91efc13a3..de09c040e 100644
--- a/backends/smt2/smtio.py
+++ b/backends/smt2/smtio.py
@@ -16,7 +16,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
-import sys, re, os, signal
+import sys, re, os, signal, json
import subprocess
if os.name == "posix":
import resource
@@ -108,6 +108,7 @@ class SmtModInfo:
self.allconsts = dict()
self.allseqs = dict()
self.asize = dict()
+ self.witness = []
class SmtIo:
@@ -337,7 +338,7 @@ class SmtIo:
def p_thread_main(self):
while True:
- data = self.p.stdout.readline().decode("ascii")
+ data = self.p.stdout.readline().decode("utf-8")
if data == "": break
self.p_queue.put(data)
self.p_queue.put("")
@@ -359,7 +360,7 @@ class SmtIo:
def p_write(self, data, flush):
assert self.p is not None
- self.p.stdin.write(bytes(data, "ascii"))
+ self.p.stdin.write(bytes(data, "utf-8"))
if flush: self.p.stdin.flush()
def p_read(self):
@@ -587,6 +588,11 @@ class SmtIo:
self.modinfo[self.curmod].allseqs[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5])
self.modinfo[self.curmod].asize[fields[2]] = int(fields[3])
+ if fields[1] == "yosys-smt2-witness":
+ data = json.loads(stmt.split(None, 2)[2])
+ if data.get("type") in ["cell", "mem", "posedge", "negedge", "input", "reg", "init", "seq", "blackbox"]:
+ self.modinfo[self.curmod].witness.append(data)
+
def hiernets(self, top, regs_only=False):
def hiernets_worker(nets, mod, cursor):
for netname in sorted(self.modinfo[mod].wsize.keys()):
@@ -658,6 +664,57 @@ class SmtIo:
hiermems_worker(mems, top, [])
return mems
+ def hierwitness(self, top, allregs=False, blackbox=True):
+ init_witnesses = []
+ seq_witnesses = []
+ clk_witnesses = []
+ mem_witnesses = []
+
+ def absolute(path, cursor, witness):
+ return {
+ **witness,
+ "path": path + tuple(witness["path"]),
+ "smtpath": cursor + [witness["smtname"]],
+ }
+
+ for witness in self.modinfo[top].witness:
+ if witness["type"] == "input":
+ seq_witnesses.append(absolute((), [], witness))
+ if witness["type"] in ("posedge", "negedge"):
+ clk_witnesses.append(absolute((), [], witness))
+
+ init_types = ["init"]
+ if allregs:
+ init_types.append("reg")
+
+ seq_types = ["seq"]
+ if blackbox:
+ seq_types.append("blackbox")
+
+ def worker(mod, path, cursor):
+ cell_paths = {}
+ for witness in self.modinfo[mod].witness:
+ if witness["type"] in init_types:
+ init_witnesses.append(absolute(path, cursor, witness))
+ if witness["type"] in seq_types:
+ seq_witnesses.append(absolute(path, cursor, witness))
+ if witness["type"] == "mem":
+ if allregs and not witness["rom"]:
+ width, size = witness["width"], witness["size"]
+ witness = {**witness, "uninitialized": {"width": width * size, "offset": 0}}
+ if not witness["uninitialized"]:
+ continue
+
+ mem_witnesses.append(absolute(path, cursor, witness))
+ if witness["type"] == "cell":
+ cell_paths[witness["smtname"]] = tuple(witness["path"])
+
+ for cellname, celltype in sorted(self.modinfo[mod].cells.items()):
+ worker(celltype, path + cell_paths.get(cellname, ("?" + cellname,)), cursor + [cellname])
+
+ worker(top, (), [])
+ return init_witnesses, seq_witnesses, clk_witnesses, mem_witnesses
+
def read(self):
stmt = []
count_brackets = 0
@@ -887,6 +944,8 @@ class SmtIo:
assert mod in self.modinfo
if path[0] == "":
return base
+ if isinstance(path[0], int):
+ return "(|%s#%d| %s)" % (mod, path[0], base)
if path[0] in self.modinfo[mod].cells:
return "(|%s_h %s| %s)" % (mod, path[0], base)
if path[0] in self.modinfo[mod].wsize:
@@ -909,6 +968,8 @@ class SmtIo:
mod = self.modinfo[mod].cells[net_path[i]]
assert mod in self.modinfo
+ if isinstance(net_path[-1], int):
+ return None
assert net_path[-1] in self.modinfo[mod].wsize
return self.modinfo[mod].wsize[net_path[-1]]
diff --git a/backends/smt2/witness.py b/backends/smt2/witness.py
new file mode 100644
index 000000000..a1e65569d
--- /dev/null
+++ b/backends/smt2/witness.py
@@ -0,0 +1,254 @@
+#!/usr/bin/env python3
+#
+# yosys -- Yosys Open SYnthesis Suite
+#
+# Copyright (C) 2022 Jannis Harder <jix@yosyshq.com> <me@jix.one>
+#
+# 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.
+#
+
+import os, sys, itertools, re
+##yosys-sys-path##
+import json
+import click
+
+from ywio import ReadWitness, WriteWitness, WitnessSig, WitnessSigMap, WitnessValues, coalesce_signals
+
+@click.group()
+def cli():
+ pass
+
+
+@cli.command(help="""
+Display a Yosys witness trace in a human readable format.
+""")
+@click.argument("input", type=click.File("r"))
+def display(input):
+ click.echo(f"Reading Yosys witness trace {input.name!r}...")
+ inyw = ReadWitness(input)
+
+ def output():
+
+ yield click.style("*** RTLIL bit-order below may differ from source level declarations ***", fg="red")
+ if inyw.clocks:
+ yield click.style("=== Clock Signals ===", fg="blue")
+ for clock in inyw.clocks:
+ yield f" {clock['edge']} {WitnessSig(clock['path'], clock['offset']).pretty()}"
+
+ for t, values in inyw.steps():
+ if t:
+ yield click.style(f"=== Step {t} ===", fg="blue")
+ else:
+ yield click.style("=== Initial State ===", fg="blue")
+
+ step_prefix = click.style(f"#{t}", fg="bright_black")
+
+ signals, missing = values.present_signals(inyw.sigmap)
+
+ assert not missing
+
+ for sig in signals:
+ display_bits = values[sig].replace("?", click.style("?", fg="bright_black"))
+ yield f" {step_prefix} {sig.pretty()} = {display_bits}"
+ click.echo_via_pager([line + "\n" for line in output()])
+
+
+@cli.command(help="""
+Display statistics of a Yosys witness trace.
+""")
+@click.argument("input", type=click.File("r"))
+def stats(input):
+ click.echo(f"Reading Yosys witness trace {input.name!r}...")
+ inyw = ReadWitness(input)
+
+ total = 0
+
+ for t, values in inyw.steps():
+ click.echo(f"{t:5}: {len(values.values):8} bits")
+ total += len(values.values)
+
+ click.echo(f"total: {total:8} bits")
+
+
+@cli.command(help="""
+Transform a Yosys witness trace.
+
+Currently no transformations are implemented, so it is only useful for testing.
+""")
+@click.argument("input", type=click.File("r"))
+@click.argument("output", type=click.File("w"))
+def yw2yw(input, output):
+ click.echo(f"Copying yosys witness trace from {input.name!r} to {output.name!r}...")
+ inyw = ReadWitness(input)
+ outyw = WriteWitness(output, "yosys-witness yw2yw")
+
+ for clock in inyw.clocks:
+ outyw.add_clock(clock["path"], clock["offset"], clock["edge"])
+
+ for sig in inyw.signals:
+ outyw.add_sig(sig.path, sig.offset, sig.width, sig.init_only)
+
+ for t, values in inyw.steps():
+ outyw.step(values)
+
+ outyw.end_trace()
+
+ click.echo(f"Copied {outyw.t + 1} time steps.")
+
+
+class AigerMap:
+ def __init__(self, mapfile):
+ data = json.load(mapfile)
+
+ self.latch_count = data["latch_count"]
+ self.input_count = data["input_count"]
+
+ self.clocks = data["clocks"]
+
+ self.sigmap = WitnessSigMap()
+ self.init_inputs = set(init["input"] for init in data["inits"])
+
+ for bit in data["inputs"] + data["seqs"] + data["inits"]:
+ self.sigmap.add_bit((tuple(bit["path"]), bit["offset"]), bit["input"])
+
+
+
+@cli.command(help="""
+Convert an AIGER witness trace into a Yosys witness trace.
+
+This requires a Yosys witness AIGER map file as generated by 'write_aiger -ywmap'.
+""")
+@click.argument("input", type=click.File("r"))
+@click.argument("mapfile", type=click.File("r"))
+@click.argument("output", type=click.File("w"))
+def aiw2yw(input, mapfile, output):
+ input_name = input.name
+ click.echo(f"Converting AIGER witness trace {input_name!r} to Yosys witness trace {output.name!r}...")
+ click.echo(f"Using Yosys witness AIGER map file {mapfile.name!r}")
+ aiger_map = AigerMap(mapfile)
+
+ header_lines = list(itertools.islice(input, 0, 2))
+
+ if len(header_lines) == 2 and header_lines[1][0] in ".bcjf":
+ status = header_lines[0].strip()
+ if status == "0":
+ raise click.ClickException(f"{input_name}: file contains no trace, the AIGER status is unsat")
+ elif status == "2":
+ raise click.ClickException(f"{input_name}: file contains no trace, the AIGER status is sat")
+ elif status != "1":
+ raise click.ClickException(f"{input_name}: unexpected data in AIGER witness file")
+ else:
+ input = itertools.chain(header_lines, input)
+
+ ffline = next(input, None)
+ if ffline is None:
+ raise click.ClickException(f"{input_name}: unexpected end of file")
+ ffline = ffline.strip()
+ if not re.match(r'[01x]*$', ffline):
+ raise click.ClickException(f"{input_name}: unexpected data in AIGER witness file")
+ if not re.match(r'[0]*$', ffline):
+ raise click.ClickException(f"{input_name}: non-default initial state not supported")
+
+ outyw = WriteWitness(output, 'yosys-witness aiw2yw')
+
+ for clock in aiger_map.clocks:
+ outyw.add_clock(clock["path"], clock["offset"], clock["edge"])
+
+ for (path, offset), id in aiger_map.sigmap.bit_to_id.items():
+ outyw.add_sig(path, offset, init_only=id in aiger_map.init_inputs)
+
+ missing = set()
+
+ while True:
+ inline = next(input, None)
+ if inline is None:
+ click.echo(f"Warning: {input_name}: file may be incomplete")
+ break
+ inline = inline.strip()
+ if inline in [".", "# DONE"]:
+ break
+ if inline.startswith("#"):
+ continue
+
+ if not re.match(r'[01x]*$', ffline):
+ raise click.ClickException(f"{input_name}: unexpected data in AIGER witness file")
+
+ if len(inline) != aiger_map.input_count:
+ raise click.ClickException(
+ f"{input_name}: {mapfile.name}: number of inputs does not match, "
+ f"{len(inline)} in witness, {aiger_map.input_count} in map file")
+
+ values = WitnessValues()
+ for i, v in enumerate(inline):
+ if v == "x" or outyw.t > 0 and i in aiger_map.init_inputs:
+ continue
+
+ try:
+ bit = aiger_map.sigmap.id_to_bit[i]
+ except IndexError:
+ bit = None
+ if bit is None:
+ missing.insert(i)
+
+ values[bit] = v
+
+ outyw.step(values)
+
+ outyw.end_trace()
+
+ if missing:
+ click.echo("The following AIGER inputs belong to unknown signals:")
+ click.echo(" " + " ".join(str(id) for id in sorted(missing)))
+
+ click.echo(f"Converted {outyw.t} time steps.")
+
+@cli.command(help="""
+Convert a Yosys witness trace into an AIGER witness trace.
+
+This requires a Yosys witness AIGER map file as generated by 'write_aiger -ywmap'.
+""")
+@click.argument("input", type=click.File("r"))
+@click.argument("mapfile", type=click.File("r"))
+@click.argument("output", type=click.File("w"))
+def yw2aiw(input, mapfile, output):
+ click.echo(f"Converting Yosys witness trace {input.name!r} to AIGER witness trace {output.name!r}...")
+ click.echo(f"Using Yosys witness AIGER map file {mapfile.name!r}")
+ aiger_map = AigerMap(mapfile)
+ inyw = ReadWitness(input)
+
+ print("1", file=output)
+ print("b0", file=output)
+ # TODO the b0 status isn't really accurate, but we don't have any better info here
+ print("0" * aiger_map.latch_count, file=output)
+
+ all_missing = set()
+
+ for t, step in inyw.steps():
+ bits, missing = step.pack_present(aiger_map.sigmap)
+ bits = bits[::-1].replace('?', 'x')
+ all_missing.update(missing)
+ bits += 'x' * (aiger_map.input_count - len(bits))
+ print(bits, file=output)
+
+ print(".", file=output)
+
+ if all_missing:
+ click.echo("The following signals are missing in the AIGER map file and will be dropped:")
+ for sig in coalesce_signals(WitnessSig(*bit) for bit in all_missing):
+ click.echo(" " + sig.pretty())
+
+
+ click.echo(f"Converted {len(inyw)} time steps.")
+
+if __name__ == "__main__":
+ cli()
diff --git a/backends/smt2/ywio.py b/backends/smt2/ywio.py
new file mode 100644
index 000000000..8469b4162
--- /dev/null
+++ b/backends/smt2/ywio.py
@@ -0,0 +1,392 @@
+#
+# yosys -- Yosys Open SYnthesis Suite
+#
+# Copyright (C) 2022 Jannis Harder <jix@yosyshq.com> <me@jix.one>
+#
+# 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.
+#
+
+import json, re
+
+from functools import total_ordering
+
+
+class PrettyJson:
+ def __init__(self, f):
+ self.f = f
+ self.indent = 0
+ self.state = ["value"]
+
+ def line(self):
+ indent = len(self.state) - bool(self.state and self.state[-1] == "value")
+ print("\n", end=" " * (2 * indent), file=self.f)
+
+ def raw(self, str):
+ print(end=str, file=self.f)
+
+ def begin_object(self):
+ self.begin_value()
+ self.raw("{")
+ self.state.append("object_first")
+
+ def begin_array(self):
+ self.begin_value()
+ self.raw("[")
+ self.state.append("array_first")
+
+ def end_object(self):
+ state = self.state.pop()
+ if state == "object":
+ self.line()
+ else:
+ assert state == "object_first"
+ self.raw("}")
+ self.end_value()
+
+ def end_array(self):
+ state = self.state.pop()
+ if state == "array":
+ self.line()
+ else:
+ assert state == "array_first"
+ self.raw("]")
+ self.end_value()
+
+ def name(self, name):
+ if self.state[-1] == "object_first":
+ self.state[-1] = "object"
+ else:
+ self.raw(",")
+ self.line()
+ json.dump(str(name), self.f)
+ self.raw(": ")
+ self.state.append("value")
+
+ def begin_value(self):
+ if self.state[-1] == "array_first":
+ self.line()
+ self.state[-1] = "array"
+ elif self.state[-1] == "array":
+ self.raw(",")
+ self.line()
+ else:
+ assert self.state.pop() == "value"
+
+ def end_value(self):
+ if not self.state:
+ print(file=self.f, flush=True)
+
+ def value(self, value):
+ self.begin_value()
+ json.dump(value, self.f)
+ self.end_value()
+
+ def entry(self, name, value):
+ self.name(name)
+ self.value(value)
+
+ def object(self, entries=None):
+ if isinstance(entries, dict):
+ entries = dict.items()
+ self.begin_object()
+ for name, value in entries:
+ self.entry(name, value)
+ self.end_object()
+
+ def array(self, values=None):
+ self.begin_array()
+ for value in values:
+ self.value(value)
+ self.end_array()
+
+
+addr_re = re.compile(r'\\\[[0-9]+\]$')
+public_name_re = re.compile(r"\\([a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?|\[[0-9]+\])$")
+
+def pretty_name(id):
+ if public_name_re.match(id):
+ return id.lstrip("\\")
+ else:
+ return id
+
+def pretty_path(path):
+ out = ""
+ for name in path:
+ name = pretty_name(name)
+ if name.startswith("["):
+ out += name
+ continue
+ if out:
+ out += "."
+ if name.startswith("\\") or name.startswith("$"):
+ out += name + " "
+ else:
+ out += name
+
+ return out
+
+@total_ordering
+class WitnessSig:
+ def __init__(self, path, offset, width=1, init_only=False):
+ path = tuple(path)
+ self.path, self.width, self.offset, self.init_only = path, width, offset, init_only
+
+ self.memory_path = None
+ self.memory_addr = None
+
+ sort_path = path
+ sort_id = -1
+ if path and addr_re.match(path[-1]):
+ self.memory_path = sort_path = path[:-1]
+ self.memory_addr = sort_id = int(path[-1][2:-1])
+
+ self.sort_key = (init_only, sort_path, sort_id, offset, width)
+
+ def bits(self):
+ return ((self.path, i) for i in range(self.offset, self.offset + self.width))
+
+ def rev_bits(self):
+ return ((self.path, i) for i in reversed(range(self.offset, self.offset + self.width)))
+
+ def pretty(self):
+ if self.width > 1:
+ last_offset = self.offset + self.width - 1
+ return f"{pretty_path(self.path)}[{last_offset}:{self.offset}]"
+ else:
+ return f"{pretty_path(self.path)}[{self.offset}]"
+
+ def __eq__(self):
+ return self.sort_key
+
+ def __hash__(self):
+ return hash(self.sort_key)
+
+ def __lt__(self, other):
+ return self.sort_key < other.sort_key
+
+
+def coalesce_signals(signals):
+ bits = {}
+ for sig in signals:
+ for bit in sig.bits():
+ if sig.init_only:
+ bits.setdefault(bit, False)
+ else:
+ bits[bit] = True
+
+ active = None
+
+ out = []
+
+ for bit, not_init in sorted(bits.items()):
+ if active:
+ if active[0] == bit[0] and active[2] == bit[1] and active[3] == not_init:
+ active[2] += 1
+ else:
+ out.append(WitnessSig(active[0], active[1], active[2] - active[1], not active[3]))
+ active = None
+
+ if active is None:
+ active = [bit[0], bit[1], bit[1] + 1, not_init]
+
+ if active:
+ out.append(WitnessSig(active[0], active[1], active[2] - active[1], not active[3]))
+
+ return sorted(out)
+
+
+class WitnessSigMap:
+ def __init__(self, signals=[]):
+ self.signals = []
+
+ self.id_to_bit = []
+ self.bit_to_id = {}
+ self.bit_to_sig = {}
+
+ for sig in signals:
+ self.add_signal(sig)
+
+ def add_signal(self, sig):
+ self.signals.append(sig)
+ for bit in sig.bits():
+ self.add_bit(bit)
+ self.bit_to_sig[bit] = sig
+
+ def add_bit(self, bit, id=None):
+ if id is None:
+ id = len(self.id_to_bit)
+ self.id_to_bit.append(bit)
+ else:
+ if len(self.id_to_bit) <= id:
+ self.id_to_bit += [None] * (id - len(self.id_to_bit) + 1)
+ self.id_to_bit[id] = bit
+ self.bit_to_id[bit] = id
+
+
+class WitnessValues:
+ def __init__(self):
+ self.values = {}
+
+ def __setitem__(self, key, value):
+ if isinstance(key, tuple) and len(key) == 2:
+ if value != "?":
+ assert isinstance(value, str)
+ assert len(value) == 1
+ self.values[key] = value
+ else:
+ assert isinstance(key, WitnessSig)
+ assert key.width == len(value)
+ if isinstance(value, str):
+ value = reversed(value)
+ for bit, bit_value in zip(key.bits(), value):
+ if bit_value != "?":
+ self.values[bit] = bit_value
+
+ def __getitem__(self, key):
+ if isinstance(key, tuple) and len(key) == 2:
+ return self.values.get(key, "?")
+ else:
+ assert isinstance(key, WitnessSig)
+ return "".join([self.values.get(bit, "?") for bit in key.rev_bits()])
+
+ def pack_present(self, sigmap):
+ missing = []
+
+ max_id = max((sigmap.bit_to_id.get(bit, -1) for bit in self.values), default=-1)
+
+ vector = ["?"] * (max_id + 1)
+ for bit, bit_value in self.values.items():
+ id = sigmap.bit_to_id.get(bit, - 1)
+ if id < 0:
+ missing.append(bit)
+ else:
+ vector[max_id - sigmap.bit_to_id[bit]] = bit_value
+
+ return "".join(vector), missing
+
+ def pack(self, sigmap):
+ packed, missing = self.pack_present(sigmap)
+ if missing:
+ raise RuntimeError(f"Cannot pack bits {missing!r}")
+ return packed
+
+ def unpack(self, sigmap, bits):
+ for i, bit_value in enumerate(reversed(bits)):
+ if bit_value != "?":
+ self.values[sigmap.id_to_bit[i]] = bit_value
+
+ def present_signals(self, sigmap):
+ signals = set(sigmap.bit_to_sig.get(bit) for bit in self.values)
+ missing_signals = None in signals
+ if missing_signals:
+ signals.discard(None)
+
+ return sorted(signals), missing_signals
+
+
+class WriteWitness:
+ def __init__(self, f, generator):
+ self.out = PrettyJson(f)
+ self.t = 0
+ self.header_written = False
+ self.clocks = []
+ self.signals = []
+
+ self.out.begin_object()
+ self.out.entry("format", "Yosys Witness Trace")
+ self.out.entry("generator", generator)
+
+ def add_clock(self, path, offset, edge):
+ assert not self.header_written
+ self.clocks.append({
+ "path": path,
+ "edge": edge,
+ "offset": offset,
+ })
+
+ def add_sig(self, path, offset, width=1, init_only=False):
+ assert not self.header_written
+ sig = WitnessSig(path, offset, width, init_only)
+ self.signals.append(sig)
+ return sig
+
+ def write_header(self):
+ assert not self.header_written
+ self.header_written = True
+ self.out.name("clocks")
+ self.out.array(self.clocks)
+
+ self.signals = coalesce_signals(self.signals)
+ self.sigmap = WitnessSigMap(self.signals)
+
+ self.out.name("signals")
+ self.out.array({
+ "path": sig.path,
+ "width": sig.width,
+ "offset": sig.offset,
+ "init_only": sig.init_only,
+ } for sig in self.signals)
+
+ self.out.name("steps")
+ self.out.begin_array()
+
+ def step(self, values):
+ if not self.header_written:
+ self.write_header()
+
+ self.out.value({"bits": values.pack(self.sigmap)})
+
+ self.t += 1
+
+ def end_trace(self):
+ if not self.header_written:
+ self.write_header()
+ self.out.end_array()
+ self.out.end_object()
+
+
+class ReadWitness:
+ def __init__(self, f):
+ data = json.load(f)
+ if not isinstance(data, dict):
+ data = {}
+
+ data_format = data.get("format", "Unknown Format")
+
+ if data_format != "Yosys Witness Trace":
+ raise ValueError(f"unsupported format {data_format!r}")
+
+ self.clocks = data["clocks"]
+ for clock in self.clocks:
+ clock["path"] = tuple(clock["path"])
+
+ self.signals = [
+ WitnessSig(sig["path"], sig["offset"], sig["width"], sig["init_only"])
+ for sig in data["signals"]
+ ]
+
+ self.sigmap = WitnessSigMap(self.signals)
+
+ self.bits = [step["bits"] for step in data["steps"]]
+
+ def step(self, t):
+ values = WitnessValues()
+ values.unpack(self.sigmap, self.bits[t])
+ return values
+
+ def steps(self):
+ for i in range(len(self.bits)):
+ yield i, self.step(i)
+
+ def __len__(self):
+ return len(self.bits)
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index d81c53dfb..9327b34ee 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -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(), that->filename.c_str(), that->location.first_line, autoidx++);
+ IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_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", that->filename.c_str(), that->location.first_line, autoidx++);
+ IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++);
RTLIL::Cell *cell = current_module->addCell(name, ID($pos));
set_src_attr(cell, that);
@@ -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(), that->filename.c_str(), that->location.first_line, autoidx++);
+ IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_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$" << that->filename << ":" << that->location.first_line << "$" << (autoidx++);
+ sstr << "$ternary$" << RTLIL::encode_filename(that->filename) << ":" << that->location.first_line << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux));
set_src_attr(cell, that);
@@ -321,7 +321,7 @@ struct AST_INTERNAL::ProcessGenerator
LookaheadRewriter la_rewriter(always);
// generate process and simple root case
- proc = current_module->addProcess(stringf("$proc$%s:%d$%d", always->filename.c_str(), always->location.first_line, autoidx++));
+ 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);
for (auto &attr : always->attributes) {
if (attr.second->type != AST_CONSTANT)
@@ -1776,7 +1776,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMRD:
{
std::stringstream sstr;
- sstr << "$memrd$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);
+ sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd));
set_src_attr(cell, this);
@@ -1814,7 +1814,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_MEMINIT:
{
std::stringstream sstr;
- sstr << "$meminit$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);
+ sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
SigSpec en_sig = children[2]->genRTLIL();
@@ -1869,7 +1869,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
IdString cellname;
if (str.empty())
- cellname = stringf("%s$%s:%d$%d", celltype.c_str(), filename.c_str(), location.first_line, autoidx++);
+ cellname = stringf("%s$%s:%d$%d", celltype.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
else
cellname = str;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 2d9d6dc79..49bf9af09 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -1240,7 +1240,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// create the indirection wire
std::stringstream sstr;
- sstr << "$indirect$" << ref->name.c_str() << "$" << filename << ":" << location.first_line << "$" << (autoidx++);
+ sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
std::string tmp_str = sstr.str();
add_wire_for_ref(ref, tmp_str);
@@ -2127,7 +2127,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::swap(data_range_left, data_range_right);
std::stringstream sstr;
- sstr << "$mem2bits$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);
+ sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
std::string wire_id = sstr.str();
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true)));
@@ -2714,14 +2714,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// mask and shift operations, disabled for now
AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true)));
- wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", filename.c_str(), location.first_line, autoidx++);
+ wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
wire_mask->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
wire_mask->is_logic = true;
while (wire_mask->simplify(true, false, false, 1, -1, false, false)) { }
current_ast_mod->children.push_back(wire_mask);
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true)));
- wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", filename.c_str(), location.first_line, autoidx++);
+ wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
wire_data->is_logic = true;
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
@@ -2732,7 +2732,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
shift_expr->detectSignWidth(shamt_width_hint, shamt_sign_hint);
AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true)));
- wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", filename.c_str(), location.first_line, autoidx++);
+ wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
wire_sel->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
wire_sel->is_logic = true;
wire_sel->is_signed = shamt_sign_hint;
@@ -2809,7 +2809,7 @@ skip_dynamic_range_lvalue_expansion:;
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && current_block != NULL)
{
std::stringstream sstr;
- sstr << "$formal$" << filename << ":" << location.first_line << "$" << (autoidx++);
+ sstr << "$formal$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN";
AstNode *wire_check = new AstNode(AST_WIRE);
@@ -2918,7 +2918,7 @@ skip_dynamic_range_lvalue_expansion:;
newNode = new AstNode(AST_BLOCK);
AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true)));
- wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", filename.c_str(), location.first_line, autoidx++);
+ wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
current_ast_mod->children.push_back(wire_tmp);
current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
@@ -2956,7 +2956,7 @@ skip_dynamic_range_lvalue_expansion:;
(children[0]->children.size() == 1 || children[0]->children.size() == 2) && children[0]->children[0]->type == AST_RANGE)
{
std::stringstream sstr;
- sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);
+ sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
int mem_width, mem_size, addr_bits;
@@ -3228,7 +3228,7 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
mkconst_int(width_hint-1, true), mkconst_int(0, true)));
- reg->str = stringf("$past$%s:%d$%d$%d", filename.c_str(), location.first_line, myidx, i);
+ reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, myidx, i);
reg->is_reg = true;
reg->is_signed = sign_hint;
@@ -3733,7 +3733,7 @@ skip_dynamic_range_lvalue_expansion:;
std::stringstream sstr;
- sstr << str << "$func$" << filename << ":" << location.first_line << "$" << (autoidx++) << '.';
+ sstr << str << "$func$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.';
std::string prefix = sstr.str();
AstNode *decl = current_scope[str];
@@ -4586,7 +4586,7 @@ static void mark_memories_assign_lhs_complex(dict<AstNode*, pool<std::string>> &
if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) {
AstNode *mem = that->id2ast;
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS))
- mem2reg_places[mem].insert(stringf("%s:%d", that->filename.c_str(), that->location.first_line));
+ mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS;
}
}
@@ -4614,14 +4614,14 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
// activate mem2reg if this is assigned in an async proc
if (flags & AstNode::MEM2REG_FL_ASYNC) {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC))
- mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));
+ mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC;
}
// remember if this is assigned blocking (=)
if (type == AST_ASSIGN_EQ) {
if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1))
- mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));
+ mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line));
proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
}
@@ -4638,11 +4638,11 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
// remember where this is
if (flags & MEM2REG_FL_INIT) {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT))
- mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));
+ mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT;
} else {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE))
- mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));
+ mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE;
}
}
@@ -4656,7 +4656,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
// flag if used after blocking assignment (in same proc)
if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) {
- mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));
+ mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line));
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2;
}
}
@@ -4846,7 +4846,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
children[0]->children[0]->children[0]->type != AST_CONSTANT)
{
std::stringstream sstr;
- sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);
+ sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";
int mem_width, mem_size, addr_bits;
@@ -4962,7 +4962,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
else
{
std::stringstream sstr;
- sstr << "$mem2reg_rd$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);
+ sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";
int mem_width, mem_size, addr_bits;
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index abf8de4d1..188ef2e04 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -464,6 +464,9 @@ struct LibertyFrontend : public Frontend {
log(" -lib\n");
log(" only create empty blackbox modules\n");
log("\n");
+ log(" -wb\n");
+ log(" mark imported cells as whiteboxes\n");
+ log("\n");
log(" -nooverwrite\n");
log(" ignore re-definitions of modules. (the default behavior is to\n");
log(" create an error message if the existing module is not a blackbox\n");
@@ -489,6 +492,7 @@ struct LibertyFrontend : public Frontend {
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_lib = false;
+ bool flag_wb = false;
bool flag_nooverwrite = false;
bool flag_overwrite = false;
bool flag_ignore_miss_func = false;
@@ -505,6 +509,10 @@ struct LibertyFrontend : public Frontend {
flag_lib = true;
continue;
}
+ if (arg == "-wb") {
+ flag_wb = true;
+ continue;
+ }
if (arg == "-ignore_redef" || arg == "-nooverwrite") {
flag_nooverwrite = true;
flag_overwrite = false;
@@ -535,6 +543,9 @@ struct LibertyFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
+ if (flag_wb && flag_lib)
+ log_error("-wb and -lib cannot be specified together!\n");
+
LibertyParser parser(*f);
int cell_count = 0;
@@ -572,6 +583,9 @@ struct LibertyFrontend : public Frontend {
if (flag_lib)
module->set_bool_attribute(ID::blackbox);
+ if (flag_wb)
+ module->set_bool_attribute(ID::whitebox);
+
for (auto &attr : attributes)
module->attributes[attr] = 1;
diff --git a/frontends/verific/README b/frontends/verific/README
index 952fb1e0c..921873af3 100644
--- a/frontends/verific/README
+++ b/frontends/verific/README
@@ -1,7 +1,7 @@
This directory contains Verific bindings for Yosys.
-Use Tabby CAD Suite from YosysHQ if you need Yosys+Verifc.
+Use Tabby CAD Suite from YosysHQ if you need Yosys+Verific.
https://www.yosyshq.com/
Contact YosysHQ at contact@yosyshq.com for free evaluation
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index bbf860c96..e0dbe1b32 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -57,7 +57,7 @@ USING_YOSYS_NAMESPACE
#include "FileSystem.h"
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
-#include "InitialAssertions.h"
+#include "VerificExtensions.h"
#endif
#ifndef YOSYSHQ_VERIFIC_API_VERSION
@@ -183,7 +183,7 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj)
{
std::string s = stringf("$verific$%s", obj->Name());
if (obj->Linefile())
- s += stringf("$%s:%d", Verific::LineFile::GetFileName(obj->Linefile()), Verific::LineFile::GetLineNo(obj->Linefile()));
+ s += stringf("$%s:%d", RTLIL::encode_filename(Verific::LineFile::GetFileName(obj->Linefile())).c_str(), Verific::LineFile::GetLineNo(obj->Linefile()));
s += stringf("$%d", autoidx++);
return s;
}
@@ -1124,6 +1124,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size());
wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
+ wire->upto = portbus->IsUp();
import_attributes(wire->attributes, portbus, nl);
bool portbus_input = portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN;
@@ -1144,7 +1145,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
wire->port_output = true;
}
net = portbus->ElementAtIndex(i)->GetNet();
- RTLIL::SigBit bit(wire, i - wire->start_offset);
+ int bitidx = wire->upto ? (wire->width - 1 - (i - wire->start_offset)) : (i - wire->start_offset);
+ RTLIL::SigBit bit(wire, bitidx);
if (net_map.count(net) == 0)
net_map[net] = bit;
else if (bit_input)
@@ -1308,6 +1310,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size());
wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex());
+ wire->upto = netbus->IsUp();
MapIter mibus;
FOREACH_NET_OF_NETBUS(netbus, mibus, net) {
if (net)
@@ -1322,7 +1325,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
{
if (netbus->ElementAtIndex(i))
{
- int bitidx = i - wire->start_offset;
+ int bitidx = wire->upto ? (wire->width - 1 - (i - wire->start_offset)) : (i - wire->start_offset);
net = netbus->ElementAtIndex(i);
RTLIL::SigBit bit(wire, bitidx);
@@ -2246,7 +2249,7 @@ void verific_import(Design *design, const std::map<std::string,std::string> &par
verific_params.Insert(i.first.c_str(), i.second.c_str());
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
- InitialAssertions::Rewrite("work", &verific_params);
+ VerificExtensions::ElaborateAndRewrite("work", &verific_params);
#endif
if (top.empty()) {
@@ -2312,6 +2315,9 @@ void verific_import(Design *design, const std::map<std::string,std::string> &par
nl_todo.erase(it);
}
+#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
+ VerificExtensions::Reset();
+#endif
hier_tree::DeleteHierarchicalTree();
veri_file::Reset();
#ifdef VERIFIC_VHDL_SUPPORT
@@ -2494,6 +2500,9 @@ struct VerificPass : public Pass {
log(" -v, -vv\n");
log(" Verbose log messages. (-vv is even more verbose than -v.)\n");
log("\n");
+ log(" -pp <filename>\n");
+ log(" Pretty print design after elaboration to specified file.\n");
+ log("\n");
log("The following additional import options are useful for debugging the Verific\n");
log("bindings (for Yosys and/or Verific developers):\n");
log("\n");
@@ -2539,6 +2548,9 @@ struct VerificPass : public Pass {
log("Get/set Verific runtime flags.\n");
log("\n");
log("\n");
+#if defined(YOSYS_ENABLE_VERIFIC) and defined(YOSYSHQ_VERIFIC_EXTENSIONS)
+ VerificExtensions::Help();
+#endif
log("Use YosysHQ Tabby CAD Suite if you need Yosys+Verific.\n");
log("https://www.yosyshq.com/\n");
log("\n");
@@ -2816,9 +2828,11 @@ struct VerificPass : public Pass {
for (auto &ext : verific_libexts)
veri_file::AddLibExt(ext.c_str());
- while (argidx < GetSize(args))
- file_names.Insert(args[argidx++].c_str());
-
+ while (argidx < GetSize(args)) {
+ std::string filename(args[argidx++]);
+ rewrite_filename(filename);
+ file_names.Insert(strdup(filename.c_str()));
+ }
if (!veri_file::AnalyzeMultipleFiles(&file_names, verilog_mode, work.c_str(), veri_file::MFCU)) {
verific_error_msg.clear();
log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n");
@@ -2831,36 +2845,48 @@ struct VerificPass : public Pass {
#ifdef VERIFIC_VHDL_SUPPORT
if (GetSize(args) > argidx && args[argidx] == "-vhdl87") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str());
- for (argidx++; argidx < GetSize(args); argidx++)
- if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_87))
- log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str());
+ for (argidx++; argidx < GetSize(args); argidx++) {
+ std::string filename(args[argidx]);
+ rewrite_filename(filename);
+ if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_87))
+ log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", filename.c_str());
+ }
verific_import_pending = true;
goto check_error;
}
if (GetSize(args) > argidx && args[argidx] == "-vhdl93") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
- for (argidx++; argidx < GetSize(args); argidx++)
- if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_93))
- log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", args[argidx].c_str());
+ for (argidx++; argidx < GetSize(args); argidx++) {
+ std::string filename(args[argidx]);
+ rewrite_filename(filename);
+ if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_93))
+ log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", filename.c_str());
+ }
verific_import_pending = true;
goto check_error;
}
if (GetSize(args) > argidx && args[argidx] == "-vhdl2k") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
- for (argidx++; argidx < GetSize(args); argidx++)
- if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2K))
- log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", args[argidx].c_str());
+ for (argidx++; argidx < GetSize(args); argidx++) {
+ std::string filename(args[argidx]);
+ rewrite_filename(filename);
+ if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_2K))
+ log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", filename.c_str());
+ }
verific_import_pending = true;
goto check_error;
}
if (GetSize(args) > argidx && (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl")) {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str());
- for (argidx++; argidx < GetSize(args); argidx++)
- if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2008))
- log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", args[argidx].c_str());
+ for (argidx++; argidx < GetSize(args); argidx++) {
+ std::string filename(args[argidx]);
+ rewrite_filename(filename);
+ if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_2008))
+ log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", filename.c_str());
+ }
verific_import_pending = true;
goto check_error;
}
@@ -2922,6 +2948,7 @@ struct VerificPass : public Pass {
bool mode_autocover = false, mode_fullinit = false;
bool flatten = false, extnets = false;
string dumpfile;
+ string ppfile;
Map parameters(STRING_HASH);
for (argidx++; argidx < GetSize(args); argidx++) {
@@ -2990,6 +3017,10 @@ struct VerificPass : public Pass {
dumpfile = args[++argidx];
continue;
}
+ if (args[argidx] == "-pp" && argidx+1 < GetSize(args)) {
+ ppfile = args[++argidx];
+ continue;
+ }
break;
}
@@ -2999,8 +3030,11 @@ struct VerificPass : public Pass {
std::set<std::string> top_mod_names;
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
- InitialAssertions::Rewrite(work, &parameters);
+ VerificExtensions::ElaborateAndRewrite(work, &parameters);
#endif
+ if (!ppfile.empty())
+ veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str());
+
if (mode_all)
{
log("Running hier_tree::ElaborateAll().\n");
@@ -3113,6 +3147,9 @@ struct VerificPass : public Pass {
nl_todo.erase(it);
}
+#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
+ VerificExtensions::Reset();
+#endif
hier_tree::DeleteHierarchicalTree();
veri_file::Reset();
#ifdef VERIFIC_VHDL_SUPPORT
@@ -3187,6 +3224,13 @@ struct VerificPass : public Pass {
}
}
}
+#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
+ if (VerificExtensions::Execute(args, argidx, work,
+ [this](const std::vector<std::string> &args, size_t argidx, std::string msg)
+ { cmd_error(args, argidx, msg); } )) {
+ goto check_error;
+ }
+#endif
cmd_error(args, argidx, "Missing or unsupported mode parameter.\n");
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
index 883531e78..e33b0a2c3 100644
--- a/frontends/verilog/preproc.cc
+++ b/frontends/verilog/preproc.cc
@@ -961,6 +961,11 @@ frontend_verilog_preproc(std::istream &f,
}
if (tok == "`resetall") {
+ default_nettype_wire = true;
+ continue;
+ }
+
+ if (tok == "`undefineall" && sv_mode) {
defines.clear();
global_defines_cache.clear();
continue;
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 7e9cfb38d..d62ba1506 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -51,6 +51,7 @@ struct CellTypes
setup_internals();
setup_internals_mem();
+ setup_internals_anyinit();
setup_stdcells();
setup_stdcells_mem();
}
@@ -155,6 +156,11 @@ struct CellTypes
setup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q});
}
+ void setup_internals_anyinit()
+ {
+ setup_type(ID($anyinit), {ID::D}, {ID::Q});
+ }
+
void setup_internals_mem()
{
setup_internals_ff();
diff --git a/kernel/constids.inc b/kernel/constids.inc
index 0f6dfc29b..239381f85 100644
--- a/kernel/constids.inc
+++ b/kernel/constids.inc
@@ -171,6 +171,7 @@ X(RD_TRANSPARENCY_MASK)
X(RD_TRANSPARENT)
X(RD_WIDE_CONTINUATION)
X(reg)
+X(replaced_by_gclk)
X(reprocess_after)
X(rom_block)
X(rom_style)
diff --git a/kernel/driver.cc b/kernel/driver.cc
index f8f940e89..e52e1fb0e 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -192,6 +192,13 @@ void yosys_atexit()
#endif
}
+#if defined(__OpenBSD__)
+namespace Yosys {
+extern char *yosys_argv0;
+extern char yosys_path[PATH_MAX];
+};
+#endif
+
int main(int argc, char **argv)
{
std::string frontend_command = "auto";
@@ -498,6 +505,12 @@ int main(int argc, char **argv)
if (print_stats)
log_hasher = new SHA1;
+#if defined(__OpenBSD__)
+ // save the executable origin for proc_self_dirname()
+ yosys_argv0 = argv[0];
+ realpath(yosys_argv0, yosys_path);
+#endif
+
#if defined(__linux__)
// set stack size to >= 128 MB
{
diff --git a/kernel/ff.cc b/kernel/ff.cc
index b0f1a924f..697ba7342 100644
--- a/kernel/ff.cc
+++ b/kernel/ff.cc
@@ -33,10 +33,14 @@ FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initva
std::string type_str = cell->type.str();
- if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
- if (cell->type == ID($ff)) {
+ if (cell->type.in(ID($anyinit), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
+ if (cell->type.in(ID($anyinit), ID($ff))) {
has_gclk = true;
sig_d = cell->getPort(ID::D);
+ if (cell->type == ID($anyinit)) {
+ is_anyinit = true;
+ log_assert(val_init.is_fully_undef());
+ }
} else if (cell->type == ID($sr)) {
// No data input at all.
} else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
@@ -274,6 +278,7 @@ FfData FfData::slice(const std::vector<int> &bits) {
res.has_sr = has_sr;
res.ce_over_srst = ce_over_srst;
res.is_fine = is_fine;
+ res.is_anyinit = is_anyinit;
res.pol_clk = pol_clk;
res.pol_ce = pol_ce;
res.pol_aload = pol_aload;
@@ -542,7 +547,7 @@ Cell *FfData::emit() {
return nullptr;
}
}
- if (initvals)
+ if (initvals && !is_anyinit)
initvals->set_init(sig_q, val_init);
if (!is_fine) {
if (has_gclk) {
@@ -552,7 +557,12 @@ Cell *FfData::emit() {
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
- cell = module->addFf(name, sig_d, sig_q);
+ if (is_anyinit) {
+ cell = module->addAnyinit(name, sig_d, sig_q);
+ log_assert(val_init.is_fully_undef());
+ } else {
+ cell = module->addFf(name, sig_d, sig_q);
+ }
} else if (!has_aload && !has_clk) {
log_assert(has_sr);
cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
@@ -603,6 +613,7 @@ Cell *FfData::emit() {
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
+ log_assert(!is_anyinit);
cell = module->addFfGate(name, sig_d, sig_q);
} else if (!has_aload && !has_clk) {
log_assert(has_sr);
diff --git a/kernel/ff.h b/kernel/ff.h
index 41721b4a1..e684d3c43 100644
--- a/kernel/ff.h
+++ b/kernel/ff.h
@@ -28,7 +28,10 @@ YOSYS_NAMESPACE_BEGIN
// Describes a flip-flop or a latch.
//
// If has_gclk, this is a formal verification FF with implicit global clock:
-// Q is simply previous cycle's D.
+// Q is simply previous cycle's D. Additionally if is_anyinit is true, this is
+// an $anyinit cell which always has an undefined initialization value. Note
+// that $anyinit is not considered to be among the FF celltypes, so a pass has
+// to explicitly opt-in to process $anyinit cells with FfData.
//
// Otherwise, the FF/latch can have any number of features selected by has_*
// attributes that determine Q's value (in order of decreasing priority):
@@ -126,6 +129,8 @@ struct FfData {
// True if this FF is a fine cell, false if it is a coarse cell.
// If true, width must be 1.
bool is_fine;
+ // True if this FF is an $anyinit cell. Depends on has_gclk.
+ bool is_anyinit;
// Polarities, corresponding to sig_*. True means active-high, false
// means active-low.
bool pol_clk;
@@ -156,6 +161,7 @@ struct FfData {
has_sr = false;
ce_over_srst = false;
is_fine = false;
+ is_anyinit = false;
pol_clk = false;
pol_aload = false;
pol_ce = false;
diff --git a/kernel/log.cc b/kernel/log.cc
index 4bcce3b28..4403dd0c7 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -627,7 +627,7 @@ const char *log_const(const RTLIL::Const &value, bool autoint)
}
}
-const char *log_id(RTLIL::IdString str)
+const char *log_id(const RTLIL::IdString &str)
{
log_id_cache.push_back(strdup(str.c_str()));
const char *p = log_id_cache.back();
diff --git a/kernel/log.h b/kernel/log.h
index ea14028dd..3bc9fd978 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -237,7 +237,7 @@ void log_check_expected();
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
const char *log_const(const RTLIL::Const &value, bool autoint = true);
-const char *log_id(RTLIL::IdString id);
+const char *log_id(const RTLIL::IdString &id);
template<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {
if (nullstr && obj == nullptr)
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index dc4ea9a78..5211c3b3f 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -199,11 +199,6 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
return res;
}
-RTLIL::Const::Const()
-{
- flags = RTLIL::CONST_FLAG_NONE;
-}
-
RTLIL::Const::Const(const std::string &str)
{
flags = RTLIL::CONST_FLAG_STRING;
@@ -395,12 +390,12 @@ bool RTLIL::Const::is_onehot(int *pos) const
return found;
}
-bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const
+bool RTLIL::AttrObject::has_attribute(const RTLIL::IdString &id) const
{
return attributes.count(id);
}
-void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
+void RTLIL::AttrObject::set_bool_attribute(const RTLIL::IdString &id, bool value)
{
if (value)
attributes[id] = RTLIL::Const(1);
@@ -408,7 +403,7 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
attributes.erase(id);
}
-bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
+bool RTLIL::AttrObject::get_bool_attribute(const RTLIL::IdString &id) const
{
const auto it = attributes.find(id);
if (it == attributes.end())
@@ -416,7 +411,7 @@ bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
return it->second.as_bool();
}
-void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value)
+void RTLIL::AttrObject::set_string_attribute(const RTLIL::IdString& id, string value)
{
if (value.empty())
attributes.erase(id);
@@ -424,7 +419,7 @@ void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value)
attributes[id] = value;
}
-string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const
+string RTLIL::AttrObject::get_string_attribute(const RTLIL::IdString &id) const
{
std::string value;
const auto it = attributes.find(id);
@@ -433,7 +428,7 @@ string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const
return value;
}
-void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
+void RTLIL::AttrObject::set_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data)
{
string attrval;
for (const auto &s : data) {
@@ -444,7 +439,7 @@ void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<str
set_string_attribute(id, attrval);
}
-void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
+void RTLIL::AttrObject::add_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data)
{
pool<string> union_data = get_strpool_attribute(id);
union_data.insert(data.begin(), data.end());
@@ -452,7 +447,7 @@ void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool<str
set_strpool_attribute(id, union_data);
}
-pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const
+pool<string> RTLIL::AttrObject::get_strpool_attribute(const RTLIL::IdString &id) const
{
pool<string> data;
if (attributes.count(id) != 0)
@@ -477,7 +472,7 @@ vector<string> RTLIL::AttrObject::get_hdlname_attribute() const
return split_tokens(get_string_attribute(ID::hdlname), " ");
}
-void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector<int> &data)
+void RTLIL::AttrObject::set_intvec_attribute(const RTLIL::IdString& id, const vector<int> &data)
{
std::stringstream attrval;
for (auto &i : data) {
@@ -488,7 +483,7 @@ void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector<in
attributes[id] = RTLIL::Const(attrval.str());
}
-vector<int> RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const
+vector<int> RTLIL::AttrObject::get_intvec_attribute(const RTLIL::IdString &id) const
{
vector<int> data;
auto it = attributes.find(id);
@@ -506,7 +501,7 @@ vector<int> RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const
return data;
}
-bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
+bool RTLIL::Selection::selected_module(const RTLIL::IdString &mod_name) const
{
if (full_selection)
return true;
@@ -517,7 +512,7 @@ bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
return false;
}
-bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const
+bool RTLIL::Selection::selected_whole_module(const RTLIL::IdString &mod_name) const
{
if (full_selection)
return true;
@@ -526,7 +521,7 @@ bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const
return false;
}
-bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const
+bool RTLIL::Selection::selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const
{
if (full_selection)
return true;
@@ -638,12 +633,12 @@ RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_);
}
-RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name)
+RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name)
{
return modules_.count(name) ? modules_.at(name) : NULL;
}
-const RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) const
+const RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) const
{
return modules_.count(name) ? modules_.at(name) : NULL;
}
@@ -825,7 +820,7 @@ void RTLIL::Design::optimize()
it.second.optimize(this);
}
-bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const
+bool RTLIL::Design::selected_module(const RTLIL::IdString& mod_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
@@ -834,7 +829,7 @@ bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const
return selection_stack.back().selected_module(mod_name);
}
-bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const
+bool RTLIL::Design::selected_whole_module(const RTLIL::IdString& mod_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
@@ -843,7 +838,7 @@ bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const
return selection_stack.back().selected_whole_module(mod_name);
}
-bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const
+bool RTLIL::Design::selected_member(const RTLIL::IdString& mod_name, const RTLIL::IdString& memb_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
@@ -987,7 +982,7 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, const dict<RTLIL::IdString
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
}
-size_t RTLIL::Module::count_id(RTLIL::IdString id)
+size_t RTLIL::Module::count_id(const RTLIL::IdString& id)
{
return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id);
}
@@ -1012,7 +1007,7 @@ namespace {
cell->name.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str());
}
- int param(RTLIL::IdString name)
+ int param(const RTLIL::IdString& name)
{
auto it = cell->parameters.find(name);
if (it == cell->parameters.end())
@@ -1021,7 +1016,7 @@ namespace {
return it->second.as_int();
}
- int param_bool(RTLIL::IdString name)
+ int param_bool(const RTLIL::IdString& name)
{
int v = param(name);
if (GetSize(cell->parameters.at(name)) > 32)
@@ -1031,7 +1026,7 @@ namespace {
return v;
}
- int param_bool(RTLIL::IdString name, bool expected)
+ int param_bool(const RTLIL::IdString& name, bool expected)
{
int v = param_bool(name);
if (v != expected)
@@ -1039,14 +1034,14 @@ namespace {
return v;
}
- void param_bits(RTLIL::IdString name, int width)
+ void param_bits(const RTLIL::IdString& name, int width)
{
param(name);
if (GetSize(cell->parameters.at(name).bits) != width)
error(__LINE__);
}
- void port(RTLIL::IdString name, int width)
+ void port(const RTLIL::IdString& name, int width)
{
auto it = cell->connections_.find(name);
if (it == cell->connections_.end())
@@ -1637,6 +1632,13 @@ namespace {
return;
}
+ if (cell->type.in(ID($anyinit))) {
+ port(ID::D, param(ID::WIDTH));
+ port(ID::Q, param(ID::WIDTH));
+ check_expected();
+ return;
+ }
+
if (cell->type == ID($equiv)) {
port(ID::A, 1);
port(ID::B, 1);
@@ -3125,6 +3127,16 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, const RTLIL::S
return cell;
}
+RTLIL::Cell* RTLIL::Module::addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src)
+{
+ RTLIL::Cell *cell = addCell(name, ID($anyinit));
+ cell->parameters[ID::WIDTH] = sig_q.size();
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->set_src_attribute(src);
+ return cell;
+}
+
RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID, width);
@@ -3259,12 +3271,12 @@ std::map<unsigned int, RTLIL::Cell*> *RTLIL::Cell::get_all_cells(void)
}
#endif
-bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const
+bool RTLIL::Cell::hasPort(const RTLIL::IdString& portname) const
{
return connections_.count(portname) != 0;
}
-void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
+void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname)
{
RTLIL::SigSpec signal;
auto conn_it = connections_.find(portname);
@@ -3287,7 +3299,7 @@ void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
}
}
-void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
+void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal)
{
auto r = connections_.insert(portname);
auto conn_it = r.first;
@@ -3309,7 +3321,7 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
conn_it->second = std::move(signal);
}
-const RTLIL::SigSpec &RTLIL::Cell::getPort(RTLIL::IdString portname) const
+const RTLIL::SigSpec &RTLIL::Cell::getPort(const RTLIL::IdString& portname) const
{
return connections_.at(portname);
}
@@ -3328,7 +3340,7 @@ bool RTLIL::Cell::known() const
return false;
}
-bool RTLIL::Cell::input(RTLIL::IdString portname) const
+bool RTLIL::Cell::input(const RTLIL::IdString& portname) const
{
if (yosys_celltypes.cell_known(type))
return yosys_celltypes.cell_input(type, portname);
@@ -3340,7 +3352,7 @@ bool RTLIL::Cell::input(RTLIL::IdString portname) const
return false;
}
-bool RTLIL::Cell::output(RTLIL::IdString portname) const
+bool RTLIL::Cell::output(const RTLIL::IdString& portname) const
{
if (yosys_celltypes.cell_known(type))
return yosys_celltypes.cell_output(type, portname);
@@ -3352,22 +3364,22 @@ bool RTLIL::Cell::output(RTLIL::IdString portname) const
return false;
}
-bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const
+bool RTLIL::Cell::hasParam(const RTLIL::IdString& paramname) const
{
return parameters.count(paramname) != 0;
}
-void RTLIL::Cell::unsetParam(RTLIL::IdString paramname)
+void RTLIL::Cell::unsetParam(const RTLIL::IdString& paramname)
{
parameters.erase(paramname);
}
-void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value)
+void RTLIL::Cell::setParam(const RTLIL::IdString& paramname, RTLIL::Const value)
{
parameters[paramname] = std::move(value);
}
-const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const
+const RTLIL::Const &RTLIL::Cell::getParam(const RTLIL::IdString& paramname) const
{
const auto &it = parameters.find(paramname);
if (it != parameters.end())
@@ -3472,61 +3484,6 @@ bool RTLIL::Cell::is_mem_cell() const
return type.in(ID($mem), ID($mem_v2)) || has_memid();
}
-RTLIL::SigChunk::SigChunk()
-{
- wire = NULL;
- width = 0;
- offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(const RTLIL::Const &value)
-{
- wire = NULL;
- data = value.bits;
- width = GetSize(data);
- offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire)
-{
- log_assert(wire != nullptr);
- this->wire = wire;
- this->width = wire->width;
- this->offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int offset, int width)
-{
- log_assert(wire != nullptr);
- this->wire = wire;
- this->width = width;
- this->offset = offset;
-}
-
-RTLIL::SigChunk::SigChunk(const std::string &str)
-{
- wire = NULL;
- data = RTLIL::Const(str).bits;
- width = GetSize(data);
- offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(int val, int width)
-{
- wire = NULL;
- data = RTLIL::Const(val, width).bits;
- this->width = GetSize(data);
- offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width)
-{
- wire = NULL;
- data = RTLIL::Const(bit, width).bits;
- this->width = GetSize(data);
- offset = 0;
-}
-
RTLIL::SigChunk::SigChunk(const RTLIL::SigBit &bit)
{
wire = bit.wire;
@@ -3538,11 +3495,6 @@ RTLIL::SigChunk::SigChunk(const RTLIL::SigBit &bit)
width = 1;
}
-RTLIL::SigChunk::SigChunk(const RTLIL::SigChunk &sigchunk)
-{
- *this = sigchunk;
-}
-
RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const
{
RTLIL::SigChunk ret;
@@ -3588,17 +3540,6 @@ bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const
return true;
}
-RTLIL::SigSpec::SigSpec()
-{
- width_ = 0;
- hash_ = 0;
-}
-
-RTLIL::SigSpec::SigSpec(const RTLIL::SigSpec &other)
-{
- *this = other;
-}
-
RTLIL::SigSpec::SigSpec(std::initializer_list<RTLIL::SigSpec> parts)
{
cover("kernel.rtlil.sigspec.init.list");
@@ -3613,23 +3554,26 @@ RTLIL::SigSpec::SigSpec(std::initializer_list<RTLIL::SigSpec> parts)
append(*it--);
}
-RTLIL::SigSpec &RTLIL::SigSpec::operator=(const RTLIL::SigSpec &other)
+RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
{
- cover("kernel.rtlil.sigspec.assign");
+ cover("kernel.rtlil.sigspec.init.const");
- width_ = other.width_;
- hash_ = other.hash_;
- chunks_ = other.chunks_;
- bits_ = other.bits_;
- return *this;
+ if (GetSize(value) != 0) {
+ chunks_.emplace_back(value);
+ width_ = chunks_.back().width;
+ } else {
+ width_ = 0;
+ }
+ hash_ = 0;
+ check();
}
-RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
+RTLIL::SigSpec::SigSpec(RTLIL::Const &&value)
{
- cover("kernel.rtlil.sigspec.init.const");
+ cover("kernel.rtlil.sigspec.init.const.move");
if (GetSize(value) != 0) {
- chunks_.emplace_back(value);
+ chunks_.emplace_back(std::move(value));
width_ = chunks_.back().width;
} else {
width_ = 0;
@@ -3652,6 +3596,20 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
check();
}
+RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk)
+{
+ cover("kernel.rtlil.sigspec.init.chunk.move");
+
+ if (chunk.width != 0) {
+ chunks_.emplace_back(std::move(chunk));
+ width_ = chunks_.back().width;
+ } else {
+ width_ = 0;
+ }
+ hash_ = 0;
+ check();
+}
+
RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire)
{
cover("kernel.rtlil.sigspec.init.wire");
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 7a0b6b9c7..27ffdff1f 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -168,7 +168,7 @@ namespace RTLIL
log_assert(p[1] != 0);
for (const char *c = p; *c; c++)
if ((unsigned)*c <= (unsigned)' ')
- log_error("Found control character or space (0x%02hhx) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
+ log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
#ifndef YOSYS_NO_IDS_REFCNT
if (global_free_idx_list_.empty()) {
@@ -414,11 +414,11 @@ namespace RTLIL
return str.substr(1);
}
- static inline std::string unescape_id(RTLIL::IdString str) {
+ static inline std::string unescape_id(const RTLIL::IdString &str) {
return unescape_id(str.str());
}
- static inline const char *id2cstr(RTLIL::IdString str) {
+ static inline const char *id2cstr(const RTLIL::IdString &str) {
return log_id(str);
}
@@ -435,11 +435,26 @@ namespace RTLIL
};
struct sort_by_id_str {
- bool operator()(RTLIL::IdString a, RTLIL::IdString b) const {
+ bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const {
return strcmp(a.c_str(), b.c_str()) < 0;
}
};
+ static inline std::string encode_filename(const std::string &filename)
+ {
+ std::stringstream val;
+ if (!std::any_of(filename.begin(), filename.end(), [](char c) {
+ return static_cast<unsigned char>(c) < 33 || static_cast<unsigned char>(c) > 126;
+ })) return filename;
+ for (unsigned char const c : filename) {
+ if (c < 33 || c > 126)
+ val << stringf("$%02x", c);
+ else
+ val << c;
+ }
+ return val.str();
+ }
+
// see calc.cc for the implementation of this functions
RTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
@@ -635,7 +650,7 @@ struct RTLIL::Const
int flags;
std::vector<RTLIL::State> bits;
- Const();
+ Const() : flags(RTLIL::CONST_FLAG_NONE) {}
Const(const std::string &str);
Const(int val, int width = 32);
Const(RTLIL::State bit, int width = 1);
@@ -696,21 +711,21 @@ struct RTLIL::AttrObject
{
dict<RTLIL::IdString, RTLIL::Const> attributes;
- bool has_attribute(RTLIL::IdString id) const;
+ bool has_attribute(const RTLIL::IdString &id) const;
- void set_bool_attribute(RTLIL::IdString id, bool value=true);
- bool get_bool_attribute(RTLIL::IdString id) const;
+ void set_bool_attribute(const RTLIL::IdString &id, bool value=true);
+ bool get_bool_attribute(const RTLIL::IdString &id) const;
bool get_blackbox_attribute(bool ignore_wb=false) const {
return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
}
- void set_string_attribute(RTLIL::IdString id, string value);
- string get_string_attribute(RTLIL::IdString id) const;
+ void set_string_attribute(const RTLIL::IdString& id, string value);
+ string get_string_attribute(const RTLIL::IdString &id) const;
- void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
- void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
- pool<string> get_strpool_attribute(RTLIL::IdString id) const;
+ void set_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);
+ void add_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);
+ pool<string> get_strpool_attribute(const RTLIL::IdString &id) const;
void set_src_attribute(const std::string &src) {
set_string_attribute(ID::src, src);
@@ -722,8 +737,8 @@ struct RTLIL::AttrObject
void set_hdlname_attribute(const vector<string> &hierarchy);
vector<string> get_hdlname_attribute() const;
- void set_intvec_attribute(RTLIL::IdString id, const vector<int> &data);
- vector<int> get_intvec_attribute(RTLIL::IdString id) const;
+ void set_intvec_attribute(const RTLIL::IdString& id, const vector<int> &data);
+ vector<int> get_intvec_attribute(const RTLIL::IdString &id) const;
};
struct RTLIL::SigChunk
@@ -732,16 +747,15 @@ struct RTLIL::SigChunk
std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0
int width, offset;
- SigChunk();
- SigChunk(const RTLIL::Const &value);
- SigChunk(RTLIL::Wire *wire);
- SigChunk(RTLIL::Wire *wire, int offset, int width = 1);
- SigChunk(const std::string &str);
- SigChunk(int val, int width = 32);
- SigChunk(RTLIL::State bit, int width = 1);
+ SigChunk() : wire(nullptr), width(0), offset(0) {}
+ SigChunk(const RTLIL::Const &value) : wire(nullptr), data(value.bits), width(GetSize(data)), offset(0) {}
+ SigChunk(RTLIL::Const &&value) : wire(nullptr), data(std::move(value.bits)), width(GetSize(data)), offset(0) {}
+ SigChunk(RTLIL::Wire *wire) : wire(wire), width(GetSize(wire)), offset(0) {}
+ SigChunk(RTLIL::Wire *wire, int offset, int width = 1) : wire(wire), width(width), offset(offset) {}
+ SigChunk(const std::string &str) : SigChunk(RTLIL::Const(str)) {}
+ SigChunk(int val, int width = 32) : SigChunk(RTLIL::Const(val, width)) {}
+ SigChunk(RTLIL::State bit, int width = 1) : SigChunk(RTLIL::Const(bit, width)) {}
SigChunk(const RTLIL::SigBit &bit);
- SigChunk(const RTLIL::SigChunk &sigchunk);
- RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default;
RTLIL::SigChunk extract(int offset, int length) const;
inline int size() const { return width; }
@@ -827,13 +841,13 @@ private:
friend struct RTLIL::Module;
public:
- SigSpec();
- SigSpec(const RTLIL::SigSpec &other);
+ SigSpec() : width_(0), hash_(0) {}
SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
- RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other);
SigSpec(const RTLIL::Const &value);
+ SigSpec(RTLIL::Const &&value);
SigSpec(const RTLIL::SigChunk &chunk);
+ SigSpec(RTLIL::SigChunk &&chunk);
SigSpec(RTLIL::Wire *wire);
SigSpec(RTLIL::Wire *wire, int offset, int width = 1);
SigSpec(const std::string &str);
@@ -846,21 +860,6 @@ public:
SigSpec(const std::set<RTLIL::SigBit> &bits);
explicit SigSpec(bool bit);
- SigSpec(RTLIL::SigSpec &&other) {
- width_ = other.width_;
- hash_ = other.hash_;
- chunks_ = std::move(other.chunks_);
- bits_ = std::move(other.bits_);
- }
-
- const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) {
- width_ = other.width_;
- hash_ = other.hash_;
- chunks_ = std::move(other.chunks_);
- bits_ = std::move(other.bits_);
- return *this;
- }
-
size_t get_hash() const {
if (!hash_) hash();
return hash_;
@@ -985,9 +984,9 @@ struct RTLIL::Selection
Selection(bool full = true) : full_selection(full) { }
- bool selected_module(RTLIL::IdString mod_name) const;
- bool selected_whole_module(RTLIL::IdString mod_name) const;
- bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const;
+ bool selected_module(const RTLIL::IdString &mod_name) const;
+ bool selected_whole_module(const RTLIL::IdString &mod_name) const;
+ bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;
void optimize(RTLIL::Design *design);
template<typename T1> void select(T1 *module) {
@@ -1053,11 +1052,11 @@ struct RTLIL::Design
~Design();
RTLIL::ObjRange<RTLIL::Module*> modules();
- RTLIL::Module *module(RTLIL::IdString name);
- const RTLIL::Module *module(RTLIL::IdString name) const;
+ RTLIL::Module *module(const RTLIL::IdString &name);
+ const RTLIL::Module *module(const RTLIL::IdString &name) const;
RTLIL::Module *top_module();
- bool has(RTLIL::IdString id) const {
+ bool has(const RTLIL::IdString &id) const {
return modules_.count(id) != 0;
}
@@ -1082,9 +1081,9 @@ struct RTLIL::Design
void check();
void optimize();
- bool selected_module(RTLIL::IdString mod_name) const;
- bool selected_whole_module(RTLIL::IdString mod_name) const;
- bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const;
+ bool selected_module(const RTLIL::IdString &mod_name) const;
+ bool selected_whole_module(const RTLIL::IdString &mod_name) const;
+ bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;
bool selected_module(RTLIL::Module *mod) const;
bool selected_whole_module(RTLIL::Module *mod) const;
@@ -1165,7 +1164,7 @@ public:
virtual ~Module();
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, bool mayfail = false);
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail = false);
- virtual size_t count_id(RTLIL::IdString id);
+ virtual size_t count_id(const RTLIL::IdString& id);
virtual void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
virtual bool reprocess_if_necessary(RTLIL::Design *design);
@@ -1200,20 +1199,20 @@ public:
return design->selected_member(name, member->name);
}
- RTLIL::Wire* wire(RTLIL::IdString id) {
+ RTLIL::Wire* wire(const RTLIL::IdString &id) {
auto it = wires_.find(id);
return it == wires_.end() ? nullptr : it->second;
}
- RTLIL::Cell* cell(RTLIL::IdString id) {
+ RTLIL::Cell* cell(const RTLIL::IdString &id) {
auto it = cells_.find(id);
return it == cells_.end() ? nullptr : it->second;
}
- const RTLIL::Wire* wire(RTLIL::IdString id) const{
+ const RTLIL::Wire* wire(const RTLIL::IdString &id) const{
auto it = wires_.find(id);
return it == wires_.end() ? nullptr : it->second;
}
- const RTLIL::Cell* cell(RTLIL::IdString id) const {
+ const RTLIL::Cell* cell(const RTLIL::IdString &id) const {
auto it = cells_.find(id);
return it == cells_.end() ? nullptr : it->second;
}
@@ -1376,6 +1375,8 @@ public:
RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,
RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
+ RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = "");
+
// The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
@@ -1483,6 +1484,10 @@ public:
#endif
};
+inline int GetSize(RTLIL::Wire *wire) {
+ return wire->width;
+}
+
struct RTLIL::Memory : public RTLIL::AttrObject
{
unsigned int hashidx_;
@@ -1521,22 +1526,22 @@ public:
dict<RTLIL::IdString, RTLIL::Const> parameters;
// access cell ports
- bool hasPort(RTLIL::IdString portname) const;
- void unsetPort(RTLIL::IdString portname);
- void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal);
- const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const;
+ bool hasPort(const RTLIL::IdString &portname) const;
+ void unsetPort(const RTLIL::IdString &portname);
+ void setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal);
+ const RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) const;
const dict<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
// information about cell ports
bool known() const;
- bool input(RTLIL::IdString portname) const;
- bool output(RTLIL::IdString portname) const;
+ bool input(const RTLIL::IdString &portname) const;
+ bool output(const RTLIL::IdString &portname) const;
// access cell parameters
- bool hasParam(RTLIL::IdString paramname) const;
- void unsetParam(RTLIL::IdString paramname);
- void setParam(RTLIL::IdString paramname, RTLIL::Const value);
- const RTLIL::Const &getParam(RTLIL::IdString paramname) const;
+ bool hasParam(const RTLIL::IdString &paramname) const;
+ void unsetParam(const RTLIL::IdString &paramname);
+ void setParam(const RTLIL::IdString &paramname, RTLIL::Const value);
+ const RTLIL::Const &getParam(const RTLIL::IdString &paramname) const;
void sort();
void check();
diff --git a/kernel/satgen.cc b/kernel/satgen.cc
index 9c40ec66d..05eeca76e 100644
--- a/kernel/satgen.cc
+++ b/kernel/satgen.cc
@@ -1176,7 +1176,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
return true;
}
- if (timestep > 0 && RTLIL::builtin_ff_cell_types().count(cell->type))
+ if (timestep > 0 && (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)))
{
FfData ff(nullptr, cell);
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 64d2b4def..a56a066fe 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -534,11 +534,6 @@ std::string escape_filename_spaces(const std::string& filename)
return out;
}
-int GetSize(RTLIL::Wire *wire)
-{
- return wire->width;
-}
-
bool already_setup = false;
void yosys_setup()
@@ -774,6 +769,10 @@ struct TclPass : public Pass {
log("If any arguments are specified, these arguments are provided to the script via\n");
log("the standard $argc and $argv variables.\n");
log("\n");
+ log("Note, tcl will not recieve the output of any yosys command. If the output\n");
+ log("of the tcl commands are needed, use the yosys command 'tee' to redirect yosys's\n");
+ log("output to a temporary file.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *) override {
if (args.size() < 2)
@@ -867,6 +866,35 @@ std::string proc_self_dirname()
{
return "/";
}
+#elif defined(__OpenBSD__)
+char yosys_path[PATH_MAX];
+char *yosys_argv0;
+
+std::string proc_self_dirname(void)
+{
+ char buf[PATH_MAX + 1] = "", *path, *p;
+ // if case argv[0] contains a valid path, return it
+ if (strlen(yosys_path) > 0) {
+ p = strrchr(yosys_path, '/');
+ snprintf(buf, sizeof buf, "%*s/", (int)(yosys_path - p), yosys_path);
+ return buf;
+ }
+ // if argv[0] does not, reconstruct the path out of $PATH
+ path = strdup(getenv("PATH"));
+ if (!path)
+ log_error("getenv(\"PATH\") failed: %s\n", strerror(errno));
+ for (p = strtok(path, ":"); p; p = strtok(NULL, ":")) {
+ snprintf(buf, sizeof buf, "%s/%s", p, yosys_argv0);
+ if (access(buf, X_OK) == 0) {
+ *(strrchr(buf, '/') + 1) = '\0';
+ free(path);
+ return buf;
+ }
+ }
+ free(path);
+ log_error("Can't determine yosys executable path\n.");
+ return NULL;
+}
#else
#error "Don't know how to determine process executable base path!"
#endif
diff --git a/kernel/yosys.h b/kernel/yosys.h
index 448f896d4..b5b1553f2 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -287,7 +287,7 @@ void remove_directory(std::string dirname);
std::string escape_filename_spaces(const std::string& filename);
template<typename T> int GetSize(const T &obj) { return obj.size(); }
-int GetSize(RTLIL::Wire *wire);
+inline int GetSize(RTLIL::Wire *wire);
extern int autoidx;
extern int yosys_xtrace;
diff --git a/libs/fst/config.h b/libs/fst/config.h
index cd036f16a..a2f0fca82 100644
--- a/libs/fst/config.h
+++ b/libs/fst/config.h
@@ -21,7 +21,7 @@
#undef HAVE_LIBPTHREAD
#undef HAVE_FSEEKO
#endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#undef HAVE_ALLOCA_H
#endif
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index 3c9fb31cc..86b1f6a9a 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -603,7 +603,7 @@ Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} c
\begin{fixme}
Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}, {\tt \$cover}, {\tt \$equiv},
-{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells.
+{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$anyinit}, {\tt \$allconst}, {\tt \$allseq} cells.
\end{fixme}
\begin{fixme}
diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex
index edc8af6e6..bc25c35cd 100644
--- a/manual/command-reference-manual.tex
+++ b/manual/command-reference-manual.tex
@@ -2256,6 +2256,16 @@ and simulus signal from FST file
number of clock cycles to simulate (default: 20)
\end{lstlisting}
+\section{gatemate\_foldinv -- fold inverters into Gatemate LUT trees}
+\label{cmd:gatemate_foldinv}
+\begin{lstlisting}[numbers=left,frame=single]
+ gatemate_foldinv [selection]
+
+
+This pass searches for $__CC_NOT cells and folds them into CC_LUT2, CC_L2T4
+and CC_L2T5 cells as created by LUT tree mapping.
+\end{lstlisting}
+
\section{glift -- create GLIFT models and optimization problems}
\label{cmd:glift}
\begin{lstlisting}[numbers=left,frame=single]
@@ -2379,6 +2389,9 @@ resolves positional module parameters, unrolls array instances, and more.
like -check, but also throw an error if blackbox modules are
instantiated, and throw an error if the design has no top module.
+ -smtcheck
+ like -simcheck, but allow smtlib2_module modules.
+
-purge_lib
by default the hierarchy command will not remove library (blackbox)
modules. use this option to also remove unused blackbox modules.
@@ -2597,7 +2610,7 @@ Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode.
\begin{lstlisting}[numbers=left,frame=single]
jny [options] [selection]
-Write a JSON netlist metadata for the current design
+Write JSON netlist metadata for the current design
-o <filename>
write to the specified file.
@@ -2947,6 +2960,12 @@ pass to word-wide DFFs and address decoders.
-iattr
for -attr, ignore case of <value>.
+
+ -rom-only
+ only perform conversion for ROMs (memories with no write ports).
+
+ -keepdc
+ when mapping ROMs, keep x-bits shared across read ports.
\end{lstlisting}
\section{memory\_memx -- emulate vlog sim behavior for mem ports}
@@ -3992,6 +4011,9 @@ Read cells from liberty file as modules into current design.
-lib
only create empty blackbox modules
+ -wb
+ mark imported cells as whiteboxes
+
-nooverwrite
ignore re-definitions of modules. (the default behavior is to
create an error message if the existing module is not a blackbox
@@ -4223,10 +4245,12 @@ Assign names auto-generated from the src attribute to all selected wires and
cells with private names.
- rename -wire [selection]
+ rename -wire [selection] [-suffix <suffix>]
Assign auto-generated names based on the wires they drive to all selected
cells with private names. Ignores cells driving privatly named wires.
+By default, the cell is named after the wire with the cell type as suffix.
+The -suffix option can be used to set the suffix to the given string instead.
rename -enumerate [-pattern <pattern>] [selection]
@@ -5985,6 +6009,9 @@ This command runs synthesis for Cologne Chip AG GateMate FPGAs.
-nomx8, -nomx4
do not use CC_MX{8,4} multiplexer cells in output netlist.
+ -luttree
+ use new LUT tree mapping approach (EXPERIMENTAL).
+
-dff
run 'abc' with -dff option
@@ -6064,7 +6091,11 @@ The following commands are executed by this synthesis command:
techmap -map +/gatemate/mux_map.v
map_luts:
- abc -dress -lut 4
+ abc -genlib +/gatemate/lut_tree_cells.genlib (with -luttree)
+ techmap -map +/gatemate/lut_tree_map.v (with -luttree)
+ gatemate_foldinv (with -luttree)
+ techmap -map +/gatemate/inv_map.v (with -luttree)
+ abc -dress -lut 4 (without -luttree)
clean
map_cells:
@@ -7379,6 +7410,10 @@ in order to avoid a name collision with the built in commands.
If any arguments are specified, these arguments are provided to the script via
the standard $argc and $argv variables.
+
+Note, tcl will not recieve the output of any yosys command. If the output
+of the tcl commands are needed, use the yosys command 'tee' to redirect yosys's
+output to a temporary file.
\end{lstlisting}
\section{techmap -- generic technology mapper}
@@ -7898,6 +7933,9 @@ Import options:
-v, -vv
Verbose log messages. (-vv is even more verbose than -v.)
+ -pp <filename>
+ Pretty print design after elaboration to specified file.
+
The following additional import options are useful for debugging the Verific
bindings (for Yosys and/or Verific developers):
@@ -7938,50 +7976,6 @@ Pretty print options:
Save output for VHDL design units.
- verific -app <application>..
-
-Execute YosysHQ formal application on loaded Verilog files.
-
-Application options:
-
- -module <module>
- Run formal application only on specified module.
-
- -blacklist <filename[:lineno]>
- Do not run application on modules from files that match the filename
- or filename and line number if provided in such format.
- Parameter can also contain comma separated list of file locations.
-
- -blfile <file>
- Do not run application on locations specified in file, they can
- represent filename or filename and location in file.
-
-Applications:
-
- WARNING: Applications only available in commercial build.
-
-
- verific -template <name> <top_module>..
-
-Generate template for specified top module of loaded design.
-
-Template options:
-
- -out
- Specifies output file for generated template, by default output is stdout
-
- -chparam name value
- Generate template using this parameter value. Otherwise default parameter
- values will be used for templat generate functionality. This option
- can be specified multiple times to override multiple parameters.
- String values must be passed in double quotes (").
-
-Templates:
-
- WARNING: Templates only available in commercial build.
-
-
-
verific -cfg [<name> [<value>]]
Get/set Verific runtime flags.
@@ -8537,6 +8531,8 @@ http://bygone.clairexen.net/intersynth/
\begin{lstlisting}[numbers=left,frame=single]
jny [options] [selection]
+Write JSON netlist metadata for the current design
+
-no-connections
Don't include connection information in the netlist output.
@@ -8546,7 +8542,8 @@ http://bygone.clairexen.net/intersynth/
-no-properties
Don't include property information in the netlist output.
-Write a JSON metadata for the current design
+The JSON schema for JNY output files is located in the "jny.schema.json" file
+which is located at "https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json"
\end{lstlisting}
\section{write\_json -- write design to a JSON file}
diff --git a/misc/jny.schema.json b/misc/jny.schema.json
new file mode 100644
index 000000000..0fff8ee57
--- /dev/null
+++ b/misc/jny.schema.json
@@ -0,0 +1,193 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json",
+ "title": "Yosys JSON Netlist metadata",
+ "description": "Yosys JSON Netlist",
+ "type": "object",
+ "properties": {
+ "generator": {
+ "type": "string",
+ "description": "JNY File Generator"
+ },
+ "version": {
+ "type": "string",
+ "description": "JNY Version"
+ },
+ "invocation": {
+ "type": "string",
+ "description": "Invocation line that generated the JNY metadata"
+ },
+ "features": {
+ "type": "array",
+ "description": "What information is contained in the JNY file",
+ "items": {
+ "type": "string"
+ }
+ },
+ "modules": {
+ "type": "array",
+ "items": { "$ref": "#/$defs/module" }
+ }
+ },
+ "required": [
+ "generator",
+ "version",
+ "invocation",
+ "features"
+ ],
+ "$defs": {
+ "module": {
+ "type": "object",
+ "description": "Module definition",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Module Name"
+ },
+ "cell_sorts": {
+ "type": "array",
+ "description": "",
+ "items": { "$ref": "#/$defs/cell_sort" }
+ },
+ "connections": {
+ "type": "array",
+ "description": "Cell connections",
+ "items": { "$ref": "#/$defs/connection" }
+ },
+ "attributes": {
+ "type": "object",
+ "description": "Attributes attached to the module"
+ },
+ "parameters": {
+ "type": "object",
+ "description": "Parameters attached to the module"
+ }
+ },
+ "required": [
+ "name",
+ "cell_sorts"
+ ]
+ },
+ "cell_sort": {
+ "type": "object",
+ "description": "Describes a type of cell",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Type of cell"
+ },
+ "ports": {
+ "type": "array",
+ "description": "Cell ports",
+ "items": { "$ref": "#/$defs/port" }
+ }
+ ,
+ "cells": {
+ "type": "array",
+ "description": "Cells of cell_sort",
+ "items": { "$ref": "#/$defs/cell" }
+ }
+ },
+ "required": [
+ "type",
+ "ports",
+ "cells"
+ ]
+ },
+ "connection": {
+ "type": "object",
+ "description": "A connection within a module or cell",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Connection name"
+ },
+ "signals": {
+ "type": "array",
+ "description": "Signals that compose the connection",
+ "items": { "$ref": "#/$defs/signal" }
+ }
+ },
+ "required": [
+ "name",
+ "signals"
+ ]
+ },
+ "port": {
+ "type": "object",
+ "description": "Cell port description",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Port name"
+ },
+ "direction": {
+ "type": "string",
+ "description": "Port direction",
+ "enum": ["i", "o", "io", ""]
+ },
+ "range": {
+ "type": "array",
+ "description": "Port width [MSB, LSB]",
+ "items": {
+ "type": "number"
+ },
+ "minContains": 1,
+ "maxContains": 2
+ }
+ },
+ "required": [
+ "name",
+ "direction",
+ "range"
+ ]
+ },
+ "cell": {
+ "type": "object",
+ "description": "Module cell definition",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Cell name"
+ },
+ "connections": {
+ "type": "array",
+ "description": "Cell connections",
+ "items": { "$ref": "#/$defs/connection" }
+ },
+ "attributes": {
+ "type": "object",
+ "description": "Attributes attached to the cell"
+ },
+ "parameters": {
+ "type": "object",
+ "description": "Parameters attached to the cell"
+ }
+ },
+ "required": [
+ "name"
+ ]
+ },
+ "signal": {
+ "type": "object",
+ "description": "A signal definition",
+ "parameters": {
+ "width": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": ["wire", "chunk"]
+ },
+ "const": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "width",
+ "type",
+ "const"
+ ]
+ }
+ }
+}
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 81da35ffe..45576c91c 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -20,6 +20,7 @@
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
+#include "kernel/hashlib.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -105,6 +106,60 @@ static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, strin
return name + suffix;
}
+static bool rename_witness(RTLIL::Design *design, dict<RTLIL::Module *, int> &cache, RTLIL::Module *module)
+{
+ auto cached = cache.find(module);
+ if (cached != cache.end()) {
+ if (cached->second == -1)
+ log_error("Cannot rename witness signals in a design containing recursive instantiations.\n");
+ return cached->second;
+ }
+ cache.emplace(module, -1);
+
+ bool has_witness_signals = false;
+ for (auto cell : module->cells())
+ {
+ RTLIL::Module *impl = design->module(cell->type);
+ if (impl != nullptr) {
+ bool witness_in_cell = rename_witness(design, cache, impl);
+ has_witness_signals |= witness_in_cell;
+ if (witness_in_cell && !cell->name.isPublic()) {
+ std::string name = cell->name.c_str() + 1;
+ for (auto &c : name)
+ if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_')
+ c = '_';
+ auto new_id = module->uniquify("\\_witness_." + name);
+ cell->set_hdlname_attribute({ "_witness_", strstr(new_id.c_str(), ".") + 1 });
+ module->rename(cell, new_id);
+ }
+ }
+
+ if (cell->type.in(ID($anyconst), ID($anyseq), ID($anyinit), ID($allconst), ID($allseq))) {
+ has_witness_signals = true;
+ auto QY = cell->type == ID($anyinit) ? ID::Q : ID::Y;
+ auto sig_out = cell->getPort(QY);
+
+ for (auto chunk : sig_out.chunks()) {
+ if (chunk.is_wire() && !chunk.wire->name.isPublic()) {
+ std::string name = stringf("%s_%s", cell->type.c_str() + 1, cell->name.c_str() + 1);
+ for (auto &c : name)
+ if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_')
+ c = '_';
+ auto new_id = module->uniquify("\\_witness_." + name);
+ auto new_wire = module->addWire(new_id, GetSize(sig_out));
+ new_wire->set_hdlname_attribute({ "_witness_", strstr(new_id.c_str(), ".") + 1 });
+ module->connect({sig_out, new_wire});
+ cell->setPort(QY, new_wire);
+ break;
+ }
+ }
+ }
+ }
+
+ cache[module] = has_witness_signals;
+ return has_witness_signals;
+}
+
struct RenamePass : public Pass {
RenamePass() : Pass("rename", "rename object in the design") { }
void help() override
@@ -146,6 +201,14 @@ struct RenamePass : public Pass {
log("pattern is '_%%_'.\n");
log("\n");
log("\n");
+ log(" rename -witness\n");
+ log("\n");
+ log("Assigns auto-generated names to all $any*/$all* output wires and containing\n");
+ log("cells that do not have a public name. This ensures that, during formal\n");
+ log("verification, a solver-found trace can be fully specified using a public\n");
+ log("hierarchical names.\n");
+ log("\n");
+ log("\n");
log(" rename -hide [selection]\n");
log("\n");
log("Assign private names (the ones with $-prefix) to all selected wires and cells\n");
@@ -156,6 +219,13 @@ struct RenamePass : public Pass {
log("\n");
log("Rename top module.\n");
log("\n");
+ log("\n");
+ log(" rename -scramble-name [-seed <seed>] [selection]\n");
+ log("\n");
+ log("Assign randomly-generated names to all selected wires and cells. The seed option\n");
+ log("can be used to change the random number generator seed from the default, but it\n");
+ log("must be non-zero.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
@@ -164,10 +234,13 @@ struct RenamePass : public Pass {
bool flag_src = false;
bool flag_wire = false;
bool flag_enumerate = false;
+ bool flag_witness = false;
bool flag_hide = false;
bool flag_top = false;
bool flag_output = false;
+ bool flag_scramble_name = false;
bool got_mode = false;
+ unsigned int seed = 1;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -193,6 +266,11 @@ struct RenamePass : public Pass {
got_mode = true;
continue;
}
+ if (arg == "-witness" && !got_mode) {
+ flag_witness = true;
+ got_mode = true;
+ continue;
+ }
if (arg == "-hide" && !got_mode) {
flag_hide = true;
got_mode = true;
@@ -203,6 +281,11 @@ struct RenamePass : public Pass {
got_mode = true;
continue;
}
+ if (arg == "-scramble-name" && !got_mode) {
+ flag_scramble_name = true;
+ got_mode = 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);
@@ -211,6 +294,11 @@ struct RenamePass : public Pass {
}
if (arg == "-suffix" && argidx + 1 < args.size()) {
cell_suffix = args[++argidx];
+ continue;
+ }
+ if (arg == "-seed" && argidx+1 < args.size()) {
+ seed = std::stoi(args[++argidx]);
+ continue;
}
break;
}
@@ -289,6 +377,19 @@ struct RenamePass : public Pass {
}
}
else
+ if (flag_witness)
+ {
+ extra_args(args, argidx, design, false);
+
+ RTLIL::Module *module = design->top_module();
+
+ if (module == nullptr)
+ log_cmd_error("No top module found!\n");
+
+ dict<RTLIL::Module *, int> cache;
+ rename_witness(design, cache, module);
+ }
+ else
if (flag_hide)
{
extra_args(args, argidx, design);
@@ -329,6 +430,42 @@ struct RenamePass : public Pass {
design->rename(module, new_name);
}
else
+ if (flag_scramble_name)
+ {
+ extra_args(args, argidx, design);
+
+ if (seed == 0)
+ log_error("Seed for -scramble-name cannot be zero.\n");
+
+ for (auto module : design->selected_modules())
+ {
+ if (module->memories.size() != 0 || module->processes.size() != 0) {
+ log_warning("Skipping module %s with unprocessed memories or processes\n", log_id(module));
+ continue;
+ }
+
+ dict<RTLIL::Wire *, IdString> new_wire_names;
+ dict<RTLIL::Cell *, IdString> new_cell_names;
+
+ for (auto wire : module->selected_wires())
+ if (wire->port_id == 0) {
+ seed = mkhash_xorshift(seed);
+ new_wire_names[wire] = stringf("$_%u_", seed);
+ }
+
+ for (auto cell : module->selected_cells()) {
+ seed = mkhash_xorshift(seed);
+ new_cell_names[cell] = stringf("$_%u_", seed);
+ }
+
+ for (auto &it : new_wire_names)
+ module->rename(it.first, it.second);
+
+ for (auto &it : new_cell_names)
+ module->rename(it.first, it.second);
+ }
+ }
+ else
{
if (argidx+2 != args.size())
log_cmd_error("Invalid number of arguments!\n");
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index a078b0b1c..590a7eb1d 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -20,6 +20,7 @@
#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
+#include "kernel/mem.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
@@ -478,6 +479,29 @@ struct SetundefPass : public Pass {
log_assert(ffbits.empty());
}
+ if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST)
+ {
+ // Do not add anyseq / anyconst to unused memory port clocks
+ std::vector<Mem> memories = Mem::get_selected_memories(module);
+ for (auto &mem : memories) {
+ bool changed = false;
+ for (auto &rd_port : mem.rd_ports) {
+ if (!rd_port.clk_enable && rd_port.clk.is_fully_undef()) {
+ changed = true;
+ rd_port.clk = State::S0;
+ }
+ }
+ for (auto &wr_port : mem.rd_ports) {
+ if (!wr_port.clk_enable && wr_port.clk.is_fully_undef()) {
+ changed = true;
+ wr_port.clk = State::S0;
+ }
+ }
+ if (changed)
+ mem.emit();
+ }
+ }
+
module->rewrite_sigspecs(worker);
if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST)
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 43deba47b..4d5605932 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -574,6 +574,7 @@ struct ShowWorker
{
ct.setup_internals();
ct.setup_internals_mem();
+ ct.setup_internals_anyinit();
ct.setup_stdcells();
ct.setup_stdcells_mem();
ct.setup_design(design);
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index c858c8631..a4984597d 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -17,10 +17,13 @@
*
*/
+#include <iterator>
+
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "passes/techmap/libparse.h"
#include "kernel/cost.h"
+#include "libs/json11/json11.hpp"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -32,14 +35,14 @@ struct statdata_t
#define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area)
- #define X(_name) int _name;
+ #define X(_name) unsigned int _name;
STAT_INT_MEMBERS
#undef X
double area;
string tech;
std::map<RTLIL::IdString, int> techinfo;
- std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
+ std::map<RTLIL::IdString, unsigned int, RTLIL::sort_by_id_str> num_cells_by_type;
std::set<RTLIL::IdString> unknown_cell_area;
statdata_t operator+(const statdata_t &other) const
@@ -53,7 +56,7 @@ struct statdata_t
return sum;
}
- statdata_t operator*(int other) const
+ statdata_t operator*(unsigned int other) const
{
statdata_t sum = *this;
#define X(_name) sum._name *= other;
@@ -148,17 +151,17 @@ struct statdata_t
void log_data(RTLIL::IdString mod_name, bool top_mod)
{
- log(" Number of wires: %6d\n", num_wires);
- log(" Number of wire bits: %6d\n", num_wire_bits);
- log(" Number of public wires: %6d\n", num_pub_wires);
- log(" Number of public wire bits: %6d\n", num_pub_wire_bits);
- log(" Number of memories: %6d\n", num_memories);
- log(" Number of memory bits: %6d\n", num_memory_bits);
- log(" Number of processes: %6d\n", num_processes);
- log(" Number of cells: %6d\n", num_cells);
+ log(" Number of wires: %6u\n", num_wires);
+ log(" Number of wire bits: %6u\n", num_wire_bits);
+ log(" Number of public wires: %6u\n", num_pub_wires);
+ log(" Number of public wire bits: %6u\n", num_pub_wire_bits);
+ log(" Number of memories: %6u\n", num_memories);
+ log(" Number of memory bits: %6u\n", num_memory_bits);
+ log(" Number of processes: %6u\n", num_processes);
+ log(" Number of cells: %6u\n", num_cells);
for (auto &it : num_cells_by_type)
if (it.second)
- log(" %-26s %6d\n", log_id(it.first), it.second);
+ log(" %-26s %6u\n", log_id(it.first), it.second);
if (!unknown_cell_area.empty()) {
log("\n");
@@ -173,13 +176,13 @@ struct statdata_t
if (tech == "xilinx")
{
- int lut6_cnt = num_cells_by_type[ID(LUT6)];
- int lut5_cnt = num_cells_by_type[ID(LUT5)];
- int lut4_cnt = num_cells_by_type[ID(LUT4)];
- int lut3_cnt = num_cells_by_type[ID(LUT3)];
- int lut2_cnt = num_cells_by_type[ID(LUT2)];
- int lut1_cnt = num_cells_by_type[ID(LUT1)];
- int lc_cnt = 0;
+ unsigned int lut6_cnt = num_cells_by_type[ID(LUT6)];
+ unsigned int lut5_cnt = num_cells_by_type[ID(LUT5)];
+ unsigned int lut4_cnt = num_cells_by_type[ID(LUT4)];
+ unsigned int lut3_cnt = num_cells_by_type[ID(LUT3)];
+ unsigned int lut2_cnt = num_cells_by_type[ID(LUT2)];
+ unsigned int lut1_cnt = num_cells_by_type[ID(LUT1)];
+ unsigned int lc_cnt = 0;
lc_cnt += lut6_cnt;
@@ -221,12 +224,12 @@ struct statdata_t
lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2;
log("\n");
- log(" Estimated number of LCs: %10d\n", lc_cnt);
+ log(" Estimated number of LCs: %10u\n", lc_cnt);
}
if (tech == "cmos")
{
- int tran_cnt = 0;
+ unsigned int tran_cnt = 0;
bool tran_cnt_exact = true;
auto &gate_costs = CellCosts::cmos_gate_cost();
@@ -243,20 +246,48 @@ struct statdata_t
}
log("\n");
- log(" Estimated number of transistors: %10d%s\n", tran_cnt, tran_cnt_exact ? "" : "+");
+ log(" Estimated number of transistors: %10u%s\n", tran_cnt, tran_cnt_exact ? "" : "+");
}
}
+
+ void log_data_json(const char *mod_name, bool first_module)
+ {
+ if (!first_module)
+ log(",\n");
+ log(" %s: {\n", json11::Json(mod_name).dump().c_str());
+ log(" \"num_wires\": %u,\n", num_wires);
+ log(" \"num_wire_bits\": %u,\n", num_wire_bits);
+ log(" \"num_pub_wires\": %u,\n", num_pub_wires);
+ log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits);
+ log(" \"num_memories\": %u,\n", num_memories);
+ log(" \"num_memory_bits\": %u,\n", num_memory_bits);
+ log(" \"num_processes\": %u,\n", num_processes);
+ log(" \"num_cells\": %u,\n", num_cells);
+ log(" \"num_cells_by_type\": {\n");
+ bool first_line = true;
+ for (auto &it : num_cells_by_type)
+ if (it.second) {
+ if (!first_line)
+ log(",\n");
+ log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second);
+ first_line = false;
+ }
+ log("\n");
+ log(" }\n");
+ log(" }");
+ }
};
-statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level)
+statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level, bool quiet = false)
{
statdata_t mod_data = mod_stat.at(mod);
- std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
+ std::map<RTLIL::IdString, unsigned int, RTLIL::sort_by_id_str> num_cells_by_type;
num_cells_by_type.swap(mod_data.num_cells_by_type);
for (auto &it : num_cells_by_type)
if (mod_stat.count(it.first) > 0) {
- log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, log_id(it.first), it.second);
+ if (!quiet)
+ log(" %*s%-*s %6u\n", 2*level, "", 26-2*level, log_id(it.first), it.second);
mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second;
mod_data.num_cells -= it.second;
} else {
@@ -314,12 +345,16 @@ struct StatPass : public Pass {
log(" annotate internal cell types with their word width.\n");
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
log("\n");
+ log(" -json\n");
+ log(" output the statistics in a machine-readable JSON format.\n");
+ log(" this is output to the console; use \"tee\" to output to a file.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Printing statistics.\n");
- bool width_mode = false;
+ bool width_mode = false, json_mode = false;
RTLIL::Module *top_mod = nullptr;
std::map<RTLIL::IdString, statdata_t> mod_stat;
dict<IdString, double> cell_area;
@@ -348,13 +383,27 @@ struct StatPass : public Pass {
top_mod = design->module(RTLIL::escape_id(args[++argidx]));
continue;
}
+ if (args[argidx] == "-json") {
+ json_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- if (techname != "" && techname != "xilinx" && techname != "cmos")
+ if (techname != "" && techname != "xilinx" && techname != "cmos" && !json_mode)
log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
+ if (json_mode) {
+ log("{\n");
+ log(" \"creator\": %s,\n", json11::Json(yosys_version_str).dump().c_str());
+ std::stringstream invocation;
+ std::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " "));
+ log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str());
+ log(" \"modules\": {\n");
+ }
+
+ bool first_module = true;
for (auto mod : design->selected_modules())
{
if (!top_mod && design->full_selection())
@@ -364,23 +413,40 @@ struct StatPass : public Pass {
statdata_t data(design, mod, width_mode, cell_area, techname);
mod_stat[mod->name] = data;
+ if (json_mode) {
+ data.log_data_json(mod->name.c_str(), first_module);
+ first_module = false;
+ } else {
+ log("\n");
+ log("=== %s%s ===\n", log_id(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
+ log("\n");
+ data.log_data(mod->name, false);
+ }
+ }
+
+ if (json_mode) {
log("\n");
- log("=== %s%s ===\n", log_id(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
- log("\n");
- data.log_data(mod->name, false);
+ log(" },\n");
}
- if (top_mod != nullptr && GetSize(mod_stat) > 1)
+ if (top_mod != nullptr)
{
- log("\n");
- log("=== design hierarchy ===\n");
- log("\n");
+ if (!json_mode && GetSize(mod_stat) > 1) {
+ log("\n");
+ log("=== design hierarchy ===\n");
+ log("\n");
+ log(" %-28s %6d\n", log_id(top_mod->name), 1);
+ }
- log(" %-28s %6d\n", log_id(top_mod->name), 1);
- statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0);
+ statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode);
+
+ if (json_mode)
+ data.log_data_json("design", true);
+ else if (GetSize(mod_stat) > 1) {
+ log("\n");
+ data.log_data(top_mod->name, true);
+ }
- log("\n");
- data.log_data(top_mod->name, true);
design->scratchpad_set_int("stat.num_wires", data.num_wires);
design->scratchpad_set_int("stat.num_wire_bits", data.num_wire_bits);
design->scratchpad_set_int("stat.num_pub_wires", data.num_pub_wires);
@@ -392,6 +458,11 @@ struct StatPass : public Pass {
design->scratchpad_set_int("stat.area", data.area);
}
+ if (json_mode) {
+ log("\n");
+ log("}\n");
+ }
+
log("\n");
}
} StatPass;
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index a2d38a0bd..f829714c4 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -280,6 +280,7 @@ struct FsmDetectPass : public Pass {
CellTypes ct;
ct.setup_internals();
+ ct.setup_internals_anyinit();
ct.setup_internals_mem();
ct.setup_stdcells();
ct.setup_stdcells_mem();
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index d40d6e59f..d27fddf1c 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -439,7 +439,8 @@ void check_cell_connections(const RTLIL::Module &module, RTLIL::Cell &cell, RTLI
}
}
-bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
+bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, bool flag_smtcheck,
+ std::vector<std::string> &libdirs)
{
bool did_something = false;
std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
@@ -477,7 +478,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
RTLIL::Module *mod = design->module(cell->type);
if (!mod)
{
- mod = get_module(*design, *cell, *module, flag_check || flag_simcheck, libdirs);
+ mod = get_module(*design, *cell, *module, flag_check || flag_simcheck || flag_smtcheck, libdirs);
// If we still don't have a module, treat the cell as a black box and skip
// it. Otherwise, we either loaded or derived something so should set the
@@ -495,11 +496,11 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
// interfaces.
if_expander.visit_connections(*cell, *mod);
- if (flag_check || flag_simcheck)
+ if (flag_check || flag_simcheck || flag_smtcheck)
check_cell_connections(*module, *cell, *mod);
if (mod->get_blackbox_attribute()) {
- if (flag_simcheck)
+ if (flag_simcheck || (flag_smtcheck && !mod->get_bool_attribute(ID::smtlib2_module)))
log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n",
cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue;
@@ -737,6 +738,9 @@ struct HierarchyPass : public Pass {
log(" like -check, but also throw an error if blackbox modules are\n");
log(" instantiated, and throw an error if the design has no top module.\n");
log("\n");
+ log(" -smtcheck\n");
+ log(" like -simcheck, but allow smtlib2_module modules.\n");
+ log("\n");
log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n");
log(" modules. use this option to also remove unused blackbox modules.\n");
@@ -803,6 +807,7 @@ struct HierarchyPass : public Pass {
bool flag_check = false;
bool flag_simcheck = false;
+ bool flag_smtcheck = false;
bool purge_lib = false;
RTLIL::Module *top_mod = NULL;
std::string load_top_mod;
@@ -821,7 +826,7 @@ struct HierarchyPass : public Pass {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
- if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !top_mod) {
+ if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !flag_smtcheck && !top_mod) {
generate_mode = true;
log("Entering generate mode.\n");
while (++argidx < args.size()) {
@@ -868,6 +873,10 @@ struct HierarchyPass : public Pass {
flag_simcheck = true;
continue;
}
+ if (args[argidx] == "-smtcheck") {
+ flag_smtcheck = true;
+ continue;
+ }
if (args[argidx] == "-purge_lib") {
purge_lib = true;
continue;
@@ -1013,7 +1022,7 @@ struct HierarchyPass : public Pass {
}
}
- if (flag_simcheck && top_mod == nullptr)
+ if ((flag_simcheck || flag_smtcheck) && top_mod == nullptr)
log_error("Design has no top module.\n");
if (top_mod != NULL) {
@@ -1039,7 +1048,7 @@ struct HierarchyPass : public Pass {
}
for (auto module : used_modules) {
- if (expand_module(design, module, flag_check, flag_simcheck, libdirs))
+ if (expand_module(design, module, flag_check, flag_simcheck, flag_smtcheck, libdirs))
did_something = true;
}
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index 845dc850f..c0c40671d 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -260,6 +260,7 @@ struct SubmodWorker
}
ct.setup_internals();
+ ct.setup_internals_anyinit();
ct.setup_internals_mem();
ct.setup_stdcells();
ct.setup_stdcells_mem();
diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc
index 898e0af85..9e147b0bf 100644
--- a/passes/memory/memory_libmap.cc
+++ b/passes/memory/memory_libmap.cc
@@ -837,7 +837,7 @@ void MemMapping::handle_priority() {
if (!port2.priority_mask[p1idx])
continue;
for (auto &cfg: cfgs) {
- auto &p1cfg = cfg.rd_ports[p1idx];
+ auto &p1cfg = cfg.wr_ports[p1idx];
auto &p2cfg = cfg.wr_ports[p2idx];
bool found = false;
for (auto &pgi: p2cfg.def->wrprio) {
@@ -1706,10 +1706,11 @@ void MemMapping::emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, cons
if (pdef.wrbe_separate) {
cell->setPort(stringf("\\PORT_%s_WR_EN", name), State::S0);
cell->setPort(stringf("\\PORT_%s_WR_BE", name), hw_wren);
- cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren));
+ if (cfg.def->width_mode != WidthMode::Single)
+ cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren));
} else {
cell->setPort(stringf("\\PORT_%s_WR_EN", name), hw_wren);
- if (cfg.def->byte != 0)
+ if (cfg.def->byte != 0 && cfg.def->width_mode != WidthMode::Single)
cell->setParam(stringf("\\PORT_%s_WR_EN_WIDTH", name), GetSize(hw_wren));
}
}
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index ca1ca483d..e2f74c2e1 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -30,6 +30,9 @@ PRIVATE_NAMESPACE_BEGIN
struct MemoryMapWorker
{
bool attr_icase = false;
+ bool rom_only = false;
+ bool keepdc = false;
+ bool formal = false;
dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes;
RTLIL::Design *design;
@@ -107,11 +110,8 @@ struct MemoryMapWorker
SigSpec init_data = mem.get_init_data();
- // delete unused memory cell
- if (mem.rd_ports.empty()) {
- mem.remove();
+ if (!mem.wr_ports.empty() && rom_only)
return;
- }
// check if attributes allow us to infer FFRAM for this memory
for (const auto &attr : attributes) {
@@ -143,9 +143,17 @@ struct MemoryMapWorker
}
}
+ // delete unused memory cell
+ if (mem.rd_ports.empty()) {
+ mem.remove();
+ return;
+ }
+
// all write ports must share the same clock
RTLIL::SigSpec refclock;
bool refclock_pol = false;
+ bool async_wr = false;
+ bool static_only = true;
for (int i = 0; i < GetSize(mem.wr_ports); i++) {
auto &port = mem.wr_ports[i];
if (port.en.is_fully_const() && !port.en.as_bool()) {
@@ -159,10 +167,20 @@ struct MemoryMapWorker
static_ports.insert(i);
continue;
}
- log("Not mapping memory %s in module %s (write port %d has no clock).\n",
- mem.memid.c_str(), module->name.c_str(), i);
- return;
+ static_only = false;
+ if (GetSize(refclock) != 0)
+ log("Not mapping memory %s in module %s (mixed clocked and async write ports).\n",
+ mem.memid.c_str(), module->name.c_str());
+ if (!formal)
+ log("Not mapping memory %s in module %s (write port %d has no clock).\n",
+ mem.memid.c_str(), module->name.c_str(), i);
+ async_wr = true;
+ continue;
}
+ static_only = false;
+ if (async_wr)
+ log("Not mapping memory %s in module %s (mixed clocked and async write ports).\n",
+ mem.memid.c_str(), module->name.c_str());
if (refclock.size() == 0) {
refclock = port.clk;
refclock_pol = port.clk_polarity;
@@ -180,28 +198,47 @@ struct MemoryMapWorker
std::vector<RTLIL::SigSpec> data_reg_in(1 << abits);
std::vector<RTLIL::SigSpec> data_reg_out(1 << abits);
+ std::vector<RTLIL::SigSpec> &data_read = async_wr ? data_reg_in : data_reg_out;
+
int count_static = 0;
for (int i = 0; i < mem.size; i++)
{
int addr = i + mem.start_offset;
int idx = addr & ((1 << abits) - 1);
+ SigSpec w_init = init_data.extract(i*mem.width, mem.width);
if (static_cells_map.count(addr) > 0)
{
- data_reg_out[idx] = static_cells_map[addr];
+ data_read[idx] = static_cells_map[addr];
count_static++;
}
+ else if (static_only && (!keepdc || w_init.is_fully_def()))
+ {
+ data_read[idx] = w_init;
+ }
else
{
- RTLIL::Cell *c = module->addCell(genid(mem.memid, "", addr), ID($dff));
- c->parameters[ID::WIDTH] = mem.width;
- if (GetSize(refclock) != 0) {
+ RTLIL::Cell *c;
+ auto ff_id = genid(mem.memid, "", addr);
+
+ if (static_only) {
+ // non-static part is a ROM, we only reach this with keepdc
+ if (formal) {
+ c = module->addCell(ff_id, ID($ff));
+ } else {
+ c = module->addCell(ff_id, ID($dff));
+ c->parameters[ID::CLK_POLARITY] = RTLIL::Const(RTLIL::State::S1);
+ c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0));
+ }
+ } else if (async_wr) {
+ log_assert(formal); // General async write not implemented yet, checked against above
+ c = module->addCell(ff_id, ID($ff));
+ } else {
+ c = module->addCell(ff_id, ID($dff));
c->parameters[ID::CLK_POLARITY] = RTLIL::Const(refclock_pol);
c->setPort(ID::CLK, refclock);
- } else {
- c->parameters[ID::CLK_POLARITY] = RTLIL::Const(RTLIL::State::S1);
- c->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::S0));
}
+ c->parameters[ID::WIDTH] = mem.width;
RTLIL::Wire *w_in = module->addWire(genid(mem.memid, "", addr, "$d"), mem.width);
data_reg_in[idx] = w_in;
@@ -212,17 +249,28 @@ struct MemoryMapWorker
w_out_name = genid(mem.memid, "", addr, "$q");
RTLIL::Wire *w_out = module->addWire(w_out_name, mem.width);
- SigSpec w_init = init_data.extract(i*mem.width, mem.width);
+
+ if (formal && mem.packed && mem.cell->name.c_str()[0] == '\\') {
+ auto hdlname = mem.cell->get_hdlname_attribute();
+ if (hdlname.empty())
+ hdlname.push_back(mem.cell->name.c_str() + 1);
+ hdlname.push_back(stringf("[%d]", addr));
+ w_out->set_hdlname_attribute(hdlname);
+ }
if (!w_init.is_fully_undef())
w_out->attributes[ID::init] = w_init.as_const();
data_reg_out[idx] = w_out;
c->setPort(ID::Q, w_out);
+
+ if (static_only)
+ module->connect(RTLIL::SigSig(w_in, w_out));
}
}
- log(" created %d $dff cells and %d static cells of width %d.\n", mem.size-count_static, count_static, mem.width);
+ log(" created %d %s cells and %d static cells of width %d.\n",
+ mem.size-count_static, formal && (static_only || async_wr) ? "$ff" : "$dff", count_static, mem.width);
int count_dff = 0, count_mux = 0, count_wrmux = 0;
@@ -260,75 +308,78 @@ struct MemoryMapWorker
}
for (int j = 0; j < (1 << abits); j++)
- if (data_reg_out[j] != SigSpec())
- module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_reg_out[j]));
+ if (data_read[j] != SigSpec())
+ module->connect(RTLIL::SigSig(rd_signals[j >> port.wide_log2].extract((j & ((1 << port.wide_log2) - 1)) * mem.width, mem.width), data_read[j]));
}
log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
- for (int i = 0; i < mem.size; i++)
+ if (!static_only)
{
- int addr = i + mem.start_offset;
- int idx = addr & ((1 << abits) - 1);
- if (static_cells_map.count(addr) > 0)
- continue;
-
- RTLIL::SigSpec sig = data_reg_out[idx];
-
- for (int j = 0; j < GetSize(mem.wr_ports); j++)
+ for (int i = 0; i < mem.size; i++)
{
- auto &port = mem.wr_ports[j];
- RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2);
- RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr)));
+ int addr = i + mem.start_offset;
+ int idx = addr & ((1 << abits) - 1);
+ if (static_cells_map.count(addr) > 0)
+ continue;
- int sub = addr & ((1 << port.wide_log2) - 1);
+ RTLIL::SigSpec sig = data_reg_out[idx];
- int wr_offset = 0;
- while (wr_offset < mem.width)
+ for (int j = 0; j < GetSize(mem.wr_ports); j++)
{
- int wr_width = 1;
- RTLIL::SigSpec wr_bit = port.en.extract(wr_offset + sub * mem.width, 1);
-
- while (wr_offset + wr_width < mem.width) {
- RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width + sub * mem.width, 1);
- if (next_wr_bit != wr_bit)
- break;
- wr_width++;
- }
+ auto &port = mem.wr_ports[j];
+ RTLIL::SigSpec wr_addr = port.addr.extract_end(port.wide_log2);
+ RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(addr >> port.wide_log2, GetSize(wr_addr)));
- RTLIL::Wire *w = w_seladdr;
+ int sub = addr & ((1 << port.wide_log2) - 1);
- if (wr_bit != State::S1)
+ int wr_offset = 0;
+ while (wr_offset < mem.width)
{
- RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and));
- c->parameters[ID::A_SIGNED] = RTLIL::Const(0);
- c->parameters[ID::B_SIGNED] = RTLIL::Const(0);
- c->parameters[ID::A_WIDTH] = RTLIL::Const(1);
- c->parameters[ID::B_WIDTH] = RTLIL::Const(1);
- c->parameters[ID::Y_WIDTH] = RTLIL::Const(1);
- c->setPort(ID::A, w);
- c->setPort(ID::B, wr_bit);
-
- w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y"));
- c->setPort(ID::Y, RTLIL::SigSpec(w));
+ int wr_width = 1;
+ RTLIL::SigSpec wr_bit = port.en.extract(wr_offset + sub * mem.width, 1);
+
+ while (wr_offset + wr_width < mem.width) {
+ RTLIL::SigSpec next_wr_bit = port.en.extract(wr_offset + wr_width + sub * mem.width, 1);
+ if (next_wr_bit != wr_bit)
+ break;
+ wr_width++;
+ }
+
+ RTLIL::Wire *w = w_seladdr;
+
+ if (wr_bit != State::S1)
+ {
+ RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wren", addr, "", j, "", wr_offset), ID($and));
+ c->parameters[ID::A_SIGNED] = RTLIL::Const(0);
+ c->parameters[ID::B_SIGNED] = RTLIL::Const(0);
+ c->parameters[ID::A_WIDTH] = RTLIL::Const(1);
+ c->parameters[ID::B_WIDTH] = RTLIL::Const(1);
+ c->parameters[ID::Y_WIDTH] = RTLIL::Const(1);
+ c->setPort(ID::A, w);
+ c->setPort(ID::B, wr_bit);
+
+ w = module->addWire(genid(mem.memid, "$wren", addr, "", j, "", wr_offset, "$y"));
+ c->setPort(ID::Y, RTLIL::SigSpec(w));
+ }
+
+ RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux));
+ c->parameters[ID::WIDTH] = wr_width;
+ c->setPort(ID::A, sig.extract(wr_offset, wr_width));
+ c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width));
+ c->setPort(ID::S, RTLIL::SigSpec(w));
+
+ w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width);
+ c->setPort(ID::Y, w);
+
+ sig.replace(wr_offset, w);
+ wr_offset += wr_width;
+ count_wrmux++;
}
-
- RTLIL::Cell *c = module->addCell(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset), ID($mux));
- c->parameters[ID::WIDTH] = wr_width;
- c->setPort(ID::A, sig.extract(wr_offset, wr_width));
- c->setPort(ID::B, port.data.extract(wr_offset + sub * mem.width, wr_width));
- c->setPort(ID::S, RTLIL::SigSpec(w));
-
- w = module->addWire(genid(mem.memid, "$wrmux", addr, "", j, "", wr_offset, "$y"), wr_width);
- c->setPort(ID::Y, w);
-
- sig.replace(wr_offset, w);
- wr_offset += wr_width;
- count_wrmux++;
}
- }
- module->connect(RTLIL::SigSig(data_reg_in[idx], sig));
+ module->connect(RTLIL::SigSig(data_reg_in[idx], sig));
+ }
}
log(" write interface: %d write mux blocks.\n", count_wrmux);
@@ -366,10 +417,25 @@ struct MemoryMapPass : public Pass {
log(" -iattr\n");
log(" for -attr, ignore case of <value>.\n");
log("\n");
+ log(" -rom-only\n");
+ log(" only perform conversion for ROMs (memories with no write ports).\n");
+ log("\n");
+ log(" -keepdc\n");
+ log(" when mapping ROMs, keep x-bits shared across read ports.\n");
+ log("\n");
+ log(" -formal\n");
+ log(" map memories for a global clock based formal verification flow.\n");
+ log(" This implies -keepdc, uses $ff cells for ROMs and sets hdlname\n");
+ log(" attributes. It also has limited support for async write ports\n");
+ log(" as generated by clk2fflogic.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool attr_icase = false;
+ bool rom_only = false;
+ bool keepdc = false;
+ bool formal = false;
dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes;
log_header(design, "Executing MEMORY_MAP pass (converting memories to logic and flip-flops).\n");
@@ -406,6 +472,22 @@ struct MemoryMapPass : public Pass {
attr_icase = true;
continue;
}
+ if (args[argidx] == "-rom-only")
+ {
+ rom_only = true;
+ continue;
+ }
+ if (args[argidx] == "-keepdc")
+ {
+ keepdc = true;
+ continue;
+ }
+ if (args[argidx] == "-formal")
+ {
+ formal = true;
+ keepdc = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -414,6 +496,9 @@ struct MemoryMapPass : public Pass {
MemoryMapWorker worker(design, mod);
worker.attr_icase = attr_icase;
worker.attributes = attributes;
+ worker.rom_only = rom_only;
+ worker.keepdc = keepdc;
+ worker.formal = formal;
worker.run();
}
}
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index cb2c261c4..dde7c5299 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -633,6 +633,7 @@ struct OptCleanPass : public Pass {
keep_cache.reset(design);
ct_reg.setup_internals_mem();
+ ct_reg.setup_internals_anyinit();
ct_reg.setup_stdcells_mem();
ct_all.setup(design);
@@ -694,6 +695,7 @@ struct CleanPass : public Pass {
keep_cache.reset(design);
ct_reg.setup_internals_mem();
+ ct_reg.setup_internals_anyinit();
ct_reg.setup_stdcells_mem();
ct_all.setup(design);
diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc
index 0ad4acec2..6ff2d1b4b 100644
--- a/passes/opt/opt_dff.cc
+++ b/passes/opt/opt_dff.cc
@@ -491,12 +491,17 @@ struct OptDffWorker
ff.has_srst = false;
ff.sig_d = ff.val_srst;
changed = true;
- } else {
+ } else if (!opt.keepdc || ff.val_init.is_fully_def()) {
log("Handling never-active EN on %s (%s) from module %s (removing D path).\n",
log_id(cell), log_id(cell->type), log_id(module));
// The D input path is effectively useless, so remove it (this will be a D latch, SR latch, or a const driver).
ff.has_ce = ff.has_clk = ff.has_srst = false;
changed = true;
+ } else {
+ // We need to keep the undefined initival around as such
+ ff.sig_d = ff.sig_q;
+ ff.has_ce = ff.has_srst = false;
+ changed = true;
}
} else if (ff.sig_ce == (ff.pol_ce ? State::S1 : State::S0)) {
// Always-active enable. Just remove it.
@@ -508,13 +513,20 @@ struct OptDffWorker
}
}
- if (ff.has_clk) {
- if (ff.sig_clk.is_fully_const()) {
+ if (ff.has_clk && ff.sig_clk.is_fully_const()) {
+ if (!opt.keepdc || ff.val_init.is_fully_def()) {
// Const clock — the D input path is effectively useless, so remove it (this will be a D latch, SR latch, or a const driver).
log("Handling const CLK on %s (%s) from module %s (removing D path).\n",
log_id(cell), log_id(cell->type), log_id(module));
ff.has_ce = ff.has_clk = ff.has_srst = false;
changed = true;
+ } else {
+ // Const clock, but we need to keep the undefined initval around as such
+ if (ff.has_ce || ff.has_srst || ff.sig_d != ff.sig_q) {
+ ff.sig_d = ff.sig_q;
+ ff.has_ce = ff.has_srst = false;
+ changed = true;
+ }
}
}
@@ -550,7 +562,7 @@ struct OptDffWorker
ff.has_srst = false;
ff.sig_d = ff.val_srst;
changed = true;
- } else {
+ } else if (!opt.keepdc || ff.val_init.is_fully_def()) {
// The D input path is effectively useless, so remove it (this will be a const-input D latch, SR latch, or a const driver).
log("Handling D = Q on %s (%s) from module %s (removing D path).\n",
log_id(cell), log_id(cell->type), log_id(module));
@@ -567,7 +579,7 @@ struct OptDffWorker
}
// The cell has been simplified as much as possible already. Now try to spice it up with enables / sync resets.
- if (ff.has_clk) {
+ if (ff.has_clk && ff.sig_d != ff.sig_q) {
if (!ff.has_arst && !ff.has_sr && (!ff.has_srst || !ff.has_ce || ff.ce_over_srst) && !opt.nosdff) {
// Try to merge sync resets.
std::map<ctrls_t, std::vector<int>> groups;
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index 1a7c93fbd..c36a38dae 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -594,11 +594,9 @@ struct OptReduceWorker
if (cell->type.in(ID($mux), ID($pmux)))
opt_pmux(cell);
-
- if (cell->type == ID($bmux))
+ else if (cell->type == ID($bmux))
opt_bmux(cell);
-
- if (cell->type == ID($demux))
+ else if (cell->type == ID($demux))
opt_demux(cell);
}
}
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 08ab6de6f..8fd4c788c 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -166,8 +166,8 @@ struct WreduceWorker
for (int i = GetSize(sig_q)-1; i >= 0; i--)
{
- if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx) &&
- (!has_reset || i >= GetSize(rst_value) || rst_value[i] == State::S0 || rst_value[i] == State::Sx)) {
+ if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || (!config->keepdc && initval[i] == State::Sx)) &&
+ (!has_reset || i >= GetSize(rst_value) || rst_value[i] == State::S0 || (!config->keepdc && rst_value[i] == State::Sx))) {
module->connect(sig_q[i], State::S0);
initvals.remove_init(sig_q[i]);
sig_d.remove(i);
@@ -175,8 +175,8 @@ struct WreduceWorker
continue;
}
- if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1] &&
- (!has_reset || i >= GetSize(rst_value) || rst_value[i] == rst_value[i-1])) {
+ if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1] && (!config->keepdc || initval[i] != State::Sx) &&
+ (!has_reset || i >= GetSize(rst_value) || (rst_value[i] == rst_value[i-1] && (!config->keepdc || rst_value[i] != State::Sx)))) {
module->connect(sig_q[i], sig_q[i-1]);
initvals.remove_init(sig_q[i]);
sig_d.remove(i);
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index da6d49433..ebe3dc536 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -10,6 +10,7 @@ OBJS += passes/sat/expose.o
OBJS += passes/sat/assertpmux.o
OBJS += passes/sat/clk2fflogic.o
OBJS += passes/sat/async2sync.o
+OBJS += passes/sat/formalff.o
OBJS += passes/sat/supercover.o
OBJS += passes/sat/fmcombine.o
OBJS += passes/sat/mutate.o
diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc
index 46c76eba9..6fdf470b1 100644
--- a/passes/sat/async2sync.cc
+++ b/passes/sat/async2sync.cc
@@ -75,6 +75,9 @@ struct Async2syncPass : public Pass {
if (ff.has_gclk)
continue;
+ if (ff.has_clk && ff.sig_clk.is_fully_const())
+ ff.has_ce = ff.has_clk = ff.has_srst = false;
+
if (ff.has_clk)
{
if (ff.has_sr) {
diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc
index b1b0567a0..2384ffced 100644
--- a/passes/sat/clk2fflogic.cc
+++ b/passes/sat/clk2fflogic.cc
@@ -233,7 +233,10 @@ struct Clk2fflogicPass : public Pass {
qval = past_q;
}
- if (ff.has_aload) {
+ // The check for a constant sig_aload is also done by opt_dff, but when using verific and running
+ // clk2fflogic before opt_dff (which does more and possibly unwanted optimizations) this check avoids
+ // generating a lot of extra logic.
+ if (ff.has_aload && ff.sig_aload != (ff.pol_aload ? State::S0 : State::S1)) {
SigSpec sig_aload = wrap_async_control(module, ff.sig_aload, ff.pol_aload, ff.is_fine, NEW_ID);
if (!ff.is_fine)
diff --git a/passes/sat/formalff.cc b/passes/sat/formalff.cc
new file mode 100644
index 000000000..209486a37
--- /dev/null
+++ b/passes/sat/formalff.cc
@@ -0,0 +1,549 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 Jannis Harder <jix@yosyshq.com> <me@jix.one>
+ *
+ * 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.h"
+#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
+#include "kernel/ff.h"
+#include "kernel/modtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+
+// Finds signal values with known constant or known unused values in the initial state
+struct InitValWorker
+{
+ Module *module;
+
+ ModWalker modwalker;
+ SigMap &sigmap;
+ FfInitVals initvals;
+
+ dict<RTLIL::SigBit, RTLIL::State> initconst_bits;
+ dict<RTLIL::SigBit, bool> used_bits;
+
+ InitValWorker(Module *module) : module(module), modwalker(module->design), sigmap(modwalker.sigmap)
+ {
+ modwalker.setup(module);
+ initvals.set(&modwalker.sigmap, module);
+
+ for (auto wire : module->wires())
+ if (wire->name.isPublic() || wire->get_bool_attribute(ID::keep))
+ for (auto bit : SigSpec(wire))
+ used_bits[sigmap(bit)] = true;
+ }
+
+ // Sign/Zero-extended indexing of individual port bits
+ static SigBit bit_in_port(RTLIL::Cell *cell, RTLIL::IdString port, RTLIL::IdString sign, int index)
+ {
+ auto sig_port = cell->getPort(port);
+ if (index < GetSize(sig_port))
+ return sig_port[index];
+ else if (cell->getParam(sign).as_bool())
+ return GetSize(sig_port) > 0 ? sig_port[GetSize(sig_port) - 1] : State::Sx;
+ else
+ return State::S0;
+ }
+
+ // Has the signal a known constant value in the initial state?
+ //
+ // For sync-only FFs outputs, this is their initval. For logic loops,
+ // multiple drivers or unknown cells this is Sx. For a small number of
+ // handled cells we recurse through their inputs. All results are cached.
+ RTLIL::State initconst(SigBit bit)
+ {
+ sigmap.apply(bit);
+
+ if (!bit.is_wire())
+ return bit.data;
+
+ auto it = initconst_bits.find(bit);
+ if (it != initconst_bits.end())
+ return it->second;
+
+ // Setting this temporarily to x takes care of any logic loops
+ initconst_bits[bit] = State::Sx;
+
+ pool<ModWalker::PortBit> portbits;
+ modwalker.get_drivers(portbits, {bit});
+
+ if (portbits.size() != 1)
+ return State::Sx;
+
+ ModWalker::PortBit portbit = *portbits.begin();
+ RTLIL::Cell *cell = portbit.cell;
+
+ if (RTLIL::builtin_ff_cell_types().count(cell->type))
+ {
+ FfData ff(&initvals, cell);
+
+ if (ff.has_aload || ff.has_sr || ff.has_arst || (!ff.has_clk && !ff.has_gclk)) {
+ for (auto bit_q : ff.sig_q) {
+ initconst_bits[sigmap(bit_q)] = State::Sx;
+ }
+ return State::Sx;
+ }
+
+ for (int i = 0; i < ff.width; i++) {
+ initconst_bits[sigmap(ff.sig_q[i])] = ff.val_init[i];
+ }
+
+ return ff.val_init[portbit.offset];
+ }
+
+ if (cell->type.in(ID($mux), ID($and), ID($or), ID($eq), ID($eqx), ID($initstate)))
+ {
+ if (cell->type == ID($mux))
+ {
+ SigBit sig_s = sigmap(cell->getPort(ID::S));
+ State init_s = initconst(sig_s);
+ State init_y;
+
+ if (init_s == State::S0) {
+ init_y = initconst(cell->getPort(ID::A)[portbit.offset]);
+ } else if (init_s == State::S1) {
+ init_y = initconst(cell->getPort(ID::B)[portbit.offset]);
+ } else {
+ State init_a = initconst(cell->getPort(ID::A)[portbit.offset]);
+ State init_b = initconst(cell->getPort(ID::B)[portbit.offset]);
+ init_y = init_a == init_b ? init_a : State::Sx;
+ }
+ initconst_bits[bit] = init_y;
+ return init_y;
+ }
+
+ if (cell->type.in(ID($and), ID($or)))
+ {
+ State init_a = initconst(bit_in_port(cell, ID::A, ID::A_SIGNED, portbit.offset));
+ State init_b = initconst(bit_in_port(cell, ID::B, ID::B_SIGNED, portbit.offset));
+ State init_y;
+ if (init_a == init_b)
+ init_y = init_a;
+ else if (cell->type == ID($and) && (init_a == State::S0 || init_b == State::S0))
+ init_y = State::S0;
+ else if (cell->type == ID($or) && (init_a == State::S1 || init_b == State::S1))
+ init_y = State::S1;
+ else
+ init_y = State::Sx;
+
+ initconst_bits[bit] = init_y;
+ return init_y;
+ }
+
+ if (cell->type.in(ID($eq), ID($eqx))) // Treats $eqx as $eq
+ {
+ if (portbit.offset > 0) {
+ initconst_bits[bit] = State::S0;
+ return State::S0;
+ }
+
+ SigSpec sig_a = cell->getPort(ID::A);
+ SigSpec sig_b = cell->getPort(ID::B);
+
+ State init_y = State::S1;
+
+ for (int i = 0; init_y != State::S0 && i < GetSize(sig_a); i++) {
+ State init_ai = initconst(bit_in_port(cell, ID::A, ID::A_SIGNED, i));
+ if (init_ai == State::Sx) {
+ init_y = State::Sx;
+ continue;
+ }
+ State init_bi = initconst(bit_in_port(cell, ID::B, ID::B_SIGNED, i));
+ if (init_bi == State::Sx)
+ init_y = State::Sx;
+ else if (init_ai != init_bi)
+ init_y = State::S0;
+ }
+
+ initconst_bits[bit] = init_y;
+ return init_y;
+ }
+
+ if (cell->type == ID($initstate))
+ {
+ initconst_bits[bit] = State::S1;
+ return State::S1;
+ }
+
+ log_assert(false);
+ }
+
+ return State::Sx;
+ }
+
+ RTLIL::Const initconst(SigSpec sig)
+ {
+ std::vector<RTLIL::State> bits;
+ for (auto bit : sig)
+ bits.push_back(initconst(bit));
+ return bits;
+ }
+
+ // Is the initial value of this signal used?
+ //
+ // An initial value of a signal is considered as used if it a) aliases a
+ // wire with a public name, an output wire or with a keep attribute b)
+ // combinationally drives such a wire or c) drive an input to an unknown
+ // cell.
+ //
+ // This recurses into driven cells for a small number of known handled
+ // celltypes. Results are cached and initconst is used to detect unused
+ // inputs for the handled celltypes.
+ bool is_initval_used(SigBit bit)
+ {
+ if (!bit.is_wire())
+ return false;
+
+ auto it = used_bits.find(bit);
+ if (it != used_bits.end())
+ return it->second;
+
+ used_bits[bit] = true; // Temporarily set to guard against logic loops
+
+ pool<ModWalker::PortBit> portbits;
+ modwalker.get_consumers(portbits, {bit});
+
+ for (auto portbit : portbits) {
+ RTLIL::Cell *cell = portbit.cell;
+ if (!cell->type.in(ID($mux), ID($and), ID($or), ID($mem_v2)) && !RTLIL::builtin_ff_cell_types().count(cell->type)) {
+ return true;
+ }
+ }
+
+ for (auto portbit : portbits)
+ {
+ RTLIL::Cell *cell = portbit.cell;
+ if (RTLIL::builtin_ff_cell_types().count(cell->type))
+ {
+ FfData ff(&initvals, cell);
+ if (ff.has_aload || ff.has_sr || ff.has_arst || ff.has_gclk || !ff.has_clk)
+ return true;
+ if (ff.has_ce && initconst(ff.sig_ce.as_bit()) == (ff.pol_ce ? State::S0 : State::S1))
+ continue;
+ if (ff.has_srst && initconst(ff.sig_ce.as_bit()) == (ff.pol_srst ? State::S1 : State::S0))
+ continue;
+
+ return true;
+ }
+ else if (cell->type == ID($mux))
+ {
+ State init_s = initconst(cell->getPort(ID::S).as_bit());
+ if (init_s == State::S0 && portbit.port == ID::B)
+ continue;
+ if (init_s == State::S1 && portbit.port == ID::A)
+ continue;
+ auto sig_y = cell->getPort(ID::Y);
+
+ if (is_initval_used(sig_y[portbit.offset]))
+ return true;
+ }
+ else if (cell->type.in(ID($and), ID($or)))
+ {
+ auto sig_a = cell->getPort(ID::A);
+ auto sig_b = cell->getPort(ID::B);
+ auto sig_y = cell->getPort(ID::Y);
+ if (GetSize(sig_y) != GetSize(sig_a) || GetSize(sig_y) != GetSize(sig_b))
+ return true; // TODO handle more of this
+ State absorbing = cell->type == ID($and) ? State::S0 : State::S1;
+ if (portbit.port == ID::A && initconst(sig_b[portbit.offset]) == absorbing)
+ continue;
+ if (portbit.port == ID::B && initconst(sig_a[portbit.offset]) == absorbing)
+ continue;
+
+ if (is_initval_used(sig_y[portbit.offset]))
+ return true;
+ }
+ else if (cell->type == ID($mem_v2))
+ {
+ // TODO Use mem.h instead to uniformily cover all cases, most
+ // likely requires processing all memories when initializing
+ // the worker
+ if (!portbit.port.in(ID::WR_DATA, ID::WR_ADDR, ID::RD_ADDR))
+ return true;
+
+ if (portbit.port == ID::WR_DATA)
+ {
+ if (initconst(cell->getPort(ID::WR_EN)[portbit.offset]) == State::S0)
+ continue;
+ }
+ else if (portbit.port == ID::WR_ADDR)
+ {
+ int port = portbit.offset / cell->getParam(ID::ABITS).as_int();
+ auto sig_en = cell->getPort(ID::WR_EN);
+ int width = cell->getParam(ID::WIDTH).as_int();
+
+ for (int i = port * width; i < (port + 1) * width; i++)
+ if (initconst(sig_en[i]) != State::S0)
+ return true;
+
+ continue;
+ }
+ else if (portbit.port == ID::RD_ADDR)
+ {
+ int port = portbit.offset / cell->getParam(ID::ABITS).as_int();
+ auto sig_en = cell->getPort(ID::RD_EN);
+
+ if (initconst(sig_en[port]) != State::S0)
+ return true;
+
+ continue;
+ }
+ else
+ return true;
+ }
+ else
+ log_assert(false);
+ }
+
+ used_bits[bit] = false;
+ return false;
+ }
+};
+
+struct FormalFfPass : public Pass {
+ FormalFfPass() : Pass("formalff", "prepare FFs for formal") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" formalff [options] [selection]\n");
+ log("\n");
+ log("This pass transforms clocked flip-flops to prepare a design for formal\n");
+ log("verification. If a design contains latches and/or multiple different clocks run\n");
+ log("the async2sync or clk2fflogic passes before using this pass.\n");
+ log("\n");
+ log(" -clk2ff\n");
+ log(" Replace all clocked flip-flops with $ff cells that use the implicit\n");
+ log(" global clock. This assumes, without checking, that the design uses a\n");
+ log(" single global clock. If that is not the case, the clk2fflogic pass\n");
+ log(" should be used instead.\n");
+ log("\n");
+ log(" -ff2anyinit\n");
+ log(" Replace uninitialized bits of $ff cells with $anyinit cells. An\n");
+ log(" $anyinit cell behaves exactly like an $ff cell with an undefined\n");
+ log(" initialization value. The difference is that $anyinit inhibits\n");
+ log(" don't-care optimizations and is used to track solver-provided values\n");
+ log(" in witness traces.\n");
+ log("\n");
+ log(" If combined with -clk2ff this also affects newly created $ff cells.\n");
+ log("\n");
+ log(" -anyinit2ff\n");
+ log(" Replaces $anyinit cells with uninitialized $ff cells. This performs the\n");
+ log(" reverse of -ff2anyinit and can be used, before running a backend pass\n");
+ log(" (or similar) that is not yet aware of $anyinit cells.\n");
+ log("\n");
+ log(" Note that after running -anyinit2ff, in general, performing don't-care\n");
+ log(" optimizations is not sound in a formal verification setting.\n");
+ log("\n");
+ log(" -fine\n");
+ log(" Emit fine-grained $_FF_ cells instead of coarse-grained $ff cells for\n");
+ log(" -anyinit2ff. Cannot be combined with -clk2ff or -ff2anyinit.\n");
+ log("\n");
+ log(" -setundef\n");
+ log(" Find FFs with undefined initialization values for which changing the\n");
+ log(" initialization does not change the observable behavior and initialize\n");
+ log(" them. For -ff2anyinit, this reduces the number of generated $anyinit\n");
+ log(" cells that drive wires with private names.\n");
+ log("\n");
+
+ // TODO: An option to check whether all FFs use the same clock before changing it to the global clock
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ bool flag_clk2ff = false;
+ bool flag_ff2anyinit = false;
+ bool flag_anyinit2ff = false;
+ bool flag_fine = false;
+ bool flag_setundef = false;
+
+ log_header(design, "Executing FORMALFF pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-clk2ff") {
+ flag_clk2ff = true;
+ continue;
+ }
+ if (args[argidx] == "-ff2anyinit") {
+ flag_ff2anyinit = true;
+ continue;
+ }
+ if (args[argidx] == "-anyinit2ff") {
+ flag_anyinit2ff = true;
+ continue;
+ }
+ if (args[argidx] == "-fine") {
+ flag_fine = true;
+ continue;
+ }
+ if (args[argidx] == "-setundef") {
+ flag_setundef = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!(flag_clk2ff || flag_ff2anyinit || flag_anyinit2ff))
+ log_cmd_error("One of the options -clk2ff, -ff2anyinit, or -anyinit2ff must be specified.\n");
+
+ if (flag_ff2anyinit && flag_anyinit2ff)
+ log_cmd_error("The options -ff2anyinit and -anyinit2ff are exclusive.\n");
+
+ if (flag_fine && !flag_anyinit2ff)
+ log_cmd_error("The option -fine requries the -anyinit2ff option.\n");
+
+ if (flag_fine && flag_clk2ff)
+ log_cmd_error("The options -fine and -clk2ff are exclusive.\n");
+
+ for (auto module : design->selected_modules())
+ {
+ if (flag_setundef)
+ {
+ InitValWorker worker(module);
+
+ for (auto cell : module->selected_cells())
+ {
+ if (RTLIL::builtin_ff_cell_types().count(cell->type))
+ {
+ FfData ff(&worker.initvals, cell);
+ if (ff.has_aload || ff.has_sr || ff.has_arst || ff.val_init.is_fully_def())
+ continue;
+
+ if (ff.has_ce && // CE can make the initval stick around
+ worker.initconst(ff.sig_ce.as_bit()) != (ff.pol_ce ? State::S1 : State::S0) && // unless it's known active
+ (!ff.has_srst || ff.ce_over_srst ||
+ worker.initconst(ff.sig_srst.as_bit()) != (ff.pol_srst ? State::S1 : State::S0))) // or a srst with priority is known active
+ continue;
+
+ auto before = ff.val_init;
+ for (int i = 0; i < ff.width; i++)
+ if (ff.val_init[i] == State::Sx && !worker.is_initval_used(ff.sig_q[i]))
+ ff.val_init[i] = State::S0;
+
+ if (ff.val_init != before) {
+ log("Setting unused undefined initial value of %s.%s (%s) from %s to %s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_const(before), log_const(ff.val_init));
+ worker.initvals.set_init(ff.sig_q, ff.val_init);
+ }
+ }
+ }
+ }
+ SigMap sigmap(module);
+ FfInitVals initvals(&sigmap, module);
+
+
+ for (auto cell : module->selected_cells())
+ {
+ if (flag_anyinit2ff && cell->type == ID($anyinit))
+ {
+ FfData ff(&initvals, cell);
+ ff.remove();
+ ff.is_anyinit = false;
+ ff.is_fine = flag_fine;
+ if (flag_fine)
+ for (int i = 0; i < ff.width; i++)
+ ff.slice({i}).emit();
+ else
+ ff.emit();
+
+ continue;
+ }
+
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
+ continue;
+
+ FfData ff(&initvals, cell);
+ bool emit = false;
+
+ if (flag_clk2ff && ff.has_clk) {
+ if (ff.sig_clk.is_fully_const())
+ log_error("Const CLK on %s (%s) from module %s, run async2sync first.\n",
+ log_id(cell), log_id(cell->type), log_id(module));
+
+ auto clk_wire = ff.sig_clk.is_wire() ? ff.sig_clk.as_wire() : nullptr;
+
+ if (clk_wire == nullptr) {
+ clk_wire = module->addWire(NEW_ID);
+ module->connect(RTLIL::SigBit(clk_wire), ff.sig_clk);
+ }
+
+ auto clk_polarity = ff.pol_clk ? State::S1 : State::S0;
+
+ std::string attribute = clk_wire->get_string_attribute(ID::replaced_by_gclk);
+
+ auto &attr = clk_wire->attributes[ID::replaced_by_gclk];
+
+ if (!attr.empty() && attr != clk_polarity)
+ log_error("CLK %s on %s (%s) from module %s also used with opposite polarity, run clk2fflogic instead.\n",
+ log_id(clk_wire), log_id(cell), log_id(cell->type), log_id(module));
+
+ attr = clk_polarity;
+ clk_wire->set_bool_attribute(ID::keep);
+
+ // TODO propagate the replaced_by_gclk attribute upwards throughout the hierarchy
+
+ ff.unmap_ce_srst();
+ ff.has_clk = false;
+ ff.has_gclk = true;
+ emit = true;
+ }
+
+ if (!ff.has_gclk) {
+ continue;
+ }
+
+ if (flag_ff2anyinit && !ff.val_init.is_fully_def())
+ {
+ ff.remove();
+ emit = false;
+
+ int cursor = 0;
+ while (cursor < ff.val_init.size())
+ {
+ bool is_anyinit = ff.val_init[cursor] == State::Sx;
+ std::vector<int> bits;
+ bits.push_back(cursor++);
+ while (cursor < ff.val_init.size() && (ff.val_init[cursor] == State::Sx) == is_anyinit)
+ bits.push_back(cursor++);
+
+ if ((int)bits.size() == ff.val_init.size()) {
+ // This check is only to make the private names more helpful for debugging
+ ff.is_anyinit = true;
+ emit = true;
+ break;
+ }
+
+ auto slice = ff.slice(bits);
+ slice.is_anyinit = is_anyinit;
+ slice.emit();
+ }
+ }
+
+ if (emit)
+ ff.emit();
+ }
+ }
+ }
+} FormalFfPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc
index 864d6f05d..1302b3383 100644
--- a/passes/sat/qbfsat.cc
+++ b/passes/sat/qbfsat.cc
@@ -216,7 +216,7 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt,
QbfSolutionType ret;
const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc";
const std::string smtbmc_warning = "z3: WARNING:";
- const std::string smtbmc_cmd = stringf("%s -s %s %s -t 1 -g --binary %s %s/problem%d.smt2 2>&1",
+ const std::string smtbmc_cmd = stringf("\"%s\" -s %s %s -t 1 -g --binary %s %s/problem%d.smt2 2>&1",
yosys_smtbmc_exe.c_str(), opt.get_solver_name().c_str(),
(opt.timeout != 0? stringf("--timeout %d", opt.timeout) : "").c_str(),
(opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file : "").c_str(),
diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc
index d085fab2d..18a25a097 100644
--- a/passes/sat/sim.cc
+++ b/passes/sat/sim.cc
@@ -81,6 +81,7 @@ struct SimShared
bool hide_internal = true;
bool writeback = false;
bool zinit = false;
+ bool hdlname = false;
int rstlen = 1;
FstData *fst = nullptr;
double start_time = 0;
@@ -157,6 +158,7 @@ struct SimInstance
dict<Wire*, pair<int, Const>> signal_database;
dict<Wire*, fstHandle> fst_handles;
+ dict<Wire*, fstHandle> fst_inputs;
dict<IdString, dict<int,fstHandle>> fst_memories;
SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
@@ -230,7 +232,7 @@ struct SimInstance
}
}
- if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
+ if (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)) {
FfData ff_data(nullptr, cell);
ff_state_t ff;
ff.past_d = Const(State::Sx, ff_data.width);
@@ -737,9 +739,17 @@ struct SimInstance
child.second->register_signals(id);
}
- void write_output_header(std::function<void(IdString)> enter_scope, std::function<void()> exit_scope, std::function<void(Wire*, int, bool)> register_signal)
+ void write_output_header(std::function<void(IdString)> enter_scope, std::function<void()> exit_scope, std::function<void(const char*, Wire*, int, bool)> register_signal)
{
- enter_scope(name());
+ int exit_scopes = 1;
+ if (shared->hdlname && instance != nullptr && instance->name.isPublic() && instance->has_attribute(ID::hdlname)) {
+ auto hdlname = instance->get_hdlname_attribute();
+ log_assert(!hdlname.empty());
+ for (auto name : hdlname)
+ enter_scope("\\" + name);
+ exit_scopes = hdlname.size();
+ } else
+ enter_scope(name());
dict<Wire*,bool> registers;
for (auto cell : module->cells())
@@ -755,13 +765,25 @@ struct SimInstance
for (auto signal : signal_database)
{
- register_signal(signal.first, signal.second.first, registers.count(signal.first)!=0);
+ if (shared->hdlname && signal.first->name.isPublic() && signal.first->has_attribute(ID::hdlname)) {
+ auto hdlname = signal.first->get_hdlname_attribute();
+ log_assert(!hdlname.empty());
+ auto signal_name = std::move(hdlname.back());
+ hdlname.pop_back();
+ for (auto name : hdlname)
+ enter_scope("\\" + name);
+ register_signal(signal_name.c_str(), signal.first, signal.second.first, registers.count(signal.first)!=0);
+ for (auto name : hdlname)
+ exit_scope();
+ } else
+ register_signal(log_id(signal.first->name), signal.first, signal.second.first, registers.count(signal.first)!=0);
}
for (auto child : children)
child.second->write_output_header(enter_scope, exit_scope, register_signal);
- exit_scope();
+ for (int i = 0; i < exit_scopes; i++)
+ exit_scope();
}
void register_output_step_values(std::map<int,Const> *data)
@@ -820,7 +842,7 @@ struct SimInstance
return did_something;
}
- void addAdditionalInputs(std::map<Wire*,fstHandle> &inputs)
+ void addAdditionalInputs()
{
for (auto cell : module->cells())
{
@@ -831,7 +853,7 @@ struct SimInstance
for(auto &item : fst_handles) {
if (item.second==0) continue; // Ignore signals not found
if (sig_y == sigmap(item.first)) {
- inputs[sig_y.as_wire()] = item.second;
+ fst_inputs[sig_y.as_wire()] = item.second;
found = true;
break;
}
@@ -842,7 +864,21 @@ struct SimInstance
}
}
for (auto child : children)
- child.second->addAdditionalInputs(inputs);
+ child.second->addAdditionalInputs();
+ }
+
+ bool setInputs()
+ {
+ bool did_something = false;
+ for(auto &item : fst_inputs) {
+ std::string v = shared->fst->valueOf(item.second);
+ did_something |= set_state(item.first, Const::from_string(v));
+ }
+
+ for (auto child : children)
+ did_something |= child.second->setInputs();
+
+ return did_something;
}
void setState(dict<int, std::pair<SigBit,bool>> bits, std::string values)
@@ -1095,18 +1131,17 @@ struct SimWorker : SimShared
}
SigMap sigmap(topmod);
- std::map<Wire*,fstHandle> inputs;
for (auto wire : topmod->wires()) {
if (wire->port_input) {
fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
if (id==0)
log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(wire->name)).c_str());
- inputs[wire] = id;
+ top->fst_inputs[wire] = id;
}
}
- top->addAdditionalInputs(inputs);
+ top->addAdditionalInputs();
uint64_t startCount = 0;
uint64_t stopCount = 0;
@@ -1152,11 +1187,7 @@ struct SimWorker : SimShared
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) {
if (verbose)
log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());
- bool did_something = false;
- for(auto &item : inputs) {
- std::string v = fst->valueOf(item.second);
- did_something |= top->set_state(item.first, Const::from_string(v));
- }
+ bool did_something = top->setInputs();
if (initial) {
did_something |= top->setInitState();
@@ -1702,7 +1733,11 @@ struct VCDWriter : public OutputWriter
worker->top->write_output_header(
[this](IdString name) { vcdfile << stringf("$scope module %s $end\n", log_id(name)); },
[this]() { vcdfile << stringf("$upscope $end\n");},
- [this,use_signal](Wire *wire, int id, bool is_reg) { if (use_signal.at(id)) vcdfile << stringf("$var %s %d n%d %s%s $end\n", is_reg ? "reg" : "wire", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire)); }
+ [this,use_signal](const char *name, Wire *wire, int id, bool is_reg) {
+ if (use_signal.at(id)) {
+ vcdfile << stringf("$var %s %d n%d %s%s $end\n", is_reg ? "reg" : "wire", GetSize(wire), id, name[0] == '$' ? "\\" : "", name);
+ }
+ }
);
vcdfile << stringf("$enddefinitions $end\n");
@@ -1760,11 +1795,10 @@ struct FSTWriter : public OutputWriter
worker->top->write_output_header(
[this](IdString name) { fstWriterSetScope(fstfile, FST_ST_VCD_MODULE, stringf("%s",log_id(name)).c_str(), nullptr); },
[this]() { fstWriterSetUpscope(fstfile); },
- [this,use_signal](Wire *wire, int id, bool is_reg) {
+ [this,use_signal](const char *name, Wire *wire, int id, bool is_reg) {
if (!use_signal.at(id)) return;
fstHandle fst_id = fstWriterCreateVar(fstfile, is_reg ? FST_VT_VCD_REG : FST_VT_VCD_WIRE, FST_VD_IMPLICIT, GetSize(wire),
- stringf("%s%s", wire->name[0] == '$' ? "\\" : "", log_id(wire)).c_str(), 0);
-
+ name, 0);
mapping.emplace(id, fst_id);
}
);
@@ -1846,7 +1880,7 @@ struct AIWWriter : public OutputWriter
worker->top->write_output_header(
[](IdString) {},
[]() {},
- [this](Wire *wire, int id, bool) { mapping[wire] = id; }
+ [this](const char */*name*/, Wire *wire, int id, bool) { mapping[wire] = id; }
);
std::map<int, Yosys::RTLIL::Const> current;
@@ -1935,6 +1969,10 @@ struct SimPass : public Pass {
log(" write the simulation results to an AIGER witness file\n");
log(" (requires a *.aim file via -map)\n");
log("\n");
+ log(" -hdlname\n");
+ log(" use the hdlname attribute when writing simulation results\n");
+ log(" (preserves hierarchy in a flattened design)\n");
+ log("\n");
log(" -x\n");
log(" ignore constant x outputs in simulation file.\n");
log("\n");
@@ -2047,6 +2085,10 @@ struct SimPass : public Pass {
worker.outputfiles.emplace_back(std::unique_ptr<AIWWriter>(new AIWWriter(&worker, aiw_filename.c_str())));
continue;
}
+ if (args[argidx] == "-hdlname") {
+ worker.hdlname = true;
+ continue;
+ }
if (args[argidx] == "-n" && argidx+1 < args.size()) {
numcycles = atoi(args[++argidx].c_str());
worker.cycles_set = true;
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 61ee99ee7..656c36b84 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -65,7 +65,9 @@
#include "frontends/blif/blifparse.h"
#ifdef YOSYS_LINK_ABC
-extern "C" int Abc_RealMain(int argc, char *argv[]);
+namespace abc {
+ int Abc_RealMain(int argc, char *argv[]);
+}
#endif
USING_YOSYS_NAMESPACE
@@ -787,15 +789,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
- std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str());
+ std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", tempdir_name.c_str());
if (!liberty_files.empty() || !genlib_files.empty()) {
for (std::string liberty_file : liberty_files)
- abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
+ abc_script += stringf("read_lib -w \"%s\"; ", liberty_file.c_str());
for (std::string liberty_file : genlib_files)
- abc_script += stringf("read_library %s; ", liberty_file.c_str());
+ abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str());
if (!constr_file.empty())
- abc_script += stringf("read_constr -v %s; ", constr_file.c_str());
+ abc_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str());
} else
if (!lut_costs.empty())
abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
@@ -1083,7 +1085,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fclose(f);
}
- buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
+ buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
#ifndef YOSYS_LINK_ABC
@@ -1098,7 +1100,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
abc_argv[2] = strdup("-f");
abc_argv[3] = strdup(tmp_script_name.c_str());
abc_argv[4] = 0;
- int ret = Abc_RealMain(4, abc_argv);
+ int ret = abc::Abc_RealMain(4, abc_argv);
free(abc_argv[0]);
free(abc_argv[1]);
free(abc_argv[2]);
diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc
index a66e95e21..2f46c89f4 100644
--- a/passes/techmap/abc9_exe.cc
+++ b/passes/techmap/abc9_exe.cc
@@ -31,7 +31,9 @@
#endif
#ifdef YOSYS_LINK_ABC
-extern "C" int Abc_RealMain(int argc, char *argv[]);
+namespace abc {
+ int Abc_RealMain(int argc, char *argv[]);
+}
#endif
std::string fold_abc9_cmd(std::string str)
@@ -173,12 +175,12 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
if (!lut_costs.empty())
abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
else if (!lut_file.empty())
- abc9_script += stringf("read_lut %s; ", lut_file.c_str());
+ abc9_script += stringf("read_lut \"%s\"; ", lut_file.c_str());
else
log_abort();
log_assert(!box_file.empty());
- abc9_script += stringf("read_box %s; ", box_file.c_str());
+ abc9_script += stringf("read_box \"%s\"; ", box_file.c_str());
abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());
if (!script_file.empty()) {
@@ -262,7 +264,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
fclose(f);
}
- buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
+ buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
#ifndef YOSYS_LINK_ABC
@@ -277,7 +279,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
abc9_argv[2] = strdup("-f");
abc9_argv[3] = strdup(tmp_script_name.c_str());
abc9_argv[4] = 0;
- int ret = Abc_RealMain(4, abc9_argv);
+ int ret = abc::Abc_RealMain(4, abc9_argv);
free(abc9_argv[0]);
free(abc9_argv[1]);
free(abc9_argv[2]);
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index b14488ff4..ab9bd7e1d 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -1697,6 +1697,23 @@ assign Y = 'bx;
endmodule
// --------------------------------------------------------
+`ifdef SIMLIB_FF
+module \$anyinit (D, Q);
+
+parameter WIDTH = 0;
+
+input [WIDTH-1:0] D;
+output reg [WIDTH-1:0] Q;
+
+initial Q <= 'bx;
+
+always @($global_clk) begin
+ Q <= D;
+end
+
+endmodule
+`endif
+// --------------------------------------------------------
module \$allconst (Y);
diff --git a/techlibs/gatemate/.gitignore b/techlibs/gatemate/.gitignore
new file mode 100644
index 000000000..f260d6e9d
--- /dev/null
+++ b/techlibs/gatemate/.gitignore
@@ -0,0 +1,4 @@
+lut_tree_cells.genlib
+lut_tree_map.v
+lut_tree_lib.mk
+
diff --git a/techlibs/gatemate/Makefile.inc b/techlibs/gatemate/Makefile.inc
index d1341d7bb..aeb318cc9 100644
--- a/techlibs/gatemate/Makefile.inc
+++ b/techlibs/gatemate/Makefile.inc
@@ -1,5 +1,6 @@
OBJS += techlibs/gatemate/synth_gatemate.o
+OBJS += techlibs/gatemate/gatemate_foldinv.o
$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/reg_map.v))
$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/mux_map.v))
@@ -12,3 +13,18 @@ $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams_map.v))
$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams.txt))
$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams_init_20.vh))
$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/brams_init_40.vh))
+$(eval $(call add_share_file,share/gatemate,techlibs/gatemate/inv_map.v))
+
+EXTRA_OBJS += techlibs/gatemate/lut_tree_lib.mk
+.SECONDARY: techlibs/gatemate/lut_tree_lib.mk
+
+techlibs/gatemate/lut_tree_lib.mk: techlibs/gatemate/make_lut_tree_lib.py
+ $(Q) mkdir -p techlibs/gatemate
+ $(P) $(PYTHON_EXECUTABLE) $<
+ $(Q) touch $@
+
+techlibs/gatemate/lut_tree_cells.genlib: techlibs/gatemate/lut_tree_lib.mk
+techlibs/gatemate/lut_tree_map.v: techlibs/gatemate/lut_tree_lib.mk
+
+$(eval $(call add_gen_share_file,share/gatemate,techlibs/gatemate/lut_tree_cells.genlib))
+$(eval $(call add_gen_share_file,share/gatemate,techlibs/gatemate/lut_tree_map.v))
diff --git a/techlibs/gatemate/cells_sim.v b/techlibs/gatemate/cells_sim.v
index 1de3d1c7a..7e88fd7cf 100644
--- a/techlibs/gatemate/cells_sim.v
+++ b/techlibs/gatemate/cells_sim.v
@@ -1409,3 +1409,47 @@ module CC_BRAM_40K (
end
endgenerate
endmodule
+
+// Models of the LUT2 tree primitives
+module CC_L2T4(
+ output O,
+ input I0, I1, I2, I3
+);
+ parameter [3:0] INIT_L00 = 4'b0000;
+ parameter [3:0] INIT_L01 = 4'b0000;
+ parameter [3:0] INIT_L10 = 4'b0000;
+
+ wire [1:0] l00_s1 = I1 ? INIT_L00[3:2] : INIT_L00[1:0];
+ wire l00 = I0 ? l00_s1[1] : l00_s1[0];
+
+ wire [1:0] l01_s1 = I3 ? INIT_L01[3:2] : INIT_L01[1:0];
+ wire l01 = I2 ? l01_s1[1] : l01_s1[0];
+
+ wire [1:0] l10_s1 = l01 ? INIT_L10[3:2] : INIT_L10[1:0];
+ assign O = l00 ? l10_s1[1] : l10_s1[0];
+
+endmodule
+
+
+module CC_L2T5(
+ output O,
+ input I0, I1, I2, I3, I4
+);
+ parameter [3:0] INIT_L02 = 4'b0000;
+ parameter [3:0] INIT_L03 = 4'b0000;
+ parameter [3:0] INIT_L11 = 4'b0000;
+ parameter [3:0] INIT_L20 = 4'b0000;
+
+ wire [1:0] l02_s1 = I1 ? INIT_L02[3:2] : INIT_L02[1:0];
+ wire l02 = I0 ? l02_s1[1] : l02_s1[0];
+
+ wire [1:0] l03_s1 = I3 ? INIT_L03[3:2] : INIT_L03[1:0];
+ wire l03 = I2 ? l03_s1[1] : l03_s1[0];
+
+ wire [1:0] l11_s1 = l03 ? INIT_L11[3:2] : INIT_L11[1:0];
+ wire l11 = l02 ? l11_s1[1] : l11_s1[0];
+
+ wire [1:0] l20_s1 = l11 ? INIT_L20[3:2] : INIT_L20[1:0];
+ assign O = I4 ? l20_s1[1] : l20_s1[0];
+
+endmodule
diff --git a/techlibs/gatemate/gatemate_foldinv.cc b/techlibs/gatemate/gatemate_foldinv.cc
new file mode 100644
index 000000000..752f8aac0
--- /dev/null
+++ b/techlibs/gatemate/gatemate_foldinv.cc
@@ -0,0 +1,219 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2021 gatecat <gatecat@ds0.me>
+ * Copyright (C) 2021 Cologne Chip AG <support@colognechip.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.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct LUTPin {
+ int input_bit;
+ IdString init_param;
+};
+
+struct LUTType {
+ dict<IdString, LUTPin> inputs;
+ IdString output_param;
+};
+
+struct FoldInvWorker {
+ FoldInvWorker(Module *module) : module(module), sigmap(module) {};
+ Module *module;
+ SigMap sigmap;
+
+ // Mapping from inverter output to inverter input
+ dict<SigBit, SigBit> inverted_bits;
+ // Mapping from inverter input to inverter
+ dict<SigBit, Cell*> inverter_input;
+
+ const dict<IdString, LUTType> lut_types = {
+ {ID(CC_LUT2), {{
+ {ID(I0), {0, ID(INIT)}},
+ {ID(I1), {1, ID(INIT)}},
+ }, ID(INIT)}},
+ {ID(CC_L2T4), {{
+ {ID(I0), {0, ID(INIT_L00)}},
+ {ID(I1), {1, ID(INIT_L00)}},
+ {ID(I2), {0, ID(INIT_L01)}},
+ {ID(I3), {1, ID(INIT_L01)}},
+ }, ID(INIT_L10)}},
+ {ID(CC_L2T5), {{
+ {ID(I0), {0, ID(INIT_L02)}},
+ {ID(I1), {1, ID(INIT_L02)}},
+ {ID(I2), {0, ID(INIT_L03)}},
+ {ID(I3), {1, ID(INIT_L03)}},
+ {ID(I4), {0, ID(INIT_L20)}},
+ }, ID(INIT_L20)}},
+ };
+
+
+ void find_inverted_bits()
+ {
+ for (auto cell : module->selected_cells()) {
+ if (cell->type != ID($__CC_NOT))
+ continue;
+ SigBit a = sigmap(cell->getPort(ID::A)[0]);
+ SigBit y = sigmap(cell->getPort(ID::Y)[0]);
+ inverted_bits[y] = a;
+ inverter_input[a] = cell;
+ }
+ }
+
+ Const invert_lut_input(Const lut, int bit)
+ {
+ Const result(State::S0, GetSize(lut));
+ for (int i = 0; i < GetSize(lut); i++) {
+ int j = i ^ (1 << bit);
+ result[j] = lut[i];
+ }
+ return result;
+ }
+
+ Const invert_lut_output(Const lut)
+ {
+ Const result(State::S0, GetSize(lut));
+ for (int i = 0; i < GetSize(lut); i++)
+ result[i] = (lut[i] == State::S1) ? State::S0 : State::S1;
+ return result;
+ }
+
+ void fold_input_inverters()
+ {
+ for (auto cell : module->selected_cells()) {
+ auto found_type = lut_types.find(cell->type);
+ if (found_type == lut_types.end())
+ continue;
+ const auto &type = found_type->second;
+ for (const auto &ipin : type.inputs) {
+ if (!cell->hasPort(ipin.first))
+ continue;
+ auto sig = cell->getPort(ipin.first);
+ if (GetSize(sig) == 0)
+ continue;
+ SigBit bit = sigmap(sig[0]);
+ auto inv = inverted_bits.find(bit);
+ if (inv == inverted_bits.end())
+ continue; // not the output of an inverter
+ // Rewire to inverter input
+ cell->unsetPort(ipin.first);
+ cell->setPort(ipin.first, inv->second);
+ // Rewrite init
+ cell->setParam(ipin.second.init_param,
+ invert_lut_input(cell->getParam(ipin.second.init_param), ipin.second.input_bit));
+ }
+ }
+ }
+
+ void fold_output_inverters()
+ {
+ pool<SigBit> used_bits;
+ // Find bits that are actually used
+ for (auto cell : module->selected_cells()) {
+ for (auto conn : cell->connections()) {
+ if (cell->output(conn.first))
+ continue;
+ for (auto bit : sigmap(conn.second))
+ used_bits.insert(bit);
+ }
+ }
+ // Find LUTs driving inverters
+ // (create a vector to avoid iterate-and-modify issues)
+ std::vector<std::pair<Cell *, Cell*>> lut_inv;
+ for (auto cell : module->selected_cells()) {
+ auto found_type = lut_types.find(cell->type);
+ if (found_type == lut_types.end())
+ continue;
+ if (!cell->hasPort(ID::O))
+ continue;
+ auto o_sig = cell->getPort(ID::O);
+ if (GetSize(o_sig) == 0)
+ continue;
+ SigBit o = sigmap(o_sig[0]);
+ auto found_inv = inverter_input.find(o);
+ if (found_inv == inverter_input.end())
+ continue; // doesn't drive an inverter
+ lut_inv.emplace_back(cell, found_inv->second);
+ }
+ for (auto pair : lut_inv) {
+ Cell *orig_lut = pair.first;
+ Cell *inv = pair.second;
+ // Find the inverter output
+ SigBit inv_y = sigmap(inv->getPort(ID::Y)[0]);
+ // Inverter output might not actually be used; if all users were folded into inputs already
+ if (!used_bits.count(inv_y))
+ continue;
+ // Create a duplicate of the LUT with an inverted output
+ // (if the uninverted version becomes unused it will be swept away)
+ Cell *dup_lut = module->addCell(NEW_ID, orig_lut->type);
+ inv->unsetPort(ID::Y);
+ dup_lut->setPort(ID::O, inv_y);
+ for (auto conn : orig_lut->connections()) {
+ if (conn.first == ID::O)
+ continue;
+ dup_lut->setPort(conn.first, conn.second);
+ }
+ for (auto param : orig_lut->parameters) {
+ if (param.first == lut_types.at(orig_lut->type).output_param)
+ dup_lut->parameters[param.first] = invert_lut_output(param.second);
+ else
+ dup_lut->parameters[param.first] = param.second;
+ }
+ }
+ }
+
+ void operator()()
+ {
+ find_inverted_bits();
+ fold_input_inverters();
+ fold_output_inverters();
+ }
+};
+
+struct GatemateFoldInvPass : public Pass {
+ GatemateFoldInvPass() : Pass("gatemate_foldinv", "fold inverters into Gatemate LUT trees") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" gatemate_foldinv [selection]\n");
+ log("\n");
+ log("\n");
+ log("This pass searches for $__CC_NOT cells and folds them into CC_LUT2, CC_L2T4\n");
+ log("and CC_L2T5 cells as created by LUT tree mapping.\n");
+ log("\n");
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ log_header(design, "Executing GATEMATE_FOLDINV pass (folding LUT tree inverters).\n");
+
+ size_t argidx = 1;
+ extra_args(args, argidx, design);
+
+ for (Module *module : design->selected_modules()) {
+ FoldInvWorker worker(module);
+ worker();
+ }
+ }
+} GatemateFoldInvPass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/techlibs/gatemate/inv_map.v b/techlibs/gatemate/inv_map.v
new file mode 100644
index 000000000..8a5051747
--- /dev/null
+++ b/techlibs/gatemate/inv_map.v
@@ -0,0 +1,4 @@
+// Any inverters not folded into LUTs are mapped to a LUT of their own
+module \$__CC_NOT (input A, output Y);
+ CC_LUT1 #(.INIT(2'b01)) _TECHMAP_REPLACE_ (.I0(A), .O(Y));
+endmodule
diff --git a/techlibs/gatemate/make_lut_tree_lib.py b/techlibs/gatemate/make_lut_tree_lib.py
new file mode 100644
index 000000000..25ca88882
--- /dev/null
+++ b/techlibs/gatemate/make_lut_tree_lib.py
@@ -0,0 +1,323 @@
+#!/usr/bin/env python3
+
+class FNode:
+ def __init__(self, fun, *args):
+ self.fun = fun
+ self.args = args
+
+ if len(self.args) == 0:
+ assert fun not in ("BUF", "NOT", "AND", "OR", "XOR", "MUX")
+
+ if len(self.args) == 1:
+ assert fun in ("BUF", "NOT")
+
+ if len(self.args) == 2:
+ assert fun in ("AND", "OR", "XOR")
+
+ if len(self.args) == 3:
+ assert fun in ("MUX")
+
+ def __str__(self):
+ if len(self.args) == 0:
+ return self.fun
+ if self.fun == "NOT" and len(self.args[0].args) == 0:
+ return "!" + self.args[0].fun
+ return self.fun + "(" + ",".join([str(a) for a in self.args]) + ")"
+
+ def as_genlib_term(self):
+ if len(self.args) == 0:
+ return self.fun
+ if self.fun == "NOT":
+ assert len(self.args[0].args) == 0
+ return "!" + self.args[0].fun
+ if self.fun == "AND":
+ return "(" + self.args[0].as_genlib_term() + "*" + self.args[1].as_genlib_term() + ")"
+ if self.fun == "OR":
+ return "(" + self.args[0].as_genlib_term() + "+" + self.args[1].as_genlib_term() + ")"
+ assert False
+
+ def mapMux(self):
+ if self.fun == "MUX":
+ A, B, C = self.args
+ return OR(AND(A, NOT(C)), AND(B, C)).mapMux()
+ return FNode(self.fun, *[a.mapMux() for a in self.args])
+
+ def mapXor(self):
+ if self.fun == "XOR":
+ A, B = self.args
+ return OR(AND(A, NOT(B)), AND(NOT(A), B)).mapXor()
+ return FNode(self.fun, *[a.mapXor() for a in self.args])
+
+ def mapNot(self):
+ if self.fun == "BUF":
+ return self.arg1.mapNot()
+ if self.fun == "NOT":
+ if self.args[0].fun == "AND":
+ return OR(NOT(self.args[0].args[0]),NOT(self.args[0].args[1])).mapNot()
+ if self.args[0].fun == "OR":
+ return AND(NOT(self.args[0].args[0]),NOT(self.args[0].args[1])).mapNot()
+ if self.args[0].fun == "NOT":
+ return self.args[0].args[0].mapNot()
+ return FNode(self.fun, *[a.mapNot() for a in self.args])
+
+ def map(self):
+ n = self
+ n = n.mapMux()
+ n = n.mapXor()
+ n = n.mapNot()
+ return n
+
+ def isInv(self):
+ if len(self.args) == 0:
+ return False
+ if self.fun == "XOR":
+ return False
+ if self.fun == "NOT":
+ return self.args[0].isNonInv()
+ for a in self.args:
+ if not a.isInv():
+ return False
+ return True
+
+ def isNonInv(self):
+ if len(self.args) == 0:
+ return True
+ if self.fun == "XOR":
+ return False
+ if self.fun == "NOT":
+ return self.args[0].isInv()
+ for a in self.args:
+ if not a.isNonInv():
+ return False
+ return True
+
+A = FNode("A")
+B = FNode("B")
+C = FNode("C")
+D = FNode("D")
+E = FNode("E")
+
+def BUF(arg): return FNode("BUF", arg)
+def NOT(arg): return FNode("NOT", arg)
+def AND(arg1, arg2): return FNode("AND", arg1, arg2)
+def OR(arg1, arg2): return FNode( "OR", arg1, arg2)
+def XOR(arg1, arg2): return FNode("XOR", arg1, arg2)
+def MUX(arg1, arg2, arg3): return FNode("MUX", arg1, arg2, arg3)
+
+# Genlib Format:
+#
+# GATE <cell-name> <cell-area> <cell-logic-function>
+#
+# PIN <pin-name> <phase> <input-load> <max-load>
+# <rise-block-delay> <rise-fanout-delay>
+# <fall-block-delay> <fall-fanout-delay>
+#
+# phase:
+# INV, NONINV, or UNKNOWN
+#
+# cell-logic-function:
+# <output> = <term with *(AND), +(OR), !(NOT)>
+
+
+cells = [
+ ["$__CC_BUF", 5, A],
+ ["$__CC_NOT", 0, NOT(A)],
+ ["$__CC_MUX", 5, MUX(A, B, C)],
+]
+
+base_cells = [
+ ["$__CC2_A", AND(A, B)],
+ ["$__CC2_O", OR(A, B)],
+ ["$__CC2_X", XOR(A, B)],
+
+ ["$__CC3_AA", AND(AND(A, B), C)],
+ ["$__CC3_OO", OR( OR(A, B), C)],
+ ["$__CC3_XX", XOR(XOR(A, B), C)],
+ ["$__CC3_AO", OR(AND(A, B), C)],
+ ["$__CC3_OA", AND( OR(A, B), C)],
+ ["$__CC3_AX", XOR(AND(A, B), C)],
+ ["$__CC3_XA", AND(XOR(A, B), C)],
+
+# ["$__CC3_AAA", AND(AND(A,B),AND(A,C))],
+# ["$__CC3_AXA", XOR(AND(A,B),AND(A,C))],
+# ["$__CC3_XAX", AND(XOR(A,B),XOR(A,C))],
+# ["$__CC3_AAX", AND(AND(A,B),XOR(A,C))],
+# ["$__CC3_AXX", XOR(AND(A,B),XOR(A,C))],
+# ["$__CC3_XXX", XOR(XOR(A,B),XOR(A,C))],
+# ["$__CC3_AAO", AND(AND(A,B), OR(A,C))],
+# ["$__CC3_AOA", OR(AND(A,B),AND(A,C))],
+# ["$__CC3_AOX", OR(AND(A,B),XOR(A,C))],
+
+# ["$__CC3_AAA_N", AND(AND(A,B),AND(NOT(A),C))],
+# ["$__CC3_AXA_N", XOR(AND(A,B),AND(NOT(A),C))],
+# ["$__CC3_XAX_N", AND(XOR(A,B),XOR(NOT(A),C))],
+# ["$__CC3_AAX_N", AND(AND(A,B),XOR(NOT(A),C))],
+# ["$__CC3_AXX_N", XOR(AND(A,B),XOR(NOT(A),C))],
+# ["$__CC3_XXX_N", XOR(XOR(A,B),XOR(NOT(A),C))],
+# ["$__CC3_AAO_N", AND(AND(A,B), OR(NOT(A),C))],
+# ["$__CC3_AOA_N", OR(AND(A,B),AND(NOT(A),C))],
+# ["$__CC3_AOX_N", OR(AND(A,B),XOR(NOT(A),C))],
+
+ ["$__CC4_AAA", AND(AND(A,B),AND(C,D))],
+ ["$__CC4_AXA", XOR(AND(A,B),AND(C,D))],
+ ["$__CC4_XAX", AND(XOR(A,B),XOR(C,D))],
+ ["$__CC4_AAX", AND(AND(A,B),XOR(C,D))],
+ ["$__CC4_AXX", XOR(AND(A,B),XOR(C,D))],
+ ["$__CC4_XXX", XOR(XOR(A,B),XOR(C,D))],
+ ["$__CC4_AAO", AND(AND(A,B), OR(C,D))],
+ ["$__CC4_AOA", OR(AND(A,B),AND(C,D))],
+ ["$__CC4_AOX", OR(AND(A,B),XOR(C,D))],
+]
+
+for name, expr in base_cells:
+ cells.append([name, 10, expr])
+
+ name = (name
+ .replace("$__CC4_", "$__CC5_")
+ .replace("$__CC3_", "$__CC4_")
+ .replace("$__CC2_", "$__CC3_"))
+
+ # Cells such as $__CC4_AA_A are redundant, as $__CC4_AAA is equivalent
+ if name not in ("$__CC4_AA", "$__CC3_A"):
+ cells.append([name + "_A", 12, AND(E, expr)])
+ if name not in ("$__CC4_OO", "$__CC3_O"):
+ cells.append([name + "_O", 12, OR(E, expr)])
+ if name not in ("$__CC4_XX", "$__CC3_X"):
+ cells.append([name + "_X", 12, XOR(E, expr)])
+
+with open("techlibs/gatemate/lut_tree_cells.genlib", "w") as glf:
+ def mkGate(name, cost, expr, max_load=9999, block_delay = 10, fanout_delay = 5):
+ name = name.replace(" ", "")
+ expr = expr.map()
+
+ phase = "UNKNOWN"
+ if expr.isInv(): phase = "INV"
+ if expr.isNonInv(): phase = "NONINV"
+
+ print("", file=glf)
+ print("GATE %s %d Y=%s;" % (name, cost, expr.as_genlib_term()), file=glf)
+ print("PIN * %s 1 %d %d %d %d %d" % (phase, max_load, block_delay, fanout_delay, block_delay, fanout_delay), file=glf)
+ print("GATE $__ZERO 0 Y=CONST0;", file=glf)
+ print("GATE $__ONE 0 Y=CONST1;", file=glf)
+ for name, cost, expr in cells:
+ mkGate(name, cost, expr)
+
+class LUTTreeNode:
+ def __init__(self, name, width, inputs=None):
+ self.name = name
+ self.width = width
+ self.inputs = inputs
+ def is_input(self):
+ return self.width == 0
+ def map(self, expr, params, ports):
+ if self.is_input():
+ # Input to LUT tree
+ if expr is None:
+ ports[self.name] = "" # disconnected input
+ else:
+ assert(len(expr.args) == 0)
+ ports[self.name] = expr.fun
+ return
+ if expr is None:
+ # Unused part of tree
+ params[self.name] = "4'b0000"
+ for i in self.inputs:
+ i.map(None, params, ports)
+ return
+ elif len(expr.args) == 0:
+ # Input to the expression; but not LUT tree
+ # Insert a route through
+ params[self.name] = "4'b1010"
+ self.inputs[0].map(expr, params, ports)
+ for i in self.inputs[1:]:
+ i.map(None, params, ports)
+ return
+ # Map uphill LUTs; uninverting arguments and keeping track of that if needed
+ arg_inv = []
+ for (i, arg) in zip(self.inputs, expr.args):
+ if arg.fun == "NOT":
+ i.map(arg.args[0], params, ports)
+ arg_inv.append(True)
+ else:
+ i.map(arg, params, ports)
+ arg_inv.append(False)
+ # Determine base init value
+ assert self.width == 2
+ if expr.fun == "AND":
+ init = 0b1000
+ elif expr.fun == "OR":
+ init = 0b1110
+ elif expr.fun == "XOR":
+ init = 0b0110
+ else:
+ assert False, expr.fun
+ # Swap bits if init inverted
+ swapped_init = 0b0000
+ for b in range(4):
+ if ((init >> b) & 0x1) == 0: continue
+ for i in range(2):
+ if arg_inv[i]:
+ b ^= (1 << i)
+ swapped_init |= (1 << b)
+ # Set init param
+ params[self.name] = "4'b{:04b}".format(swapped_init)
+
+def LUT2(name, i0, i1): return LUTTreeNode(name, 2, [i0, i1])
+def I(name): return LUTTreeNode(name, 0)
+
+lut_prims = {
+ "CC_LUT2": LUT2("INIT", I("I0"), I("I1")),
+ "CC_L2T4": LUT2(
+ "INIT_L10",
+ LUT2("INIT_L00", I("I0"), I("I1")),
+ LUT2("INIT_L01", I("I2"), I("I3")),
+ ),
+ "CC_L2T5": LUT2(
+ "INIT_L20", I("I4"), LUT2("INIT_L11",
+ LUT2("INIT_L02", I("I0"), I("I1")),
+ LUT2("INIT_L03", I("I2"), I("I3")),
+ )
+ )
+}
+
+with open("techlibs/gatemate/lut_tree_map.v", "w") as vf:
+ # Non-automatic rules
+ print("""
+module \\$__ZERO (output Y); assign Y = 1'b0; endmodule
+module \\$__ONE (output Y); assign Y = 1'b1; endmodule
+
+module \\$__CC_BUF (input A, output Y); assign Y = A; endmodule
+
+module \\$__CC_MUX (input A, B, C, output Y);
+ CC_MX2 _TECHMAP_REPLACE_ (
+ .D0(A), .D1(B), .S0(C),
+ .Y(Y)
+ );
+endmodule
+""", file=vf)
+ for name, cost, expr in cells:
+ expr = expr.mapMux().mapNot() # Don't map XOR
+ if name in ("$__CC_BUF", "$__CC_NOT", "$__CC_MUX"):
+ # Special cases
+ continue
+ if name.startswith("$__CC2_"):
+ prim = "CC_LUT2"
+ elif name.startswith("$__CC5_") or (name.startswith("$__CC4_") and cost == 12):
+ prim = "CC_L2T5"
+ else:
+ prim = "CC_L2T4"
+ ports = {}
+ params = {}
+ lut_prims[prim].map(expr, params, ports)
+ print("", file=vf)
+ print("module \\%s (input %s, output Y);" % (name,
+ ", ".join(sorted(set(x for x in ports.values() if x)))), file=vf)
+ print(" %s #(" % prim, file=vf)
+ for k, v in sorted(params.items(), key=lambda x: x[0]):
+ print(" .%s(%s)," % (k, v), file=vf)
+ print(" ) _TECHMAP_REPLACE_ (", file=vf)
+ print(" %s," % ", ".join(".%s(%s)" % (k, v) for k, v in sorted(ports.items(), key=lambda x:x[0])),
+ file=vf)
+ print(" .O(Y)", file=vf)
+ print(" );", file=vf)
+ print("endmodule", file=vf)
diff --git a/techlibs/gatemate/synth_gatemate.cc b/techlibs/gatemate/synth_gatemate.cc
index 93b16b2e0..dd4fde643 100644
--- a/techlibs/gatemate/synth_gatemate.cc
+++ b/techlibs/gatemate/synth_gatemate.cc
@@ -67,7 +67,10 @@ struct SynthGateMatePass : public ScriptPass
log("\n");
log(" -nomx8, -nomx4\n");
log(" do not use CC_MX{8,4} multiplexer cells in output netlist.\n");
- log("\n");;
+ log("\n");
+ log(" -luttree\n");
+ log(" use new LUT tree mapping approach (EXPERIMENTAL).\n");
+ log("\n");
log(" -dff\n");
log(" run 'abc' with -dff option\n");
log("\n");
@@ -87,7 +90,7 @@ struct SynthGateMatePass : public ScriptPass
}
string top_opt, vlog_file, json_file;
- bool noflatten, nobram, noaddf, nomult, nomx4, nomx8, dff, retime, noiopad, noclkbuf;
+ bool noflatten, nobram, noaddf, nomult, nomx4, nomx8, luttree, dff, retime, noiopad, noclkbuf;
void clear_flags() override
{
@@ -100,6 +103,7 @@ struct SynthGateMatePass : public ScriptPass
nomult = false;
nomx4 = false;
nomx8 = false;
+ luttree = false;
dff = false;
retime = false;
noiopad = false;
@@ -158,6 +162,10 @@ struct SynthGateMatePass : public ScriptPass
nomx8 = true;
continue;
}
+ if (args[argidx] == "-luttree") {
+ luttree = true;
+ continue;
+ }
if (args[argidx] == "-dff") {
dff = true;
continue;
@@ -298,11 +306,23 @@ struct SynthGateMatePass : public ScriptPass
if (check_label("map_luts"))
{
- std::string abc_args = " -dress -lut 4";
- if (dff) {
- abc_args += " -dff";
+ if (luttree || help_mode) {
+ std::string abc_args = " -genlib +/gatemate/lut_tree_cells.genlib";
+ if (dff) {
+ abc_args += " -dff";
+ }
+ run("abc " + abc_args, "(with -luttree)");
+ run("techmap -map +/gatemate/lut_tree_map.v", "(with -luttree)");
+ run("gatemate_foldinv", "(with -luttree)");
+ run("techmap -map +/gatemate/inv_map.v", "(with -luttree)");
+ }
+ if (!luttree || help_mode) {
+ std::string abc_args = " -dress -lut 4";
+ if (dff) {
+ abc_args += " -dff";
+ }
+ run("abc " + abc_args, "(without -luttree)");
}
- run("abc " + abc_args);
run("clean");
}
diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc
index 15a0c41e0..0dffdf498 100644
--- a/techlibs/gowin/synth_gowin.cc
+++ b/techlibs/gowin/synth_gowin.cc
@@ -131,7 +131,6 @@ struct SynthGowinPass : public ScriptPass
if (args[argidx] == "-json" && argidx+1 < args.size()) {
json_file = args[++argidx];
nobram = true;
- nolutram = true;
continue;
}
if (args[argidx] == "-run" && argidx+1 < args.size()) {
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index 2e1c6807a..52e8e2e3a 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -302,7 +302,9 @@ endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFE (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input D
);
`SB_DFF_INIT
@@ -589,7 +591,10 @@ endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFESR (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, R, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input R,
+ input D
);
`SB_DFF_INIT
@@ -647,7 +652,10 @@ endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFER (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, R, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input R,
+ input D
);
`SB_DFF_INIT
@@ -724,7 +732,10 @@ endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFESS (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, S, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input S,
+ input D
);
`SB_DFF_INIT
@@ -782,7 +793,10 @@ endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFES (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, S, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input S,
+ input D
);
`SB_DFF_INIT
@@ -899,7 +913,9 @@ endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFNE (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input D
);
`SB_DFF_INIT
@@ -1186,7 +1202,10 @@ endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFNESR (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, R, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input R,
+ input D
);
`SB_DFF_INIT
@@ -1244,7 +1263,10 @@ endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFNER (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, R, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input R,
+ input D
);
`SB_DFF_INIT
@@ -1321,7 +1343,10 @@ endmodule
(* abc9_flop, lib_whitebox *)
module SB_DFFNESS (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, S, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input S,
+ input D
);
`SB_DFF_INIT
@@ -1379,7 +1404,10 @@ endmodule
(* abc9_box, lib_whitebox *)
module SB_DFFNES (
output reg Q,
- input C, E `ICE40_DEFAULT_ASSIGNMENT_1, S, D
+ input C,
+ input E `ICE40_DEFAULT_ASSIGNMENT_1,
+ input S,
+ input D
);
`SB_DFF_INIT
diff --git a/techlibs/nexus/brams_map.v b/techlibs/nexus/brams_map.v
index 3cada2414..17306cded 100644
--- a/techlibs/nexus/brams_map.v
+++ b/techlibs/nexus/brams_map.v
@@ -32,10 +32,10 @@ output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
function [319:0] init_slice;
input integer idx;
- integer i, j;
+ integer i;
init_slice = 0;
- for (i = 0; i < 16; i = i + 1) begin
- init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18];
+ for (i = 0; i < 32; i = i + 1) begin
+ init_slice[i*10+:9] = INIT[(idx * 32 + i) * 9+:9];
end
endfunction
@@ -43,8 +43,28 @@ wire [17:0] DOA;
wire [17:0] DOB;
wire [17:0] DIA = PORT_A_WR_DATA;
wire [17:0] DIB = PORT_B_WR_DATA;
-wire [13:0] ADA = PORT_A_WIDTH == 18 ? {PORT_A_ADDR[13:2], PORT_A_WR_BE} : PORT_A_ADDR;
-wire [13:0] ADB = PORT_B_WIDTH == 18 ? {PORT_B_ADDR[13:2], PORT_B_WR_BE} : PORT_B_ADDR;
+wire [13:0] ADA;
+wire [13:0] ADB;
+
+generate
+
+case(PORT_A_WIDTH)
+1: assign ADA = PORT_A_ADDR;
+2: assign ADA = {PORT_A_ADDR[13:1], 1'b1};
+4: assign ADA = {PORT_A_ADDR[13:2], 2'b11};
+9: assign ADA = {PORT_A_ADDR[13:3], 3'b111};
+18: assign ADA = {PORT_A_ADDR[13:4], 2'b11, PORT_A_WR_BE};
+endcase
+
+case(PORT_B_WIDTH)
+1: assign ADB = PORT_B_ADDR;
+2: assign ADB = {PORT_B_ADDR[13:1], 1'b1};
+4: assign ADB = {PORT_B_ADDR[13:2], 2'b11};
+9: assign ADB = {PORT_B_ADDR[13:3], 3'b111};
+18: assign ADB = {PORT_B_ADDR[13:4], 2'b11, PORT_B_WR_BE};
+endcase
+
+endgenerate
assign PORT_A_RD_DATA = DOA;
assign PORT_B_RD_DATA = DOB;
@@ -122,8 +142,8 @@ DP16K #(
.RESETMODE_B(PORT_B_OPTION_RESETMODE),
.ASYNC_RST_RELEASE_A(PORT_A_OPTION_RESETMODE),
.ASYNC_RST_RELEASE_B(PORT_B_OPTION_RESETMODE),
- .CSDECODE_A("000"),
- .CSDECODE_B("000"),
+ .CSDECODE_A("111"),
+ .CSDECODE_B("111"),
.GSR("DISABLED"),
) _TECHMAP_REPLACE_ (
.CLKA(PORT_A_CLK),
@@ -176,10 +196,10 @@ input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
function [319:0] init_slice;
input integer idx;
- integer i, j;
+ integer i;
init_slice = 0;
- for (i = 0; i < 16; i = i + 1) begin
- init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18];
+ for (i = 0; i < 32; i = i + 1) begin
+ init_slice[i*10+:9] = INIT[(idx * 32 + i) * 9+:9];
end
endfunction
@@ -188,11 +208,29 @@ wire [35:0] DO;
assign PORT_R_RD_DATA = DO;
-wire [13:0] ADW = PORT_W_WIDTH == 36 ? {PORT_W_ADDR[13:4], PORT_W_WR_EN} :
- (PORT_W_WIDTH == 18 ? {PORT_W_ADDR[13:2], PORT_W_WR_EN} : PORT_W_ADDR);
+wire [13:0] ADW;
+wire [13:0] ADR;
generate
+case (PORT_W_WIDTH)
+1: assign ADW = PORT_W_ADDR;
+2: assign ADW = {PORT_W_ADDR[13:1], 1'b1};
+4: assign ADW = {PORT_W_ADDR[13:2], 2'b11};
+9: assign ADW = {PORT_W_ADDR[13:3], 3'b111};
+18: assign ADW = {PORT_W_ADDR[13:4], 2'b11, PORT_W_WR_EN};
+36: assign ADW = {PORT_W_ADDR[13:5], 1'b1, PORT_W_WR_EN};
+endcase
+
+case (PORT_R_WIDTH)
+1: assign ADR = PORT_R_ADDR;
+2: assign ADR = {PORT_R_ADDR[13:1], 1'b1};
+4: assign ADR = {PORT_R_ADDR[13:2], 2'b11};
+9: assign ADR = {PORT_R_ADDR[13:3], 3'b111};
+18: assign ADR = {PORT_R_ADDR[13:4], 4'b1111};
+36: assign ADR = {PORT_R_ADDR[13:5], 5'b11111};
+endcase
+
if (OPTION_SAME_CLOCK) begin
PDPSC16K #(
@@ -265,8 +303,8 @@ PDPSC16K #(
.OUTREG("BYPASSED"),
.RESETMODE(PORT_R_OPTION_RESETMODE),
.ASYNC_RST_RELEASE(PORT_R_OPTION_RESETMODE),
- .CSDECODE_W("000"),
- .CSDECODE_R("000"),
+ .CSDECODE_W("111"),
+ .CSDECODE_R("111"),
.ECC("DISABLED"),
.GSR("DISABLED"),
) _TECHMAP_REPLACE_ (
@@ -280,7 +318,7 @@ PDPSC16K #(
.CER(PORT_R_CLK_EN),
.RST(PORT_R_OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST),
.CSR(3'b111),
- .ADR(PORT_R_ADDR),
+ .ADR(ADR),
.DO(DO),
);
@@ -356,8 +394,8 @@ PDP16K #(
.OUTREG("BYPASSED"),
.RESETMODE(PORT_R_OPTION_RESETMODE),
.ASYNC_RST_RELEASE(PORT_R_OPTION_RESETMODE),
- .CSDECODE_W("000"),
- .CSDECODE_R("000"),
+ .CSDECODE_W("111"),
+ .CSDECODE_R("111"),
.ECC("DISABLED"),
.GSR("DISABLED"),
) _TECHMAP_REPLACE_ (
@@ -371,7 +409,7 @@ PDP16K #(
.CER(PORT_R_CLK_EN),
.RST(PORT_R_OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST),
.CSR(3'b111),
- .ADR(PORT_R_ADDR),
+ .ADR(ADR),
.DO(DO),
);
diff --git a/tests/arch/gatemate/gen_luttrees.py b/tests/arch/gatemate/gen_luttrees.py
new file mode 100644
index 000000000..27d2225a2
--- /dev/null
+++ b/tests/arch/gatemate/gen_luttrees.py
@@ -0,0 +1,48 @@
+from random import Random
+
+def main():
+ r = Random(1)
+
+ N = 750
+ with open("tests/arch/gatemate/luttrees.v", "w") as v:
+ print(f"module luttrees(input [{N-1}:0] a, b, c, d, e, output [{N-1}:0] q);", file=v)
+ for i in range(N):
+ def f():
+ return r.choice(["&", "|", "^"])
+
+ def a(x):
+ return f"({r.choice(['', '!'])}{x}[{i}])"
+
+ # Bias towards testing bigger functions
+ k = r.choice([2, 3, 4, 4, 4, 5, 5, 5])
+ if k == 2:
+ expr = f"{a('a')}{f()}{a('b')}"
+ elif k == 3:
+ expr = f"({a('a')}{f()}{a('b')}){f()}{a('c')}"
+ elif k == 4:
+ # Two types of 4-input function
+ if r.choice([False, True]):
+ expr = f"(({a('a')}{f()}{a('b')}){f()}{a('c')}){f()}{a('d')}"
+ else:
+ expr = f"({a('a')}{f()}{a('b')}){f()}({a('c')}{f()}{a('d')})"
+ elif k == 5:
+ expr = f"(({a('a')}{f()}{a('b')}){f()}({a('c')}{f()}{a('d')})){f()}{a('e')}"
+ print(f" assign q[{i}] = {expr};", file=v)
+ print("endmodule", file=v)
+ with open("tests/arch/gatemate/luttrees.ys", "w") as s:
+ print(f"""
+read_verilog luttrees.v
+design -save read
+
+hierarchy -top luttrees
+proc
+equiv_opt -async2sync -assert -map +/gatemate/cells_sim.v synth_gatemate -noiopad -luttree -nomx4 -nomx8 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd luttrees # Constrain all select calls below inside the top module
+
+select -assert-count {N} t:CC_LUT2 t:CC_L2T4 t:CC_L2T5 %%
+select -assert-none t:CC_LUT2 t:CC_L2T4 t:CC_L2T5 %% t:* %D
+""", file=s)
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/arch/gatemate/luttrees.v b/tests/arch/gatemate/luttrees.v
new file mode 100644
index 000000000..7fc02916d
--- /dev/null
+++ b/tests/arch/gatemate/luttrees.v
@@ -0,0 +1,752 @@
+module luttrees(input [749:0] a, b, c, d, e, output [749:0] q);
+ assign q[0] = ((!a[0])&(!b[0]))|((!c[0])^(!d[0]));
+ assign q[1] = ((!a[1])&(!b[1]))|((c[1])^(!d[1]));
+ assign q[2] = ((a[2])|(b[2]))&((c[2])^(d[2]));
+ assign q[3] = (((a[3])|(b[3]))^((c[3])|(!d[3])))^(e[3]);
+ assign q[4] = (((a[4])^(b[4]))|((!c[4])&(!d[4])))^(e[4]);
+ assign q[5] = (((a[5])^(!b[5]))^(!c[5]))^(d[5]);
+ assign q[6] = (((!a[6])^(!b[6]))^(c[6]))|(d[6]);
+ assign q[7] = (((!a[7])^(b[7]))|((!c[7])&(!d[7])))^(e[7]);
+ assign q[8] = (((!a[8])|(b[8]))|(c[8]))|(!d[8]);
+ assign q[9] = ((a[9])&(b[9]))^((c[9])|(!d[9]));
+ assign q[10] = (((!a[10])|(b[10]))|((c[10])^(d[10])))|(e[10]);
+ assign q[11] = (((!a[11])^(b[11]))^((!c[11])|(!d[11])))|(!e[11]);
+ assign q[12] = (!a[12])|(b[12]);
+ assign q[13] = ((a[13])&(!b[13]))&((c[13])&(d[13]));
+ assign q[14] = (((a[14])|(b[14]))|((c[14])^(d[14])))|(!e[14]);
+ assign q[15] = ((a[15])&(!b[15]))^(c[15]);
+ assign q[16] = (((!a[16])^(!b[16]))|(!c[16]))&(d[16]);
+ assign q[17] = (((!a[17])|(b[17]))|(c[17]))|(d[17]);
+ assign q[18] = (((a[18])&(b[18]))|((c[18])&(d[18])))|(!e[18]);
+ assign q[19] = (((a[19])^(b[19]))|(!c[19]))^(!d[19]);
+ assign q[20] = (!a[20])&(b[20]);
+ assign q[21] = (!a[21])&(b[21]);
+ assign q[22] = (((a[22])|(!b[22]))&(c[22]))^(d[22]);
+ assign q[23] = (((a[23])^(b[23]))|(c[23]))|(d[23]);
+ assign q[24] = (((a[24])|(b[24]))^(!c[24]))|(!d[24]);
+ assign q[25] = (!a[25])^(!b[25]);
+ assign q[26] = ((a[26])&(!b[26]))^((c[26])|(!d[26]));
+ assign q[27] = (((a[27])|(!b[27]))^(!c[27]))^(d[27]);
+ assign q[28] = ((a[28])&(b[28]))&(c[28]);
+ assign q[29] = (((!a[29])^(!b[29]))|(!c[29]))|(d[29]);
+ assign q[30] = ((!a[30])&(b[30]))|((c[30])|(d[30]));
+ assign q[31] = (((a[31])&(!b[31]))&((!c[31])&(d[31])))^(e[31]);
+ assign q[32] = (((!a[32])^(b[32]))|(!c[32]))&(d[32]);
+ assign q[33] = ((a[33])&(!b[33]))&((c[33])&(d[33]));
+ assign q[34] = (((a[34])&(!b[34]))&((c[34])&(d[34])))|(!e[34]);
+ assign q[35] = (((!a[35])|(b[35]))&(!c[35]))&(d[35]);
+ assign q[36] = (!a[36])^(!b[36]);
+ assign q[37] = (((!a[37])|(!b[37]))&((c[37])|(!d[37])))&(!e[37]);
+ assign q[38] = (((!a[38])|(b[38]))^(c[38]))|(d[38]);
+ assign q[39] = (((a[39])|(b[39]))|(c[39]))^(!d[39]);
+ assign q[40] = (((!a[40])&(!b[40]))&(!c[40]))^(!d[40]);
+ assign q[41] = (((a[41])^(b[41]))&(c[41]))&(d[41]);
+ assign q[42] = (((a[42])|(b[42]))^((c[42])&(d[42])))|(!e[42]);
+ assign q[43] = (((!a[43])&(b[43]))^((!c[43])&(d[43])))&(e[43]);
+ assign q[44] = (((!a[44])&(!b[44]))&(c[44]))&(d[44]);
+ assign q[45] = (((a[45])&(!b[45]))|((c[45])&(d[45])))|(e[45]);
+ assign q[46] = (((!a[46])^(!b[46]))^((!c[46])^(!d[46])))&(!e[46]);
+ assign q[47] = (((a[47])|(!b[47]))&((!c[47])^(d[47])))&(!e[47]);
+ assign q[48] = ((a[48])|(!b[48]))|((!c[48])&(d[48]));
+ assign q[49] = (((a[49])&(!b[49]))^(!c[49]))^(d[49]);
+ assign q[50] = (((!a[50])^(!b[50]))&(!c[50]))|(!d[50]);
+ assign q[51] = ((a[51])^(!b[51]))&((c[51])|(!d[51]));
+ assign q[52] = (((a[52])^(!b[52]))^(c[52]))&(!d[52]);
+ assign q[53] = ((!a[53])|(b[53]))^((c[53])|(!d[53]));
+ assign q[54] = (((!a[54])^(b[54]))^((c[54])^(d[54])))|(e[54]);
+ assign q[55] = ((a[55])^(b[55]))|((c[55])|(!d[55]));
+ assign q[56] = (((a[56])|(!b[56]))&((!c[56])&(d[56])))|(!e[56]);
+ assign q[57] = ((!a[57])|(b[57]))|(c[57]);
+ assign q[58] = (((a[58])&(b[58]))|(c[58]))&(!d[58]);
+ assign q[59] = ((!a[59])|(!b[59]))^((!c[59])&(!d[59]));
+ assign q[60] = (((!a[60])&(b[60]))^((!c[60])&(!d[60])))&(e[60]);
+ assign q[61] = ((a[61])^(!b[61]))^(c[61]);
+ assign q[62] = ((!a[62])^(!b[62]))|(!c[62]);
+ assign q[63] = (((a[63])&(!b[63]))^((!c[63])|(!d[63])))^(!e[63]);
+ assign q[64] = (((!a[64])&(!b[64]))|((c[64])^(d[64])))|(e[64]);
+ assign q[65] = (((!a[65])^(!b[65]))^((c[65])|(d[65])))|(e[65]);
+ assign q[66] = (((!a[66])|(!b[66]))^((c[66])|(d[66])))^(!e[66]);
+ assign q[67] = (!a[67])^(b[67]);
+ assign q[68] = (((!a[68])&(b[68]))^((c[68])|(!d[68])))^(!e[68]);
+ assign q[69] = ((!a[69])|(!b[69]))&((!c[69])^(d[69]));
+ assign q[70] = ((!a[70])&(!b[70]))&((!c[70])&(d[70]));
+ assign q[71] = ((!a[71])^(!b[71]))^((!c[71])&(d[71]));
+ assign q[72] = (((!a[72])&(b[72]))^(!c[72]))|(d[72]);
+ assign q[73] = (((!a[73])|(b[73]))|(!c[73]))&(!d[73]);
+ assign q[74] = (((a[74])|(b[74]))^(c[74]))^(!d[74]);
+ assign q[75] = (((!a[75])&(!b[75]))&((c[75])^(d[75])))^(!e[75]);
+ assign q[76] = (((!a[76])^(b[76]))&(c[76]))^(!d[76]);
+ assign q[77] = (((!a[77])|(b[77]))&((c[77])^(!d[77])))&(e[77]);
+ assign q[78] = (((!a[78])|(b[78]))&(c[78]))&(d[78]);
+ assign q[79] = ((!a[79])^(!b[79]))|((!c[79])&(d[79]));
+ assign q[80] = ((a[80])|(b[80]))|(!c[80]);
+ assign q[81] = (((a[81])&(b[81]))|((!c[81])^(!d[81])))&(!e[81]);
+ assign q[82] = (((!a[82])^(b[82]))&(c[82]))&(d[82]);
+ assign q[83] = (!a[83])|(!b[83]);
+ assign q[84] = ((!a[84])&(b[84]))&((c[84])|(d[84]));
+ assign q[85] = (!a[85])|(b[85]);
+ assign q[86] = ((!a[86])^(!b[86]))&(c[86]);
+ assign q[87] = (a[87])&(!b[87]);
+ assign q[88] = ((!a[88])&(b[88]))&(!c[88]);
+ assign q[89] = (((a[89])^(!b[89]))|(!c[89]))^(!d[89]);
+ assign q[90] = ((a[90])&(b[90]))|((!c[90])^(d[90]));
+ assign q[91] = (((!a[91])^(b[91]))^((!c[91])^(d[91])))^(!e[91]);
+ assign q[92] = ((!a[92])&(b[92]))&(c[92]);
+ assign q[93] = (((a[93])&(b[93]))^(!c[93]))^(!d[93]);
+ assign q[94] = ((!a[94])&(b[94]))^(c[94]);
+ assign q[95] = (((a[95])|(!b[95]))&((!c[95])&(!d[95])))|(e[95]);
+ assign q[96] = ((!a[96])&(!b[96]))|((c[96])|(!d[96]));
+ assign q[97] = ((!a[97])&(!b[97]))&(c[97]);
+ assign q[98] = (((!a[98])^(!b[98]))^((!c[98])&(d[98])))^(!e[98]);
+ assign q[99] = (!a[99])^(b[99]);
+ assign q[100] = (((!a[100])^(!b[100]))&(!c[100]))|(d[100]);
+ assign q[101] = ((a[101])|(!b[101]))|(!c[101]);
+ assign q[102] = (((!a[102])|(!b[102]))^((c[102])^(d[102])))&(!e[102]);
+ assign q[103] = (((!a[103])^(b[103]))|((!c[103])|(!d[103])))|(!e[103]);
+ assign q[104] = ((a[104])&(b[104]))^(!c[104]);
+ assign q[105] = ((!a[105])|(!b[105]))|((!c[105])|(!d[105]));
+ assign q[106] = ((a[106])|(b[106]))^((c[106])&(d[106]));
+ assign q[107] = (((a[107])&(!b[107]))^((c[107])&(!d[107])))&(e[107]);
+ assign q[108] = ((a[108])^(b[108]))^(!c[108]);
+ assign q[109] = (!a[109])|(!b[109]);
+ assign q[110] = ((!a[110])&(!b[110]))|((!c[110])^(d[110]));
+ assign q[111] = (((a[111])|(!b[111]))&((c[111])^(!d[111])))^(!e[111]);
+ assign q[112] = ((!a[112])^(!b[112]))&(!c[112]);
+ assign q[113] = (((a[113])&(!b[113]))^((c[113])^(d[113])))|(!e[113]);
+ assign q[114] = (((!a[114])^(!b[114]))|(!c[114]))&(!d[114]);
+ assign q[115] = ((!a[115])^(b[115]))|((c[115])|(!d[115]));
+ assign q[116] = (((!a[116])^(b[116]))&((c[116])&(!d[116])))|(!e[116]);
+ assign q[117] = (((!a[117])|(!b[117]))|(c[117]))|(!d[117]);
+ assign q[118] = (((a[118])&(b[118]))|(!c[118]))&(!d[118]);
+ assign q[119] = (((!a[119])^(!b[119]))^((!c[119])^(!d[119])))|(!e[119]);
+ assign q[120] = (((a[120])^(!b[120]))|((!c[120])&(d[120])))&(e[120]);
+ assign q[121] = ((a[121])&(!b[121]))&((!c[121])&(!d[121]));
+ assign q[122] = ((a[122])|(b[122]))^((c[122])^(!d[122]));
+ assign q[123] = (((a[123])^(b[123]))^((!c[123])^(d[123])))|(!e[123]);
+ assign q[124] = (((a[124])&(b[124]))|(c[124]))^(!d[124]);
+ assign q[125] = (((!a[125])&(!b[125]))&(c[125]))|(d[125]);
+ assign q[126] = (((!a[126])^(!b[126]))|(c[126]))^(!d[126]);
+ assign q[127] = (((a[127])&(!b[127]))^((!c[127])&(!d[127])))|(e[127]);
+ assign q[128] = (((!a[128])^(b[128]))|(c[128]))&(!d[128]);
+ assign q[129] = (((a[129])^(b[129]))|(!c[129]))|(!d[129]);
+ assign q[130] = (((!a[130])&(!b[130]))|(!c[130]))&(!d[130]);
+ assign q[131] = ((!a[131])^(b[131]))&((!c[131])^(d[131]));
+ assign q[132] = (((!a[132])|(!b[132]))&(c[132]))&(!d[132]);
+ assign q[133] = ((a[133])^(b[133]))^((c[133])&(d[133]));
+ assign q[134] = (((!a[134])&(b[134]))|(c[134]))&(d[134]);
+ assign q[135] = (((!a[135])^(!b[135]))&(c[135]))|(!d[135]);
+ assign q[136] = ((!a[136])&(b[136]))|((c[136])&(d[136]));
+ assign q[137] = (((a[137])|(b[137]))|(c[137]))&(d[137]);
+ assign q[138] = (((!a[138])^(b[138]))&((!c[138])|(d[138])))^(!e[138]);
+ assign q[139] = ((!a[139])^(b[139]))^(!c[139]);
+ assign q[140] = (((a[140])^(!b[140]))^((!c[140])^(!d[140])))|(e[140]);
+ assign q[141] = ((a[141])^(b[141]))&((c[141])&(!d[141]));
+ assign q[142] = ((!a[142])^(!b[142]))^((!c[142])|(d[142]));
+ assign q[143] = (((a[143])^(!b[143]))&((!c[143])^(d[143])))^(!e[143]);
+ assign q[144] = (((a[144])&(b[144]))^((c[144])^(d[144])))|(!e[144]);
+ assign q[145] = (((!a[145])&(b[145]))|((!c[145])|(d[145])))^(e[145]);
+ assign q[146] = (((a[146])^(b[146]))^(c[146]))|(d[146]);
+ assign q[147] = (((a[147])|(!b[147]))|((!c[147])|(!d[147])))^(!e[147]);
+ assign q[148] = (a[148])|(b[148]);
+ assign q[149] = (a[149])&(b[149]);
+ assign q[150] = (((!a[150])^(!b[150]))|((c[150])^(d[150])))&(!e[150]);
+ assign q[151] = ((a[151])^(!b[151]))|((!c[151])|(d[151]));
+ assign q[152] = (((!a[152])|(!b[152]))|((!c[152])|(d[152])))^(e[152]);
+ assign q[153] = (!a[153])^(b[153]);
+ assign q[154] = (((!a[154])^(b[154]))^(c[154]))|(d[154]);
+ assign q[155] = (((a[155])|(b[155]))&((c[155])|(!d[155])))^(e[155]);
+ assign q[156] = (((!a[156])|(!b[156]))^((c[156])|(!d[156])))|(e[156]);
+ assign q[157] = (((!a[157])&(b[157]))&((!c[157])|(d[157])))&(e[157]);
+ assign q[158] = (((!a[158])^(!b[158]))&(c[158]))^(d[158]);
+ assign q[159] = ((!a[159])|(b[159]))^((!c[159])&(d[159]));
+ assign q[160] = (((a[160])^(b[160]))|((c[160])&(d[160])))&(!e[160]);
+ assign q[161] = (a[161])|(b[161]);
+ assign q[162] = (a[162])^(b[162]);
+ assign q[163] = (((!a[163])&(b[163]))|(c[163]))^(d[163]);
+ assign q[164] = (((a[164])^(b[164]))&((c[164])|(!d[164])))|(!e[164]);
+ assign q[165] = ((!a[165])^(!b[165]))^((!c[165])^(d[165]));
+ assign q[166] = (((!a[166])&(!b[166]))|((!c[166])&(!d[166])))^(!e[166]);
+ assign q[167] = ((!a[167])|(b[167]))|((!c[167])|(!d[167]));
+ assign q[168] = (((!a[168])^(!b[168]))&((c[168])&(!d[168])))&(e[168]);
+ assign q[169] = ((a[169])^(!b[169]))^(c[169]);
+ assign q[170] = (((!a[170])^(b[170]))&(c[170]))&(d[170]);
+ assign q[171] = (!a[171])|(!b[171]);
+ assign q[172] = ((a[172])&(!b[172]))&((!c[172])&(!d[172]));
+ assign q[173] = (((a[173])&(!b[173]))^((c[173])|(!d[173])))^(!e[173]);
+ assign q[174] = ((!a[174])&(!b[174]))&(!c[174]);
+ assign q[175] = ((!a[175])|(!b[175]))^(c[175]);
+ assign q[176] = (!a[176])&(b[176]);
+ assign q[177] = ((a[177])|(b[177]))^(c[177]);
+ assign q[178] = (((a[178])^(b[178]))|((c[178])^(!d[178])))^(e[178]);
+ assign q[179] = ((a[179])^(!b[179]))^(!c[179]);
+ assign q[180] = (((a[180])^(b[180]))^(c[180]))|(!d[180]);
+ assign q[181] = (((!a[181])|(!b[181]))&((c[181])&(d[181])))|(e[181]);
+ assign q[182] = (((a[182])|(!b[182]))&((c[182])&(d[182])))|(!e[182]);
+ assign q[183] = ((a[183])^(!b[183]))^((!c[183])&(d[183]));
+ assign q[184] = (((a[184])|(b[184]))|((c[184])^(d[184])))&(!e[184]);
+ assign q[185] = (((a[185])^(b[185]))^((!c[185])&(!d[185])))^(!e[185]);
+ assign q[186] = (((!a[186])|(!b[186]))&((!c[186])&(!d[186])))|(!e[186]);
+ assign q[187] = (((a[187])^(!b[187]))|(!c[187]))^(d[187]);
+ assign q[188] = ((a[188])^(b[188]))&(!c[188]);
+ assign q[189] = (((!a[189])^(b[189]))^((!c[189])^(d[189])))|(e[189]);
+ assign q[190] = (((!a[190])^(b[190]))&((!c[190])|(d[190])))&(e[190]);
+ assign q[191] = ((!a[191])|(!b[191]))|(!c[191]);
+ assign q[192] = (((a[192])^(b[192]))^(c[192]))|(!d[192]);
+ assign q[193] = ((a[193])^(b[193]))|((!c[193])&(d[193]));
+ assign q[194] = (((a[194])&(b[194]))|(!c[194]))&(!d[194]);
+ assign q[195] = ((!a[195])|(!b[195]))^((c[195])&(!d[195]));
+ assign q[196] = (((a[196])&(!b[196]))|((c[196])^(d[196])))^(!e[196]);
+ assign q[197] = ((a[197])&(b[197]))^((c[197])^(!d[197]));
+ assign q[198] = (((a[198])&(!b[198]))|((!c[198])^(!d[198])))&(e[198]);
+ assign q[199] = (!a[199])&(b[199]);
+ assign q[200] = ((a[200])&(b[200]))^((c[200])&(d[200]));
+ assign q[201] = (((!a[201])&(!b[201]))^(!c[201]))|(!d[201]);
+ assign q[202] = ((a[202])^(b[202]))&(!c[202]);
+ assign q[203] = (((!a[203])|(b[203]))|((c[203])&(!d[203])))^(!e[203]);
+ assign q[204] = (((a[204])^(!b[204]))&((!c[204])^(!d[204])))^(!e[204]);
+ assign q[205] = (((a[205])|(!b[205]))^((!c[205])^(!d[205])))|(!e[205]);
+ assign q[206] = (a[206])|(!b[206]);
+ assign q[207] = (((a[207])^(!b[207]))&((!c[207])|(d[207])))|(!e[207]);
+ assign q[208] = (a[208])|(b[208]);
+ assign q[209] = ((!a[209])|(b[209]))|((!c[209])|(d[209]));
+ assign q[210] = ((!a[210])&(b[210]))&((!c[210])|(!d[210]));
+ assign q[211] = ((a[211])^(!b[211]))|((!c[211])|(!d[211]));
+ assign q[212] = (((a[212])&(!b[212]))&((c[212])^(d[212])))^(e[212]);
+ assign q[213] = (((!a[213])&(b[213]))^(!c[213]))^(!d[213]);
+ assign q[214] = (!a[214])|(!b[214]);
+ assign q[215] = ((a[215])|(!b[215]))^((!c[215])^(!d[215]));
+ assign q[216] = (((a[216])^(!b[216]))^((!c[216])|(d[216])))|(e[216]);
+ assign q[217] = (((a[217])^(b[217]))^((!c[217])|(!d[217])))&(e[217]);
+ assign q[218] = ((a[218])&(!b[218]))&(c[218]);
+ assign q[219] = ((a[219])|(b[219]))&((c[219])&(d[219]));
+ assign q[220] = (((!a[220])&(b[220]))^((c[220])|(d[220])))|(!e[220]);
+ assign q[221] = ((a[221])&(!b[221]))&((c[221])^(!d[221]));
+ assign q[222] = (!a[222])|(!b[222]);
+ assign q[223] = ((a[223])^(b[223]))^(c[223]);
+ assign q[224] = ((a[224])&(!b[224]))&((c[224])|(d[224]));
+ assign q[225] = ((!a[225])&(b[225]))&(!c[225]);
+ assign q[226] = (((a[226])^(b[226]))|((c[226])&(d[226])))&(e[226]);
+ assign q[227] = ((a[227])&(b[227]))|((!c[227])^(!d[227]));
+ assign q[228] = ((!a[228])&(!b[228]))|((!c[228])|(!d[228]));
+ assign q[229] = (((a[229])|(b[229]))|((!c[229])&(d[229])))&(e[229]);
+ assign q[230] = (((!a[230])^(!b[230]))|((!c[230])|(!d[230])))|(!e[230]);
+ assign q[231] = (((!a[231])|(b[231]))|((c[231])|(d[231])))|(e[231]);
+ assign q[232] = ((!a[232])^(b[232]))&((c[232])&(!d[232]));
+ assign q[233] = (((!a[233])&(!b[233]))|(!c[233]))&(!d[233]);
+ assign q[234] = (((!a[234])&(b[234]))^(!c[234]))&(d[234]);
+ assign q[235] = (((a[235])&(b[235]))^((!c[235])^(!d[235])))^(!e[235]);
+ assign q[236] = (((!a[236])^(b[236]))&((!c[236])&(!d[236])))^(e[236]);
+ assign q[237] = (a[237])|(!b[237]);
+ assign q[238] = (((a[238])|(b[238]))&((!c[238])^(d[238])))&(e[238]);
+ assign q[239] = ((!a[239])^(!b[239]))&((c[239])&(d[239]));
+ assign q[240] = (((!a[240])^(!b[240]))&(!c[240]))&(!d[240]);
+ assign q[241] = ((!a[241])&(b[241]))&(c[241]);
+ assign q[242] = ((a[242])|(!b[242]))&((c[242])|(d[242]));
+ assign q[243] = ((a[243])|(b[243]))^((!c[243])&(d[243]));
+ assign q[244] = (((!a[244])^(b[244]))&(!c[244]))|(!d[244]);
+ assign q[245] = (((a[245])^(!b[245]))^(!c[245]))^(!d[245]);
+ assign q[246] = ((!a[246])|(!b[246]))&(!c[246]);
+ assign q[247] = ((!a[247])&(b[247]))|(c[247]);
+ assign q[248] = (((!a[248])|(!b[248]))|((!c[248])&(!d[248])))&(!e[248]);
+ assign q[249] = (a[249])|(!b[249]);
+ assign q[250] = (((!a[250])^(!b[250]))^(!c[250]))^(!d[250]);
+ assign q[251] = (((a[251])|(b[251]))|(!c[251]))^(d[251]);
+ assign q[252] = (((!a[252])&(!b[252]))^((c[252])&(d[252])))&(e[252]);
+ assign q[253] = (!a[253])^(!b[253]);
+ assign q[254] = (((a[254])^(!b[254]))|((c[254])|(!d[254])))&(!e[254]);
+ assign q[255] = (!a[255])|(!b[255]);
+ assign q[256] = (((a[256])|(!b[256]))&(c[256]))&(!d[256]);
+ assign q[257] = (!a[257])^(!b[257]);
+ assign q[258] = (((!a[258])&(b[258]))^(c[258]))|(d[258]);
+ assign q[259] = (((!a[259])&(!b[259]))|(c[259]))&(!d[259]);
+ assign q[260] = ((!a[260])&(!b[260]))|((!c[260])^(!d[260]));
+ assign q[261] = (((a[261])|(b[261]))^(c[261]))|(d[261]);
+ assign q[262] = (((!a[262])^(b[262]))^((!c[262])|(!d[262])))|(e[262]);
+ assign q[263] = (a[263])^(b[263]);
+ assign q[264] = ((!a[264])&(!b[264]))|(c[264]);
+ assign q[265] = (((!a[265])^(b[265]))^((c[265])^(!d[265])))|(!e[265]);
+ assign q[266] = (((a[266])^(!b[266]))&(c[266]))^(d[266]);
+ assign q[267] = ((a[267])|(!b[267]))|(!c[267]);
+ assign q[268] = ((!a[268])&(!b[268]))|(!c[268]);
+ assign q[269] = (((!a[269])^(b[269]))&((!c[269])^(!d[269])))^(!e[269]);
+ assign q[270] = (((a[270])|(b[270]))^(c[270]))&(d[270]);
+ assign q[271] = (((a[271])&(b[271]))|((c[271])|(d[271])))|(!e[271]);
+ assign q[272] = (((a[272])|(!b[272]))^(!c[272]))|(!d[272]);
+ assign q[273] = (((!a[273])|(b[273]))&((!c[273])&(!d[273])))&(!e[273]);
+ assign q[274] = ((a[274])^(!b[274]))|(!c[274]);
+ assign q[275] = (((!a[275])^(!b[275]))|((!c[275])^(!d[275])))^(e[275]);
+ assign q[276] = ((a[276])^(b[276]))&((!c[276])^(d[276]));
+ assign q[277] = (((!a[277])&(!b[277]))|((!c[277])^(!d[277])))&(!e[277]);
+ assign q[278] = (((!a[278])^(!b[278]))^(c[278]))&(!d[278]);
+ assign q[279] = (((a[279])&(b[279]))^((!c[279])|(d[279])))^(!e[279]);
+ assign q[280] = ((!a[280])&(!b[280]))&(!c[280]);
+ assign q[281] = ((a[281])|(b[281]))|((!c[281])|(!d[281]));
+ assign q[282] = ((a[282])&(b[282]))&((c[282])|(d[282]));
+ assign q[283] = (((a[283])|(!b[283]))^((c[283])&(!d[283])))&(e[283]);
+ assign q[284] = (((!a[284])&(b[284]))&(!c[284]))^(d[284]);
+ assign q[285] = (((a[285])|(!b[285]))&(!c[285]))|(d[285]);
+ assign q[286] = (((a[286])^(b[286]))&((c[286])^(!d[286])))&(!e[286]);
+ assign q[287] = ((a[287])&(!b[287]))|((c[287])|(!d[287]));
+ assign q[288] = ((!a[288])|(!b[288]))|((!c[288])|(!d[288]));
+ assign q[289] = ((a[289])&(b[289]))&((c[289])&(!d[289]));
+ assign q[290] = (((!a[290])^(b[290]))&((c[290])^(d[290])))&(!e[290]);
+ assign q[291] = (((a[291])&(!b[291]))|(!c[291]))^(d[291]);
+ assign q[292] = (((a[292])^(!b[292]))^((c[292])|(d[292])))&(e[292]);
+ assign q[293] = (((a[293])&(!b[293]))&((c[293])|(d[293])))|(e[293]);
+ assign q[294] = (((a[294])^(!b[294]))&((!c[294])^(d[294])))&(!e[294]);
+ assign q[295] = (((a[295])^(!b[295]))|((!c[295])|(d[295])))&(e[295]);
+ assign q[296] = (((a[296])&(!b[296]))&((c[296])&(d[296])))&(!e[296]);
+ assign q[297] = ((!a[297])|(b[297]))^((!c[297])^(!d[297]));
+ assign q[298] = (((a[298])^(b[298]))|((!c[298])|(d[298])))|(!e[298]);
+ assign q[299] = (((!a[299])^(b[299]))|((c[299])^(!d[299])))|(!e[299]);
+ assign q[300] = (((!a[300])^(!b[300]))^(!c[300]))|(d[300]);
+ assign q[301] = ((a[301])&(!b[301]))&((!c[301])|(!d[301]));
+ assign q[302] = ((a[302])^(b[302]))|((c[302])|(!d[302]));
+ assign q[303] = (((!a[303])&(b[303]))^((c[303])|(d[303])))|(!e[303]);
+ assign q[304] = (!a[304])^(b[304]);
+ assign q[305] = (((a[305])&(!b[305]))^((!c[305])&(!d[305])))^(!e[305]);
+ assign q[306] = (a[306])&(b[306]);
+ assign q[307] = ((a[307])&(!b[307]))&(c[307]);
+ assign q[308] = ((a[308])&(!b[308]))^((!c[308])|(d[308]));
+ assign q[309] = ((a[309])^(!b[309]))&((c[309])|(!d[309]));
+ assign q[310] = (((!a[310])|(b[310]))&((c[310])^(d[310])))^(!e[310]);
+ assign q[311] = (((!a[311])|(b[311]))&((c[311])&(d[311])))|(e[311]);
+ assign q[312] = (((!a[312])&(b[312]))|((c[312])^(!d[312])))&(!e[312]);
+ assign q[313] = (!a[313])|(!b[313]);
+ assign q[314] = ((a[314])^(!b[314]))^((c[314])|(!d[314]));
+ assign q[315] = (a[315])&(!b[315]);
+ assign q[316] = ((!a[316])^(!b[316]))&(!c[316]);
+ assign q[317] = ((a[317])&(!b[317]))^(c[317]);
+ assign q[318] = (((!a[318])^(!b[318]))|(!c[318]))&(!d[318]);
+ assign q[319] = (((a[319])&(!b[319]))|(!c[319]))^(d[319]);
+ assign q[320] = (((!a[320])^(!b[320]))|(c[320]))|(d[320]);
+ assign q[321] = ((a[321])|(!b[321]))|((c[321])|(d[321]));
+ assign q[322] = ((!a[322])^(!b[322]))&(!c[322]);
+ assign q[323] = (((!a[323])&(b[323]))|(c[323]))|(d[323]);
+ assign q[324] = ((!a[324])&(!b[324]))^((c[324])|(d[324]));
+ assign q[325] = ((a[325])&(!b[325]))|(!c[325]);
+ assign q[326] = ((!a[326])^(!b[326]))|(c[326]);
+ assign q[327] = (((a[327])|(b[327]))&((c[327])|(!d[327])))^(!e[327]);
+ assign q[328] = ((!a[328])|(b[328]))&((c[328])&(d[328]));
+ assign q[329] = (((a[329])&(b[329]))^(c[329]))|(!d[329]);
+ assign q[330] = ((a[330])|(b[330]))|((c[330])^(!d[330]));
+ assign q[331] = (((!a[331])|(b[331]))&(c[331]))&(d[331]);
+ assign q[332] = (((!a[332])&(b[332]))|((!c[332])^(d[332])))&(e[332]);
+ assign q[333] = (((a[333])^(!b[333]))|(!c[333]))|(!d[333]);
+ assign q[334] = ((a[334])&(!b[334]))&((c[334])&(!d[334]));
+ assign q[335] = (((!a[335])&(b[335]))^((c[335])&(d[335])))&(e[335]);
+ assign q[336] = (!a[336])^(b[336]);
+ assign q[337] = (((a[337])^(b[337]))&(c[337]))&(d[337]);
+ assign q[338] = (((a[338])^(!b[338]))&(!c[338]))&(!d[338]);
+ assign q[339] = (((!a[339])^(!b[339]))|((!c[339])|(d[339])))&(!e[339]);
+ assign q[340] = (((a[340])^(b[340]))^((c[340])^(d[340])))|(e[340]);
+ assign q[341] = (((!a[341])&(!b[341]))^(!c[341]))^(d[341]);
+ assign q[342] = (a[342])^(!b[342]);
+ assign q[343] = (((!a[343])^(b[343]))&((c[343])|(!d[343])))|(e[343]);
+ assign q[344] = ((a[344])&(b[344]))&((!c[344])&(d[344]));
+ assign q[345] = (((!a[345])&(b[345]))&((c[345])^(!d[345])))|(e[345]);
+ assign q[346] = (((a[346])^(!b[346]))&(c[346]))&(!d[346]);
+ assign q[347] = (((!a[347])^(!b[347]))|((c[347])|(!d[347])))|(!e[347]);
+ assign q[348] = (((a[348])|(b[348]))&((!c[348])&(d[348])))|(!e[348]);
+ assign q[349] = (!a[349])&(b[349]);
+ assign q[350] = (((!a[350])^(b[350]))|((c[350])|(!d[350])))&(e[350]);
+ assign q[351] = (((!a[351])^(!b[351]))^((c[351])|(!d[351])))&(!e[351]);
+ assign q[352] = ((!a[352])|(b[352]))^(c[352]);
+ assign q[353] = (((a[353])&(!b[353]))^((c[353])&(!d[353])))|(!e[353]);
+ assign q[354] = (((!a[354])^(b[354]))^((!c[354])^(d[354])))^(e[354]);
+ assign q[355] = (a[355])|(b[355]);
+ assign q[356] = (((a[356])^(!b[356]))^(!c[356]))&(!d[356]);
+ assign q[357] = (((a[357])&(!b[357]))^((c[357])&(!d[357])))^(e[357]);
+ assign q[358] = (((a[358])&(b[358]))&((!c[358])&(d[358])))|(e[358]);
+ assign q[359] = (((a[359])&(!b[359]))&((!c[359])^(!d[359])))&(e[359]);
+ assign q[360] = (((!a[360])|(!b[360]))|((!c[360])|(d[360])))&(!e[360]);
+ assign q[361] = (((a[361])|(b[361]))^((c[361])|(!d[361])))^(!e[361]);
+ assign q[362] = (((!a[362])|(!b[362]))|(c[362]))|(d[362]);
+ assign q[363] = ((a[363])|(!b[363]))&((!c[363])^(!d[363]));
+ assign q[364] = (((a[364])&(!b[364]))&((c[364])&(d[364])))|(e[364]);
+ assign q[365] = ((a[365])|(!b[365]))&((c[365])|(d[365]));
+ assign q[366] = (((a[366])|(!b[366]))&((!c[366])|(!d[366])))^(!e[366]);
+ assign q[367] = ((a[367])^(!b[367]))^((!c[367])|(!d[367]));
+ assign q[368] = (((!a[368])&(b[368]))&((!c[368])|(!d[368])))&(!e[368]);
+ assign q[369] = ((a[369])^(b[369]))|((c[369])|(d[369]));
+ assign q[370] = (((a[370])^(b[370]))^(!c[370]))|(!d[370]);
+ assign q[371] = (((a[371])^(b[371]))&((!c[371])&(d[371])))&(!e[371]);
+ assign q[372] = (((!a[372])|(!b[372]))|((!c[372])&(d[372])))&(!e[372]);
+ assign q[373] = ((a[373])&(b[373]))&((!c[373])&(!d[373]));
+ assign q[374] = (((!a[374])^(!b[374]))^((!c[374])&(!d[374])))|(e[374]);
+ assign q[375] = ((!a[375])&(b[375]))^(!c[375]);
+ assign q[376] = (!a[376])|(b[376]);
+ assign q[377] = (((!a[377])^(b[377]))^((!c[377])^(!d[377])))^(e[377]);
+ assign q[378] = (((a[378])|(!b[378]))^((c[378])^(d[378])))&(!e[378]);
+ assign q[379] = (((a[379])|(b[379]))&((!c[379])^(!d[379])))^(e[379]);
+ assign q[380] = (((!a[380])^(!b[380]))^((c[380])|(!d[380])))&(!e[380]);
+ assign q[381] = (((!a[381])^(b[381]))^(c[381]))^(!d[381]);
+ assign q[382] = (((!a[382])^(b[382]))^(!c[382]))&(!d[382]);
+ assign q[383] = (((!a[383])&(!b[383]))&((c[383])^(d[383])))|(e[383]);
+ assign q[384] = (((a[384])&(b[384]))&((c[384])&(d[384])))^(e[384]);
+ assign q[385] = ((a[385])|(!b[385]))&(!c[385]);
+ assign q[386] = ((a[386])|(b[386]))&(!c[386]);
+ assign q[387] = (((!a[387])^(b[387]))|(c[387]))^(d[387]);
+ assign q[388] = (!a[388])&(!b[388]);
+ assign q[389] = ((a[389])^(b[389]))^(!c[389]);
+ assign q[390] = (((!a[390])|(b[390]))^(c[390]))|(d[390]);
+ assign q[391] = (!a[391])^(!b[391]);
+ assign q[392] = ((!a[392])^(b[392]))|(c[392]);
+ assign q[393] = (((!a[393])&(!b[393]))^((c[393])^(d[393])))^(e[393]);
+ assign q[394] = (((!a[394])^(b[394]))|(!c[394]))|(!d[394]);
+ assign q[395] = ((!a[395])&(!b[395]))^(!c[395]);
+ assign q[396] = ((a[396])^(b[396]))|((!c[396])|(d[396]));
+ assign q[397] = (((a[397])|(!b[397]))&((!c[397])&(d[397])))&(!e[397]);
+ assign q[398] = (((a[398])&(!b[398]))^((c[398])&(d[398])))|(!e[398]);
+ assign q[399] = (((!a[399])^(!b[399]))^((c[399])&(d[399])))|(!e[399]);
+ assign q[400] = (!a[400])&(b[400]);
+ assign q[401] = (((a[401])&(!b[401]))^(!c[401]))^(!d[401]);
+ assign q[402] = ((a[402])|(!b[402]))^((!c[402])^(!d[402]));
+ assign q[403] = (((!a[403])|(!b[403]))|((c[403])|(d[403])))^(!e[403]);
+ assign q[404] = (((!a[404])^(b[404]))&((c[404])&(d[404])))^(!e[404]);
+ assign q[405] = (((!a[405])^(b[405]))&(!c[405]))&(d[405]);
+ assign q[406] = (((!a[406])|(b[406]))|((c[406])^(!d[406])))&(!e[406]);
+ assign q[407] = (!a[407])|(b[407]);
+ assign q[408] = (((!a[408])&(!b[408]))|(!c[408]))&(!d[408]);
+ assign q[409] = (!a[409])^(!b[409]);
+ assign q[410] = (((!a[410])|(b[410]))|((!c[410])|(d[410])))|(!e[410]);
+ assign q[411] = (((!a[411])^(b[411]))|((c[411])&(d[411])))|(e[411]);
+ assign q[412] = ((!a[412])&(!b[412]))&((c[412])|(d[412]));
+ assign q[413] = (((!a[413])^(b[413]))^((c[413])&(!d[413])))&(!e[413]);
+ assign q[414] = (a[414])^(!b[414]);
+ assign q[415] = (((!a[415])^(b[415]))&(c[415]))|(!d[415]);
+ assign q[416] = ((!a[416])|(!b[416]))&(c[416]);
+ assign q[417] = (((!a[417])^(!b[417]))^((c[417])^(d[417])))|(!e[417]);
+ assign q[418] = ((!a[418])&(!b[418]))^((!c[418])&(!d[418]));
+ assign q[419] = (!a[419])&(!b[419]);
+ assign q[420] = ((a[420])^(!b[420]))|(!c[420]);
+ assign q[421] = ((!a[421])&(!b[421]))&((!c[421])^(d[421]));
+ assign q[422] = ((!a[422])^(b[422]))^((!c[422])&(!d[422]));
+ assign q[423] = (((a[423])|(b[423]))^((c[423])&(d[423])))^(!e[423]);
+ assign q[424] = (a[424])|(b[424]);
+ assign q[425] = (!a[425])^(b[425]);
+ assign q[426] = (!a[426])^(!b[426]);
+ assign q[427] = ((a[427])&(!b[427]))^((!c[427])^(!d[427]));
+ assign q[428] = (((!a[428])&(!b[428]))^(!c[428]))^(d[428]);
+ assign q[429] = (((!a[429])^(b[429]))&(c[429]))&(d[429]);
+ assign q[430] = ((!a[430])&(b[430]))^((c[430])^(d[430]));
+ assign q[431] = (((!a[431])|(b[431]))^((!c[431])|(d[431])))&(e[431]);
+ assign q[432] = (((!a[432])|(!b[432]))|((!c[432])^(d[432])))|(!e[432]);
+ assign q[433] = (((a[433])^(!b[433]))&(!c[433]))&(d[433]);
+ assign q[434] = ((!a[434])&(!b[434]))|((c[434])|(!d[434]));
+ assign q[435] = (!a[435])|(!b[435]);
+ assign q[436] = (((!a[436])^(!b[436]))&((!c[436])|(!d[436])))&(e[436]);
+ assign q[437] = (((!a[437])^(!b[437]))^(!c[437]))&(!d[437]);
+ assign q[438] = (!a[438])^(b[438]);
+ assign q[439] = ((a[439])^(!b[439]))|(c[439]);
+ assign q[440] = ((a[440])^(!b[440]))|((!c[440])&(!d[440]));
+ assign q[441] = (((a[441])&(b[441]))^((c[441])&(d[441])))|(e[441]);
+ assign q[442] = (!a[442])|(b[442]);
+ assign q[443] = (!a[443])^(b[443]);
+ assign q[444] = ((a[444])^(!b[444]))|((c[444])&(d[444]));
+ assign q[445] = (((a[445])|(!b[445]))&(c[445]))|(d[445]);
+ assign q[446] = ((a[446])&(b[446]))^((c[446])^(!d[446]));
+ assign q[447] = ((!a[447])&(!b[447]))^(!c[447]);
+ assign q[448] = (((!a[448])^(b[448]))&(c[448]))|(!d[448]);
+ assign q[449] = (((a[449])|(!b[449]))|((c[449])&(d[449])))|(!e[449]);
+ assign q[450] = (((!a[450])|(b[450]))|(c[450]))^(!d[450]);
+ assign q[451] = ((a[451])^(b[451]))|((c[451])^(d[451]));
+ assign q[452] = (((a[452])^(!b[452]))|(c[452]))|(d[452]);
+ assign q[453] = (!a[453])^(!b[453]);
+ assign q[454] = (((a[454])|(!b[454]))|(c[454]))^(d[454]);
+ assign q[455] = ((!a[455])&(b[455]))^((!c[455])|(!d[455]));
+ assign q[456] = (((a[456])^(!b[456]))|((c[456])^(d[456])))^(e[456]);
+ assign q[457] = (((a[457])&(!b[457]))^(c[457]))|(d[457]);
+ assign q[458] = (((!a[458])^(b[458]))^(c[458]))&(!d[458]);
+ assign q[459] = (((!a[459])&(b[459]))^((!c[459])&(!d[459])))&(e[459]);
+ assign q[460] = ((!a[460])^(!b[460]))|((c[460])&(!d[460]));
+ assign q[461] = ((a[461])&(!b[461]))&(c[461]);
+ assign q[462] = (((a[462])|(b[462]))^((c[462])^(d[462])))|(!e[462]);
+ assign q[463] = (((a[463])|(!b[463]))&((!c[463])|(d[463])))|(e[463]);
+ assign q[464] = (((!a[464])^(b[464]))&((!c[464])|(!d[464])))^(e[464]);
+ assign q[465] = ((!a[465])|(b[465]))&((c[465])&(d[465]));
+ assign q[466] = (((!a[466])^(b[466]))|((!c[466])&(d[466])))&(e[466]);
+ assign q[467] = (((!a[467])|(!b[467]))&((!c[467])&(!d[467])))^(!e[467]);
+ assign q[468] = ((!a[468])^(!b[468]))&((c[468])&(!d[468]));
+ assign q[469] = (((a[469])^(b[469]))^(c[469]))&(!d[469]);
+ assign q[470] = (((a[470])&(b[470]))^(c[470]))&(d[470]);
+ assign q[471] = (((!a[471])&(b[471]))^(c[471]))&(!d[471]);
+ assign q[472] = (((!a[472])|(b[472]))|((!c[472])|(!d[472])))|(!e[472]);
+ assign q[473] = (((a[473])|(b[473]))|((c[473])^(d[473])))|(e[473]);
+ assign q[474] = (a[474])^(!b[474]);
+ assign q[475] = (a[475])&(!b[475]);
+ assign q[476] = (((a[476])^(!b[476]))&((c[476])&(d[476])))|(!e[476]);
+ assign q[477] = ((a[477])^(b[477]))&(!c[477]);
+ assign q[478] = (((a[478])|(!b[478]))&((c[478])^(d[478])))|(e[478]);
+ assign q[479] = (((a[479])|(!b[479]))&((c[479])&(!d[479])))|(!e[479]);
+ assign q[480] = (((!a[480])|(b[480]))&((!c[480])|(!d[480])))|(e[480]);
+ assign q[481] = (((!a[481])&(b[481]))|((!c[481])^(d[481])))&(!e[481]);
+ assign q[482] = (a[482])^(!b[482]);
+ assign q[483] = (a[483])|(b[483]);
+ assign q[484] = (((a[484])|(!b[484]))&(c[484]))|(!d[484]);
+ assign q[485] = (((a[485])^(!b[485]))&(c[485]))|(!d[485]);
+ assign q[486] = ((!a[486])^(b[486]))&(c[486]);
+ assign q[487] = ((!a[487])&(b[487]))^((!c[487])^(!d[487]));
+ assign q[488] = ((a[488])&(b[488]))^((c[488])^(d[488]));
+ assign q[489] = (a[489])^(!b[489]);
+ assign q[490] = (((!a[490])^(b[490]))&(!c[490]))|(!d[490]);
+ assign q[491] = (a[491])^(!b[491]);
+ assign q[492] = (!a[492])|(!b[492]);
+ assign q[493] = (((!a[493])|(!b[493]))|((c[493])^(d[493])))^(e[493]);
+ assign q[494] = (((a[494])&(b[494]))^((c[494])&(!d[494])))&(e[494]);
+ assign q[495] = (((a[495])|(!b[495]))|((!c[495])^(d[495])))^(!e[495]);
+ assign q[496] = (((a[496])^(b[496]))&((!c[496])^(!d[496])))&(!e[496]);
+ assign q[497] = (((a[497])^(!b[497]))|((!c[497])&(d[497])))|(e[497]);
+ assign q[498] = (((!a[498])|(!b[498]))&(c[498]))&(!d[498]);
+ assign q[499] = (((a[499])|(b[499]))^((c[499])^(!d[499])))|(!e[499]);
+ assign q[500] = ((a[500])&(b[500]))^((!c[500])^(!d[500]));
+ assign q[501] = (((a[501])&(!b[501]))|(!c[501]))|(!d[501]);
+ assign q[502] = (((a[502])^(!b[502]))^(!c[502]))|(!d[502]);
+ assign q[503] = (((!a[503])&(b[503]))|(!c[503]))^(!d[503]);
+ assign q[504] = (((a[504])&(b[504]))|(c[504]))|(d[504]);
+ assign q[505] = (((!a[505])&(b[505]))&((c[505])&(!d[505])))^(!e[505]);
+ assign q[506] = (((!a[506])|(b[506]))|(c[506]))&(!d[506]);
+ assign q[507] = (((!a[507])^(b[507]))^(c[507]))&(d[507]);
+ assign q[508] = (((!a[508])&(b[508]))|((!c[508])|(d[508])))|(!e[508]);
+ assign q[509] = (!a[509])|(b[509]);
+ assign q[510] = (((a[510])|(!b[510]))^(c[510]))^(d[510]);
+ assign q[511] = ((!a[511])|(!b[511]))|((c[511])|(d[511]));
+ assign q[512] = ((a[512])|(!b[512]))&((!c[512])&(d[512]));
+ assign q[513] = (!a[513])&(!b[513]);
+ assign q[514] = (((a[514])|(!b[514]))^(!c[514]))&(d[514]);
+ assign q[515] = (((!a[515])|(!b[515]))^(c[515]))|(!d[515]);
+ assign q[516] = ((a[516])|(b[516]))|((c[516])&(!d[516]));
+ assign q[517] = (((a[517])^(!b[517]))^((c[517])&(!d[517])))&(e[517]);
+ assign q[518] = (((a[518])&(!b[518]))^((c[518])|(!d[518])))^(!e[518]);
+ assign q[519] = (((!a[519])^(!b[519]))&((c[519])&(d[519])))|(e[519]);
+ assign q[520] = ((a[520])^(b[520]))|((c[520])&(!d[520]));
+ assign q[521] = (((!a[521])^(!b[521]))^((!c[521])|(!d[521])))|(e[521]);
+ assign q[522] = (((a[522])|(b[522]))|(c[522]))&(!d[522]);
+ assign q[523] = (((a[523])|(b[523]))^((c[523])|(!d[523])))|(e[523]);
+ assign q[524] = ((!a[524])^(b[524]))&(c[524]);
+ assign q[525] = (a[525])&(b[525]);
+ assign q[526] = ((a[526])|(!b[526]))^((!c[526])^(!d[526]));
+ assign q[527] = ((!a[527])&(!b[527]))&((!c[527])|(!d[527]));
+ assign q[528] = ((a[528])^(b[528]))&(!c[528]);
+ assign q[529] = ((a[529])^(b[529]))|((c[529])|(!d[529]));
+ assign q[530] = ((!a[530])&(b[530]))|((c[530])&(!d[530]));
+ assign q[531] = (a[531])|(b[531]);
+ assign q[532] = (((!a[532])|(b[532]))&(c[532]))|(d[532]);
+ assign q[533] = ((a[533])&(!b[533]))&((c[533])&(!d[533]));
+ assign q[534] = (((a[534])&(!b[534]))&(!c[534]))|(d[534]);
+ assign q[535] = ((!a[535])^(b[535]))|((c[535])&(!d[535]));
+ assign q[536] = (((a[536])&(!b[536]))|((c[536])|(!d[536])))|(!e[536]);
+ assign q[537] = ((!a[537])^(b[537]))^((c[537])&(!d[537]));
+ assign q[538] = (((!a[538])&(b[538]))&(c[538]))|(d[538]);
+ assign q[539] = (a[539])|(!b[539]);
+ assign q[540] = (((!a[540])|(!b[540]))^((!c[540])|(d[540])))&(!e[540]);
+ assign q[541] = ((!a[541])&(!b[541]))&((c[541])^(d[541]));
+ assign q[542] = (((a[542])|(!b[542]))^(!c[542]))&(d[542]);
+ assign q[543] = (((!a[543])&(b[543]))&(!c[543]))^(d[543]);
+ assign q[544] = (((!a[544])|(b[544]))&((!c[544])&(d[544])))&(e[544]);
+ assign q[545] = (((a[545])^(!b[545]))|(!c[545]))&(d[545]);
+ assign q[546] = (((!a[546])|(!b[546]))^((!c[546])|(d[546])))&(!e[546]);
+ assign q[547] = (((a[547])^(!b[547]))|(c[547]))|(!d[547]);
+ assign q[548] = (((!a[548])^(b[548]))&((c[548])|(!d[548])))&(!e[548]);
+ assign q[549] = ((a[549])|(!b[549]))^((!c[549])^(d[549]));
+ assign q[550] = ((!a[550])&(!b[550]))^(c[550]);
+ assign q[551] = (((!a[551])&(b[551]))|((c[551])&(!d[551])))&(!e[551]);
+ assign q[552] = (((a[552])|(b[552]))^((!c[552])|(!d[552])))&(!e[552]);
+ assign q[553] = (((a[553])|(b[553]))|((!c[553])|(d[553])))&(e[553]);
+ assign q[554] = (((a[554])&(!b[554]))^(!c[554]))^(d[554]);
+ assign q[555] = ((!a[555])^(b[555]))|(!c[555]);
+ assign q[556] = (((!a[556])^(!b[556]))^(!c[556]))|(d[556]);
+ assign q[557] = ((a[557])&(!b[557]))|((c[557])&(d[557]));
+ assign q[558] = (((a[558])&(!b[558]))^((!c[558])^(!d[558])))^(!e[558]);
+ assign q[559] = (((!a[559])|(!b[559]))|((!c[559])|(!d[559])))^(!e[559]);
+ assign q[560] = ((!a[560])|(!b[560]))|((!c[560])^(d[560]));
+ assign q[561] = (((!a[561])|(b[561]))|(c[561]))^(!d[561]);
+ assign q[562] = ((!a[562])&(!b[562]))&((!c[562])^(!d[562]));
+ assign q[563] = (((a[563])^(b[563]))^(!c[563]))|(d[563]);
+ assign q[564] = (((!a[564])|(b[564]))|(!c[564]))|(d[564]);
+ assign q[565] = (((a[565])&(!b[565]))&((c[565])|(d[565])))|(!e[565]);
+ assign q[566] = (((a[566])&(b[566]))^(!c[566]))|(!d[566]);
+ assign q[567] = (((!a[567])&(!b[567]))&((c[567])&(!d[567])))|(!e[567]);
+ assign q[568] = (((!a[568])|(!b[568]))|(!c[568]))&(!d[568]);
+ assign q[569] = (!a[569])&(b[569]);
+ assign q[570] = ((!a[570])|(b[570]))|((!c[570])|(!d[570]));
+ assign q[571] = (((a[571])|(b[571]))&((!c[571])|(!d[571])))&(!e[571]);
+ assign q[572] = ((!a[572])&(b[572]))|((c[572])|(!d[572]));
+ assign q[573] = ((a[573])^(!b[573]))|((!c[573])|(!d[573]));
+ assign q[574] = (((!a[574])|(b[574]))&((!c[574])&(!d[574])))&(!e[574]);
+ assign q[575] = (((!a[575])&(b[575]))&((!c[575])|(!d[575])))|(!e[575]);
+ assign q[576] = (((a[576])|(!b[576]))^((c[576])^(d[576])))|(e[576]);
+ assign q[577] = (((a[577])|(b[577]))&(c[577]))^(d[577]);
+ assign q[578] = ((a[578])^(!b[578]))&(!c[578]);
+ assign q[579] = (((!a[579])&(!b[579]))^((!c[579])|(!d[579])))|(!e[579]);
+ assign q[580] = (((!a[580])|(b[580]))|(!c[580]))^(d[580]);
+ assign q[581] = ((a[581])&(b[581]))&((!c[581])|(d[581]));
+ assign q[582] = (((!a[582])^(b[582]))|(!c[582]))&(!d[582]);
+ assign q[583] = (a[583])&(b[583]);
+ assign q[584] = (((!a[584])|(b[584]))|((c[584])^(d[584])))^(e[584]);
+ assign q[585] = ((a[585])&(b[585]))|((!c[585])|(!d[585]));
+ assign q[586] = (((a[586])|(b[586]))^((!c[586])|(d[586])))^(!e[586]);
+ assign q[587] = ((a[587])|(!b[587]))&(!c[587]);
+ assign q[588] = (((!a[588])&(b[588]))^((!c[588])|(!d[588])))|(!e[588]);
+ assign q[589] = (((!a[589])|(b[589]))&((!c[589])|(d[589])))&(e[589]);
+ assign q[590] = (((a[590])^(b[590]))^((!c[590])&(d[590])))&(!e[590]);
+ assign q[591] = ((a[591])^(!b[591]))|(!c[591]);
+ assign q[592] = ((a[592])|(!b[592]))^((!c[592])^(!d[592]));
+ assign q[593] = ((!a[593])|(b[593]))&((c[593])&(!d[593]));
+ assign q[594] = ((!a[594])&(!b[594]))^(!c[594]);
+ assign q[595] = (((!a[595])^(b[595]))|(!c[595]))&(d[595]);
+ assign q[596] = (((a[596])|(!b[596]))&(!c[596]))|(!d[596]);
+ assign q[597] = (a[597])&(!b[597]);
+ assign q[598] = ((a[598])^(b[598]))|((!c[598])&(d[598]));
+ assign q[599] = ((a[599])&(b[599]))&(!c[599]);
+ assign q[600] = ((!a[600])|(b[600]))|((!c[600])^(!d[600]));
+ assign q[601] = ((a[601])&(!b[601]))|((c[601])^(!d[601]));
+ assign q[602] = ((!a[602])&(!b[602]))^(!c[602]);
+ assign q[603] = ((a[603])&(!b[603]))^((c[603])&(!d[603]));
+ assign q[604] = ((a[604])&(!b[604]))&((c[604])^(!d[604]));
+ assign q[605] = (((!a[605])|(b[605]))&((c[605])|(d[605])))|(e[605]);
+ assign q[606] = (((a[606])|(!b[606]))|((!c[606])^(d[606])))&(e[606]);
+ assign q[607] = ((a[607])&(!b[607]))^(!c[607]);
+ assign q[608] = ((a[608])^(!b[608]))&(!c[608]);
+ assign q[609] = ((a[609])^(!b[609]))&((!c[609])&(d[609]));
+ assign q[610] = ((!a[610])&(!b[610]))&(c[610]);
+ assign q[611] = (((!a[611])|(b[611]))&(!c[611]))|(!d[611]);
+ assign q[612] = (((a[612])^(!b[612]))&((!c[612])|(d[612])))^(e[612]);
+ assign q[613] = (((!a[613])|(b[613]))^((c[613])&(!d[613])))|(!e[613]);
+ assign q[614] = (a[614])^(!b[614]);
+ assign q[615] = (((!a[615])^(b[615]))|(!c[615]))^(d[615]);
+ assign q[616] = ((!a[616])&(!b[616]))|((c[616])&(!d[616]));
+ assign q[617] = (((a[617])^(b[617]))|(c[617]))|(d[617]);
+ assign q[618] = (((!a[618])^(!b[618]))^((c[618])^(d[618])))^(e[618]);
+ assign q[619] = (((!a[619])|(!b[619]))|(c[619]))^(!d[619]);
+ assign q[620] = (!a[620])^(!b[620]);
+ assign q[621] = ((!a[621])&(!b[621]))&((!c[621])|(d[621]));
+ assign q[622] = (((a[622])^(b[622]))&((!c[622])|(!d[622])))|(!e[622]);
+ assign q[623] = (((a[623])&(!b[623]))^(c[623]))&(d[623]);
+ assign q[624] = (((a[624])&(b[624]))|(c[624]))^(!d[624]);
+ assign q[625] = (((!a[625])^(!b[625]))&((!c[625])|(d[625])))&(!e[625]);
+ assign q[626] = (((!a[626])&(!b[626]))^(!c[626]))|(!d[626]);
+ assign q[627] = ((!a[627])|(b[627]))|(c[627]);
+ assign q[628] = (((!a[628])&(!b[628]))^((!c[628])|(!d[628])))^(e[628]);
+ assign q[629] = ((a[629])&(!b[629]))|((c[629])^(d[629]));
+ assign q[630] = (((!a[630])|(b[630]))^((c[630])|(!d[630])))|(!e[630]);
+ assign q[631] = (((!a[631])&(b[631]))&(!c[631]))^(!d[631]);
+ assign q[632] = (((a[632])&(!b[632]))&(!c[632]))|(!d[632]);
+ assign q[633] = (((a[633])|(b[633]))^(c[633]))|(d[633]);
+ assign q[634] = (((a[634])&(b[634]))|((c[634])|(d[634])))&(e[634]);
+ assign q[635] = (((a[635])&(!b[635]))&((c[635])&(!d[635])))&(!e[635]);
+ assign q[636] = (((!a[636])|(b[636]))^((!c[636])^(d[636])))^(e[636]);
+ assign q[637] = (((a[637])&(b[637]))&((!c[637])&(d[637])))|(!e[637]);
+ assign q[638] = ((!a[638])|(!b[638]))&(!c[638]);
+ assign q[639] = (((a[639])|(!b[639]))&((c[639])|(d[639])))^(!e[639]);
+ assign q[640] = (!a[640])&(b[640]);
+ assign q[641] = ((!a[641])^(!b[641]))^((!c[641])^(d[641]));
+ assign q[642] = (((!a[642])^(!b[642]))&(c[642]))&(!d[642]);
+ assign q[643] = (!a[643])^(!b[643]);
+ assign q[644] = ((!a[644])|(!b[644]))|((!c[644])^(!d[644]));
+ assign q[645] = (((a[645])&(b[645]))^((c[645])&(!d[645])))|(e[645]);
+ assign q[646] = ((a[646])&(!b[646]))&(c[646]);
+ assign q[647] = ((a[647])&(!b[647]))^((!c[647])^(!d[647]));
+ assign q[648] = (((!a[648])|(b[648]))&((!c[648])&(d[648])))|(e[648]);
+ assign q[649] = ((!a[649])|(b[649]))|((c[649])&(!d[649]));
+ assign q[650] = (((!a[650])&(b[650]))^(c[650]))^(d[650]);
+ assign q[651] = ((a[651])|(b[651]))^(!c[651]);
+ assign q[652] = (((a[652])^(b[652]))&((c[652])|(d[652])))|(e[652]);
+ assign q[653] = (((!a[653])|(b[653]))^(c[653]))^(d[653]);
+ assign q[654] = (((a[654])^(!b[654]))^(!c[654]))^(d[654]);
+ assign q[655] = (((!a[655])|(b[655]))|((!c[655])&(d[655])))&(e[655]);
+ assign q[656] = (((a[656])^(b[656]))|((!c[656])^(!d[656])))^(!e[656]);
+ assign q[657] = ((a[657])&(!b[657]))&(c[657]);
+ assign q[658] = (((!a[658])|(b[658]))|((!c[658])^(!d[658])))|(e[658]);
+ assign q[659] = (((a[659])&(b[659]))&((c[659])|(!d[659])))^(e[659]);
+ assign q[660] = (((!a[660])&(!b[660]))|((!c[660])|(!d[660])))&(e[660]);
+ assign q[661] = ((a[661])&(!b[661]))^((!c[661])^(!d[661]));
+ assign q[662] = (((!a[662])|(!b[662]))|((c[662])|(!d[662])))^(!e[662]);
+ assign q[663] = (a[663])^(b[663]);
+ assign q[664] = ((!a[664])&(!b[664]))|((!c[664])&(!d[664]));
+ assign q[665] = (((a[665])|(b[665]))&((!c[665])&(!d[665])))^(e[665]);
+ assign q[666] = (((a[666])&(b[666]))|((c[666])|(d[666])))|(!e[666]);
+ assign q[667] = ((a[667])&(!b[667]))&(!c[667]);
+ assign q[668] = (((!a[668])&(b[668]))^(c[668]))|(d[668]);
+ assign q[669] = (((!a[669])^(b[669]))^((!c[669])^(!d[669])))&(e[669]);
+ assign q[670] = ((!a[670])|(b[670]))&((c[670])|(!d[670]));
+ assign q[671] = (((a[671])&(!b[671]))^(c[671]))^(!d[671]);
+ assign q[672] = (((a[672])^(b[672]))^((c[672])&(!d[672])))|(!e[672]);
+ assign q[673] = (((a[673])^(!b[673]))&((c[673])|(d[673])))|(!e[673]);
+ assign q[674] = ((!a[674])|(!b[674]))|((!c[674])^(d[674]));
+ assign q[675] = ((!a[675])^(b[675]))&((!c[675])|(!d[675]));
+ assign q[676] = (((!a[676])&(!b[676]))^((!c[676])&(d[676])))|(!e[676]);
+ assign q[677] = (((!a[677])&(!b[677]))^(c[677]))&(!d[677]);
+ assign q[678] = (((!a[678])|(!b[678]))&((c[678])^(!d[678])))&(e[678]);
+ assign q[679] = (!a[679])|(b[679]);
+ assign q[680] = (a[680])&(!b[680]);
+ assign q[681] = (((!a[681])|(b[681]))|((c[681])&(d[681])))|(!e[681]);
+ assign q[682] = ((a[682])&(!b[682]))^((!c[682])|(!d[682]));
+ assign q[683] = ((!a[683])&(!b[683]))|((!c[683])^(!d[683]));
+ assign q[684] = (!a[684])&(!b[684]);
+ assign q[685] = (((a[685])&(!b[685]))|((c[685])&(!d[685])))|(!e[685]);
+ assign q[686] = (a[686])^(!b[686]);
+ assign q[687] = (((!a[687])|(b[687]))&((!c[687])|(d[687])))^(e[687]);
+ assign q[688] = (((a[688])^(!b[688]))^((!c[688])&(!d[688])))&(!e[688]);
+ assign q[689] = (((!a[689])^(b[689]))^(c[689]))&(!d[689]);
+ assign q[690] = ((a[690])^(!b[690]))|((!c[690])|(!d[690]));
+ assign q[691] = (((!a[691])^(b[691]))&((!c[691])&(!d[691])))^(!e[691]);
+ assign q[692] = ((a[692])^(!b[692]))|((c[692])|(!d[692]));
+ assign q[693] = (((a[693])&(b[693]))&((!c[693])|(d[693])))^(e[693]);
+ assign q[694] = ((!a[694])^(!b[694]))^((c[694])^(!d[694]));
+ assign q[695] = ((a[695])&(b[695]))&((!c[695])|(!d[695]));
+ assign q[696] = ((a[696])|(b[696]))&((c[696])|(d[696]));
+ assign q[697] = (((!a[697])^(b[697]))|((c[697])^(!d[697])))|(e[697]);
+ assign q[698] = (((a[698])|(b[698]))|((!c[698])&(!d[698])))^(!e[698]);
+ assign q[699] = (((!a[699])|(!b[699]))&(c[699]))|(!d[699]);
+ assign q[700] = ((!a[700])&(b[700]))|((!c[700])|(d[700]));
+ assign q[701] = (((!a[701])|(b[701]))|((c[701])^(d[701])))&(e[701]);
+ assign q[702] = (((!a[702])&(b[702]))&(c[702]))&(!d[702]);
+ assign q[703] = ((!a[703])&(!b[703]))|((c[703])|(d[703]));
+ assign q[704] = (((a[704])^(b[704]))^((c[704])&(d[704])))|(!e[704]);
+ assign q[705] = ((a[705])^(!b[705]))^((!c[705])^(!d[705]));
+ assign q[706] = (((!a[706])^(b[706]))^((!c[706])&(!d[706])))&(e[706]);
+ assign q[707] = ((a[707])&(!b[707]))|((c[707])^(d[707]));
+ assign q[708] = (((a[708])^(b[708]))|(!c[708]))|(d[708]);
+ assign q[709] = (((!a[709])&(b[709]))^((!c[709])&(!d[709])))&(!e[709]);
+ assign q[710] = ((!a[710])^(!b[710]))^(c[710]);
+ assign q[711] = (!a[711])&(b[711]);
+ assign q[712] = ((a[712])^(b[712]))&((c[712])^(!d[712]));
+ assign q[713] = (((a[713])^(b[713]))|((!c[713])^(d[713])))|(!e[713]);
+ assign q[714] = (((a[714])|(b[714]))&((c[714])^(d[714])))^(!e[714]);
+ assign q[715] = ((a[715])|(b[715]))|((!c[715])^(d[715]));
+ assign q[716] = (((a[716])|(b[716]))^(c[716]))^(!d[716]);
+ assign q[717] = (((!a[717])|(!b[717]))^((!c[717])^(!d[717])))^(e[717]);
+ assign q[718] = (((a[718])^(!b[718]))&(!c[718]))^(d[718]);
+ assign q[719] = (((!a[719])^(!b[719]))&((!c[719])|(d[719])))&(!e[719]);
+ assign q[720] = ((!a[720])^(b[720]))|(c[720]);
+ assign q[721] = ((!a[721])&(!b[721]))|((c[721])&(d[721]));
+ assign q[722] = (((!a[722])|(!b[722]))&((!c[722])&(!d[722])))&(!e[722]);
+ assign q[723] = ((a[723])|(b[723]))&((c[723])|(d[723]));
+ assign q[724] = (((!a[724])|(b[724]))^((c[724])^(!d[724])))^(e[724]);
+ assign q[725] = (((!a[725])^(!b[725]))|(!c[725]))&(!d[725]);
+ assign q[726] = ((a[726])^(!b[726]))^(c[726]);
+ assign q[727] = ((!a[727])&(!b[727]))^(c[727]);
+ assign q[728] = ((!a[728])^(!b[728]))^(c[728]);
+ assign q[729] = ((!a[729])&(b[729]))&(!c[729]);
+ assign q[730] = (((a[730])|(!b[730]))&(!c[730]))&(!d[730]);
+ assign q[731] = ((!a[731])|(!b[731]))^(c[731]);
+ assign q[732] = ((!a[732])&(!b[732]))|(c[732]);
+ assign q[733] = ((!a[733])&(!b[733]))^(!c[733]);
+ assign q[734] = (((a[734])|(b[734]))|((!c[734])^(!d[734])))|(!e[734]);
+ assign q[735] = (a[735])^(b[735]);
+ assign q[736] = ((!a[736])|(b[736]))&(!c[736]);
+ assign q[737] = (((!a[737])|(b[737]))|(c[737]))&(!d[737]);
+ assign q[738] = (((a[738])^(b[738]))^((c[738])^(!d[738])))|(e[738]);
+ assign q[739] = (!a[739])^(b[739]);
+ assign q[740] = (((a[740])|(b[740]))^((!c[740])^(!d[740])))&(!e[740]);
+ assign q[741] = ((!a[741])&(b[741]))^((!c[741])^(!d[741]));
+ assign q[742] = (((a[742])|(b[742]))|(c[742]))|(d[742]);
+ assign q[743] = (((a[743])&(b[743]))&((c[743])&(d[743])))|(!e[743]);
+ assign q[744] = (((!a[744])&(!b[744]))^((!c[744])&(d[744])))^(e[744]);
+ assign q[745] = (((!a[745])&(b[745]))^((!c[745])|(!d[745])))^(e[745]);
+ assign q[746] = (((a[746])&(b[746]))^(!c[746]))&(!d[746]);
+ assign q[747] = (((!a[747])^(b[747]))^((!c[747])^(d[747])))|(e[747]);
+ assign q[748] = (((a[748])^(b[748]))|((c[748])^(d[748])))&(!e[748]);
+ assign q[749] = (((a[749])^(b[749]))|((c[749])|(!d[749])))|(e[749]);
+endmodule
diff --git a/tests/arch/gatemate/luttrees.ys b/tests/arch/gatemate/luttrees.ys
new file mode 100644
index 000000000..545643226
--- /dev/null
+++ b/tests/arch/gatemate/luttrees.ys
@@ -0,0 +1,13 @@
+
+read_verilog luttrees.v
+design -save read
+
+hierarchy -top luttrees
+proc
+equiv_opt -async2sync -assert -map +/gatemate/cells_sim.v synth_gatemate -noiopad -luttree -nomx4 -nomx8 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd luttrees # Constrain all select calls below inside the top module
+
+select -assert-count 750 t:CC_LUT2 t:CC_L2T4 t:CC_L2T5 %%
+select -assert-none t:CC_LUT2 t:CC_L2T4 t:CC_L2T5 %% t:* %D
+
diff --git a/tests/arch/ice40/.gitignore b/tests/arch/ice40/.gitignore
index 9a71dca69..54f908bdb 100644
--- a/tests/arch/ice40/.gitignore
+++ b/tests/arch/ice40/.gitignore
@@ -1,4 +1,5 @@
*.log
+*.json
/run-test.mk
+*_synth.v
+*_testbench
diff --git a/tests/gen-tests-makefile.sh b/tests/gen-tests-makefile.sh
index ab8fb7013..cde9ab1b9 100755
--- a/tests/gen-tests-makefile.sh
+++ b/tests/gen-tests-makefile.sh
@@ -17,7 +17,7 @@ generate_target() {
generate_ys_test() {
ys_file=$1
yosys_args=${2:-}
- generate_target "$ys_file" "$YOSYS_BASEDIR/yosys -ql ${ys_file%.*}.log $yosys_args $ys_file"
+ generate_target "$ys_file" "\"$YOSYS_BASEDIR/yosys\" -ql ${ys_file%.*}.log $yosys_args $ys_file"
}
# $ generate_bash_test bash_file
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index e4aef9917..f96eb8d71 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-libs=""
+libs=()
genvcd=false
use_xsim=false
use_modelsim=false
@@ -15,7 +15,7 @@ xinclude_opts=""
minclude_opts=""
scriptfiles=""
scriptopt=""
-toolsdir="$(cd $(dirname $0); pwd)"
+toolsdir="$(cd "$(dirname "$0")"; pwd)"
warn_iverilog_git=false
# The following are used in verilog to firrtl regression tests.
# Typically these will be passed as environment variables:
@@ -25,8 +25,8 @@ firrtl2verilog=""
xfirrtl="../xfirrtl"
abcprog="$toolsdir/../../yosys-abc"
-if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then
- ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1
+if [ ! -f "$toolsdir/cmp_tbdata" -o "$toolsdir/cmp_tbdata.c" -nt "$toolsdir/cmp_tbdata" ]; then
+ ( set -ex; ${CC:-gcc} -Wall -o "$toolsdir/cmp_tbdata" "$toolsdir/cmp_tbdata.c"; ) || exit 1
fi
while getopts xmGl:wkjvref:s:p:n:S:I:A:-: opt; do
@@ -38,7 +38,7 @@ while getopts xmGl:wkjvref:s:p:n:S:I:A:-: opt; do
G)
warn_iverilog_git=true ;;
l)
- libs="$libs $(cd $(dirname $OPTARG); pwd)/$(basename $OPTARG)";;
+ libs+=("$(cd "$(dirname "$OPTARG")"; pwd)/$(basename "$OPTARG")");;
w)
genvcd=true ;;
k)
@@ -162,7 +162,7 @@ do
cp ../${bn}_tb.v ${bn}_tb.v
fi
if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi
- compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.${refext} $libs \
+ compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.${refext} "${libs[@]}" \
"$toolsdir"/../../techlibs/common/simlib.v \
"$toolsdir"/../../techlibs/common/simcells.v
if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
@@ -171,11 +171,11 @@ do
test_passes() {
"$toolsdir"/../../yosys -b "verilog $backend_opts" -o ${bn}_syn${test_count}.v "$@"
compile_and_run ${bn}_tb_syn${test_count} ${bn}_out_syn${test_count} \
- ${bn}_tb.v ${bn}_syn${test_count}.v $libs \
+ ${bn}_tb.v ${bn}_syn${test_count}.v "${libs[@]}" \
"$toolsdir"/../../techlibs/common/simlib.v \
"$toolsdir"/../../techlibs/common/simcells.v
if $genvcd; then mv testbench.vcd ${bn}_syn${test_count}.vcd; fi
- $toolsdir/cmp_tbdata ${bn}_out_ref ${bn}_out_syn${test_count}
+ "$toolsdir/cmp_tbdata" ${bn}_out_ref ${bn}_out_syn${test_count}
test_count=$(( test_count + 1 ))
}
diff --git a/tests/various/aiger_dff.ys b/tests/various/aiger_dff.ys
new file mode 100644
index 000000000..057f3d774
--- /dev/null
+++ b/tests/various/aiger_dff.ys
@@ -0,0 +1,7 @@
+read_verilog -icells <<EOT
+module top(input clk, d, output q);
+\$_DFF_N_ dffn(.C(clk), .D(d), .Q(q));
+endmodule
+EOT
+write_aiger -zinit -ywmap aiger_dff.out /dev/null
+!grep -qF negedge aiger_dff.out
diff --git a/tests/various/rename_scramble_name.ys b/tests/various/rename_scramble_name.ys
new file mode 100644
index 000000000..9a36d0922
--- /dev/null
+++ b/tests/various/rename_scramble_name.ys
@@ -0,0 +1,31 @@
+read_verilog <<EOF
+module top();
+ wire a, b, c;
+endmodule
+EOF
+
+proc
+hierarchy -top top
+rename -seed 2 -scramble-name w:*
+select -assert-none w:a w:b w:c
+select -assert-count 3 w:$_*_
+select -assert-none w:$_*_ %% %n
+design -reset
+
+read_verilog <<EOF
+module foo(input a, b, output c);
+ assign c = a + b;
+endmodule
+
+module top();
+ wire a, b, c;
+ foo bar(.a(a), .b(b), .c(c));
+endmodule
+EOF
+
+proc
+hierarchy -top top
+rename -seed 2 -scramble-name c:bar
+select -assert-none c:bar
+select -assert-count 1 c:$_*_
+select -assert-none c:$_*_ w:* foo/c:$add$<<EOF:2$1 %% %n
diff --git a/tests/various/smtlib2_module-expected.smt2 b/tests/various/smtlib2_module-expected.smt2
index ace858ca8..74e2f3fca 100644
--- a/tests/various/smtlib2_module-expected.smt2
+++ b/tests/various/smtlib2_module-expected.smt2
@@ -4,11 +4,14 @@
(declare-fun |smtlib2_is| (|smtlib2_s|) Bool)
(declare-fun |smtlib2#0| (|smtlib2_s|) (_ BitVec 8)) ; \a
; yosys-smt2-input a 8
+; yosys-smt2-witness {"offset": 0, "path": ["\\a"], "smtname": "a", "type": "input", "width": 8}
(define-fun |smtlib2_n a| ((state |smtlib2_s|)) (_ BitVec 8) (|smtlib2#0| state))
(declare-fun |smtlib2#1| (|smtlib2_s|) (_ BitVec 8)) ; \b
; yosys-smt2-input b 8
+; yosys-smt2-witness {"offset": 0, "path": ["\\b"], "smtname": "b", "type": "input", "width": 8}
(define-fun |smtlib2_n b| ((state |smtlib2_s|)) (_ BitVec 8) (|smtlib2#1| state))
; yosys-smt2-output add 8
+; yosys-smt2-witness {"offset": 0, "path": ["\\add"], "smtname": "add", "type": "blackbox", "width": 8}
(define-fun |smtlib2_n add| ((state |smtlib2_s|)) (_ BitVec 8) (let (
(|a| (|smtlib2_n a| state))
(|b| (|smtlib2_n b| state))
@@ -16,6 +19,7 @@
(bvadd a b)
))
; yosys-smt2-output eq 1
+; yosys-smt2-witness {"offset": 0, "path": ["\\eq"], "smtname": "eq", "type": "blackbox", "width": 1}
(define-fun |smtlib2_n eq| ((state |smtlib2_s|)) Bool (let (
(|a| (|smtlib2_n a| state))
(|b| (|smtlib2_n b| state))
@@ -23,6 +27,7 @@
(= a b)
))
; yosys-smt2-output sub 8
+; yosys-smt2-witness {"offset": 0, "path": ["\\sub"], "smtname": "sub", "type": "blackbox", "width": 8}
(define-fun |smtlib2_n sub| ((state |smtlib2_s|)) (_ BitVec 8) (let (
(|a| (|smtlib2_n a| state))
(|b| (|smtlib2_n b| state))
@@ -38,13 +43,16 @@
(declare-sort |uut_s| 0)
(declare-fun |uut_is| (|uut_s|) Bool)
; yosys-smt2-cell smtlib2 s
+; yosys-smt2-witness {"path": ["\\s"], "smtname": "s", "type": "cell"}
(declare-fun |uut#0| (|uut_s|) (_ BitVec 8)) ; \add
(declare-fun |uut#1| (|uut_s|) Bool) ; \eq
(declare-fun |uut#2| (|uut_s|) (_ BitVec 8)) ; \sub
(declare-fun |uut_h s| (|uut_s|) |smtlib2_s|)
; yosys-smt2-anyconst uut#3 8 smtlib2_module.v:14.17-14.26
+; yosys-smt2-witness {"offset": 0, "path": ["\\a"], "smtname": 3, "type": "init", "width": 8}
(declare-fun |uut#3| (|uut_s|) (_ BitVec 8)) ; \a
; yosys-smt2-anyconst uut#4 8 smtlib2_module.v:14.32-14.41
+; yosys-smt2-witness {"offset": 0, "path": ["\\b"], "smtname": 4, "type": "init", "width": 8}
(declare-fun |uut#4| (|uut_s|) (_ BitVec 8)) ; \b
(define-fun |uut#5| ((state |uut_s|)) (_ BitVec 8) (bvadd (|uut#3| state) (|uut#4| state))) ; \add2
(define-fun |uut#6| ((state |uut_s|)) Bool (= (|uut#0| state) (|uut#5| state))) ; $0$formal$smtlib2_module.v:28$1_CHECK[0:0]$9