aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format13
-rw-r--r--.gitignore3
-rw-r--r--Makefile86
-rw-r--r--README.md26
-rw-r--r--backends/aiger/xaiger.cc315
-rw-r--r--backends/blif/blif.cc26
-rw-r--r--backends/btor/btor.cc8
-rw-r--r--backends/firrtl/firrtl.cc100
-rw-r--r--backends/ilang/ilang_backend.cc5
-rw-r--r--backends/json/json.cc115
-rw-r--r--backends/verilog/verilog_backend.cc132
-rw-r--r--frontends/aiger/aigerparse.cc618
-rw-r--r--frontends/aiger/aigerparse.h1
-rw-r--r--frontends/ast/ast.cc25
-rw-r--r--frontends/ast/ast.h4
-rw-r--r--frontends/ast/genrtlil.cc42
-rw-r--r--frontends/ast/simplify.cc8
-rw-r--r--frontends/ilang/ilang_lexer.l1
-rw-r--r--frontends/ilang/ilang_parser.y20
-rw-r--r--frontends/verific/verific.cc95
-rw-r--r--frontends/verific/verific.h2
-rw-r--r--frontends/verilog/Makefile.inc2
-rw-r--r--frontends/verilog/const2ast.cc26
-rw-r--r--frontends/verilog/verilog_frontend.cc22
-rw-r--r--frontends/verilog/verilog_frontend.h7
-rw-r--r--frontends/verilog/verilog_lexer.l25
-rw-r--r--frontends/verilog/verilog_parser.y351
-rw-r--r--kernel/cellaigs.cc2
-rw-r--r--kernel/celltypes.h7
-rw-r--r--kernel/driver.cc4
-rw-r--r--kernel/log.cc9
-rw-r--r--kernel/rtlil.cc83
-rw-r--r--kernel/rtlil.h66
-rw-r--r--kernel/yosys.cc20
-rw-r--r--kernel/yosys.h3
-rw-r--r--libs/subcircuit/subcircuit.cc10
-rw-r--r--manual/CHAPTER_CellLib.tex4
-rw-r--r--misc/__init__.py (renamed from __init__.py)0
-rw-r--r--misc/py_wrap_generator.py (renamed from py_wrap_generator.py)0
-rw-r--r--passes/cmds/bugpoint.cc6
-rw-r--r--passes/cmds/cover.cc10
-rw-r--r--passes/cmds/qwp.cc2
-rw-r--r--passes/cmds/stat.cc79
-rw-r--r--passes/equiv/equiv_opt.cc19
-rw-r--r--passes/hierarchy/hierarchy.cc267
-rw-r--r--passes/opt/opt_clean.cc203
-rw-r--r--passes/opt/opt_expr.cc50
-rw-r--r--passes/opt/opt_muxtree.cc14
-rw-r--r--passes/opt/opt_rmdff.cc72
-rw-r--r--passes/opt/wreduce.cc50
-rw-r--r--passes/pmgen/.gitignore1
-rw-r--r--passes/pmgen/Makefile.inc17
-rw-r--r--passes/pmgen/README.md26
-rw-r--r--passes/pmgen/ice40_dsp.cc117
-rw-r--r--passes/pmgen/ice40_dsp.pmg2
-rw-r--r--passes/pmgen/peepopt.cc68
-rw-r--r--passes/pmgen/peepopt_muldiv.pmg36
-rw-r--r--passes/pmgen/peepopt_shiftmul.pmg87
-rw-r--r--passes/pmgen/pmgen.py263
-rw-r--r--passes/sat/expose.cc4
-rw-r--r--passes/sat/fmcombine.cc41
-rw-r--r--passes/sat/sat.cc1
-rw-r--r--passes/techmap/abc.cc29
-rw-r--r--passes/techmap/abc9.cc362
-rw-r--r--passes/techmap/dffinit.cc3
-rw-r--r--passes/techmap/flowmap.cc4
-rw-r--r--passes/techmap/libparse.cc2
-rw-r--r--passes/techmap/shregmap.cc12
-rw-r--r--passes/techmap/zinit.cc2
-rw-r--r--techlibs/common/prep.cc6
-rw-r--r--techlibs/common/simlib.v176
-rw-r--r--techlibs/common/synth.cc2
-rw-r--r--techlibs/ecp5/synth_ecp5.cc2
-rw-r--r--techlibs/ice40/cells_sim.v11
-rw-r--r--techlibs/ice40/synth_ice40.cc12
-rw-r--r--techlibs/intel/synth_intel.cc433
-rw-r--r--techlibs/xilinx/Makefile.inc2
-rw-r--r--techlibs/xilinx/abc.box42
-rw-r--r--techlibs/xilinx/abc.lut14
-rw-r--r--techlibs/xilinx/arith_map.v4
-rw-r--r--techlibs/xilinx/cells_map.v137
-rw-r--r--techlibs/xilinx/cells_sim.v31
-rw-r--r--techlibs/xilinx/cells_xtra.sh4
-rw-r--r--techlibs/xilinx/cells_xtra.v18
-rw-r--r--techlibs/xilinx/drams.txt4
-rw-r--r--techlibs/xilinx/ff_map.v13
-rw-r--r--techlibs/xilinx/synth_xilinx.cc311
-rw-r--r--tests/memories/firrtl_938.v22
-rw-r--r--tests/simple/dff_init.v12
-rw-r--r--tests/simple/forloops.v25
-rw-r--r--tests/simple/localparam_attr.v11
-rw-r--r--tests/simple/mem2reg.v22
-rw-r--r--tests/simple/param_attr.v11
-rw-r--r--tests/simple/peepopt.v9
-rw-r--r--tests/simple/wandwor.v36
-rw-r--r--tests/simple/xfirrtl1
-rw-r--r--tests/simple_abc9/abc.box2
-rw-r--r--tests/simple_abc9/abc9.v108
-rwxr-xr-xtests/simple_abc9/run-test.sh2
-rwxr-xr-xtests/svinterfaces/runone.sh8
-rwxr-xr-xtests/tools/autotest.sh5
-rw-r--r--tests/various/chparam.sh52
-rw-r--r--tests/various/opt_rmdff.v50
-rw-r--r--tests/various/opt_rmdff.ys26
-rw-r--r--tests/various/specify.v30
-rw-r--r--tests/various/specify.ys56
106 files changed, 4120 insertions, 1725 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000..28d13da25
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+# Default Linux style
+BasedOnStyle: LLVM
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Linux
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+
+# From CodingReadme
+TabWidth: 8
+ContinuationIndentWidth: 2
+ColumnLimit: 150
+# BreakBeforeBraces: Linux
diff --git a/.gitignore b/.gitignore
index e24f7975a..76f53cd06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
*.gch
*.gcda
*.gcno
+__pycache__
/.cproject
/.project
/.settings
@@ -28,6 +29,8 @@
/yosys-smtbmc-script.py
/yosys-filterlib
/yosys-filterlib.exe
+/kernel/*.pyh
+/kernel/python_wrappers.cc
/kernel/version_*.cc
/share
/yosys-win32-mxebin-*
diff --git a/Makefile b/Makefile
index 249c1d0ee..377a5f6b5 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@
CONFIG := clang
# CONFIG := gcc
# CONFIG := gcc-4.8
+# CONFIG := afl-gcc
# CONFIG := emcc
# CONFIG := mxe
# CONFIG := msys2
@@ -21,11 +22,6 @@ ENABLE_PROTOBUF := 0
# python wrappers
ENABLE_PYOSYS := 0
-PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
-PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
-PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
-PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
-PYTHON_DESTDIR := `$(PYTHON_EXECUTABLE)-config --prefix`/lib/python$(PYTHON_VERSION)/dist-packages
# other configuration flags
ENABLE_GCOV := 0
@@ -89,6 +85,9 @@ PLUGIN_LDFLAGS += -undefined dynamic_lookup
# homebrew search paths
ifneq ($(shell which brew),)
BREW_PREFIX := $(shell brew --prefix)/opt
+$(info $$BREW_PREFIX is [${BREW_PREFIX}])
+CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost
+LDFLAGS += -L$(BREW_PREFIX)/boost/lib
CXXFLAGS += -I$(BREW_PREFIX)/readline/include
LDFLAGS += -L$(BREW_PREFIX)/readline/lib
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
@@ -119,7 +118,7 @@ OBJS = kernel/version_$(GIT_REV).o
# 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 = 3709744
+ABCREV = 62487de
ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
@@ -138,6 +137,21 @@ $(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$
include Makefile.conf
endif
+ifeq ($(ENABLE_PYOSYS),1)
+PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
+PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
+PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
+PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
+PYTHON_PREFIX := $(shell $(PYTHON_EXECUTABLE)-config --prefix)
+PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages
+
+# Reload Makefile.conf to override python specific variables if defined
+ifneq ($(wildcard Makefile.conf),)
+include Makefile.conf
+endif
+
+endif
+
ifeq ($(CONFIG),clang)
CXX = clang
LD = clang++
@@ -185,6 +199,12 @@ LD = gcc-4.8
CXXFLAGS += -std=c++11 -Os
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
+else ifeq ($(CONFIG),afl-gcc)
+CXX = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc
+LD = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc
+CXXFLAGS += -std=c++11 -Os
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
+
else ifeq ($(CONFIG),cygwin)
CXX = gcc
LD = gcc
@@ -272,29 +292,50 @@ endif
ifeq ($(ENABLE_PYOSYS),1)
#Detect name of boost_python library. Some distros usbe boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers
+ifeq ($(OS), Darwin)
+BOOST_PYTHON_LIB ?= $(shell \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
+ if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
+ echo ""; fi; fi; fi; fi;)
+else
BOOST_PYTHON_LIB ?= $(shell \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
echo ""; fi; fi; fi; fi;)
+endif
ifeq ($(BOOST_PYTHON_LIB),)
$(error BOOST_PYTHON_LIB could not be detected. Please define manualy)
endif
+ifeq ($(OS), Darwin)
+ifeq ($(PYTHON_MAJOR_VERSION),3)
+LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
+CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
+else
+LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
+CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
+endif
+else
ifeq ($(PYTHON_MAJOR_VERSION),3)
-LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
-CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON
+LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
+CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
else
-LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
-CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON
+LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
+CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON
+endif
endif
+ifeq ($(ENABLE_PYOSYS),1)
PY_WRAPPER_FILE = kernel/python_wrappers
OBJS += $(PY_WRAPPER_FILE).o
PY_GEN_SCRIPT= py_wrap_generator
-PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()")
+PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()")
+endif
endif
ifeq ($(ENABLE_READLINE),1)
@@ -540,7 +581,11 @@ yosys$(EXE): $(OBJS)
$(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
+ifeq ($(OS), Darwin)
+ $(P) $(LD) -o libyosys.so -shared -Wl,-install_name,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
+else
$(P) $(LD) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
+endif
%.o: %.cc
$(Q) mkdir -p $(dir $@)
@@ -550,9 +595,11 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
$(Q) mkdir -p $(dir $@)
$(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P -
-$(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES)
+ifeq ($(ENABLE_PYOSYS),1)
+$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES)
$(Q) mkdir -p $(dir $@)
- $(P) python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")"
+ $(P) python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")"
+endif
%.o: %.cpp
$(Q) mkdir -p $(dir $@)
@@ -679,13 +726,13 @@ endif
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
ifeq ($(ENABLE_LIBYOSYS),1)
- $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)
+ $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
+ $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so
- $(INSTALL_SUDO) ldconfig
ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
- $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys
- $(INSTALL_SUDO) cp __init__.py $(PYTHON_DESTDIR)/pyosys
+ $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/
+ $(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/
endif
endif
@@ -787,6 +834,9 @@ config-gcc-static: clean
config-gcc-4.8: clean
echo 'CONFIG := gcc-4.8' > Makefile.conf
+config-afl-gcc: clean
+ echo 'CONFIG := afl-gcc' > Makefile.conf
+
config-emcc: clean
echo 'CONFIG := emcc' > Makefile.conf
echo 'ENABLE_TCL := 0' >> Makefile.conf
@@ -833,5 +883,5 @@ echo-git-rev:
-include techlibs/*/*.d
.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator coverage vcxsrc mxebin
-.PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-gprof config-sudo
+.PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-afl-gcc config-gprof config-sudo
diff --git a/README.md b/README.md
index 46bed4242..19306cda3 100644
--- a/README.md
+++ b/README.md
@@ -257,13 +257,9 @@ for them:
- Non-synthesizable language features as defined in
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
-- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types
+- The ``tri``, ``triand`` and ``trior`` net types
-- The ``config`` keyword and library map files
-
-- The ``disable``, ``primitive`` and ``specify`` statements
-
-- Latched logic (is synthesized as logic with feedback loops)
+- The ``config`` and ``disable`` keywords and library map files
Verilog Attributes and non-standard features
@@ -370,7 +366,7 @@ Verilog Attributes and non-standard features
- When defining a macro with `define, all text between triple double quotes
is interpreted as macro body, even if it contains unescaped newlines. The
- tipple double quotes are removed from the macro body. For example:
+ triple double quotes are removed from the macro body. For example:
`define MY_MACRO(a, b) """
assign a = 23;
@@ -420,9 +416,15 @@ Verilog Attributes and non-standard features
expressions as <size>. If the expression is not a simple identifier, it
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
-- The system tasks ``$finish`` and ``$display`` are supported in initial blocks
- in an unconditional context (only if/case statements on parameters
- and constant values). The intended use for this is synthesis-time DRC.
+- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
+ initial blocks in an unconditional context (only if/case statements on
+ expressions over parameters and constant values are allowed). The intended
+ use for this is synthesis-time DRC.
+
+- There is limited support for converting specify .. endspecify statements to
+ special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in
+ blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
+ functionality. (By default specify .. endspecify blocks are ignored.)
Non-standard or SystemVerilog features for formal verification
@@ -457,7 +459,7 @@ Non-standard or SystemVerilog features for formal verification
supported in any clocked block.
- The syntax ``@($global_clock)`` can be used to create FFs that have no
- explicit clock input ($ff cells). The same can be achieved by using
+ explicit clock input (``$ff`` cells). The same can be achieved by using
``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>``
is marked with the ``(* gclk *)`` Verilog attribute.
@@ -470,7 +472,7 @@ from SystemVerilog:
- The ``assert`` statement from SystemVerilog is supported in its most basic
form. In module context: ``assert property (<expression>);`` and within an
- always block: ``assert(<expression>);``. It is transformed to a $assert cell.
+ always block: ``assert(<expression>);``. It is transformed to an ``$assert`` cell.
- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are
also supported. The same limitations as with the ``assert`` statement apply.
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 7126002f6..7a139f68f 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -49,7 +49,8 @@ struct XAigerWriter
dict<SigBit, SigBit> not_map, ff_map, alias_map;
dict<SigBit, pair<SigBit, SigBit>> and_map;
//pool<SigBit> initstate_bits;
- vector<std::pair<SigBit,int>> ci_bits, co_bits;
+ vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits;
+ vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits;
vector<std::pair<SigBit,SigBit>> ff_bits;
vector<pair<int, int>> aig_gates;
@@ -152,10 +153,11 @@ struct XAigerWriter
undriven_bits.insert(bit);
unused_bits.insert(bit);
- if (wire->port_input)
- input_bits.insert(bit);
- else if (keep)
+ if (wire->port_input || keep) {
+ if (bit != wirebit)
+ alias_map[bit] = wirebit;
input_bits.insert(wirebit);
+ }
if (wire->port_output || keep) {
if (bit != wirebit)
@@ -166,7 +168,7 @@ struct XAigerWriter
}
for (auto bit : input_bits)
- undriven_bits.erase(bit);
+ undriven_bits.erase(sigmap(bit));
for (auto bit : output_bits)
if (!bit.wire->port_input)
@@ -303,8 +305,10 @@ struct XAigerWriter
}
}
if (is_output) {
+ input_bits.insert(b);
SigBit O = sigmap(b);
- input_bits.insert(O);
+ if (O != b)
+ alias_map[O] = b;
undriven_bits.erase(O);
}
}
@@ -321,46 +325,109 @@ struct XAigerWriter
for (auto user_cell : it.second)
toposort.edge(driver_cell, user_cell);
-#ifndef NDEBUG
- toposort.analyze_loops = true;
-#endif
- toposort.sort();
-#ifndef NDEBUG
- for (auto &it : toposort.loops) {
- log(" loop");
- for (auto cell : it)
- log(" %s", log_id(cell));
- log("\n");
- }
-#endif
- log_assert(!toposort.found_loops);
+ pool<RTLIL::Module*> abc_carry_modules;
+ toposort.sort();
for (auto cell_name : toposort.sorted) {
RTLIL::Cell *cell = module->cell(cell_name);
RTLIL::Module* box_module = module->design->module(cell->type);
if (!box_module || !box_module->attributes.count("\\abc_box_id"))
continue;
- // Box ordering is alphabetical
- cell->connections_.sort(RTLIL::sort_by_id_str());
- for (const auto &c : cell->connections()) {
- for (auto b : c.second.bits()) {
- auto is_input = cell->input(c.first);
- auto is_output = cell->output(c.first);
- log_assert(is_input || is_output);
- if (is_input) {
+ if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) {
+ RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
+ RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
+ for (const auto &port_name : box_module->ports) {
+ RTLIL::Wire* w = box_module->wire(port_name);
+ log_assert(w);
+ if (w->port_input) {
+ if (w->attributes.count("\\abc_carry_in")) {
+ log_assert(!carry_in);
+ carry_in = w;
+ }
+ log_assert(!last_in || last_in->port_id < w->port_id);
+ last_in = w;
+ }
+ if (w->port_output) {
+ if (w->attributes.count("\\abc_carry_out")) {
+ log_assert(!carry_out);
+ carry_out = w;
+ }
+ log_assert(!last_out || last_out->port_id < w->port_id);
+ last_out = w;
+ }
+ }
+
+ if (carry_in) {
+ log_assert(last_in);
+ std::swap(box_module->ports[carry_in->port_id-1], box_module->ports[last_in->port_id-1]);
+ std::swap(carry_in->port_id, last_in->port_id);
+ }
+ if (carry_out) {
+ log_assert(last_out);
+ std::swap(box_module->ports[carry_out->port_id-1], box_module->ports[last_out->port_id-1]);
+ std::swap(carry_out->port_id, last_out->port_id);
+ }
+ }
+
+ // Fully pad all unused input connections of this box cell with S0
+ // Fully pad all undriven output connections of this box cell with anonymous wires
+ // NB: Assume box_module->ports are sorted alphabetically
+ // (as RTLIL::Module::fixup_ports() would do)
+ for (const auto &port_name : box_module->ports) {
+ RTLIL::Wire* w = box_module->wire(port_name);
+ log_assert(w);
+ auto it = cell->connections_.find(port_name);
+ if (w->port_input) {
+ RTLIL::SigSpec rhs;
+ if (it != cell->connections_.end()) {
+ if (GetSize(it->second) < GetSize(w))
+ it->second.append(RTLIL::SigSpec(RTLIL::S0, GetSize(w)-GetSize(it->second)));
+ rhs = it->second;
+ }
+ else {
+ rhs = RTLIL::SigSpec(RTLIL::S0, GetSize(w));
+ cell->setPort(port_name, rhs);
+ }
+
+ int offset = 0;
+ for (const auto &b : rhs.bits()) {
SigBit I = sigmap(b);
if (I != b)
alias_map[b] = I;
- co_bits.emplace_back(b, 0);
+ co_bits.emplace_back(b, cell, port_name, offset++, 0);
+ unused_bits.erase(b);
}
- if (is_output) {
+ }
+ if (w->port_output) {
+ RTLIL::SigSpec rhs;
+ auto it = cell->connections_.find(w->name);
+ if (it != cell->connections_.end()) {
+ if (GetSize(it->second) < GetSize(w))
+ it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second)));
+ rhs = it->second;
+ }
+ else {
+ rhs = module->addWire(NEW_ID, GetSize(w));
+ cell->setPort(port_name, rhs);
+ }
+
+ int offset = 0;
+ for (const auto &b : rhs.bits()) {
+ ci_bits.emplace_back(b, cell, port_name, offset++);
SigBit O = sigmap(b);
- ci_bits.emplace_back(O, 0);
+ if (O != b)
+ alias_map[O] = b;
+ undriven_bits.erase(O);
+
+ auto jt = input_bits.find(b);
+ if (jt != input_bits.end()) {
+ log_assert(b.wire->attributes.count("\\keep"));
+ input_bits.erase(b);
+ }
}
}
}
-
box_list.emplace_back(cell);
}
@@ -375,9 +442,10 @@ struct XAigerWriter
if ((wire->port_input && wire->port_output && !undriven_bits.count(bit))
|| wire->attributes.count("\\keep")) {
log_assert(input_bits.count(bit) && output_bits.count(bit));
- RTLIL::Wire *new_wire = module->wire(wire->name.str() + "$inout.out");
+ RTLIL::IdString wire_name = wire->name.str() + "$inout.out";
+ RTLIL::Wire *new_wire = module->wire(wire_name);
if (!new_wire)
- new_wire = module->addWire(wire->name.str() + "$inout.out", GetSize(wire));
+ new_wire = module->addWire(wire_name, GetSize(wire));
SigBit new_bit(new_wire, bit.offset);
module->connect(new_bit, bit);
if (not_map.count(bit))
@@ -394,13 +462,10 @@ struct XAigerWriter
}
}
- // Do some CI/CO post-processing:
// Erase all POs that are undriven
- for (auto bit : undriven_bits)
- output_bits.erase(bit);
- // CIs cannot be undriven
- for (const auto &c : ci_bits)
- undriven_bits.erase(c.first);
+ if (!holes_mode)
+ for (auto bit : undriven_bits)
+ output_bits.erase(bit);
for (auto bit : unused_bits)
undriven_bits.erase(bit);
@@ -414,8 +479,20 @@ struct XAigerWriter
}
init_map.sort();
- input_bits.sort();
- output_bits.sort();
+ if (holes_mode) {
+ struct sort_by_port_id {
+ bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const {
+ return a.wire->port_id < b.wire->port_id;
+ }
+ };
+ input_bits.sort(sort_by_port_id());
+ output_bits.sort(sort_by_port_id());
+ }
+ else {
+ input_bits.sort();
+ output_bits.sort();
+ }
+
not_map.sort();
ff_map.sort();
and_map.sort();
@@ -425,6 +502,7 @@ struct XAigerWriter
for (auto bit : input_bits) {
aig_m++, aig_i++;
+ log_assert(!aig_map.count(bit));
aig_map[bit] = 2*aig_m;
}
@@ -436,12 +514,14 @@ struct XAigerWriter
dict<SigBit, int> ff_aig_map;
for (auto &c : ci_bits) {
+ RTLIL::SigBit bit = std::get<0>(c);
aig_m++, aig_i++;
- c.second = 2*aig_m;
- auto r = aig_map.insert(std::make_pair(c.first, c.second));
- if (!r.second) {
- ff_aig_map[c.first] = c.second;
- }
+ log_assert(!aig_map.count(bit));
+ aig_map[bit] = 2*aig_m;
+ //auto r = aig_map.insert(std::make_pair(c.first, c.second));
+ //if (!r.second) {
+ // ff_aig_map[std::get<0>(c)] = 2*aig_m;
+ //}
}
if (imode && input_bits.empty()) {
@@ -505,9 +585,8 @@ struct XAigerWriter
// aig_latchin.push_back(1);
for (auto &c : co_bits) {
- RTLIL::SigBit bit = c.first;
- c.second = aig_o++;
- ordered_outputs[bit] = c.second;
+ RTLIL::SigBit bit = std::get<0>(c);
+ std::get<4>(c) = ordered_outputs[bit] = aig_o++;
aig_outputs.push_back(bit2aig(bit));
}
@@ -693,49 +772,77 @@ struct XAigerWriter
if (omode && num_outputs == 0)
num_outputs = 1;
write_h_buffer(1);
+ log_debug("ciNum = %zu\n", input_bits.size() + ff_bits.size() + ci_bits.size());
write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size());
- write_h_buffer(num_outputs + ff_bits.size() + co_bits.size());
- write_h_buffer(input_bits.size() + ff_bits.size());
- write_h_buffer(num_outputs + ff_bits.size());
+ log_debug("coNum = %zu\n", num_outputs + ff_bits.size() + co_bits.size());
+ write_h_buffer(num_outputs + ff_bits.size()+ co_bits.size());
+ log_debug("piNum = %zu\n", input_bits.size() + ff_bits.size());
+ write_h_buffer(input_bits.size()+ ff_bits.size());
+ log_debug("poNum = %d\n", num_outputs);
+ write_h_buffer(num_outputs);
+ log_debug("boxNum = %zu\n", box_list.size());
write_h_buffer(box_list.size());
RTLIL::Module *holes_module = nullptr;
holes_module = module->design->addModule("\\__holes__");
+ log_assert(holes_module);
+ int port_id = 1;
+ int box_count = 0;
for (auto cell : box_list) {
+ RTLIL::Module* box_module = module->design->module(cell->type);
int box_inputs = 0, box_outputs = 0;
- int box_id = module->design->module(cell->type)->attributes.at("\\abc_box_id").as_int();
Cell *holes_cell = nullptr;
- if (holes_module && !holes_module->cell(stringf("\\u%d", box_id)))
- holes_cell = holes_module->addCell(stringf("\\u%d", box_id), cell->type);
- RTLIL::Wire *holes_wire;
- // NB: cell->connections_ already sorted from before
- for (const auto &c : cell->connections()) {
- log_assert(c.second.size() == 1);
- if (cell->input(c.first)) {
- box_inputs += c.second.size();
- if (holes_cell) {
+ if (box_module->get_bool_attribute("\\whitebox"))
+ holes_cell = holes_module->addCell(cell->name, cell->type);
+
+ // NB: Assume box_module->ports are sorted alphabetically
+ // (as RTLIL::Module::fixup_ports() would do)
+ for (const auto &port_name : box_module->ports) {
+ RTLIL::Wire *w = box_module->wire(port_name);
+ log_assert(w);
+ RTLIL::Wire *holes_wire;
+ RTLIL::SigSpec port_wire;
+ if (w->port_input) {
+ for (int i = 0; i < GetSize(w); i++) {
+ box_inputs++;
holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
if (!holes_wire) {
holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
holes_wire->port_input = true;
+ holes_wire->port_id = port_id++;
+ holes_module->ports.push_back(holes_wire->name);
}
- holes_cell->setPort(c.first, holes_wire);
+ if (holes_cell)
+ port_wire.append(holes_wire);
}
+ if (!port_wire.empty())
+ holes_cell->setPort(w->name, port_wire);
}
- if (cell->output(c.first)) {
- box_outputs += c.second.size();
- if (holes_cell) {
- holes_wire = holes_module->addWire(stringf("\\%s.%s", cell->type.c_str(), c.first.c_str()));
+ if (w->port_output) {
+ box_outputs += GetSize(w);
+ for (int i = 0; i < GetSize(w); i++) {
+ if (GetSize(w) == 1)
+ holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), w->name.c_str()));
+ else
+ holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), w->name.c_str(), i));
holes_wire->port_output = true;
- holes_cell->setPort(c.first, holes_wire);
+ holes_wire->port_id = port_id++;
+ holes_module->ports.push_back(holes_wire->name);
+ if (holes_cell)
+ port_wire.append(holes_wire);
+ else
+ holes_module->connect(holes_wire, RTLIL::S0);
}
+ if (!port_wire.empty())
+ holes_cell->setPort(w->name, port_wire);
}
}
+
write_h_buffer(box_inputs);
write_h_buffer(box_outputs);
- write_h_buffer(box_id);
- write_h_buffer(0 /* OldBoxNum */);
+ write_h_buffer(box_module->attributes.at("\\abc_box_id").as_int());
+ write_h_buffer(box_count++);
}
f << "h";
@@ -778,13 +885,25 @@ struct XAigerWriter
}
if (holes_module) {
- holes_module->fixup_ports();
+ // NB: fixup_ports() will sort ports by name
+ //holes_module->fixup_ports();
+ holes_module->check();
holes_module->design->selection_stack.emplace_back(false);
RTLIL::Selection& sel = holes_module->design->selection_stack.back();
sel.select(holes_module);
- Pass::call(holes_module->design, "flatten -wb; aigmap; clean -purge");
+ // TODO: Should not need to opt_merge if we only instantiate
+ // each box type once...
+ Pass::call(holes_module->design, "opt_merge -share_all");
+
+ Pass::call(holes_module->design, "flatten -wb");
+
+ // TODO: Should techmap all lib_whitebox-es once
+ //Pass::call(holes_module->design, "techmap");
+
+ Pass::call(holes_module->design, "aigmap");
+ Pass::call(holes_module->design, "clean -purge");
holes_module->design->selection_stack.pop_back();
@@ -804,6 +923,29 @@ struct XAigerWriter
f.write(buffer_str.data(), buffer_str.size());
holes_module->design->remove(holes_module);
}
+
+ std::stringstream r_buffer;
+ auto write_r_buffer = [&r_buffer](int i32) {
+ // TODO: Don't assume we're on little endian
+#ifdef _WIN32
+ int i32_be = _byteswap_ulong(i32);
+#else
+ int i32_be = __builtin_bswap32(i32);
+#endif
+ r_buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
+ };
+ write_r_buffer(0);
+
+ f << "r";
+ buffer_str = r_buffer.str();
+ // TODO: Don't assume we're on little endian
+#ifdef _WIN32
+ buffer_size_be = _byteswap_ulong(buffer_str.size());
+#else
+ buffer_size_be = __builtin_bswap32(buffer_str.size());
+#endif
+ f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
+ f.write(buffer_str.data(), buffer_str.size());
}
f << stringf("Generated by %s\n", yosys_version_str);
@@ -835,7 +977,7 @@ struct XAigerWriter
if (output_bits.count(b)) {
int o = ordered_outputs.at(b);
- output_lines[o] += stringf("output %d %d %s\n", o, i, log_id(wire));
+ output_lines[o] += stringf("output %lu %d %s\n", o - co_bits.size(), i, log_id(wire));
continue;
}
@@ -865,38 +1007,23 @@ struct XAigerWriter
}
}
- for (const auto &c : ci_bits) {
- RTLIL::SigBit b = c.first;
- RTLIL::Wire *wire = b.wire;
- int i = b.offset;
- int a = bit2aig(b);
- log_assert((a & 1) == 0);
- input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire));
- }
-
- for (const auto &c : co_bits) {
- RTLIL::SigBit b = c.first;
- RTLIL::Wire *wire = b.wire;
- int o = c.second;
- if (wire)
- output_lines[o] += stringf("output %d %d %s\n", o, b.offset, log_id(wire));
- else
- output_lines[o] += stringf("output %d %d __const%d__\n", o, 0, b.data);
- }
-
input_lines.sort();
for (auto &it : input_lines)
f << it.second;
- log_assert(input_lines.size() == input_bits.size() + ci_bits.size());
+ log_assert(input_lines.size() == input_bits.size());
init_lines.sort();
for (auto &it : init_lines)
f << it.second;
+ int box_count = 0;
+ for (auto cell : box_list)
+ f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name));
+
output_lines.sort();
for (auto &it : output_lines)
f << it.second;
- log_assert(output_lines.size() == output_bits.size() + co_bits.size());
+ log_assert(output_lines.size() == output_bits.size());
if (omode && output_bits.empty())
f << "output " << output_lines.size() << " 0 __dummy_o__\n";
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index b6dbd84cb..a1761b662 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -409,12 +409,26 @@ struct BlifDumper
f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type));
for (auto &conn : cell->connections())
- for (int i = 0; i < conn.second.size(); i++) {
- if (conn.second.size() == 1)
- f << stringf(" %s", cstr(conn.first));
- else
- f << stringf(" %s[%d]", cstr(conn.first), i);
- f << stringf("=%s", cstr(conn.second.extract(i, 1)));
+ {
+ if (conn.second.size() == 1) {
+ f << stringf(" %s=%s", cstr(conn.first), cstr(conn.second[0]));
+ continue;
+ }
+
+ Module *m = design->module(cell->type);
+ Wire *w = m ? m->wire(conn.first) : nullptr;
+
+ if (w == nullptr) {
+ for (int i = 0; i < GetSize(conn.second); i++)
+ f << stringf(" %s[%d]=%s", cstr(conn.first), i, cstr(conn.second[i]));
+ } else {
+ for (int i = 0; i < std::min(GetSize(conn.second), GetSize(w)); i++) {
+ SigBit sig(w, i);
+ f << stringf(" %s[%d]=%s", cstr(conn.first), sig.wire->upto ?
+ sig.wire->start_offset+sig.wire->width-sig.offset-1 :
+ sig.wire->start_offset+sig.offset, cstr(conn.second[i]));
+ }
+ }
}
f << stringf("\n");
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 91f238fa5..511a11942 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -129,7 +129,13 @@ struct BtorWorker
void export_cell(Cell *cell)
{
- log_assert(cell_recursion_guard.count(cell) == 0);
+ if (cell_recursion_guard.count(cell)) {
+ string cell_list;
+ for (auto c : cell_recursion_guard)
+ cell_list += stringf("\n %s", log_id(c));
+ log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list.c_str());
+ }
+
cell_recursion_guard.insert(cell);
btorf_push(log_id(cell));
diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index ed6e9f8ee..1c7a7351f 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -146,7 +146,7 @@ struct FirrtlWorker
if (!mask.is_fully_def())
this->ena = SigSpec(RTLIL::Const(1));
}
- string gen_read(const char * /* indent */) {
+ string gen_read(const char * /* indent */) {
log_error("gen_read called on write_port: %s\n", name.c_str());
return stringf("gen_read called on write_port: %s\n", name.c_str());
}
@@ -163,31 +163,61 @@ struct FirrtlWorker
}
};
/* Memories defined within this module. */
- struct memory {
- string name; // memory name
- int abits; // number of address bits
- int size; // size (in units) of the memory
- int width; // size (in bits) of each element
- int read_latency;
- int write_latency;
- vector<read_port> read_ports;
- vector<write_port> write_ports;
- std::string init_file;
- std::string init_file_srcFileSpec;
- memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {}
- memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
- void add_memory_read_port(read_port &rp) {
- read_ports.push_back(rp);
- }
- void add_memory_write_port(write_port &wp) {
- write_ports.push_back(wp);
- }
- void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
- this->init_file = init_file;
- this->init_file_srcFileSpec = init_file_srcFileSpec;
+ struct memory {
+ Cell *pCell; // for error reporting
+ string name; // memory name
+ int abits; // number of address bits
+ int size; // size (in units) of the memory
+ int width; // size (in bits) of each element
+ int read_latency;
+ int write_latency;
+ vector<read_port> read_ports;
+ vector<write_port> write_ports;
+ std::string init_file;
+ std::string init_file_srcFileSpec;
+ string srcLine;
+ memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {
+ // Provide defaults for abits or size if one (but not the other) is specified.
+ if (this->abits == 0 && this->size != 0) {
+ this->abits = ceil_log2(this->size);
+ } else if (this->abits != 0 && this->size == 0) {
+ this->size = 1 << this->abits;
+ }
+ // Sanity-check this construction.
+ if (this->name == "") {
+ log_error("Nameless memory%s\n", this->atLine());
+ }
+ if (this->abits == 0 && this->size == 0) {
+ log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine());
+ }
+ if (this->width == 0) {
+ log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine());
+ }
}
+ // We need a default constructor for the dict insert.
+ memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
+
+ const char *atLine() {
+ if (srcLine == "") {
+ if (pCell) {
+ auto p = pCell->attributes.find("\\src");
+ srcLine = " at " + p->second.decode_string();
+ }
+ }
+ return srcLine.c_str();
+ }
+ void add_memory_read_port(read_port &rp) {
+ read_ports.push_back(rp);
+ }
+ void add_memory_write_port(write_port &wp) {
+ write_ports.push_back(wp);
+ }
+ void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
+ this->init_file = init_file;
+ this->init_file_srcFileSpec = init_file_srcFileSpec;
+ }
- };
+ };
dict<string, memory> memories;
void register_memory(memory &m)
@@ -314,6 +344,7 @@ struct FirrtlWorker
switch (dir) {
case FD_INOUT:
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
+ /* FALLTHRU */
case FD_OUT:
sourceExpr = firstName;
sinkExpr = secondExpr;
@@ -321,7 +352,7 @@ struct FirrtlWorker
break;
case FD_NODIRECTION:
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
- /* FALL_THROUGH */
+ /* FALLTHRU */
case FD_IN:
sourceExpr = secondExpr;
sinkExpr = firstName;
@@ -418,8 +449,10 @@ struct FirrtlWorker
string primop;
bool always_uint = false;
if (cell->type == "$not") primop = "not";
- else if (cell->type == "$neg") primop = "neg";
- else if (cell->type == "$logic_not") {
+ else if (cell->type == "$neg") {
+ primop = "neg";
+ is_signed = true; // Result of "neg" is signed (an SInt).
+ } else if (cell->type == "$logic_not") {
primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
}
@@ -531,6 +564,7 @@ struct FirrtlWorker
auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) {
primop = "shl";
+ b_expr = std::to_string(b_sig.as_int());
} else {
primop = "dshl";
// Convert from FIRRTL left shift semantics.
@@ -544,6 +578,7 @@ struct FirrtlWorker
auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) {
primop = "shr";
+ b_expr = std::to_string(b_sig.as_int());
} else {
primop = "dshr";
}
@@ -604,7 +639,7 @@ struct FirrtlWorker
int abits = cell->parameters.at("\\ABITS").as_int();
int width = cell->parameters.at("\\WIDTH").as_int();
int size = cell->parameters.at("\\SIZE").as_int();
- memory m(mem_id, abits, size, width);
+ memory m(cell, mem_id, abits, size, width);
int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
@@ -681,6 +716,8 @@ struct FirrtlWorker
{
std::string cell_type = fid(cell->type);
std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string());
+ int abits = cell->parameters.at("\\ABITS").as_int();
+ int width = cell->parameters.at("\\WIDTH").as_int();
memory *mp = nullptr;
if (cell->type == "$meminit" ) {
log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str());
@@ -693,6 +730,11 @@ struct FirrtlWorker
Const clk_enable = cell->parameters.at("\\CLK_ENABLE");
Const clk_polarity = cell->parameters.at("\\CLK_POLARITY");
+ // Do we already have an entry for this memory?
+ if (memories.count(mem_id) == 0) {
+ memory m(cell, mem_id, abits, 0, width);
+ register_memory(m);
+ }
mp = &memories.at(mem_id);
int portNum = 0;
bool transparency = false;
@@ -890,7 +932,7 @@ struct FirrtlWorker
// If we have any memory definitions, output them.
for (auto kv : memories) {
- memory m = kv.second;
+ memory &m = kv.second;
f << stringf(" mem %s:\n", m.name.c_str());
f << stringf(" data-type => UInt<%d>\n", m.width);
f << stringf(" depth => %d\n", m.size);
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
index dc39e5e08..04d1ee311 100644
--- a/backends/ilang/ilang_backend.cc
+++ b/backends/ilang/ilang_backend.cc
@@ -160,7 +160,10 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
}
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
for (auto &it : cell->parameters) {
- f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str());
+ f << stringf("%s parameter%s%s %s ", indent.c_str(),
+ (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
+ (it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
+ it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
diff --git a/backends/json/json.cc b/backends/json/json.cc
index b4f82a3fe..f5c687981 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -130,75 +130,72 @@ struct JsonWriter
f << stringf(" }");
first = false;
}
- f << stringf("\n }");
+ f << stringf("\n },\n");
- if (!module->get_blackbox_attribute()) {
- f << stringf(",\n \"cells\": {");
- first = true;
- for (auto c : module->cells()) {
- if (use_selection && !module->selected(c))
- continue;
- f << stringf("%s\n", first ? "" : ",");
- f << stringf(" %s: {\n", get_name(c->name).c_str());
- f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
- f << stringf(" \"type\": %s,\n", get_name(c->type).c_str());
- if (aig_mode) {
- Aig aig(c);
- if (!aig.name.empty()) {
- f << stringf(" \"model\": \"%s\",\n", aig.name.c_str());
- aig_models.insert(aig);
- }
- }
- f << stringf(" \"parameters\": {");
- write_parameters(c->parameters);
- f << stringf("\n },\n");
- f << stringf(" \"attributes\": {");
- write_parameters(c->attributes);
- f << stringf("\n },\n");
- if (c->known()) {
- f << stringf(" \"port_directions\": {");
- bool first2 = true;
- for (auto &conn : c->connections()) {
- string direction = "output";
- if (c->input(conn.first))
- direction = c->output(conn.first) ? "inout" : "input";
- f << stringf("%s\n", first2 ? "" : ",");
- f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str());
- first2 = false;
- }
- f << stringf("\n },\n");
+ f << stringf(" \"cells\": {");
+ first = true;
+ for (auto c : module->cells()) {
+ if (use_selection && !module->selected(c))
+ continue;
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s: {\n", get_name(c->name).c_str());
+ f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
+ f << stringf(" \"type\": %s,\n", get_name(c->type).c_str());
+ if (aig_mode) {
+ Aig aig(c);
+ if (!aig.name.empty()) {
+ f << stringf(" \"model\": \"%s\",\n", aig.name.c_str());
+ aig_models.insert(aig);
}
- f << stringf(" \"connections\": {");
+ }
+ f << stringf(" \"parameters\": {");
+ write_parameters(c->parameters);
+ f << stringf("\n },\n");
+ f << stringf(" \"attributes\": {");
+ write_parameters(c->attributes);
+ f << stringf("\n },\n");
+ if (c->known()) {
+ f << stringf(" \"port_directions\": {");
bool first2 = true;
for (auto &conn : c->connections()) {
+ string direction = "output";
+ if (c->input(conn.first))
+ direction = c->output(conn.first) ? "inout" : "input";
f << stringf("%s\n", first2 ? "" : ",");
- f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
+ f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str());
first2 = false;
}
- f << stringf("\n }\n");
- f << stringf(" }");
- first = false;
+ f << stringf("\n },\n");
}
- f << stringf("\n },\n");
-
- f << stringf(" \"netnames\": {");
- first = true;
- for (auto w : module->wires()) {
- if (use_selection && !module->selected(w))
- continue;
- f << stringf("%s\n", first ? "" : ",");
- f << stringf(" %s: {\n", get_name(w->name).c_str());
- f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
- f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
- f << stringf(" \"attributes\": {");
- write_parameters(w->attributes);
- f << stringf("\n }\n");
- f << stringf(" }");
- first = false;
+ f << stringf(" \"connections\": {");
+ bool first2 = true;
+ for (auto &conn : c->connections()) {
+ f << stringf("%s\n", first2 ? "" : ",");
+ f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
+ first2 = false;
}
- f << stringf("\n }");
+ f << stringf("\n }\n");
+ f << stringf(" }");
+ first = false;
+ }
+ f << stringf("\n },\n");
+
+ f << stringf(" \"netnames\": {");
+ first = true;
+ for (auto w : module->wires()) {
+ if (use_selection && !module->selected(w))
+ continue;
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s: {\n", get_name(w->name).c_str());
+ f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
+ f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
+ f << stringf(" \"attributes\": {");
+ write_parameters(w->attributes);
+ f << stringf("\n }\n");
+ f << stringf(" }");
+ first = false;
}
- f << stringf("\n");
+ f << stringf("\n }\n");
f << stringf(" }");
}
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 9967482d6..827af5d85 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -183,8 +183,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
return true;
}
-void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false)
+void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false)
{
+ bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
if (width < 0)
width = data.bits.size() - offset;
if (width == 0) {
@@ -275,7 +276,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
}
}
} else {
- f << stringf("\"");
+ if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
+ f << stringf("\"");
std::string str = data.decode_string();
for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '\n')
@@ -293,7 +295,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
else
f << str[i];
}
- f << stringf("\"");
+ if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
+ f << stringf("\"");
}
}
@@ -373,7 +376,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString,
else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
f << stringf(" 1 ");
else
- dump_const(f, it->second, -1, 0, false, false, attr2comment);
+ dump_const(f, it->second, -1, 0, false, attr2comment);
f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
}
}
@@ -1242,6 +1245,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
+ if (cell->type.in("$assert", "$assume", "$cover"))
+ {
+ f << stringf("%s" "always @* if (", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\EN"));
+ f << stringf(") %s(", cell->type.c_str()+1);
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(");\n");
+ return true;
+ }
+
+ if (cell->type.in("$specify2", "$specify3"))
+ {
+ f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
+
+ SigSpec en = cell->getPort("\\EN");
+ if (en != State::S1) {
+ f << stringf("if (");
+ dump_sigspec(f, cell->getPort("\\EN"));
+ f << stringf(") ");
+ }
+
+ f << "(";
+ if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool())
+ f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
+
+ dump_sigspec(f, cell->getPort("\\SRC"));
+
+ f << " ";
+ if (cell->getParam("\\SRC_DST_PEN").as_bool())
+ f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
+ f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> ");
+
+ if (cell->type == "$specify3") {
+ f << "(";
+ dump_sigspec(f, cell->getPort("\\DST"));
+ f << " ";
+ if (cell->getParam("\\DAT_DST_PEN").as_bool())
+ f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
+ f << ": ";
+ dump_sigspec(f, cell->getPort("\\DAT"));
+ f << ")";
+ } else {
+ dump_sigspec(f, cell->getPort("\\DST"));
+ }
+
+ bool bak_decimal = decimal;
+ decimal = 1;
+
+ f << ") = (";
+ dump_const(f, cell->getParam("\\T_RISE_MIN"));
+ f << ":";
+ dump_const(f, cell->getParam("\\T_RISE_TYP"));
+ f << ":";
+ dump_const(f, cell->getParam("\\T_RISE_MAX"));
+ f << ", ";
+ dump_const(f, cell->getParam("\\T_FALL_MIN"));
+ f << ":";
+ dump_const(f, cell->getParam("\\T_FALL_TYP"));
+ f << ":";
+ dump_const(f, cell->getParam("\\T_FALL_MAX"));
+ f << ");\n";
+
+ decimal = bak_decimal;
+
+ f << stringf("%s" "endspecify\n", indent.c_str());
+ return true;
+ }
+
+ if (cell->type == "$specrule")
+ {
+ f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
+
+ string spec_type = cell->getParam("\\TYPE").decode_string();
+ f << stringf("%s(", spec_type.c_str());
+
+ if (cell->getParam("\\SRC_PEN").as_bool())
+ f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
+ dump_sigspec(f, cell->getPort("\\SRC"));
+
+ if (cell->getPort("\\SRC_EN") != State::S1) {
+ f << " &&& ";
+ dump_sigspec(f, cell->getPort("\\SRC_EN"));
+ }
+
+ f << ", ";
+ if (cell->getParam("\\DST_PEN").as_bool())
+ f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
+ dump_sigspec(f, cell->getPort("\\DST"));
+
+ if (cell->getPort("\\DST_EN") != State::S1) {
+ f << " &&& ";
+ dump_sigspec(f, cell->getPort("\\DST_EN"));
+ }
+
+ bool bak_decimal = decimal;
+ decimal = 1;
+
+ f << ", ";
+ dump_const(f, cell->getParam("\\T_LIMIT"));
+
+ if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") {
+ f << ", ";
+ dump_const(f, cell->getParam("\\T_LIMIT2"));
+ }
+
+ f << ");\n";
+ decimal = bak_decimal;
+
+ f << stringf("%s" "endspecify\n", indent.c_str());
+ return true;
+ }
+
// FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
// FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
@@ -1264,8 +1379,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (it != cell->parameters.begin())
f << stringf(",");
f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
- bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
- dump_const(f, it->second, -1, 0, false, is_signed);
+ dump_const(f, it->second);
f << stringf(")");
}
f << stringf("\n%s" ")", indent.c_str());
@@ -1312,8 +1426,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (defparam && cell->parameters.size() > 0) {
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
- bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
- dump_const(f, it->second, -1, 0, false, is_signed);
+ dump_const(f, it->second);
f << stringf(";\n");
}
}
@@ -1505,7 +1618,8 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
SigSpec sig = active_sigmap(wire);
Const val = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
- active_initdata[sig[i]] = val.bits.at(i);
+ if (val[i] == State::S0 || val[i] == State::S1)
+ active_initdata[sig[i]] = val[i];
}
if (!module->processes.empty())
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index 904a1079d..69404b19d 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -57,11 +57,15 @@ void AigerReader::parse_aiger()
// Optional values
B = C = J = F = 0;
- for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) {
- if (f.peek() != ' ') break;
- if (!(f >> i))
- log_error("Invalid AIGER header\n");
- }
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> B)) log_error("Invalid AIGER header\n");
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> C)) log_error("Invalid AIGER header\n");
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> J)) log_error("Invalid AIGER header\n");
+ if (f.peek() != ' ') goto end_of_header;
+ if (!(f >> F)) log_error("Invalid AIGER header\n");
+end_of_header:
std::string line;
std::getline(f, line); // Ignore up to start of next line, as standard
@@ -113,103 +117,7 @@ void AigerReader::parse_aiger()
std::getline(f, line); // Ignore up to start of next line
}
- dict<RTLIL::IdString, int> wideports_cache;
-
- if (!map_filename.empty()) {
- std::ifstream mf(map_filename);
- std::string type, symbol;
- int variable, index;
- while (mf >> type >> variable >> index >> symbol) {
- RTLIL::IdString escaped_symbol = RTLIL::escape_id(symbol);
- if (type == "input") {
- log_assert(static_cast<unsigned>(variable) < inputs.size());
- RTLIL::Wire* wire = inputs[variable];
- log_assert(wire);
- log_assert(wire->port_input);
-
- if (index == 0)
- module->rename(wire, RTLIL::escape_id(symbol));
- else if (index > 0) {
- module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", symbol.c_str(), index)));
- if (wideports)
- wideports_cache[escaped_symbol] = std::max(wideports_cache[escaped_symbol], index);
- }
- }
- else if (type == "output") {
- log_assert(static_cast<unsigned>(variable) < outputs.size());
- RTLIL::Wire* wire = outputs[variable];
- log_assert(wire);
- // Ignore direct output -> input connections
- if (!wire->port_output)
- continue;
- log_assert(wire->port_output);
-
- if (index == 0)
- module->rename(wire, RTLIL::escape_id(symbol));
- else if (index > 0) {
- module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", symbol.c_str(), index)));
- if (wideports)
- wideports_cache[escaped_symbol] = std::max(wideports_cache[escaped_symbol], index);
- }
- }
- else
- log_error("Symbol type '%s' not recognised.\n", type.c_str());
- }
- }
-
- for (auto &wp : wideports_cache) {
- auto name = wp.first;
- int width = wp.second + 1;
-
- RTLIL::Wire *wire = module->wire(name);
- if (wire)
- module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0)));
-
- // Do not make ports with a mix of input/output into
- // wide ports
- bool port_input = false, port_output = false;
- for (int i = 0; i < width; i++) {
- RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
- RTLIL::Wire *other_wire = module->wire(other_name);
- if (other_wire) {
- port_input = port_input || other_wire->port_input;
- port_output = port_output || other_wire->port_output;
- }
- }
- if ((port_input && port_output) || (!port_input && !port_output))
- continue;
-
- wire = module->addWire(name, width);
- wire->port_input = port_input;
- wire->port_output = port_output;
-
- for (int i = 0; i < width; i++) {
- RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
- RTLIL::Wire *other_wire = module->wire(other_name);
- if (other_wire) {
- other_wire->port_input = false;
- other_wire->port_output = false;
- if (wire->port_input)
- module->connect(other_wire, SigSpec(wire, i));
- else
- module->connect(SigSpec(wire, i), other_wire);
- }
- }
- }
-
- module->fixup_ports();
- design->add(module);
-
- Pass::call(design, "clean");
-
- for (auto cell : module->cells().to_vector()) {
- if (cell->type != "$lut") continue;
- auto y_port = cell->getPort("\\Y").as_bit();
- if (y_port.wire->width == 1)
- module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str()));
- else
- module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset));
- }
+ post_process();
}
static uint32_t parse_xaiger_literal(std::istream &f)
@@ -254,29 +162,6 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
return wire;
}
-static std::pair<RTLIL::IdString, int> wideports_split(std::string name)
-{
- int pos = -1;
-
- if (name.empty() || name.back() != ']')
- goto failed;
-
- for (int i = 0; i+1 < GetSize(name); i++) {
- if (name[i] == '[')
- pos = i;
- else if (name[i] < '0' || name[i] > '9')
- pos = -1;
- else if (i == pos+1 && name[i] == '0' && name[i+1] != ']')
- pos = -1;
- }
-
- if (pos >= 0)
- return std::pair<RTLIL::IdString, int>(RTLIL::escape_id(name.substr(0, pos)), atoi(name.c_str() + pos+1));
-
-failed:
- return std::pair<RTLIL::IdString, int>(name, 0);
-}
-
void AigerReader::parse_xaiger()
{
std::string header;
@@ -307,13 +192,17 @@ void AigerReader::parse_xaiger()
else
log_abort();
+ dict<int,IdString> box_lookup;
+ for (auto m : design->modules()) {
+ auto it = m->attributes.find("\\abc_box_id");
+ if (it == m->attributes.end())
+ continue;
+ box_lookup[it->second.as_int()] = m->name;
+ }
+
// Parse footer (symbol table, comments, etc.)
- unsigned l1;
std::string s;
bool comment_seen = false;
- std::vector<std::pair<RTLIL::Wire*,RTLIL::IdString>> deferred_renames;
- std::vector<std::pair<RTLIL::Wire*,RTLIL::IdString>> deferred_inouts;
- deferred_renames.reserve(inputs.size() + latches.size() + outputs.size());
for (int c = f.peek(); c != EOF; c = f.peek()) {
if (comment_seen || c == 'c') {
if (!comment_seen) {
@@ -383,7 +272,21 @@ void AigerReader::parse_xaiger()
f >> s;
log_debug("n: '%s'\n", s.c_str());
}
- else if (c == 'a' || c == 'i' || c == 'o' || c == 'h') {
+ else if (c == 'h') {
+ f.ignore(sizeof(uint32_t));
+ uint32_t version = parse_xaiger_literal(f);
+ log_assert(version == 1);
+ f.ignore(4*sizeof(uint32_t));
+ uint32_t boxNum = parse_xaiger_literal(f);
+ for (unsigned i = 0; i < boxNum; i++) {
+ f.ignore(2*sizeof(uint32_t));
+ uint32_t boxUniqueId = parse_xaiger_literal(f);
+ log_assert(boxUniqueId > 0);
+ uint32_t oldBoxNum = parse_xaiger_literal(f);
+ module->addCell(stringf("$__box%u__", oldBoxNum), box_lookup.at(boxUniqueId));
+ }
+ }
+ else if (c == 'a' || c == 'i' || c == 'o') {
uint32_t dataSize = parse_xaiger_literal(f);
f.ignore(dataSize);
}
@@ -391,221 +294,11 @@ void AigerReader::parse_xaiger()
break;
}
}
- else if (c == 'i' || c == 'l' || c == 'o') {
- f.ignore(1);
- if (!(f >> l1 >> s))
- log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
-
- if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
- log_error("Line %u has invalid symbol position!\n", line_count);
-
- RTLIL::Wire* wire;
- if (c == 'i') wire = inputs[l1];
- else if (c == 'l') wire = latches[l1];
- else if (c == 'o') wire = outputs[l1];
- else log_abort();
-
- RTLIL::IdString escaped_s = RTLIL::escape_id(s);
-
- if (escaped_s.ends_with("$inout.out")) {
- deferred_inouts.emplace_back(wire, escaped_s.substr(0, escaped_s.size()-10));
- goto next_line;
- }
- else if (wideports && (wire->port_input || wire->port_output)) {
- RTLIL::IdString wide_symbol;
- int index;
- std::tie(wide_symbol,index) = wideports_split(escaped_s.str());
- if (wide_symbol.ends_with("$inout.out")) {
- deferred_inouts.emplace_back(wire, stringf("%s[%d]", wide_symbol.substr(0, wide_symbol.size()-10).c_str(), index));
- goto next_line;
- }
- }
- deferred_renames.emplace_back(wire, escaped_s);
-
-next_line:
- std::getline(f, line); // Ignore up to start of next line
- ++line_count;
- }
else
log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
}
- dict<RTLIL::IdString, int> wideports_cache;
- for (const auto &i : deferred_renames) {
- RTLIL::Wire *wire = i.first;
-
- module->rename(wire, i.second);
-
- if (wideports && (wire->port_input || wire->port_output)) {
- RTLIL::IdString escaped_symbol;
- int index;
- std::tie(escaped_symbol,index) = wideports_split(wire->name.str());
- if (index > 0)
- wideports_cache[escaped_symbol] = std::max(wideports_cache[escaped_symbol], index);
- }
- }
-
- for (const auto &i : deferred_inouts) {
- RTLIL::Wire *out_wire = i.first;
- log_assert(out_wire->port_output);
- out_wire->port_output = false;
- RTLIL::Wire *wire = module->wire(i.second);
- log_assert(wire);
- log_assert(wire->port_input && !wire->port_output);
- wire->port_output = true;
- module->connect(wire, out_wire);
- }
-
- if (!map_filename.empty()) {
- std::ifstream mf(map_filename);
- std::string type, symbol;
- int variable, index;
- while (mf >> type >> variable >> index >> symbol) {
- RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
- if (type == "input") {
- log_assert(static_cast<unsigned>(variable) < inputs.size());
- RTLIL::Wire* wire = inputs[variable];
- log_assert(wire);
- log_assert(wire->port_input);
-
- if (index == 0) {
- // Cope with the fact that a CI might be identical
- // to a PI (necessary due to ABC); in those cases
- // simply connect the latter to the former
- RTLIL::Wire* existing = module->wire(escaped_s);
- if (!existing)
- module->rename(wire, escaped_s);
- else {
- wire->port_input = false;
- module->connect(wire, existing);
- }
- }
- else if (index > 0) {
- std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
- RTLIL::Wire* existing = module->wire(indexed_name);
- if (!existing) {
- module->rename(wire, indexed_name);
- if (wideports)
- wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
- }
- else {
- module->connect(wire, existing);
- wire->port_input = false;
- }
- }
- }
- else if (type == "output") {
- log_assert(static_cast<unsigned>(variable) < outputs.size());
- RTLIL::Wire* wire = outputs[variable];
- log_assert(wire);
- log_assert(wire->port_output);
- if (escaped_s.in("\\__dummy_o__", "\\__const0__", "\\__const1__")) {
- wire->port_output = false;
- continue;
- }
-
- if (index == 0) {
- // Cope with the fact that a CO might be identical
- // to a PO (necessary due to ABC); in those cases
- // simply connect the latter to the former
- RTLIL::Wire* existing = module->wire(escaped_s);
- if (!existing) {
- if (escaped_s.ends_with("$inout.out")) {
- wire->port_output = false;
- RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10));
- log_assert(in_wire);
- log_assert(in_wire->port_input && !in_wire->port_output);
- in_wire->port_output = true;
- module->connect(in_wire, wire);
- }
- else
- module->rename(wire, escaped_s);
- }
- else {
- wire->port_output = false;
- module->connect(wire, existing);
- }
- }
- else if (index > 0) {
- std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
- RTLIL::Wire* existing = module->wire(indexed_name);
- if (!existing) {
- if (escaped_s.ends_with("$inout.out")) {
- wire->port_output = false;
- RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index));
- log_assert(in_wire);
- log_assert(in_wire->port_input && !in_wire->port_output);
- in_wire->port_output = true;
- module->connect(in_wire, wire);
- }
- else {
- module->rename(wire, indexed_name);
- if (wideports)
- wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
- }
- }
- else {
- module->connect(wire, existing);
- wire->port_output = false;
- }
- }
- }
- else
- log_error("Symbol type '%s' not recognised.\n", type.c_str());
- }
- }
-
- for (auto &wp : wideports_cache) {
- auto name = wp.first;
- int width = wp.second + 1;
-
- RTLIL::Wire *wire = module->wire(name);
- if (wire)
- module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0)));
-
- // Do not make ports with a mix of input/output into
- // wide ports
- bool port_input = false, port_output = false;
- for (int i = 0; i < width; i++) {
- RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
- RTLIL::Wire *other_wire = module->wire(other_name);
- if (other_wire) {
- port_input = port_input || other_wire->port_input;
- port_output = port_output || other_wire->port_output;
- }
- }
- if ((port_input && port_output) || (!port_input && !port_output))
- continue;
-
- wire = module->addWire(name, width);
- wire->port_input = port_input;
- wire->port_output = port_output;
-
- for (int i = 0; i < width; i++) {
- RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
- RTLIL::Wire *other_wire = module->wire(other_name);
- if (other_wire) {
- other_wire->port_input = false;
- other_wire->port_output = false;
- if (wire->port_input)
- module->connect(other_wire, SigSpec(wire, i));
- else
- module->connect(SigSpec(wire, i), other_wire);
- }
- }
- }
-
- module->fixup_ports();
- design->add(module);
-
- for (auto cell : module->cells().to_vector()) {
- if (cell->type != "$lut") continue;
- auto y_port = cell->getPort("\\Y").as_bit();
- if (y_port.wire->width == 1)
- module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str()));
- else
- module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset));
- }
+ post_process();
}
void AigerReader::parse_aiger_ascii()
@@ -817,7 +510,7 @@ void AigerReader::parse_aiger_binary()
log_debug("%d is an output\n", l1);
const unsigned variable = l1 >> 1;
const bool invert = l1 & 1;
- RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_inv" the right suffix?
+ RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix?
wire = module->wire(wire_name);
if (!wire)
wire = createWireIfNotExists(module, l1);
@@ -865,6 +558,247 @@ void AigerReader::parse_aiger_binary()
}
}
+void AigerReader::post_process()
+{
+ dict<RTLIL::IdString, int> wideports_cache;
+
+ if (!map_filename.empty()) {
+ std::ifstream mf(map_filename);
+ std::string type, symbol;
+ int variable, index;
+ int pi_count = 0, ci_count = 0, co_count = 0;
+ pool<RTLIL::Module*> abc_carry_modules;
+ while (mf >> type >> variable >> index >> symbol) {
+ RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
+ if (type == "input") {
+ log_assert(static_cast<unsigned>(variable) < inputs.size());
+ RTLIL::Wire* wire = inputs[variable];
+ log_assert(wire);
+ log_assert(wire->port_input);
+ pi_count++;
+
+ if (index == 0) {
+ // Cope with the fact that a CI might be identical
+ // to a PI (necessary due to ABC); in those cases
+ // simply connect the latter to the former
+ RTLIL::Wire* existing = module->wire(escaped_s);
+ if (!existing)
+ module->rename(wire, escaped_s);
+ else {
+ wire->port_input = false;
+ module->connect(wire, existing);
+ }
+ }
+ else if (index > 0) {
+ std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
+ RTLIL::Wire* existing = module->wire(indexed_name);
+ if (!existing) {
+ module->rename(wire, indexed_name);
+ if (wideports)
+ wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
+ }
+ else {
+ module->connect(wire, existing);
+ wire->port_input = false;
+ }
+ }
+ }
+ else if (type == "output") {
+ log_assert(static_cast<unsigned>(variable + co_count) < outputs.size());
+ RTLIL::Wire* wire = outputs[variable + co_count];
+ log_assert(wire);
+ log_assert(wire->port_output);
+ if (escaped_s.in("\\__dummy_o__", "\\__const0__", "\\__const1__")) {
+ wire->port_output = false;
+ continue;
+ }
+
+ if (index == 0) {
+ // Cope with the fact that a CO might be identical
+ // to a PO (necessary due to ABC); in those cases
+ // simply connect the latter to the former
+ RTLIL::Wire* existing = module->wire(escaped_s);
+ if (!existing) {
+ if (escaped_s.ends_with("$inout.out")) {
+ wire->port_output = false;
+ RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10));
+ log_assert(in_wire);
+ log_assert(in_wire->port_input && !in_wire->port_output);
+ in_wire->port_output = true;
+ module->connect(in_wire, wire);
+ }
+ else
+ module->rename(wire, escaped_s);
+ }
+ else {
+ wire->port_output = false;
+ module->connect(wire, existing);
+ }
+ }
+ else if (index > 0) {
+ std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
+ RTLIL::Wire* existing = module->wire(indexed_name);
+ if (!existing) {
+ if (escaped_s.ends_with("$inout.out")) {
+ wire->port_output = false;
+ RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index));
+ log_assert(in_wire);
+ log_assert(in_wire->port_input && !in_wire->port_output);
+ in_wire->port_output = true;
+ module->connect(in_wire, wire);
+ }
+ else {
+ module->rename(wire, indexed_name);
+ if (wideports)
+ wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
+ }
+ }
+ else {
+ module->connect(wire, existing);
+ wire->port_output = false;
+ }
+ }
+ }
+ else if (type == "box") {
+ RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable));
+ if (cell) {
+ module->rename(cell, escaped_s);
+ RTLIL::Module* box_module = design->module(cell->type);
+ log_assert(box_module);
+
+ if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) {
+ RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
+ RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
+ for (const auto &port_name : box_module->ports) {
+ RTLIL::Wire* w = box_module->wire(port_name);
+ log_assert(w);
+ if (w->port_input) {
+ if (w->attributes.count("\\abc_carry_in")) {
+ log_assert(!carry_in);
+ carry_in = w;
+ }
+ log_assert(!last_in || last_in->port_id < w->port_id);
+ last_in = w;
+ }
+ if (w->port_output) {
+ if (w->attributes.count("\\abc_carry_out")) {
+ log_assert(!carry_out);
+ carry_out = w;
+ }
+ log_assert(!last_out || last_out->port_id < w->port_id);
+ last_out = w;
+ }
+ }
+
+ if (carry_in != last_in) {
+ std::swap(box_module->ports[carry_in->port_id], box_module->ports[last_in->port_id]);
+ std::swap(carry_in->port_id, last_in->port_id);
+ }
+ if (carry_out != last_out) {
+ log_assert(last_out);
+ std::swap(box_module->ports[carry_out->port_id], box_module->ports[last_out->port_id]);
+ std::swap(carry_out->port_id, last_out->port_id);
+ }
+ }
+
+ // NB: Assume box_module->ports are sorted alphabetically
+ // (as RTLIL::Module::fixup_ports() would do)
+ for (auto port_name : box_module->ports) {
+ RTLIL::Wire* w = box_module->wire(port_name);
+ log_assert(w);
+ RTLIL::SigSpec rhs;
+ RTLIL::Wire* wire = nullptr;
+ for (int i = 0; i < GetSize(w); i++) {
+ if (w->port_input) {
+ log_assert(static_cast<unsigned>(co_count) < outputs.size());
+ wire = outputs[co_count++];
+ log_assert(wire);
+ log_assert(wire->port_output);
+ wire->port_output = false;
+ }
+ if (w->port_output) {
+ log_assert(static_cast<unsigned>(pi_count + ci_count) < inputs.size());
+ wire = inputs[pi_count + ci_count++];
+ log_assert(wire);
+ log_assert(wire->port_input);
+ wire->port_input = false;
+ }
+ rhs.append(wire);
+ if (GetSize(w) == 1)
+ module->rename(wire, RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name))));
+ else
+ module->rename(wire, RTLIL::escape_id(stringf("%s.%s[%d]", log_id(cell), log_id(port_name), i)));
+ }
+ cell->setPort(port_name, rhs);
+ }
+ }
+ }
+ else
+ log_error("Symbol type '%s' not recognised.\n", type.c_str());
+ }
+ }
+
+ for (auto &wp : wideports_cache) {
+ auto name = wp.first;
+ int width = wp.second + 1;
+
+ RTLIL::Wire *wire = module->wire(name);
+ if (wire)
+ module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0)));
+
+ // Do not make ports with a mix of input/output into
+ // wide ports
+ bool port_input = false, port_output = false;
+ for (int i = 0; i < width; i++) {
+ RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
+ RTLIL::Wire *other_wire = module->wire(other_name);
+ if (other_wire) {
+ port_input = port_input || other_wire->port_input;
+ port_output = port_output || other_wire->port_output;
+ }
+ }
+ if ((port_input && port_output) || (!port_input && !port_output))
+ continue;
+
+ wire = module->addWire(name, width);
+ wire->port_input = port_input;
+ wire->port_output = port_output;
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
+ RTLIL::Wire *other_wire = module->wire(other_name);
+ if (other_wire) {
+ other_wire->port_input = false;
+ other_wire->port_output = false;
+ if (wire->port_input)
+ module->connect(other_wire, SigSpec(wire, i));
+ else
+ module->connect(SigSpec(wire, i), other_wire);
+ }
+ }
+ }
+
+ module->fixup_ports();
+ design->add(module);
+
+ design->selection_stack.emplace_back(false);
+ RTLIL::Selection& sel = design->selection_stack.back();
+ sel.select(module);
+
+ Pass::call(design, "clean");
+
+ design->selection_stack.pop_back();
+
+ for (auto cell : module->cells().to_vector()) {
+ if (cell->type != "$lut") continue;
+ auto y_port = cell->getPort("\\Y").as_bit();
+ if (y_port.wire->width == 1)
+ module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str()));
+ else
+ module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset));
+ }
+}
+
struct AigerFrontend : public Frontend {
AigerFrontend() : Frontend("aiger", "read AIGER file") { }
void help() YS_OVERRIDE
diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h
index 39757545f..8c9f3a0c9 100644
--- a/frontends/aiger/aigerparse.h
+++ b/frontends/aiger/aigerparse.h
@@ -47,6 +47,7 @@ struct AigerReader
void parse_xaiger();
void parse_aiger_ascii();
void parse_aiger_binary();
+ void post_process();
};
YOSYS_NAMESPACE_END
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 9f88b08c1..83993eea9 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -194,6 +194,9 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
is_logic = false;
is_signed = false;
is_string = false;
+ is_wand = false;
+ is_wor = false;
+ is_unsized = false;
was_checked = false;
range_valid = false;
range_swapped = false;
@@ -722,7 +725,7 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
}
// create an AST node for a constant (using a bit vector as value)
-AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
+AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized)
{
AstNode *node = new AstNode(AST_CONSTANT);
node->is_signed = is_signed;
@@ -736,9 +739,15 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
node->range_valid = true;
node->range_left = node->bits.size()-1;
node->range_right = 0;
+ node->is_unsized = is_unsized;
return node;
}
+AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed)
+{
+ return mkconst_bits(v, is_signed, false);
+}
+
// create an AST node for a constant (using a string in bit vector form as value)
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
{
@@ -775,6 +784,14 @@ bool AstNode::bits_only_01() const
return true;
}
+RTLIL::Const AstNode::bitsAsUnsizedConst(int width)
+{
+ RTLIL::State extbit = bits.back();
+ while (width > int(bits.size()))
+ bits.push_back(extbit);
+ return RTLIL::Const(bits);
+}
+
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
{
std::vector<RTLIL::State> bits = this->bits;
@@ -951,6 +968,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
continue;
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
continue;
+ if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
+ (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule"))
+ continue;
blackbox_module = false;
break;
}
@@ -1035,6 +1055,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
child->delete_children();
child->children.push_back(AstNode::mkconst_int(0, false, 0));
new_children.push_back(child);
+ } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
+ (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
+ new_children.push_back(child);
} else {
delete child;
}
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 281cbe086..46d482f1a 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -173,7 +173,7 @@ namespace AST
// node content - most of it is unused in most node types
std::string str;
std::vector<RTLIL::State> bits;
- bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked;
+ bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized;
int port_id, range_left, range_right;
uint32_t integer;
double realvalue;
@@ -262,6 +262,7 @@ namespace AST
// helper functions for creating AST nodes for constants
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
+ static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
static AstNode *mkconst_str(const std::string &str);
@@ -269,6 +270,7 @@ namespace AST
// helper function for creating sign-extended const objects
RTLIL::Const bitsAsConst(int width, bool is_signed);
RTLIL::Const bitsAsConst(int width = -1);
+ RTLIL::Const bitsAsUnsizedConst(int width);
RTLIL::Const asAttrConst();
RTLIL::Const asParaConst();
uint64_t asInt(bool is_signed);
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index b3a2a84be..d2651c9aa 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id_ast->children[0]->range_valid)
log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
+ if (children.size() > 1)
+ range = children[1];
} else
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) {
@@ -902,7 +904,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (!range_valid)
log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str());
- log_assert(range_left >= range_right || (range_left == -1 && range_right == 0));
+ if (!(range_left >= range_right || (range_left == -1 && range_right == 0)))
+ log_file_error(filename, linenum, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1);
RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -917,6 +920,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
wire->attributes[attr.first] = attr.second->asAttrConst();
}
+
+ if (is_wand) wire->set_bool_attribute("\\wand");
+ if (is_wor) wire->set_bool_attribute("\\wor");
}
break;
@@ -961,8 +967,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint);
is_signed = sign_hint;
- if (type == AST_CONSTANT)
- return RTLIL::SigSpec(bitsAsConst());
+ if (type == AST_CONSTANT) {
+ if (is_unsized) {
+ return RTLIL::SigSpec(bitsAsUnsizedConst(width_hint));
+ } else {
+ return RTLIL::SigSpec(bitsAsConst());
+ }
+ }
RTLIL::SigSpec sig = realAsConst(width_hint);
log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
@@ -1490,10 +1501,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue;
}
if (child->type == AST_PARASET) {
+ int extra_const_flags = 0;
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) {
log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
log_id(cell), log_id(paraname), child->children[0]->realvalue);
+ extra_const_flags = RTLIL::CONST_FLAG_REAL;
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]);
delete strnode;
@@ -1502,6 +1515,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst();
+ cell->parameters[paraname].flags |= extra_const_flags;
continue;
}
if (child->type == AST_ARGUMENT) {
@@ -1521,9 +1535,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
+ if (cell->type.in("$specify2", "$specify3")) {
+ int src_width = GetSize(cell->getPort("\\SRC"));
+ int dst_width = GetSize(cell->getPort("\\DST"));
+ bool full = cell->getParam("\\FULL").as_bool();
+ if (!full && src_width != dst_width)
+ log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n");
+ if (cell->type == "$specify3") {
+ int dat_width = GetSize(cell->getPort("\\DAT"));
+ if (dat_width != dst_width)
+ log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n");
+ }
+ cell->setParam("\\SRC_WIDTH", Const(src_width));
+ cell->setParam("\\DST_WIDTH", Const(dst_width));
+ }
+ if (cell->type == "$specrule") {
+ int src_width = GetSize(cell->getPort("\\SRC"));
+ int dst_width = GetSize(cell->getPort("\\DST"));
+ cell->setParam("\\SRC_WIDTH", Const(src_width));
+ cell->setParam("\\DST_WIDTH", Const(dst_width));
+ }
}
break;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 3e453bd7f..e947125bf 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -1172,6 +1172,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
varbuf->children[0] = buf;
}
+ if (type == AST_FOR) {
+ AstNode *buf = next_ast->clone();
+ delete buf->children[1];
+ buf->children[1] = varbuf->children[0]->clone();
+ current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
+ }
+
current_scope[varbuf->str] = backup_scope_varbuf;
delete varbuf;
delete_children();
@@ -1598,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
+ wire_tmp->is_logic = true;
AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
wire_tmp_id->str = wire_tmp->str;
diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l
index d8e01ae4d..4fd0ae855 100644
--- a/frontends/ilang/ilang_lexer.l
+++ b/frontends/ilang/ilang_lexer.l
@@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE
"attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; }
"signed" { return TOK_SIGNED; }
+"real" { return TOK_REAL; }
"wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; }
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index f83824088..44c99906a 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -45,7 +45,16 @@ YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE
%}
-%name-prefix "rtlil_frontend_ilang_yy"
+%define api.prefix {rtlil_frontend_ilang_yy}
+
+/* The union is defined in the header, so we need to provide all the
+ * includes it requires
+ */
+%code requires {
+#include <string>
+#include <vector>
+#include "frontends/ilang/ilang_frontend.h"
+}
%union {
char *string;
@@ -61,7 +70,7 @@ USING_YOSYS_NAMESPACE
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
-%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
+%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
%type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list
@@ -241,6 +250,12 @@ cell_body:
free($4);
delete $5;
} |
+ cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL {
+ current_cell->parameters[$4] = *$5;
+ current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL;
+ free($4);
+ delete $5;
+ } |
cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->hasPort($3))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
@@ -445,4 +460,3 @@ conn_stmt:
delete $2;
delete $3;
};
-
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index ed9727b88..21a1bbbbe 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -46,7 +46,7 @@ USING_YOSYS_NAMESPACE
#include "VeriModule.h"
#include "VeriWrite.h"
#include "VhdlUnits.h"
-#include "Message.h"
+#include "VeriLibrary.h"
#ifdef __clang__
#pragma clang diagnostic pop
@@ -776,13 +776,14 @@ void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates)
void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo)
{
- std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name());
+ std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name();
+ std::string module_name = nl->IsOperator() ? "$verific$" + netlist_name : RTLIL::escape_id(netlist_name);
netlist = nl;
if (design->has(module_name)) {
if (!nl->IsOperator() && !is_blackbox(nl))
- log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name());
+ log_cmd_error("Re-definition of module `%s'.\n", netlist_name.c_str());
return;
}
@@ -1752,32 +1753,64 @@ struct VerificExtNets
}
};
-void verific_import(Design *design, std::string top)
+void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top)
{
verific_sva_fsm_limit = 16;
std::set<Netlist*> nl_todo, nl_done;
- {
- VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
- VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
+ VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
+ VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
+ Array *netlists = NULL;
+ Array veri_libs, vhdl_libs;
+ if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
+ if (veri_lib) veri_libs.InsertLast(veri_lib);
- Array veri_libs, vhdl_libs;
- if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
- if (veri_lib) veri_libs.InsertLast(veri_lib);
+ Map verific_params(STRING_HASH);
+ for (const auto &i : parameters)
+ verific_params.Insert(i.first.c_str(), i.second.c_str());
- Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
- Netlist *nl;
- int i;
+ if (top.empty()) {
+ netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
+ }
+ else {
+ Array veri_modules, vhdl_units;
- FOREACH_ARRAY_ITEM(netlists, i, nl) {
- if (top.empty() || nl->Owner()->Name() == top)
- nl_todo.insert(nl);
+ if (veri_lib) {
+ VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1);
+ if (veri_module) {
+ veri_modules.InsertLast(veri_module);
+ }
+
+ // Also elaborate all root modules since they may contain bind statements
+ MapIter mi;
+ FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
+ if (!veri_module->IsRootModule()) continue;
+ veri_modules.InsertLast(veri_module);
+ }
}
- delete netlists;
+ if (vhdl_lib) {
+ VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str());
+ if (vhdl_unit)
+ vhdl_units.InsertLast(vhdl_unit);
+ }
+
+ netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params);
}
+ Netlist *nl;
+ int i;
+
+ FOREACH_ARRAY_ITEM(netlists, i, nl) {
+ if (top.empty() && nl->CellBaseName() != top)
+ continue;
+ nl->AddAtt(new Att(" \\top", NULL));
+ nl_todo.insert(nl);
+ }
+
+ delete netlists;
+
if (!verific_error_msg.empty())
log_error("%s\n", verific_error_msg.c_str());
@@ -2212,8 +2245,8 @@ struct VerificPass : public Pass {
continue;
}
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
- const std::string &key = args[++argidx];
- const std::string &value = args[++argidx];
+ const std::string &key = args[++argidx];
+ const std::string &value = args[++argidx];
unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
1 /* force_overwrite */);
if (!new_insertion)
@@ -2270,12 +2303,22 @@ struct VerificPass : public Pass {
for (; argidx < GetSize(args); argidx++)
{
const char *name = args[argidx].c_str();
+ VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
+
+ if (veri_lib) {
+ VeriModule *veri_module = veri_lib->GetModule(name, 1);
+ if (veri_module) {
+ log("Adding Verilog module '%s' to elaboration queue.\n", name);
+ veri_modules.InsertLast(veri_module);
+ continue;
+ }
- VeriModule *veri_module = veri_file::GetModule(name);
- if (veri_module) {
- log("Adding Verilog module '%s' to elaboration queue.\n", name);
- veri_modules.InsertLast(veri_module);
- continue;
+ // Also elaborate all root modules since they may contain bind statements
+ MapIter mi;
+ FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
+ if (!veri_module->IsRootModule()) continue;
+ veri_modules.InsertLast(veri_module);
+ }
}
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
@@ -2294,8 +2337,10 @@ struct VerificPass : public Pass {
Netlist *nl;
int i;
- FOREACH_ARRAY_ITEM(netlists, i, nl)
+ FOREACH_ARRAY_ITEM(netlists, i, nl) {
+ nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl);
+ }
delete netlists;
}
diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h
index b331dd4b9..88a6cc0ba 100644
--- a/frontends/verific/verific.h
+++ b/frontends/verific/verific.h
@@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
extern int verific_verbose;
extern bool verific_import_pending;
-extern void verific_import(Design *design, std::string top = std::string());
+extern void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top = std::string());
extern pool<int> verific_sva_prims;
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index 0a1f97ac0..6a8462b41 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -14,7 +14,7 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
-frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=100000
+frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=10000000
OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index 7848c626d..57d366dbf 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -71,7 +71,7 @@ static int my_ilog2(int x)
}
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
-static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type)
+static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized)
{
// all digits in string (MSB at index 0)
std::vector<uint8_t> digits;
@@ -129,6 +129,9 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
return;
}
+ if (is_unsized && (len > len_in_bits))
+ log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
+
for (len = len - 1; len >= 0; len--)
if (data[len] == RTLIL::S1)
break;
@@ -186,7 +189,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
// Simple base-10 integer
if (*endptr == 0) {
std::vector<RTLIL::State> data;
- my_strtobin(data, str, -1, 10, case_type);
+ my_strtobin(data, str, -1, 10, case_type, false);
if (data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
return AstNode::mkconst_bits(data, true);
@@ -201,6 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
std::vector<RTLIL::State> data;
bool is_signed = false;
+ bool is_unsized = false;
if (*(endptr+1) == 's') {
is_signed = true;
endptr++;
@@ -209,28 +213,34 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
case 'b':
case 'B':
- my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 2, case_type, false);
break;
case 'o':
case 'O':
- my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 8, case_type, false);
break;
case 'd':
case 'D':
- my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 10, case_type, false);
break;
case 'h':
case 'H':
- my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
+ my_strtobin(data, endptr+2, len_in_bits, 16, case_type, false);
break;
default:
- return NULL;
+ char next_char = char(tolower(*(endptr+1)));
+ if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
+ my_strtobin(data, endptr+1, 1, 2, case_type, true);
+ is_unsized = true;
+ } else {
+ return NULL;
+ }
}
if (len_in_bits < 0) {
if (is_signed && data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
}
- return AstNode::mkconst_bits(data, is_signed);
+ return AstNode::mkconst_bits(data, is_signed, is_unsized);
}
return NULL;
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index ed6ce2ecb..01e589efb 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -158,6 +158,9 @@ struct VerilogFrontend : public Frontend {
log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
log(" all modules.\n");
log("\n");
+ log(" -specify\n");
+ log(" parse and import specify blocks\n");
+ log("\n");
log(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n");
log(" high-level front-end.\n");
@@ -228,6 +231,8 @@ struct VerilogFrontend : public Frontend {
bool flag_nooverwrite = false;
bool flag_overwrite = false;
bool flag_defer = false;
+ bool flag_noblackbox = false;
+ bool flag_nowb = false;
std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs;
std::list<std::string> attributes;
@@ -237,13 +242,10 @@ struct VerilogFrontend : public Frontend {
formal_mode = false;
norestrict_mode = false;
assume_asserts_mode = false;
- noblackbox_mode = false;
lib_mode = false;
- nowb_mode = false;
+ specify_mode = false;
default_nettype_wire = true;
- log_header(design, "Executing Verilog-2005 frontend.\n");
-
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
size_t argidx;
@@ -342,7 +344,7 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-noblackbox") {
- noblackbox_mode = true;
+ flag_noblackbox = true;
continue;
}
if (arg == "-lib") {
@@ -351,7 +353,11 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-nowb") {
- nowb_mode = true;
+ flag_nowb = true;
+ continue;
+ }
+ if (arg == "-specify") {
+ specify_mode = true;
continue;
}
if (arg == "-noopt") {
@@ -415,6 +421,8 @@ struct VerilogFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
+ log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
+
log("Parsing %s%s input from `%s' to AST representation.\n",
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
@@ -450,7 +458,7 @@ struct VerilogFrontend : public Frontend {
error_on_dpi_function(current_ast);
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
- flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
+ flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index ca40946cb..a7c9b2fe6 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -69,14 +69,11 @@ namespace VERILOG_FRONTEND
// running in -assert-assumes mode
extern bool assert_assumes_mode;
- // running in -noblackbox mode
- extern bool noblackbox_mode;
-
// running in -lib mode
extern bool lib_mode;
- // running in -nowb mode
- extern bool nowb_mode;
+ // running in -specify mode
+ extern bool specify_mode;
// lexer input stream
extern std::istream *lexin;
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 6ef38252a..9558bbfb9 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -148,7 +148,7 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
-"specify" { return TOK_SPECIFY; }
+"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
"endspecify" { return TOK_ENDSPECIFY; }
"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
@@ -206,7 +206,9 @@ YOSYS_NAMESPACE_END
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
+"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); }
+"var" { SV_KEYWORD(TOK_VAR); }
"bit" { SV_KEYWORD(TOK_REG); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
@@ -216,6 +218,8 @@ YOSYS_NAMESPACE_END
"output" { return TOK_OUTPUT; }
"inout" { return TOK_INOUT; }
"wire" { return TOK_WIRE; }
+"wor" { return TOK_WOR; }
+"wand" { return TOK_WAND; }
"reg" { return TOK_REG; }
"integer" { return TOK_INTEGER; }
"signed" { return TOK_SIGNED; }
@@ -230,7 +234,7 @@ YOSYS_NAMESPACE_END
return TOK_CONSTVAL;
}
-[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
+[0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONSTVAL;
}
@@ -301,6 +305,12 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID;
}
+"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
+ if (!specify_mode) REJECT;
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_ID;
+}
+
"$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; }
@@ -411,6 +421,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; }
+[-+]?[=*]> {
+ if (!specify_mode) REJECT;
+ frontend_verilog_yylval.string = new std::string(yytext);
+ return TOK_SPECIFY_OPER;
+}
+
+"&&&" {
+ if (!specify_mode) REJECT;
+ return TOK_SPECIFY_AND;
+}
+
"/*" { BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 40968d17a..8244a8f44 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
- bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode;
+ bool sv_mode, formal_mode, lib_mode, specify_mode;
bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const;
@@ -94,29 +94,58 @@ static void free_attr(std::map<std::string, AstNode*> *al)
delete al;
}
+struct specify_target {
+ char polarity_op;
+ AstNode *dst, *dat;
+};
+
+struct specify_triple {
+ AstNode *t_min, *t_avg, *t_max;
+};
+
+struct specify_rise_fall {
+ specify_triple rise;
+ specify_triple fall;
+};
+
%}
-%name-prefix "frontend_verilog_yy"
+%define api.prefix {frontend_verilog_yy}
+
+/* The union is defined in the header, so we need to provide all the
+ * includes it requires
+ */
+%code requires {
+#include <map>
+#include <string>
+#include "frontends/verilog/verilog_frontend.h"
+}
%union {
std::string *string;
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
+ struct specify_target *specify_target_ptr;
+ struct specify_triple *specify_triple_ptr;
+ struct specify_rise_fall *specify_rise_fall_ptr;
bool boolean;
+ char ch;
}
-%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
-%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
+%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
+%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER
+%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
-%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT
-%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
+%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
+%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
-%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM
+%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
+%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
@@ -130,6 +159,12 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr
+%type <specify_target_ptr> specify_target
+%type <specify_triple_ptr> specify_triple
+%type <specify_rise_fall_ptr> specify_rise_fall
+%type <ast> specify_if specify_condition specify_opt_arg
+%type <ch> specify_edge
+
// operator precedence from low to high
%left OP_LOR
%left OP_LAND
@@ -450,12 +485,21 @@ wire_type_token_io:
wire_type_token:
TOK_WIRE {
} |
+ TOK_WOR {
+ astbuf3->is_wor = true;
+ } |
+ TOK_WAND {
+ astbuf3->is_wand = true;
+ } |
TOK_REG {
astbuf3->is_reg = true;
} |
TOK_LOGIC {
astbuf3->is_logic = true;
} |
+ TOK_VAR {
+ astbuf3->is_logic = true;
+ } |
TOK_INTEGER {
astbuf3->is_reg = true;
astbuf3->range_left = 31;
@@ -539,7 +583,7 @@ module_body:
module_body_stmt:
task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
- always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl;
+ always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl:
TOK_CHECKER TOK_ID ';' {
@@ -697,15 +741,254 @@ task_func_body:
task_func_body behavioral_stmt |
/* empty */;
+/*************************** specify parser ***************************/
+
specify_block:
- TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
- TOK_SPECIFY TOK_ENDSPECIFY ;
+ TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
-specify_item_opt:
- specify_item_opt specify_item |
- specify_item ;
+specify_item_list:
+ specify_item specify_item_list |
+ /* empty */;
specify_item:
+ specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' {
+ AstNode *en_expr = $1;
+ char specify_edge = $3;
+ AstNode *src_expr = $4;
+ string *oper = $5;
+ specify_target *target = $6;
+ specify_rise_fall *timing = $9;
+
+ if (specify_edge != 0 && target->dat == nullptr)
+ frontend_verilog_yyerror("Found specify edge but no data spec.\n");
+
+ AstNode *cell = new AstNode(AST_CELL);
+ ast_stack.back()->children.push_back(cell);
+ cell->str = stringf("$specify$%d", autoidx++);
+ cell->children.push_back(new AstNode(AST_CELLTYPE));
+ cell->children.back()->str = target->dat ? "$specify3" : "$specify2";
+
+ char oper_polarity = 0;
+ char oper_type = oper->at(0);
+
+ if (oper->size() == 3) {
+ oper_polarity = oper->at(0);
+ oper_type = oper->at(1);
+ }
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1)));
+ cell->children.back()->str = "\\FULL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1)));
+ cell->children.back()->str = "\\SRC_DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1)));
+ cell->children.back()->str = "\\SRC_DST_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min));
+ cell->children.back()->str = "\\T_RISE_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg));
+ cell->children.back()->str = "\\T_RISE_TYP";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max));
+ cell->children.back()->str = "\\T_RISE_MAX";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min));
+ cell->children.back()->str = "\\T_FALL_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg));
+ cell->children.back()->str = "\\T_FALL_TYP";
+
+ cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max));
+ cell->children.back()->str = "\\T_FALL_MAX";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1)));
+ cell->children.back()->str = "\\EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
+ cell->children.back()->str = "\\SRC";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst));
+ cell->children.back()->str = "\\DST";
+
+ if (target->dat)
+ {
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1)));
+ cell->children.back()->str = "\\EDGE_EN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1)));
+ cell->children.back()->str = "\\EDGE_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1)));
+ cell->children.back()->str = "\\DAT_DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1)));
+ cell->children.back()->str = "\\DAT_DST_POL";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat));
+ cell->children.back()->str = "\\DAT";
+ }
+
+ delete oper;
+ delete target;
+ delete timing;
+ } |
+ TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' {
+ if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
+ *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
+ frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
+
+ AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
+ AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
+ AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
+
+ AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
+ AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
+ AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
+
+ AstNode *limit = $11;
+ AstNode *limit2 = $12;
+
+ AstNode *cell = new AstNode(AST_CELL);
+ ast_stack.back()->children.push_back(cell);
+ cell->str = stringf("$specify$%d", autoidx++);
+ cell->children.push_back(new AstNode(AST_CELLTYPE));
+ cell->children.back()->str = "$specrule";
+
+ cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
+ cell->children.back()->str = "\\TYPE";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit));
+ cell->children.back()->str = "\\T_LIMIT";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true)));
+ cell->children.back()->str = "\\T_LIMIT2";
+
+ cell->children.push_back(new AstNode(AST_PARASET, src_pen));
+ cell->children.back()->str = "\\SRC_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, src_pol));
+ cell->children.back()->str = "\\SRC_POL";
+
+ cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
+ cell->children.back()->str = "\\DST_PEN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
+ cell->children.back()->str = "\\DST_POL";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
+ cell->children.back()->str = "\\SRC_EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
+ cell->children.back()->str = "\\SRC";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
+ cell->children.back()->str = "\\DST_EN";
+
+ cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
+ cell->children.back()->str = "\\DST";
+
+ delete $1;
+ };
+
+specify_opt_arg:
+ ',' expr {
+ $$ = $2;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
+specify_if:
+ TOK_IF '(' expr ')' {
+ $$ = $3;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
+specify_condition:
+ TOK_SPECIFY_AND expr {
+ $$ = $2;
+ } |
+ /* empty */ {
+ $$ = nullptr;
+ };
+
+specify_target:
+ expr {
+ $$ = new specify_target;
+ $$->polarity_op = 0;
+ $$->dst = $1;
+ $$->dat = nullptr;
+ } |
+ '(' expr ':' expr ')'{
+ $$ = new specify_target;
+ $$->polarity_op = 0;
+ $$->dst = $2;
+ $$->dat = $4;
+ } |
+ '(' expr TOK_NEG_INDEXED expr ')'{
+ $$ = new specify_target;
+ $$->polarity_op = '-';
+ $$->dst = $2;
+ $$->dat = $4;
+ } |
+ '(' expr TOK_POS_INDEXED expr ')'{
+ $$ = new specify_target;
+ $$->polarity_op = '+';
+ $$->dst = $2;
+ $$->dat = $4;
+ };
+
+specify_edge:
+ TOK_POSEDGE { $$ = 'p'; } |
+ TOK_NEGEDGE { $$ = 'n'; } |
+ { $$ = 0; };
+
+specify_rise_fall:
+ specify_triple {
+ $$ = new specify_rise_fall;
+ $$->rise = *$1;
+ $$->fall.t_min = $1->t_min->clone();
+ $$->fall.t_avg = $1->t_avg->clone();
+ $$->fall.t_max = $1->t_max->clone();
+ delete $1;
+ } |
+ '(' specify_triple ',' specify_triple ')' {
+ $$ = new specify_rise_fall;
+ $$->rise = *$2;
+ $$->fall = *$4;
+ delete $2;
+ delete $4;
+ };
+
+specify_triple:
+ expr {
+ $$ = new specify_triple;
+ $$->t_min = $1;
+ $$->t_avg = $1->clone();
+ $$->t_max = $1->clone();
+ } |
+ expr ':' expr ':' expr {
+ $$ = new specify_triple;
+ $$->t_min = $1;
+ $$->t_avg = $3;
+ $$->t_max = $5;
+ };
+
+/******************** ignored specify parser **************************/
+
+ignored_specify_block:
+ TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY |
+ TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ;
+
+ignored_specify_item_opt:
+ ignored_specify_item_opt ignored_specify_item |
+ ignored_specify_item ;
+
+ignored_specify_item:
specparam_declaration
// | pulsestyle_declaration
// | showcancelled_declaration
@@ -721,13 +1004,13 @@ specparam_declaration:
// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
// exxxxtending this for SV specparam would change this anyhow
specparam_range:
- '[' constant_expression ':' constant_expression ']' ;
+ '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment:
- TOK_ID '=' constant_mintypmax_expression ;
+ ignspec_id '=' constant_mintypmax_expression ;
/*
pulsestyle_declaration :
@@ -802,19 +1085,19 @@ opt_polarity_operator :
// Good enough for the time being
specify_input_terminal_descriptor :
- TOK_ID ;
+ ignspec_id ;
// Good enough for the time being
specify_output_terminal_descriptor :
- TOK_ID ;
+ ignspec_id ;
system_timing_declaration :
- TOK_ID '(' system_timing_args ')' ';' ;
+ ignspec_id '(' system_timing_args ')' ';' ;
system_timing_arg :
- TOK_POSEDGE TOK_ID |
- TOK_NEGEDGE TOK_ID |
- expr ;
+ TOK_POSEDGE ignspec_id |
+ TOK_NEGEDGE ignspec_id |
+ ignspec_expr ;
system_timing_args :
system_timing_arg |
@@ -871,19 +1154,27 @@ tzx_path_delay_expression :
*/
path_delay_expression :
- constant_expression;
+ ignspec_constant_expression;
constant_mintypmax_expression :
- constant_expression
- | constant_expression ':' constant_expression ':' constant_expression
+ ignspec_constant_expression
+ | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression
;
// for the time being this is OK, but we may write our own expr here.
// as I'm not sure it is legal to use a full expr here (probably not)
// On the other hand, other rules requiring constant expressions also use 'expr'
// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
-constant_expression:
- expr ;
+ignspec_constant_expression:
+ expr { delete $1; };
+
+ignspec_expr:
+ expr { delete $1; };
+
+ignspec_id:
+ TOK_ID { delete $1; };
+
+/**********************************************************************/
param_signed:
TOK_SIGNED {
@@ -917,7 +1208,7 @@ param_range:
};
param_decl:
- TOK_PARAMETER {
+ attr TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' {
@@ -925,7 +1216,7 @@ param_decl:
};
localparam_decl:
- TOK_LOCALPARAM {
+ attr TOK_LOCALPARAM {
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' {
@@ -1341,6 +1632,9 @@ opt_property:
TOK_PROPERTY {
$$ = true;
} |
+ TOK_FINAL {
+ $$ = false;
+ } |
/* empty */ {
$$ = false;
};
@@ -2139,4 +2433,3 @@ concat_list:
$$ = $3;
$$->children.push_back($1);
};
-
diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc
index 5fd76afe5..26c625f89 100644
--- a/kernel/cellaigs.cc
+++ b/kernel/cellaigs.cc
@@ -453,7 +453,7 @@ Aig::Aig(Cell *cell)
int B = mk.inport("\\B");
int C = mk.inport("\\C");
int D = mk.inport("\\D");
- int Y = mk.nand_gate(mk.nor_gate(A, B), mk.nor_gate(C, D));
+ int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D));
mk.outport(Y, "\\Y");
goto optimize;
}
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index ae88f4aaf..4e91eddda 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -85,6 +85,8 @@ struct CellTypes
setup_internals_eval();
IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
+ IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT";
+ IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST";
setup_type("$tribuf", {A, EN}, {Y}, true);
@@ -99,6 +101,9 @@ struct CellTypes
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$equiv", {A, B}, {Y}, true);
+ setup_type("$specify2", {EN, SRC, DST}, pool<RTLIL::IdString>(), true);
+ setup_type("$specify3", {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true);
+ setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true);
}
void setup_internals_eval()
@@ -464,7 +469,7 @@ struct CellTypes
if (cell->type == "$_AOI4_")
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
if (cell->type == "$_OAI4_")
- return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
+ return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1));
log_assert(arg4.bits.size() == 0);
return eval(cell, arg1, arg2, arg3, errp);
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 1bc7a5935..f273057dd 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -529,13 +529,13 @@ int main(int argc, char **argv)
log_error("Can't open dependencies file for writing: %s\n", strerror(errno));
bool first = true;
for (auto fn : yosys_output_files) {
- fprintf(f, "%s%s", first ? "" : " ", fn.c_str());
+ fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces(fn).c_str());
first = false;
}
fprintf(f, ":");
for (auto fn : yosys_input_files) {
if (yosys_output_files.count(fn) == 0)
- fprintf(f, " %s", fn.c_str());
+ fprintf(f, " %s", escape_filename_spaces(fn).c_str());
}
fprintf(f, "\n");
}
diff --git a/kernel/log.cc b/kernel/log.cc
index 9a9104e26..fa74a6a3c 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -230,6 +230,9 @@ static void logv_warning_with_prefix(const char *prefix,
}
else
{
+ int bak_log_make_debug = log_make_debug;
+ log_make_debug = 0;
+
for (auto &re : log_werror_regexes)
if (std::regex_search(message, re))
log_error("%s", message.c_str());
@@ -254,6 +257,7 @@ static void logv_warning_with_prefix(const char *prefix,
}
log_warnings_count++;
+ log_make_debug = bak_log_make_debug;
}
}
@@ -285,6 +289,9 @@ static void logv_error_with_prefix(const char *prefix,
#ifdef EMSCRIPTEN
auto backup_log_files = log_files;
#endif
+ int bak_log_make_debug = log_make_debug;
+ log_make_debug = 0;
+ log_suppressed();
if (log_errfile != NULL)
log_files.push_back(log_errfile);
@@ -298,6 +305,8 @@ static void logv_error_with_prefix(const char *prefix,
log("%s%s", prefix, log_last_error.c_str());
log_flush();
+ log_make_debug = bak_log_make_debug;
+
if (log_error_atexit)
log_error_atexit();
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 7e1159cac..790ba52a3 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -218,15 +218,19 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
{
if (value)
attributes[id] = RTLIL::Const(1);
- else if (attributes.count(id))
- attributes.erase(id);
+ else {
+ const auto it = attributes.find(id);
+ if (it != attributes.end())
+ attributes.erase(it);
+ }
}
bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
{
- if (attributes.count(id) == 0)
+ const auto it = attributes.find(id);
+ if (it == attributes.end())
return false;
- return attributes.at(id).as_bool();
+ return it->second.as_bool();
}
void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
@@ -1194,6 +1198,46 @@ namespace {
return;
}
+ if (cell->type.in("$specify2", "$specify3")) {
+ param_bool("\\FULL");
+ param_bool("\\SRC_DST_PEN");
+ param_bool("\\SRC_DST_POL");
+ param("\\T_RISE_MIN");
+ param("\\T_RISE_TYP");
+ param("\\T_RISE_MAX");
+ param("\\T_FALL_MIN");
+ param("\\T_FALL_TYP");
+ param("\\T_FALL_MAX");
+ port("\\EN", 1);
+ port("\\SRC", param("\\SRC_WIDTH"));
+ port("\\DST", param("\\DST_WIDTH"));
+ if (cell->type == "$specify3") {
+ param_bool("\\EDGE_EN");
+ param_bool("\\EDGE_POL");
+ param_bool("\\DAT_DST_PEN");
+ param_bool("\\DAT_DST_POL");
+ port("\\DAT", param("\\DST_WIDTH"));
+ }
+ check_expected();
+ return;
+ }
+
+ if (cell->type == "$specrule") {
+ param("\\TYPE");
+ param_bool("\\SRC_PEN");
+ param_bool("\\SRC_POL");
+ param_bool("\\DST_PEN");
+ param_bool("\\DST_POL");
+ param("\\T_LIMIT");
+ param("\\T_LIMIT2");
+ port("\\SRC_EN", 1);
+ port("\\DST_EN", 1);
+ port("\\SRC", param("\\SRC_WIDTH"));
+ port("\\DST", param("\\DST_WIDTH"));
+ check_expected();
+ return;
+ }
+
if (cell->type == "$_BUF_") { check_gate("AY"); return; }
if (cell->type == "$_NOT_") { check_gate("AY"); return; }
if (cell->type == "$_AND_") { check_gate("ABY"); return; }
@@ -1470,7 +1514,10 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
cell->module = this;
}
-namespace {
+void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
+{
+ log_assert(refcount_wires_ == 0);
+
struct DeleteWireWorker
{
RTLIL::Module *module;
@@ -1485,17 +1532,29 @@ namespace {
}
sig = chunks;
}
- };
-}
-void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
-{
- log_assert(refcount_wires_ == 0);
+ void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) {
+ log_assert(GetSize(lhs) == GetSize(rhs));
+ RTLIL::SigSpec new_lhs, new_rhs;
+ for (int i = 0; i < GetSize(lhs); i++) {
+ RTLIL::SigBit lhs_bit = lhs[i];
+ if (lhs_bit.wire != nullptr && wires_p->count(lhs_bit.wire))
+ continue;
+ RTLIL::SigBit rhs_bit = rhs[i];
+ if (rhs_bit.wire != nullptr && wires_p->count(rhs_bit.wire))
+ continue;
+ new_lhs.append(lhs_bit);
+ new_rhs.append(rhs_bit);
+ }
+ lhs = new_lhs;
+ rhs = new_rhs;
+ }
+ };
DeleteWireWorker delete_wire_worker;
delete_wire_worker.module = this;
delete_wire_worker.wires_p = &wires;
- rewrite_sigspecs(delete_wire_worker);
+ rewrite_sigspecs2(delete_wire_worker);
for (auto &it : wires) {
log_assert(wires_.count(it->name) != 0);
@@ -3456,7 +3515,7 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
pack();
other.pack();
- if (chunks_.size() != chunks_.size())
+ if (chunks_.size() != other.chunks_.size())
return false;
updhash();
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 757e0dfa4..d3ad57d72 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -50,7 +50,7 @@ namespace RTLIL
CONST_FLAG_NONE = 0,
CONST_FLAG_STRING = 1,
CONST_FLAG_SIGNED = 2, // only used for parameters
- CONST_FLAG_REAL = 4 // unused -- to be used for parameters
+ CONST_FLAG_REAL = 4 // only used for parameters
};
struct Const;
@@ -524,6 +524,7 @@ struct RTLIL::Const
Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }
Const(const std::vector<bool> &bits);
Const(const RTLIL::Const &c);
+ RTLIL::Const &operator =(const RTLIL::Const &other) = default;
bool operator <(const RTLIL::Const &other) const;
bool operator ==(const RTLIL::Const &other) const;
@@ -603,8 +604,10 @@ struct RTLIL::SigChunk
SigChunk(RTLIL::State bit, int width = 1);
SigChunk(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; }
bool operator <(const RTLIL::SigChunk &other) const;
bool operator ==(const RTLIL::SigChunk &other) const;
@@ -628,6 +631,7 @@ struct RTLIL::SigBit
SigBit(const RTLIL::SigChunk &chunk, int index);
SigBit(const RTLIL::SigSpec &sig);
SigBit(const RTLIL::SigBit &sigbit);
+ RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default;
bool operator <(const RTLIL::SigBit &other) const;
bool operator ==(const RTLIL::SigBit &other) const;
@@ -1004,6 +1008,7 @@ public:
void fixup_ports();
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
void cloneInto(RTLIL::Module *new_mod) const;
virtual RTLIL::Module *clone() const;
@@ -1309,6 +1314,7 @@ public:
}
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
@@ -1327,6 +1333,7 @@ struct RTLIL::CaseRule
bool empty() const;
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::CaseRule *clone() const;
};
@@ -1340,6 +1347,7 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
bool empty() const;
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SwitchRule *clone() const;
};
@@ -1350,6 +1358,7 @@ struct RTLIL::SyncRule
std::vector<RTLIL::SigSig> actions;
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SyncRule *clone() const;
};
@@ -1362,6 +1371,7 @@ struct RTLIL::Process : public RTLIL::AttrObject
~Process();
template<typename T> void rewrite_sigspecs(T &functor);
+ template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::Process *clone() const;
};
@@ -1424,12 +1434,30 @@ void RTLIL::Module::rewrite_sigspecs(T &functor)
}
template<typename T>
+void RTLIL::Module::rewrite_sigspecs2(T &functor)
+{
+ for (auto &it : cells_)
+ it.second->rewrite_sigspecs2(functor);
+ for (auto &it : processes)
+ it.second->rewrite_sigspecs2(functor);
+ for (auto &it : connections_) {
+ functor(it.first, it.second);
+ }
+}
+
+template<typename T>
void RTLIL::Cell::rewrite_sigspecs(T &functor) {
for (auto &it : connections_)
functor(it.second);
}
template<typename T>
+void RTLIL::Cell::rewrite_sigspecs2(T &functor) {
+ for (auto &it : connections_)
+ functor(it.second);
+}
+
+template<typename T>
void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
for (auto &it : compare)
functor(it);
@@ -1442,6 +1470,17 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
}
template<typename T>
+void RTLIL::CaseRule::rewrite_sigspecs2(T &functor) {
+ for (auto &it : compare)
+ functor(it);
+ for (auto &it : actions) {
+ functor(it.first, it.second);
+ }
+ for (auto it : switches)
+ it->rewrite_sigspecs2(functor);
+}
+
+template<typename T>
void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
{
functor(signal);
@@ -1450,6 +1489,14 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
}
template<typename T>
+void RTLIL::SwitchRule::rewrite_sigspecs2(T &functor)
+{
+ functor(signal);
+ for (auto it : cases)
+ it->rewrite_sigspecs2(functor);
+}
+
+template<typename T>
void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
{
functor(signal);
@@ -1460,6 +1507,15 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
}
template<typename T>
+void RTLIL::SyncRule::rewrite_sigspecs2(T &functor)
+{
+ functor(signal);
+ for (auto &it : actions) {
+ functor(it.first, it.second);
+ }
+}
+
+template<typename T>
void RTLIL::Process::rewrite_sigspecs(T &functor)
{
root_case.rewrite_sigspecs(functor);
@@ -1467,6 +1523,14 @@ void RTLIL::Process::rewrite_sigspecs(T &functor)
it->rewrite_sigspecs(functor);
}
+template<typename T>
+void RTLIL::Process::rewrite_sigspecs2(T &functor)
+{
+ root_case.rewrite_sigspecs2(functor);
+ for (auto it : syncs)
+ it->rewrite_sigspecs2(functor);
+}
+
YOSYS_NAMESPACE_END
#endif
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index a12355f1d..377572fc2 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -151,14 +151,16 @@ void yosys_banner()
int ceil_log2(int x)
{
+#if defined(__GNUC__)
+ return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0;
+#else
if (x <= 0)
return 0;
-
for (int i = 0; i < 32; i++)
if (((x-1) >> i) == 0)
return i;
-
log_abort();
+#endif
}
std::string stringf(const char *fmt, ...)
@@ -482,6 +484,20 @@ void remove_directory(std::string dirname)
#endif
}
+std::string escape_filename_spaces(const std::string& filename)
+{
+ std::string out;
+ out.reserve(filename.size());
+ for (auto c : filename)
+ {
+ if (c == ' ')
+ out += "\\ ";
+ else
+ out.push_back(c);
+ }
+ return out;
+}
+
int GetSize(RTLIL::Wire *wire)
{
return wire->width;
diff --git a/kernel/yosys.h b/kernel/yosys.h
index 2cf6188b4..c7b671724 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -244,7 +244,7 @@ extern bool memhasher_active;
inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner();
-int ceil_log2(int x);
+int ceil_log2(int x) YS_ATTRIBUTE(const);
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
std::string vstringf(const char *fmt, va_list ap);
int readsome(std::istream &f, char *s, int n);
@@ -257,6 +257,7 @@ std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false);
bool is_absolute_path(std::string filename);
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);
diff --git a/libs/subcircuit/subcircuit.cc b/libs/subcircuit/subcircuit.cc
index 7c7236833..e8361a67e 100644
--- a/libs/subcircuit/subcircuit.cc
+++ b/libs/subcircuit/subcircuit.cc
@@ -320,12 +320,10 @@ class SubCircuit::SolverWorker
static int numberOfPermutations(const std::vector<std::string> &list)
{
- int numPermutations = 1;
- for (int i = 0; i < int(list.size()); i++) {
- assert(numPermutations < maxPermutationsLimit);
- numPermutations *= i+1;
- }
- return numPermutations;
+ constexpr size_t mappedPermutationsSize = 10;
+ constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
+ assert(list.size() < mappedPermutationsSize);
+ return mappedPermutations[list.size()];
}
static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx)
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index e64919182..cb1bcf1be 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -466,6 +466,10 @@ Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}
\end{fixme}
\begin{fixme}
+Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells.
+\end{fixme}
+
+\begin{fixme}
Add information about {\tt \$slice} and {\tt \$concat} cells.
\end{fixme}
diff --git a/__init__.py b/misc/__init__.py
index 330fd6d86..330fd6d86 100644
--- a/__init__.py
+++ b/misc/__init__.py
diff --git a/py_wrap_generator.py b/misc/py_wrap_generator.py
index 09f934040..09f934040 100644
--- a/py_wrap_generator.py
+++ b/misc/py_wrap_generator.py
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
index 4b22f6d2d..038ab7c7c 100644
--- a/passes/cmds/bugpoint.cc
+++ b/passes/cmds/bugpoint.cc
@@ -281,6 +281,9 @@ struct BugpointPass : public Pass {
}
extra_args(args, argidx, design);
+ if (script.empty())
+ log_cmd_error("Missing -script option.\n");
+
if (!has_part)
{
modules = true;
@@ -298,7 +301,7 @@ struct BugpointPass : public Pass {
if (!check_logfile(grep))
log_cmd_error("The provided grep string is not found in the log file!\n");
- int seed = 0, crashing_seed = seed;
+ int seed = 0;
bool found_something = false, stage2 = false;
while (true)
{
@@ -324,7 +327,6 @@ struct BugpointPass : public Pass {
if (crashing_design != design)
delete crashing_design;
crashing_design = simplified;
- crashing_seed = seed;
found_something = true;
}
else
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 0ec747671..1128116b4 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -98,21 +98,23 @@ struct CoverPass : public Pass {
}
if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
- std::string filename = args[++argidx];
+ const std::string &filename = args[++argidx];
+ FILE *f = nullptr;
if (args[argidx-1] == "-d") {
#ifdef _WIN32
log_cmd_error("The 'cover -d' option is not supported on win32.\n");
#else
char filename_buffer[4096];
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
- filename = mkstemps(filename_buffer, 4);
+ f = fdopen(mkstemps(filename_buffer, 4), "w");
#endif
+ } else {
+ f = fopen(filename.c_str(), open_mode);
}
- FILE *f = fopen(filename.c_str(), open_mode);
if (f == NULL) {
for (auto f : out_files)
fclose(f);
- log_cmd_error("Can't create file %s.\n", args[argidx].c_str());
+ log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx].c_str());
}
out_files.push_back(f);
continue;
diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc
index 1c64a7b77..adbe89e31 100644
--- a/passes/cmds/qwp.cc
+++ b/passes/cmds/qwp.cc
@@ -291,7 +291,7 @@ struct QwpWorker
// gaussian elimination
for (int i = 0; i < N; i++)
{
- if (config.verbose && ((i+1) % (N/15)) == 0)
+ if (config.verbose && N > 15 && ((i+1) % (N/15)) == 0)
log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N);
// find best row
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 54f4ea817..c42f7fcdd 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -37,7 +37,9 @@ struct statdata_t
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::set<RTLIL::IdString> unknown_cell_area;
@@ -70,8 +72,10 @@ struct statdata_t
#undef X
}
- statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area)
+ statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area, string techname)
{
+ tech = techname;
+
#define X(_name) _name = 0;
STAT_NUMERIC_MEMBERS
#undef X
@@ -153,7 +157,8 @@ struct statdata_t
log(" Number of processes: %6d\n", num_processes);
log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type)
- log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
+ if (it.second)
+ log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
if (!unknown_cell_area.empty()) {
log("\n");
@@ -165,6 +170,59 @@ struct statdata_t
log("\n");
log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
}
+
+ if (tech == "xilinx")
+ {
+ int lut6_cnt = num_cells_by_type["\\LUT6"];
+ int lut5_cnt = num_cells_by_type["\\LUT5"];
+ int lut4_cnt = num_cells_by_type["\\LUT4"];
+ int lut3_cnt = num_cells_by_type["\\LUT3"];
+ int lut2_cnt = num_cells_by_type["\\LUT2"];
+ int lut1_cnt = num_cells_by_type["\\LUT1"];
+ int lc_cnt = 0;
+
+ lc_cnt += lut6_cnt;
+
+ lc_cnt += lut5_cnt;
+ if (lut1_cnt) {
+ int cnt = std::min(lut5_cnt, lut1_cnt);
+ lut5_cnt -= cnt;
+ lut1_cnt -= cnt;
+ }
+
+ lc_cnt += lut4_cnt;
+ if (lut1_cnt) {
+ int cnt = std::min(lut4_cnt, lut1_cnt);
+ lut4_cnt -= cnt;
+ lut1_cnt -= cnt;
+ }
+ if (lut2_cnt) {
+ int cnt = std::min(lut4_cnt, lut2_cnt);
+ lut4_cnt -= cnt;
+ lut2_cnt -= cnt;
+ }
+
+ lc_cnt += lut3_cnt;
+ if (lut1_cnt) {
+ int cnt = std::min(lut3_cnt, lut1_cnt);
+ lut3_cnt -= cnt;
+ lut1_cnt -= cnt;
+ }
+ if (lut2_cnt) {
+ int cnt = std::min(lut3_cnt, lut2_cnt);
+ lut3_cnt -= cnt;
+ lut2_cnt -= cnt;
+ }
+ if (lut3_cnt) {
+ int cnt = (lut3_cnt + 1) / 2;
+ lut3_cnt -= cnt;
+ }
+
+ lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2;
+
+ log("\n");
+ log(" Estimated number of LCs: %10d\n", lc_cnt);
+ }
}
};
@@ -226,6 +284,10 @@ struct StatPass : public Pass {
log(" -liberty <liberty_file>\n");
log(" use cell area information from the provided liberty file\n");
log("\n");
+ log(" -tech <technology>\n");
+ log(" print area estemate for the specified technology. Corrently supported\n");
+ log(" calues for <technology>: xilinx\n");
+ log("\n");
log(" -width\n");
log(" annotate internal cell types with their word width.\n");
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
@@ -239,6 +301,7 @@ struct StatPass : public Pass {
RTLIL::Module *top_mod = NULL;
std::map<RTLIL::IdString, statdata_t> mod_stat;
dict<IdString, double> cell_area;
+ string techname;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -253,6 +316,10 @@ struct StatPass : public Pass {
read_liberty_cellarea(cell_area, liberty_file);
continue;
}
+ if (args[argidx] == "-tech" && argidx+1 < args.size()) {
+ techname = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-top" && argidx+1 < args.size()) {
if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
@@ -263,13 +330,19 @@ struct StatPass : public Pass {
}
extra_args(args, argidx, design);
+ if (techname != "" && techname != "xilinx")
+ log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
+
for (auto mod : design->selected_modules())
{
if (!top_mod && design->full_selection())
if (mod->get_bool_attribute("\\top"))
top_mod = mod;
- statdata_t data(design, mod, width_mode, cell_area);
+ if (mod->attributes.count("\\abc_box_id"))
+ continue;
+
+ statdata_t data(design, mod, width_mode, cell_area, techname);
mod_stat[mod->name] = data;
log("\n");
diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc
index e5dda9c24..3596dfd7b 100644
--- a/passes/equiv/equiv_opt.cc
+++ b/passes/equiv/equiv_opt.cc
@@ -44,7 +44,10 @@ struct EquivOptPass:public ScriptPass
log(" useful for handling architecture-specific primitives.\n");
log("\n");
log(" -assert\n");
- log(" produce an error if the circuits are not equivalent\n");
+ log(" produce an error if the circuits are not equivalent.\n");
+ log("\n");
+ log(" -undef\n");
+ log(" enable modelling of undef states during equiv_induct.\n");
log("\n");
log("The following commands are executed by this verification command:\n");
help_script();
@@ -52,13 +55,14 @@ struct EquivOptPass:public ScriptPass
}
std::string command, techmap_opts;
- bool assert;
+ bool assert, undef;
void clear_flags() YS_OVERRIDE
{
command = "";
techmap_opts = "";
assert = false;
+ undef = false;
}
void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE
@@ -84,6 +88,10 @@ struct EquivOptPass:public ScriptPass
assert = true;
continue;
}
+ if (args[argidx] == "-undef") {
+ undef = true;
+ continue;
+ }
break;
}
@@ -139,7 +147,12 @@ struct EquivOptPass:public ScriptPass
if (check_label("prove")) {
run("equiv_make gold gate equiv");
- run("equiv_induct equiv");
+ if (help_mode)
+ run("equiv_induct [-undef] equiv");
+ else if (undef)
+ run("equiv_induct -undef equiv");
+ else
+ run("equiv_induct equiv");
if (help_mode)
run("equiv_status [-assert] equiv");
else if (assert)
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index b8ff99884..24e64a9b2 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -562,7 +562,8 @@ struct HierarchyPass : public Pass {
log("In parametric designs, a module might exists in several variations with\n");
log("different parameter values. This pass looks at all modules in the current\n");
log("design an re-runs the language frontends for the parametric modules as\n");
- log("needed.\n");
+ log("needed. It also resolves assignments to wired logic data types (wand/wor),\n");
+ log("resolves positional module parameters, unroll array instances, and more.\n");
log("\n");
log(" -check\n");
log(" also check the design hierarchy. this generates an error when\n");
@@ -570,7 +571,7 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -simcheck\n");
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(" instantiated, and throw an error if the design has no top module.\n");
log("\n");
log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n");
@@ -583,20 +584,20 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -keep_positionals\n");
log(" per default this pass also converts positional arguments in cells\n");
- log(" to arguments using port names. this option disables this behavior.\n");
+ log(" to arguments using port names. This option disables this behavior.\n");
log("\n");
log(" -keep_portwidths\n");
log(" per default this pass adjusts the port width on cells that are\n");
- log(" module instances when the width does not match the module port. this\n");
+ log(" module instances when the width does not match the module port. This\n");
log(" option disables this behavior.\n");
log("\n");
log(" -nokeep_asserts\n");
log(" per default this pass sets the \"keep\" attribute on all modules\n");
- log(" that directly or indirectly contain one or more $assert cells. this\n");
- log(" option disables this behavior.\n");
+ log(" that directly or indirectly contain one or more formal properties.\n");
+ log(" This option disables this behavior.\n");
log("\n");
log(" -top <module>\n");
- log(" use the specified top module to built a design hierarchy. modules\n");
+ log(" use the specified top module to build the design hierarchy. Modules\n");
log(" outside this tree (unused modules) are removed.\n");
log("\n");
log(" when the -top option is used, the 'top' attribute will be set on the\n");
@@ -606,6 +607,12 @@ struct HierarchyPass : public Pass {
log(" -auto-top\n");
log(" automatically determine the top of the design hierarchy and mark it.\n");
log("\n");
+ log(" -chparam name value \n");
+ log(" elaborate the top module using this parameter value. Modules on which\n");
+ log(" this parameter does not exist may cause a warning message to be output.\n");
+ log(" This option can be specified multiple times to override multiple\n");
+ log(" parameters. String values must be passed in double quotes (\").\n");
+ log("\n");
log("In -generate mode this pass generates blackbox modules for the given cell\n");
log("types (wildcards supported). For this the design is searched for cells that\n");
log("match the given types and then the given port declarations are used to\n");
@@ -641,6 +648,7 @@ struct HierarchyPass : public Pass {
bool nokeep_asserts = false;
std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports;
+ std::map<std::string, std::string> parameters;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -715,28 +723,61 @@ struct HierarchyPass : public Pass {
if (args[argidx] == "-top") {
if (++argidx >= args.size())
log_cmd_error("Option -top requires an additional argument!\n");
- top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
- if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
- dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
- design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
- top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
- }
- if (top_mod == NULL)
- load_top_mod = args[argidx];
+ load_top_mod = args[argidx];
continue;
}
if (args[argidx] == "-auto-top") {
auto_top_mode = true;
continue;
}
+ if (args[argidx] == "-chparam" && argidx+2 < args.size()) {
+ const std::string &key = args[++argidx];
+ const std::string &value = args[++argidx];
+ auto r = parameters.emplace(key, value);
+ if (!r.second) {
+ log_warning("-chparam %s already specified: overwriting.\n", key.c_str());
+ r.first->second = value;
+ }
+ continue;
+ }
break;
}
extra_args(args, argidx, design, false);
- if (!load_top_mod.empty()) {
+ if (!load_top_mod.empty())
+ {
+ IdString top_name = RTLIL::escape_id(load_top_mod);
+ IdString abstract_id = "$abstract" + RTLIL::escape_id(load_top_mod);
+ top_mod = design->module(top_name);
+
+ dict<RTLIL::IdString, RTLIL::Const> top_parameters;
+ for (auto &para : parameters) {
+ SigSpec sig_value;
+ if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
+ log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
+ top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
+ }
+
+ if (top_mod == nullptr && design->module(abstract_id))
+ top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters));
+ else if (top_mod != nullptr && !top_parameters.empty())
+ top_mod = design->module(top_mod->derive(design, top_parameters));
+
+ if (top_mod != nullptr && top_mod->name != top_name) {
+ Module *m = top_mod->clone();
+ m->name = top_name;
+ Module *old_mod = design->module(top_name);
+ if (old_mod)
+ design->remove(old_mod);
+ design->add(m);
+ top_mod = m;
+ }
+ }
+
+ if (top_mod == nullptr && !load_top_mod.empty()) {
#ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending) {
- verific_import(design, load_top_mod);
+ verific_import(design, parameters, load_top_mod);
top_mod = design->module(RTLIL::escape_id(load_top_mod));
}
#endif
@@ -745,7 +786,7 @@ struct HierarchyPass : public Pass {
} else {
#ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending)
- verific_import(design);
+ verific_import(design, parameters);
#endif
}
@@ -846,7 +887,7 @@ struct HierarchyPass : public Pass {
std::map<RTLIL::Module*, bool> cache;
for (auto mod : design->modules())
if (set_keep_assert(cache, mod)) {
- log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod));
+ log("Module %s directly or indirectly contains formal properties -> setting \"keep\" attribute.\n", log_id(mod));
mod->set_bool_attribute("\\keep");
}
}
@@ -903,62 +944,178 @@ struct HierarchyPass : public Pass {
std::vector<Module*> design_modules = design->modules();
for (auto module : design_modules)
- for (auto cell : module->cells())
{
- Module *m = design->module(cell->type);
+ pool<Wire*> wand_wor_index;
+ dict<Wire*, SigSpec> wand_map, wor_map;
+ vector<SigSig> new_connections;
- if (m == nullptr)
- continue;
+ for (auto wire : module->wires())
+ {
+ if (wire->get_bool_attribute("\\wand")) {
+ wand_map[wire] = SigSpec();
+ wand_wor_index.insert(wire);
+ }
+ if (wire->get_bool_attribute("\\wor")) {
+ wor_map[wire] = SigSpec();
+ wand_wor_index.insert(wire);
+ }
+ }
+
+ for (auto &conn : module->connections())
+ {
+ SigSig new_conn;
+ int cursor = 0;
- if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
- IdString new_m_name = m->derive(design, cell->parameters, true);
- if (new_m_name.empty())
+ for (auto c : conn.first.chunks())
+ {
+ Wire *w = c.wire;
+ SigSpec rhs = conn.second.extract(cursor, GetSize(c));
+
+ if (wand_wor_index.count(w) == 0) {
+ new_conn.first.append(c);
+ new_conn.second.append(rhs);
+ } else {
+ if (wand_map.count(w)) {
+ SigSpec sig = SigSpec(State::S1, GetSize(w));
+ sig.replace(c.offset, rhs);
+ wand_map.at(w).append(sig);
+ } else {
+ SigSpec sig = SigSpec(State::S0, GetSize(w));
+ sig.replace(c.offset, rhs);
+ wor_map.at(w).append(sig);
+ }
+ }
+ cursor += GetSize(c);
+ }
+ new_connections.push_back(new_conn);
+ }
+ module->new_connections(new_connections);
+
+ for (auto cell : module->cells())
+ {
+ if (!cell->known())
continue;
- if (new_m_name != m->name) {
- m = design->module(new_m_name);
- blackbox_derivatives.insert(m);
+
+ for (auto &conn : cell->connections())
+ {
+ if (!cell->output(conn.first))
+ continue;
+
+ SigSpec new_sig;
+ bool update_port = false;
+
+ for (auto c : conn.second.chunks())
+ {
+ Wire *w = c.wire;
+
+ if (wand_wor_index.count(w) == 0) {
+ new_sig.append(c);
+ continue;
+ }
+
+ Wire *t = module->addWire(NEW_ID, GetSize(c));
+ new_sig.append(t);
+ update_port = true;
+
+ if (wand_map.count(w)) {
+ SigSpec sig = SigSpec(State::S1, GetSize(w));
+ sig.replace(c.offset, t);
+ wand_map.at(w).append(sig);
+ } else {
+ SigSpec sig = SigSpec(State::S0, GetSize(w));
+ sig.replace(c.offset, t);
+ wor_map.at(w).append(sig);
+ }
+ }
+
+ if (update_port)
+ cell->setPort(conn.first, new_sig);
}
}
- for (auto &conn : cell->connections())
+ for (auto w : wand_wor_index)
{
- Wire *w = m->wire(conn.first);
+ bool wand = wand_map.count(w);
+ SigSpec sigs = wand ? wand_map.at(w) : wor_map.at(w);
- if (w == nullptr || w->port_id == 0)
+ if (GetSize(sigs) == 0)
continue;
- if (GetSize(conn.second) == 0)
+ if (GetSize(w) == 1) {
+ if (wand)
+ module->addReduceAnd(NEW_ID, sigs, w);
+ else
+ module->addReduceOr(NEW_ID, sigs, w);
continue;
+ }
+
+ SigSpec s = sigs.extract(0, GetSize(w));
+ for (int i = GetSize(w); i < GetSize(sigs); i += GetSize(w)) {
+ if (wand)
+ s = module->And(NEW_ID, s, sigs.extract(i, GetSize(w)));
+ else
+ s = module->Or(NEW_ID, s, sigs.extract(i, GetSize(w)));
+ }
+ module->connect(w, s);
+ }
- SigSpec sig = conn.second;
+ for (auto cell : module->cells())
+ {
+ Module *m = design->module(cell->type);
- if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
- {
- if (GetSize(w) < GetSize(conn.second))
- {
- int n = GetSize(conn.second) - GetSize(w);
- if (!w->port_input && w->port_output)
- module->connect(sig.extract(GetSize(w), n), Const(0, n));
- sig.remove(GetSize(w), n);
+ if (m == nullptr)
+ continue;
+
+ if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
+ IdString new_m_name = m->derive(design, cell->parameters, true);
+ if (new_m_name.empty())
+ continue;
+ if (new_m_name != m->name) {
+ m = design->module(new_m_name);
+ blackbox_derivatives.insert(m);
}
- else
+ }
+
+ for (auto &conn : cell->connections())
+ {
+ Wire *w = m->wire(conn.first);
+
+ if (w == nullptr || w->port_id == 0)
+ continue;
+
+ if (GetSize(conn.second) == 0)
+ continue;
+
+ SigSpec sig = conn.second;
+
+ if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
{
- int n = GetSize(w) - GetSize(conn.second);
- if (w->port_input && !w->port_output)
- sig.append(Const(0, n));
+ if (GetSize(w) < GetSize(conn.second))
+ {
+ int n = GetSize(conn.second) - GetSize(w);
+ if (!w->port_input && w->port_output)
+ module->connect(sig.extract(GetSize(w), n), Const(0, n));
+ sig.remove(GetSize(w), n);
+ }
else
- sig.append(module->addWire(NEW_ID, n));
+ {
+ int n = GetSize(w) - GetSize(conn.second);
+ if (w->port_input && !w->port_output)
+ sig.append(Const(0, n));
+ else
+ sig.append(module->addWire(NEW_ID, n));
+ }
+
+ if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
+ log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
+ log_id(conn.first), GetSize(conn.second), GetSize(sig));
+ cell->setPort(conn.first, sig);
}
- if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
- log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
- log_id(conn.first), GetSize(conn.second), GetSize(sig));
- cell->setPort(conn.first, sig);
+ if (w->port_output && !w->port_input && sig.has_const())
+ log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
+ log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
}
-
- if (w->port_output && !w->port_input && sig.has_const())
- log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
- log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
}
}
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index c38e9df5e..7011d4602 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell)
{
- if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover"))
+ if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
return true;
if (cell->has_keep_attr())
@@ -85,22 +85,34 @@ void rmunused_module_cells(Module *module, bool verbose)
{
SigMap sigmap(module);
pool<Cell*> queue, unused;
+ pool<SigBit> used_raw_bits;
dict<SigBit, pool<Cell*>> wire2driver;
+ dict<SigBit, vector<string>> driver_driver_logs;
+
+ SigMap raw_sigmap;
+ for (auto &it : module->connections_) {
+ for (int i = 0; i < GetSize(it.second); i++) {
+ if (it.second[i].wire != nullptr)
+ raw_sigmap.add(it.first[i], it.second[i]);
+ }
+ }
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
- if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
- for (auto raw_bit : it2.second) {
- if (raw_bit.wire == nullptr)
- continue;
- auto bit = sigmap(raw_bit);
- if (bit.wire == nullptr)
- log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
- log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module));
- if (bit.wire != nullptr)
- wire2driver[bit].insert(cell);
- }
+ if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
+ continue;
+ for (auto raw_bit : it2.second) {
+ if (raw_bit.wire == nullptr)
+ continue;
+ auto bit = sigmap(raw_bit);
+ if (bit.wire == nullptr)
+ driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
+ "for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
+ log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
+ if (bit.wire != nullptr)
+ wire2driver[bit].insert(cell);
+ }
}
if (keep_cache.query(cell))
queue.insert(cell);
@@ -114,6 +126,8 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto bit : sigmap(wire))
for (auto c : wire2driver[bit])
queue.insert(c), unused.erase(c);
+ for (auto raw_bit : SigSpec(wire))
+ used_raw_bits.insert(raw_sigmap(raw_bit));
}
}
@@ -142,6 +156,22 @@ void rmunused_module_cells(Module *module, bool verbose)
module->remove(cell);
count_rm_cells++;
}
+
+ for (auto &it : module->cells_) {
+ Cell *cell = it.second;
+ for (auto &it2 : cell->connections()) {
+ if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first))
+ continue;
+ for (auto raw_bit : raw_sigmap(it2.second))
+ used_raw_bits.insert(raw_bit);
+ }
+ }
+
+ for (auto it : driver_driver_logs) {
+ if (used_raw_bits.count(it.first))
+ for (auto msg : it.second)
+ log_warning("%s\n", msg.c_str());
+ }
}
int count_nontrivial_wire_attrs(RTLIL::Wire *w)
@@ -202,7 +232,7 @@ bool check_public_name(RTLIL::IdString id)
return true;
}
-void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
+bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
{
SigPool register_signals;
SigPool connected_signals;
@@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
module->connections_.clear();
SigPool used_signals;
+ SigPool raw_used_signals;
SigPool used_signals_nodrivers;
for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second);
+ raw_used_signals.add(it2.second);
used_signals.add(it2.second);
if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second);
@@ -259,6 +291,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
RTLIL::Wire *wire = it.second;
if (wire->port_id > 0) {
RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
+ raw_used_signals.add(sig);
assign_map.apply(sig);
used_signals.add(sig);
if (!wire->port_input)
@@ -271,72 +304,103 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
}
}
- std::vector<RTLIL::Wire*> maybe_del_wires;
+ pool<RTLIL::Wire*> del_wires_queue;
for (auto wire : module->wires())
{
- if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) {
- RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
- assign_map.apply(s2);
- if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
- maybe_del_wires.push_back(wire);
- } else {
- log_assert(GetSize(s1) == GetSize(s2));
- RTLIL::SigSig new_conn;
- for (int i = 0; i < GetSize(s1); i++)
- if (s1[i] != s2[i]) {
- new_conn.first.append_bit(s1[i]);
- new_conn.second.append_bit(s2[i]);
+ SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
+ log_assert(GetSize(s1) == GetSize(s2));
+
+ Const initval;
+ if (wire->attributes.count("\\init"))
+ initval = wire->attributes.at("\\init");
+ if (GetSize(initval) != GetSize(wire))
+ initval.bits.resize(GetSize(wire), State::Sx);
+ if (initval.is_fully_undef())
+ wire->attributes.erase("\\init");
+
+ if (GetSize(wire) == 0) {
+ // delete zero-width wires, unless they are module ports
+ if (wire->port_id == 0)
+ goto delete_this_wire;
+ } else
+ if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
+ // do not delete anything with "keep" or module ports or initialized wires
+ } else
+ if (!purge_mode && check_public_name(wire->name)) {
+ // do not get rid of public names unless in purge mode
+ } else
+ if (!raw_used_signals.check_any(s1)) {
+ // delete wires that aren't used by anything directly
+ goto delete_this_wire;
+ } else
+ if (!used_signals.check_any(s2)) {
+ // delete wires that aren't used by anything indirectly, even though other wires may alias it
+ goto delete_this_wire;
+ }
+
+ if (0)
+ {
+ delete_this_wire:
+ del_wires_queue.insert(wire);
+ }
+ else
+ {
+ RTLIL::SigSig new_conn;
+ for (int i = 0; i < GetSize(s1); i++)
+ if (s1[i] != s2[i]) {
+ if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) {
+ s2[i] = initval[i];
+ initval[i] = State::Sx;
}
- if (new_conn.first.size() > 0) {
- used_signals.add(new_conn.first);
- used_signals.add(new_conn.second);
- module->connect(new_conn);
+ new_conn.first.append_bit(s1[i]);
+ new_conn.second.append_bit(s2[i]);
}
+ if (new_conn.first.size() > 0) {
+ if (initval.is_fully_undef())
+ wire->attributes.erase("\\init");
+ else
+ wire->attributes.at("\\init") = initval;
+ used_signals.add(new_conn.first);
+ used_signals.add(new_conn.second);
+ module->connect(new_conn);
}
- } else {
- if (!used_signals.check_any(RTLIL::SigSpec(wire)))
- maybe_del_wires.push_back(wire);
- }
- RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
- if (!used_signals_nodrivers.check_any(sig)) {
- std::string unused_bits;
- for (int i = 0; i < GetSize(sig); i++) {
- if (sig[i].wire == NULL)
- continue;
- if (!used_signals_nodrivers.check(sig[i])) {
- if (!unused_bits.empty())
- unused_bits += " ";
- unused_bits += stringf("%d", i);
+ if (!used_signals_nodrivers.check_all(s2)) {
+ std::string unused_bits;
+ for (int i = 0; i < GetSize(s2); i++) {
+ if (s2[i].wire == NULL)
+ continue;
+ if (!used_signals_nodrivers.check(s2[i])) {
+ if (!unused_bits.empty())
+ unused_bits += " ";
+ unused_bits += stringf("%d", i);
+ }
}
- }
- if (unused_bits.empty() || wire->port_id != 0)
+ if (unused_bits.empty() || wire->port_id != 0)
+ wire->attributes.erase("\\unused_bits");
+ else
+ wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
+ } else {
wire->attributes.erase("\\unused_bits");
- else
- wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
- } else {
- wire->attributes.erase("\\unused_bits");
+ }
}
}
+ int del_temp_wires_count = 0;
+ for (auto wire : del_wires_queue) {
+ if (ys_debug() || (check_public_name(wire->name) && verbose))
+ log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
+ else
+ del_temp_wires_count++;
+ }
- pool<RTLIL::Wire*> del_wires;
+ module->remove(del_wires_queue);
+ count_rm_wires += GetSize(del_wires_queue);
- int del_wires_count = 0;
- for (auto wire : maybe_del_wires)
- if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
- if (check_public_name(wire->name) && verbose) {
- log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
- }
- del_wires.insert(wire);
- del_wires_count++;
- }
+ if (verbose && del_temp_wires_count)
+ log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
- module->remove(del_wires);
- count_rm_wires += del_wires.size();
-
- if (verbose && del_wires_count > 0)
- log_debug(" removed %d unused temporary wires.\n", del_wires_count);
+ return !del_wires_queue.empty();
}
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@@ -434,10 +498,10 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
module->design->scratchpad_set_bool("opt.did_something", true);
rmunused_module_cells(module, verbose);
- rmunused_module_signals(module, purge_mode, verbose);
+ while (rmunused_module_signals(module, purge_mode, verbose)) { }
if (rminit && rmunused_module_init(module, purge_mode, verbose))
- rmunused_module_signals(module, purge_mode, verbose);
+ while (rmunused_module_signals(module, purge_mode, verbose)) { }
}
struct OptCleanPass : public Pass {
@@ -483,6 +547,9 @@ struct OptCleanPass : public Pass {
ct_all.setup(design);
+ count_rm_cells = 0;
+ count_rm_wires = 0;
+
for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn())
continue;
@@ -548,7 +615,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) {
if (module->has_processes())
continue;
- rmunused_module(module, purge_mode, false, false);
+ rmunused_module(module, purge_mode, ys_debug(), false);
}
log_suppressed();
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index af6d352af..512ef0cbf 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -39,6 +39,9 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
SigPool used_signals;
SigPool all_signals;
+ dict<SigBit, pair<Wire*, State>> initbits;
+ pool<Wire*> revisit_initwires;
+
for (auto cell : module->cells())
for (auto &conn : cell->connections()) {
if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
@@ -48,9 +51,17 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
}
for (auto wire : module->wires()) {
+ if (wire->attributes.count("\\init")) {
+ SigSpec sig = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ initbits[sig[i]] = make_pair(wire, initval[i]);
+ }
+ }
if (wire->port_input)
driven_signals.add(sigmap(wire));
- if (wire->port_output)
+ if (wire->port_output || wire->get_bool_attribute("\\keep"))
used_signals.add(sigmap(wire));
all_signals.add(sigmap(wire));
}
@@ -67,10 +78,43 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
if (sig.size() == 0)
continue;
- log_debug("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c));
- module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
+ Const val(RTLIL::State::Sx, GetSize(sig));
+ for (int i = 0; i < GetSize(sig); i++) {
+ SigBit bit = sigmap(sig[i]);
+ auto cursor = initbits.find(bit);
+ if (cursor != initbits.end()) {
+ revisit_initwires.insert(cursor->second.first);
+ val[i] = cursor->second.second;
+ }
+ }
+
+ log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val));
+ module->connect(sig, val);
did_something = true;
}
+
+ if (!revisit_initwires.empty())
+ {
+ SigMap sm2(module);
+
+ for (auto wire : revisit_initwires) {
+ SigSpec sig = sm2(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
+ if (SigBit(initval[i]) == sig[i])
+ initval[i] = State::Sx;
+ }
+ if (initval.is_fully_undef()) {
+ log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire));
+ wire->attributes.erase("\\init");
+ did_something = true;
+ } else if (initval != wire->attributes.at("\\init")) {
+ log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval));
+ wire->attributes["\\init"] = initval;
+ did_something = true;
+ }
+ }
+ }
}
void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index dbebf21e0..6511e091b 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -184,6 +184,10 @@ struct OptMuxtreeWorker
log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
+ if (glob_abort_cnt == 0) {
+ log(" Giving up (too many iterations)\n");
+ return;
+ }
}
while (!root_mux_rerun.empty()) {
@@ -192,9 +196,14 @@ struct OptMuxtreeWorker
log_assert(root_enable_muxes.at(mux_idx));
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
+ if (glob_abort_cnt == 0) {
+ log(" Giving up (too many iterations)\n");
+ return;
+ }
}
log(" Analyzing evaluation results.\n");
+ log_assert(glob_abort_cnt > 0);
for (auto &mi : mux2info)
{
@@ -397,10 +406,8 @@ struct OptMuxtreeWorker
void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
- if (glob_abort_cnt == 0) {
- log(" Giving up (too many iterations)\n");
+ if (glob_abort_cnt == 0)
return;
- }
glob_abort_cnt--;
muxinfo_t &muxinfo = mux2info[mux_idx];
@@ -454,6 +461,7 @@ struct OptMuxtreeWorker
void eval_root_mux(int mux_idx)
{
+ log_assert(glob_abort_cnt > 0);
knowledge_t knowledge;
knowledge.known_inactive.resize(GetSize(bit2info));
knowledge.known_active.resize(GetSize(bit2info));
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index e8570f0eb..2abffa2a9 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -260,8 +260,8 @@ delete_dlatch:
bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
{
- RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r;
- RTLIL::Const val_cp, val_rp, val_rv;
+ RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e;
+ RTLIL::Const val_cp, val_rp, val_rv, val_ep;
if (dff->type == "$_FF_") {
sig_d = dff->getPort("\\D");
@@ -285,6 +285,16 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
val_rv = RTLIL::Const(dff->type[8] == '1', 1);
}
+ else if (dff->type.substr(0,7) == "$_DFFE_" && dff->type.substr(9) == "_" &&
+ (dff->type[7] == 'N' || dff->type[7] == 'P') &&
+ (dff->type[8] == 'N' || dff->type[8] == 'P')) {
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\C");
+ sig_e = dff->getPort("\\E");
+ val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
+ val_ep = RTLIL::Const(dff->type[7] == 'P', 1);
+ }
else if (dff->type == "$ff") {
sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q");
@@ -295,6 +305,14 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
sig_c = dff->getPort("\\CLK");
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
}
+ else if (dff->type == "$dffe") {
+ sig_e = dff->getPort("\\EN");
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\CLK");
+ val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
+ val_ep = RTLIL::Const(dff->parameters["\\EN_POLARITY"].as_bool(), 1);
+ }
else if (dff->type == "$adff") {
sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q");
@@ -337,39 +355,60 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
}
}
+ // If clock is driven by a constant and (i) no reset signal
+ // (ii) Q has no initial value
+ // (iii) initial value is same as reset value
if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
if (val_rv.bits.size() == 0)
val_rv = val_init;
+ // Q is permanently reset value or initial value
mod->connect(sig_q, val_rv);
goto delete_dff;
}
+ // If D is fully undefined and reset signal present and (i) Q has no initial value
+ // (ii) initial value is same as reset value
if (sig_d.is_fully_undef() && sig_r.size() && (!has_init || val_init == val_rv)) {
+ // Q is permanently reset value
mod->connect(sig_q, val_rv);
goto delete_dff;
}
+ // If D is fully undefined and no reset signal and Q has an initial value
if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
+ // Q is permanently initial value
mod->connect(sig_q, val_init);
goto delete_dff;
}
+ // If D is fully constant and (i) no reset signal
+ // (ii) reset value is same as constant D
+ // and (a) has no initial value
+ // (b) initial value same as constant D
if (sig_d.is_fully_const() && (!sig_r.size() || val_rv == sig_d.as_const()) && (!has_init || val_init == sig_d.as_const())) {
+ // Q is permanently D
mod->connect(sig_q, sig_d);
goto delete_dff;
}
+ // If D input is same as Q output and (i) no reset signal
+ // (ii) no initial signal
+ // (iii) initial value is same as reset value
if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
+ // Q is permanently reset value or initial value
if (sig_r.size())
mod->connect(sig_q, val_rv);
- if (has_init)
+ else if (has_init)
mod->connect(sig_q, val_init);
goto delete_dff;
}
+ // If reset signal is present, and is fully constant
if (!sig_r.empty() && sig_r.is_fully_const())
{
+ // If reset value is permanently active or if reset is undefined
if (sig_r == val_rp || sig_r.is_fully_undef()) {
+ // Q is permanently reset value
mod->connect(sig_q, val_rv);
goto delete_dff;
}
@@ -389,6 +428,30 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
dff->unsetPort("\\R");
}
+ // If enable signal is present, and is fully constant
+ if (!sig_e.empty() && sig_e.is_fully_const())
+ {
+ // If enable value is permanently inactive
+ if (sig_e != val_ep) {
+ // Q is permanently initial value
+ mod->connect(sig_q, val_init);
+ goto delete_dff;
+ }
+
+ log("Removing unused enable from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
+
+ if (dff->type == "$dffe") {
+ dff->type = "$dff";
+ dff->unsetPort("\\EN");
+ dff->unsetParam("\\EN_POLARITY");
+ return true;
+ }
+
+ log_assert(dff->type.substr(0,7) == "$_DFFE_");
+ dff->type = stringf("$_DFF_%c_", + dff->type[7]);
+ dff->unsetPort("\\E");
+ }
+
return false;
delete_dff:
@@ -489,7 +552,8 @@ struct OptRmdffPass : public Pass {
if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
- "$ff", "$dff", "$adff"))
+ "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_",
+ "$ff", "$dff", "$dffe", "$adff"))
dff_list.push_back(cell->name);
if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 52245ce3e..1fbc41082 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
struct WreduceConfig
{
pool<IdString> supported_cell_types;
+ bool keepdc = false;
WreduceConfig()
{
@@ -82,7 +83,7 @@ struct WreduceWorker
SigBit ref = sig_a[i];
for (int k = 0; k < GetSize(sig_s); k++) {
- if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i])
+ if ((config->keepdc || (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx)) && ref != sig_b[k*GetSize(sig_a) + i])
goto no_match_ab;
if (sig_b[k*GetSize(sig_a) + i] != Sx)
ref = sig_b[k*GetSize(sig_a) + i];
@@ -180,6 +181,8 @@ struct WreduceWorker
}
auto info = mi.query(sig_q[i]);
+ if (info == nullptr)
+ return;
if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i);
@@ -462,12 +465,10 @@ struct WreduceWorker
SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++) {
- log_dump(initsig[i], remove_init_bits.count(initsig[i]));
if (!remove_init_bits.count(initsig[i]))
new_initval[i] = initval[i];
}
w->attributes.at("\\init") = new_initval;
- log_dump(w->name, initval, new_initval);
}
}
}
@@ -495,6 +496,9 @@ struct WreducePass : public Pass {
log(" Do not change the width of memory address ports. Use this options in\n");
log(" flows that use the 'memory_memx' pass.\n");
log("\n");
+ log(" -keepdc\n");
+ log(" Do not optimize explicit don't-care values.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
@@ -509,6 +513,10 @@ struct WreducePass : public Pass {
opt_memx = true;
continue;
}
+ if (args[argidx] == "-keepdc") {
+ config.keepdc = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -531,6 +539,42 @@ struct WreducePass : public Pass {
module->connect(sig, Const(0, GetSize(sig)));
}
}
+
+ if (c->type.in("$div", "$mod", "$pow"))
+ {
+ SigSpec A = c->getPort("\\A");
+ int original_a_width = GetSize(A);
+ if (c->getParam("\\A_SIGNED").as_bool()) {
+ while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0)
+ A.remove(GetSize(A)-1, 1);
+ } else {
+ while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0)
+ A.remove(GetSize(A)-1, 1);
+ }
+ if (original_a_width != GetSize(A)) {
+ log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n",
+ original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type));
+ c->setPort("\\A", A);
+ c->setParam("\\A_WIDTH", GetSize(A));
+ }
+
+ SigSpec B = c->getPort("\\B");
+ int original_b_width = GetSize(B);
+ if (c->getParam("\\B_SIGNED").as_bool()) {
+ while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0)
+ B.remove(GetSize(B)-1, 1);
+ } else {
+ while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0)
+ B.remove(GetSize(B)-1, 1);
+ }
+ if (original_b_width != GetSize(B)) {
+ log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n",
+ original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type));
+ c->setPort("\\B", B);
+ c->setParam("\\B_WIDTH", GetSize(B));
+ }
+ }
+
if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) {
IdString memid = c->getParam("\\MEMID").decode_string();
RTLIL::Memory *mem = module->memories.at(memid);
diff --git a/passes/pmgen/.gitignore b/passes/pmgen/.gitignore
index c9263057e..0ad36ea2c 100644
--- a/passes/pmgen/.gitignore
+++ b/passes/pmgen/.gitignore
@@ -1 +1,2 @@
/ice40_dsp_pm.h
+/peepopt_pm.h
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
index e0609d9ba..7911132db 100644
--- a/passes/pmgen/Makefile.inc
+++ b/passes/pmgen/Makefile.inc
@@ -1,8 +1,23 @@
OBJS += passes/pmgen/ice40_dsp.o
+OBJS += passes/pmgen/peepopt.o
+
+# --------------------------------------
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h
.SECONDARY: passes/pmgen/ice40_dsp_pm.h
passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
- $(P) mkdir -p passes/pmgen && python3 $^ $@
+ $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^)
+
+# --------------------------------------
+
+passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
+EXTRA_OBJS += passes/pmgen/peepopt_pm.h
+.SECONDARY: passes/pmgen/peepopt_pm.h
+
+PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg
+PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
+
+passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
+ $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)
diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md
index 7a46558b1..2f0b1fd5a 100644
--- a/passes/pmgen/README.md
+++ b/passes/pmgen/README.md
@@ -29,19 +29,25 @@ up in any future matches:
pm.blacklist(some_cell);
-The `.run(callback_function)` method searches for all matches and calls the
-callback function for each found match:
+The `.run_<pattern_name>(callback_function)` method searches for all matches
+for the pattern`<pattern_name>` and calls the callback function for each found
+match:
- pm.run([&](){
+ pm.run_foobar([&](){
log("found matching 'foo' cell: %s\n", log_id(pm.st.foo));
log(" with 'bar' cell: %s\n", log_id(pm.st.bar));
});
The `.pmg` file declares matcher state variables that are accessible via the
-`.st.<state_name>` members. (The `.st` member is of type `foobar_pm::state_t`.)
+`.st_<pattern_name>.<state_name>` members. (The `.st_<pattern_name>` member is
+of type `foobar_pm::state_<pattern_name>_t`.)
Similarly the `.pmg` file declares user data variables that become members of
-`.ud`, a struct of type `foobar_pm::udata_t`.
+`.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`.
+
+There are four versions of the `run_<pattern_name>()` method: Without callback,
+callback without arguments, callback with reference to `pm`, and callback with
+reference to `pm.st_<pattern_name>`.
The .pmg File Format
@@ -52,6 +58,12 @@ lines consist of whitespace-separated tokens.
Lines in `.pmg` files starting with `//` are comments.
+Declaring a pattern
+-------------------
+
+A `.pmg` file contains one or more patterns. Each pattern starts with a line
+with the `pattern` keyword followed by the name of the pattern.
+
Declaring state variables
-------------------------
@@ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith
and saved and restored as needed.
They are automatically initialized to the default constructed value of their type
-when `.run(callback_function)` is called.
+when `.run_<pattern_name>(callback_function)` is called.
Declaring udata variables
-------------------------
@@ -220,5 +232,5 @@ But in some cases it is more natural to utilize the implicit branch statement:
portAB = \B;
endcode
-There is an implicit `code..endcode` block at the end of each `.pgm` file
+There is an implicit `code..endcode` block at the end of each `.pmg` file
that just accepts everything that gets all the way there.
diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc
index 3a054a463..39d033a04 100644
--- a/passes/pmgen/ice40_dsp.cc
+++ b/passes/pmgen/ice40_dsp.cc
@@ -19,47 +19,50 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
-#include "passes/pmgen/ice40_dsp_pm.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+#include "passes/pmgen/ice40_dsp_pm.h"
+
void create_ice40_dsp(ice40_dsp_pm &pm)
{
+ auto &st = pm.st_ice40_dsp;
+
#if 0
log("\n");
- log("ffA: %s\n", log_id(pm.st.ffA, "--"));
- log("ffB: %s\n", log_id(pm.st.ffB, "--"));
- log("mul: %s\n", log_id(pm.st.mul, "--"));
- log("ffY: %s\n", log_id(pm.st.ffY, "--"));
- log("addAB: %s\n", log_id(pm.st.addAB, "--"));
- log("muxAB: %s\n", log_id(pm.st.muxAB, "--"));
- log("ffS: %s\n", log_id(pm.st.ffS, "--"));
+ log("ffA: %s\n", log_id(st.ffA, "--"));
+ log("ffB: %s\n", log_id(st.ffB, "--"));
+ log("mul: %s\n", log_id(st.mul, "--"));
+ log("ffY: %s\n", log_id(st.ffY, "--"));
+ log("addAB: %s\n", log_id(st.addAB, "--"));
+ log("muxAB: %s\n", log_id(st.muxAB, "--"));
+ log("ffS: %s\n", log_id(st.ffS, "--"));
#endif
- log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(pm.st.mul));
+ log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul));
- if (GetSize(pm.st.sigA) > 16) {
- log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA));
+ if (GetSize(st.sigA) > 16) {
+ log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA));
return;
}
- if (GetSize(pm.st.sigB) > 16) {
- log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB));
+ if (GetSize(st.sigB) > 16) {
+ log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB));
return;
}
- if (GetSize(pm.st.sigS) > 32) {
- log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS));
+ if (GetSize(st.sigS) > 32) {
+ log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS));
return;
}
- if (GetSize(pm.st.sigY) > 32) {
- log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY));
+ if (GetSize(st.sigY) > 32) {
+ log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY));
return;
}
- bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool();
+ bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool();
if (mul_signed) {
log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n");
@@ -69,21 +72,21 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
log(" replacing $mul with SB_MAC16 cell.\n");
Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");
- pm.module->swap_names(cell, pm.st.mul);
+ pm.module->swap_names(cell, st.mul);
// SB_MAC16 Input Interface
- SigSpec A = pm.st.sigA;
+ SigSpec A = st.sigA;
A.extend_u0(16, mul_signed);
- SigSpec B = pm.st.sigB;
+ SigSpec B = st.sigB;
B.extend_u0(16, mul_signed);
SigSpec CD;
- if (pm.st.muxA)
- CD = pm.st.muxA->getPort("\\B");
- if (pm.st.muxB)
- CD = pm.st.muxB->getPort("\\A");
+ if (st.muxA)
+ CD = st.muxA->getPort("\\B");
+ if (st.muxB)
+ CD = st.muxB->getPort("\\A");
CD.extend_u0(32, mul_signed);
cell->setPort("\\A", A);
@@ -91,8 +94,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\C", CD.extract(0, 16));
cell->setPort("\\D", CD.extract(16, 16));
- cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0);
- cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0);
+ cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0);
+ cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0);
cell->setPort("\\AHOLD", State::S0);
cell->setPort("\\BHOLD", State::S0);
@@ -102,25 +105,25 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\IRSTTOP", State::S0);
cell->setPort("\\IRSTBOT", State::S0);
- if (pm.st.clock_vld)
+ if (st.clock_vld)
{
- cell->setPort("\\CLK", pm.st.clock);
+ cell->setPort("\\CLK", st.clock);
cell->setPort("\\CE", State::S1);
- cell->setParam("\\NEG_TRIGGER", pm.st.clock_pol ? State::S0 : State::S1);
+ cell->setParam("\\NEG_TRIGGER", st.clock_pol ? State::S0 : State::S1);
- log(" clock: %s (%s)", log_signal(pm.st.clock), pm.st.clock_pol ? "posedge" : "negedge");
+ log(" clock: %s (%s)", log_signal(st.clock), st.clock_pol ? "posedge" : "negedge");
- if (pm.st.ffA)
- log(" ffA:%s", log_id(pm.st.ffA));
+ if (st.ffA)
+ log(" ffA:%s", log_id(st.ffA));
- if (pm.st.ffB)
- log(" ffB:%s", log_id(pm.st.ffB));
+ if (st.ffB)
+ log(" ffB:%s", log_id(st.ffB));
- if (pm.st.ffY)
- log(" ffY:%s", log_id(pm.st.ffY));
+ if (st.ffY)
+ log(" ffY:%s", log_id(st.ffY));
- if (pm.st.ffS)
- log(" ffS:%s", log_id(pm.st.ffS));
+ if (st.ffS)
+ log(" ffS:%s", log_id(st.ffS));
log("\n");
}
@@ -144,16 +147,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
// SB_MAC16 Output Interface
- SigSpec O = pm.st.ffS ? pm.st.sigS : pm.st.sigY;
+ SigSpec O = st.ffS ? st.sigS : st.sigY;
if (GetSize(O) < 32)
O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
cell->setPort("\\O", O);
- if (pm.st.addAB) {
- log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type));
- cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
- cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
+ if (st.addAB) {
+ log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
+ cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1);
+ cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1);
} else {
cell->setPort("\\ADDSUBTOP", State::S0);
cell->setPort("\\ADDSUBBOT", State::S0);
@@ -166,10 +169,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\OHOLDBOT", State::S0);
SigSpec acc_reset = State::S0;
- if (pm.st.muxA)
- acc_reset = pm.st.muxA->getPort("\\S");
- if (pm.st.muxB)
- acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S"));
+ if (st.muxA)
+ acc_reset = st.muxA->getPort("\\S");
+ if (st.muxB)
+ acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S"));
cell->setPort("\\OLOADTOP", acc_reset);
cell->setPort("\\OLOADBOT", acc_reset);
@@ -179,17 +182,17 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam("\\C_REG", State::S0);
cell->setParam("\\D_REG", State::S0);
- cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
- cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
- cell->setParam("\\PIPELINE_16x16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0);
+ cell->setParam("\\TOP_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
+ cell->setParam("\\BOT_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
+ cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0);
cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0);
- cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2));
+ cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2));
cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0);
cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2));
- cell->setParam("\\BOTOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2));
+ cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2));
cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0);
cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2));
@@ -198,9 +201,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0);
cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
- pm.autoremove(pm.st.mul);
- pm.autoremove(pm.st.ffY);
- pm.autoremove(pm.st.ffS);
+ pm.autoremove(st.mul);
+ pm.autoremove(st.ffY);
+ pm.autoremove(st.ffS);
}
struct Ice40DspPass : public Pass {
@@ -230,7 +233,7 @@ struct Ice40DspPass : public Pass {
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
- ice40_dsp_pm(module, module->selected_cells()).run(create_ice40_dsp);
+ ice40_dsp_pm(module, module->selected_cells()).run_ice40_dsp(create_ice40_dsp);
}
} Ice40DspPass;
diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg
index 96c62e313..1f3590d4e 100644
--- a/passes/pmgen/ice40_dsp.pmg
+++ b/passes/pmgen/ice40_dsp.pmg
@@ -1,3 +1,5 @@
+pattern ice40_dsp
+
state <SigBit> clock
state <bool> clock_pol clock_vld
state <SigSpec> sigA sigB sigY sigS
diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc
new file mode 100644
index 000000000..e7f95cf85
--- /dev/null
+++ b/passes/pmgen/peepopt.cc
@@ -0,0 +1,68 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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
+
+bool did_something;
+
+#include "passes/pmgen/peepopt_pm.h"
+
+struct PeepoptPass : public Pass {
+ PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" peepopt [options] [selection]\n");
+ log("\n");
+ log("This pass applies a collection of peephole optimizers to the current design.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules()) {
+ did_something = true;
+ while (did_something) {
+ did_something = false;
+ peepopt_pm pm(module, module->selected_cells());
+ pm.run_shiftmul();
+ pm.run_muldiv();
+ }
+ }
+ }
+} PeepoptPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/peepopt_muldiv.pmg b/passes/pmgen/peepopt_muldiv.pmg
new file mode 100644
index 000000000..06c275834
--- /dev/null
+++ b/passes/pmgen/peepopt_muldiv.pmg
@@ -0,0 +1,36 @@
+pattern muldiv
+
+state <SigSpec> t x y
+
+match mul
+ select mul->type == $mul
+ select GetSize(port(mul, \A)) + GetSize(port(mul, \B)) <= GetSize(port(mul, \Y))
+endmatch
+
+code t x y
+ t = port(mul, \Y);
+ x = port(mul, \A);
+ y = port(mul, \B);
+ branch;
+ std::swap(x, y);
+endcode
+
+match div
+ select div->type.in($div)
+ index <SigSpec> port(div, \A) === t
+ index <SigSpec> port(div, \B) === x
+endmatch
+
+code
+ SigSpec div_y = port(div, \Y);
+ SigSpec val_y = y;
+
+ if (GetSize(div_y) != GetSize(val_y))
+ val_y.extend_u0(GetSize(div_y), param(div, \A_SIGNED).as_bool());
+
+ did_something = true;
+ log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div));
+ module->connect(div_y, val_y);
+ autoremove(div);
+ reject;
+endcode
diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg
new file mode 100644
index 000000000..fe861b728
--- /dev/null
+++ b/passes/pmgen/peepopt_shiftmul.pmg
@@ -0,0 +1,87 @@
+pattern shiftmul
+
+state <SigSpec> shamt
+
+match shift
+ select shift->type.in($shift, $shiftx, $shr)
+endmatch
+
+code shamt
+ shamt = port(shift, \B);
+ if (shamt.empty())
+ reject;
+ if (shamt[GetSize(shamt)-1] == State::S0) {
+ do {
+ shamt.remove(GetSize(shamt)-1);
+ if (shamt.empty())
+ reject;
+ } while (shamt[GetSize(shamt)-1] == State::S0);
+ } else
+ if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) {
+ reject;
+ }
+ if (GetSize(shamt) > 20)
+ reject;
+endcode
+
+match mul
+ select mul->type.in($mul)
+ select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const()
+ index <SigSpec> port(mul, \Y) === shamt
+endmatch
+
+code
+ IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B;
+ IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED;
+ Const const_factor_cnst = port(mul, const_factor_port).as_const();
+ int const_factor = const_factor_cnst.as_int();
+
+ if (GetSize(const_factor_cnst) == 0)
+ reject;
+
+ if (const_factor_cnst.bits[GetSize(const_factor_cnst)-1] != State::S0 &&
+ param(mul, const_factor_signed).as_bool())
+ reject;
+
+ if (GetSize(const_factor_cnst) > 20)
+ reject;
+
+ if (GetSize(port(shift, \Y)) > const_factor)
+ reject;
+
+ did_something = true;
+ log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul));
+
+ int new_const_factor_log2 = ceil_log2(const_factor);
+ int new_const_factor = 1 << new_const_factor_log2;
+
+ SigSpec padding(State::Sx, new_const_factor-const_factor);
+ SigSpec old_a = port(shift, \A), new_a;
+ int trunc = 0;
+
+ if (GetSize(old_a) % const_factor != 0) {
+ trunc = const_factor - GetSize(old_a) % const_factor;
+ old_a.append(SigSpec(State::Sx, trunc));
+ }
+
+ for (int i = 0; i*const_factor < GetSize(old_a); i++) {
+ SigSpec slice = old_a.extract(i*const_factor, const_factor);
+ new_a.append(slice);
+ new_a.append(padding);
+ }
+
+ if (trunc > 0)
+ new_a.remove(GetSize(new_a)-trunc, trunc);
+
+ SigSpec new_b = {port(mul, const_factor_port == \A ? \B : \A), SigSpec(State::S0, new_const_factor_log2)};
+ if (param(shift, \B_SIGNED).as_bool())
+ new_b.append(State::S0);
+
+ shift->setPort(\A, new_a);
+ shift->setParam(\A_WIDTH, GetSize(new_a));
+ shift->setPort(\B, new_b);
+ shift->setParam(\B_WIDTH, GetSize(new_b));
+
+ blacklist(shift);
+ reject;
+endcode
diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py
index d9747b065..81052afce 100644
--- a/passes/pmgen/pmgen.py
+++ b/passes/pmgen/pmgen.py
@@ -3,15 +3,42 @@
import re
import sys
import pprint
+import getopt
pp = pprint.PrettyPrinter(indent=4)
-pmgfile = sys.argv[1]
-assert pmgfile.endswith(".pmg")
-prefix = pmgfile[0:-4]
-prefix = prefix.split('/')[-1]
-outfile = sys.argv[2]
-
+prefix = None
+pmgfiles = list()
+outfile = None
+debug = False
+genhdr = False
+
+opts, args = getopt.getopt(sys.argv[1:], "p:o:dg")
+
+for o, a in opts:
+ if o == "-p":
+ prefix = a
+ elif o == "-o":
+ outfile = a
+ elif o == "-d":
+ debug = True
+ elif o == "-g":
+ genhdr = True
+
+if outfile is None:
+ outfile = "/dev/stdout"
+
+for a in args:
+ assert a.endswith(".pmg")
+ if prefix is None and len(args) == 1:
+ prefix = a[0:-4]
+ prefix = prefix.split('/')[-1]
+ pmgfiles.append(a)
+
+assert prefix is not None
+
+current_pattern = None
+patterns = dict()
state_types = dict()
udata_types = dict()
blocks = list()
@@ -77,7 +104,8 @@ def rewrite_cpp(s):
return "".join(t)
-with open(pmgfile, "r") as f:
+def process_pmgfile(f):
+ global current_pattern
while True:
line = f.readline()
if line == "": break
@@ -87,14 +115,31 @@ with open(pmgfile, "r") as f:
if len(cmd) == 0 or cmd[0].startswith("//"): continue
cmd = cmd[0]
+ if cmd == "pattern":
+ if current_pattern is not None:
+ block = dict()
+ block["type"] = "final"
+ block["pattern"] = current_pattern
+ blocks.append(block)
+ line = line.split()
+ assert len(line) == 2
+ assert line[1] not in patterns
+ current_pattern = line[1]
+ patterns[current_pattern] = len(blocks)
+ state_types[current_pattern] = dict()
+ udata_types[current_pattern] = dict()
+ continue
+
+ assert current_pattern is not None
+
if cmd == "state":
m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
assert m
type_str = m.group(1)
states_str = m.group(2)
for s in re.split(r"\s+", states_str):
- assert s not in state_types
- state_types[s] = type_str
+ assert s not in state_types[current_pattern]
+ state_types[current_pattern][s] = type_str
continue
if cmd == "udata":
@@ -103,19 +148,20 @@ with open(pmgfile, "r") as f:
type_str = m.group(1)
udatas_str = m.group(2)
for s in re.split(r"\s+", udatas_str):
- assert s not in udata_types
- udata_types[s] = type_str
+ assert s not in udata_types[current_pattern]
+ udata_types[current_pattern][s] = type_str
continue
if cmd == "match":
block = dict()
block["type"] = "match"
+ block["pattern"] = current_pattern
line = line.split()
assert len(line) == 2
- assert line[1] not in state_types
+ assert line[1] not in state_types[current_pattern]
block["cell"] = line[1]
- state_types[line[1]] = "Cell*";
+ state_types[current_pattern][line[1]] = "Cell*";
block["if"] = list()
block["select"] = list()
@@ -158,15 +204,18 @@ with open(pmgfile, "r") as f:
assert False
blocks.append(block)
+ continue
if cmd == "code":
block = dict()
block["type"] = "code"
+ block["pattern"] = current_pattern
+
block["code"] = list()
block["states"] = set()
for s in line.split()[1:]:
- assert s in state_types
+ assert s in state_types[current_pattern]
block["states"].add(s)
while True:
@@ -179,18 +228,37 @@ with open(pmgfile, "r") as f:
block["code"].append(rewrite_cpp(l.rstrip()))
blocks.append(block)
+ continue
-with open(outfile, "w") as f:
- print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f)
- print("", file=f)
+ assert False
- print("#include \"kernel/yosys.h\"", file=f)
- print("#include \"kernel/sigtools.h\"", file=f)
- print("", file=f)
+for fn in pmgfiles:
+ with open(fn, "r") as f:
+ process_pmgfile(f)
+
+if current_pattern is not None:
+ block = dict()
+ block["type"] = "final"
+ block["pattern"] = current_pattern
+ blocks.append(block)
+
+current_pattern = None
+
+if debug:
+ pp.pprint(blocks)
- print("YOSYS_NAMESPACE_BEGIN", file=f)
+with open(outfile, "w") as f:
+ for fn in pmgfiles:
+ print("// Generated by pmgen.py from {}".format(fn), file=f)
print("", file=f)
+ if genhdr:
+ print("#include \"kernel/yosys.h\"", file=f)
+ print("#include \"kernel/sigtools.h\"", file=f)
+ print("", file=f)
+ print("YOSYS_NAMESPACE_BEGIN", file=f)
+ print("", file=f)
+
print("struct {}_pm {{".format(prefix), file=f)
print(" Module *module;", file=f)
print(" SigMap sigmap;", file=f)
@@ -212,17 +280,19 @@ with open(outfile, "w") as f:
print(" int rollback;", file=f)
print("", file=f)
- print(" struct state_t {", file=f)
- for s, t in sorted(state_types.items()):
- print(" {} {};".format(t, s), file=f)
- print(" } st;", file=f)
- print("", file=f)
+ for current_pattern in sorted(patterns.keys()):
+ print(" struct state_{}_t {{".format(current_pattern), file=f)
+ for s, t in sorted(state_types[current_pattern].items()):
+ print(" {} {};".format(t, s), file=f)
+ print(" }} st_{};".format(current_pattern), file=f)
+ print("", file=f)
- print(" struct udata_t {", file=f)
- for s, t in sorted(udata_types.items()):
- print(" {} {};".format(t, s), file=f)
- print(" } ud;", file=f)
- print("", file=f)
+ print(" struct udata_{}_t {{".format(current_pattern), file=f)
+ for s, t in sorted(udata_types[current_pattern].items()):
+ print(" {} {};".format(t, s), file=f)
+ print(" }} ud_{};".format(current_pattern), file=f)
+ print("", file=f)
+ current_pattern = None
for v, n in sorted(ids.items()):
if n[0] == "\\":
@@ -258,20 +328,24 @@ with open(outfile, "w") as f:
print(" }", file=f)
print("", file=f)
- print(" void check_blacklist() {", file=f)
- print(" if (!blacklist_dirty)", file=f)
- print(" return;", file=f)
- print(" blacklist_dirty = false;", file=f)
- for index in range(len(blocks)):
- block = blocks[index]
- if block["type"] == "match":
- print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f)
- print(" rollback = {};".format(index+1), file=f)
- print(" return;", file=f)
- print(" }", file=f)
- print(" rollback = 0;", file=f)
- print(" }", file=f)
- print("", file=f)
+ for current_pattern in sorted(patterns.keys()):
+ print(" void check_blacklist_{}() {{".format(current_pattern), file=f)
+ print(" if (!blacklist_dirty)", file=f)
+ print(" return;", file=f)
+ print(" blacklist_dirty = false;", file=f)
+ for index in range(len(blocks)):
+ block = blocks[index]
+ if block["pattern"] != current_pattern:
+ continue
+ if block["type"] == "match":
+ print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f)
+ print(" rollback = {};".format(index+1), file=f)
+ print(" return;", file=f)
+ print(" }", file=f)
+ print(" rollback = 0;", file=f)
+ print(" }", file=f)
+ print("", file=f)
+ current_pattern = None
print(" SigSpec port(Cell *cell, IdString portname) {", file=f)
print(" return sigmap(cell->getPort(portname));", file=f)
@@ -294,11 +368,13 @@ with open(outfile, "w") as f:
print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
print(" module(module), sigmap(module) {", file=f)
- for s, t in sorted(udata_types.items()):
- if t.endswith("*"):
- print(" ud.{} = nullptr;".format(s), file=f)
- else:
- print(" ud.{} = {}();".format(s, t), file=f)
+ for current_pattern in sorted(patterns.keys()):
+ for s, t in sorted(udata_types[current_pattern].items()):
+ if t.endswith("*"):
+ print(" ud_{}.{} = nullptr;".format(current_pattern,s), file=f)
+ else:
+ print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
+ current_pattern = None
print(" for (auto cell : module->cells()) {", file=f)
print(" for (auto &conn : cell->connections())", file=f)
print(" add_siguser(conn.second, cell);", file=f)
@@ -328,34 +404,52 @@ with open(outfile, "w") as f:
print(" }", file=f)
print("", file=f)
- print(" void run(std::function<void()> on_accept_f) {", file=f)
- print(" on_accept = on_accept_f;", file=f)
- print(" rollback = 0;", file=f)
- print(" blacklist_dirty = false;", file=f)
- for s, t in sorted(state_types.items()):
- if t.endswith("*"):
- print(" st.{} = nullptr;".format(s), file=f)
- else:
- print(" st.{} = {}();".format(s, t), file=f)
- print(" block_0();", file=f)
- print(" }", file=f)
- print("", file=f)
-
- print(" void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f)
- print(" run([&](){on_accept_f(*this);});", file=f)
- print(" }", file=f)
- print("", file=f)
+ for current_pattern in sorted(patterns.keys()):
+ print(" void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
+ print(" on_accept = on_accept_f;", file=f)
+ print(" rollback = 0;", file=f)
+ print(" blacklist_dirty = false;", file=f)
+ for s, t in sorted(state_types[current_pattern].items()):
+ if t.endswith("*"):
+ print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f)
+ else:
+ print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
+ print(" block_{}();".format(patterns[current_pattern]), file=f)
+ print(" }", file=f)
+ print("", file=f)
+ print(" void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
+ print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f)
+ print(" }", file=f)
+ print("", file=f)
+ print(" void run_{}(std::function<void(state_{}_t&)> on_accept_f) {{".format(current_pattern, current_pattern), file=f)
+ print(" run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f)
+ print(" }", file=f)
+ print("", file=f)
+ print(" void run_{}() {{".format(current_pattern), file=f)
+ print(" run_{}([](){{}});".format(current_pattern, current_pattern), file=f)
+ print(" }", file=f)
+ print("", file=f)
+ current_pattern = None
for index in range(len(blocks)):
block = blocks[index]
print(" void block_{}() {{".format(index), file=f)
+ current_pattern = block["pattern"]
+
+ if block["type"] == "final":
+ print(" on_accept();", file=f)
+ print(" check_blacklist_{}();".format(current_pattern), file=f)
+ print(" }", file=f)
+ if index+1 != len(blocks):
+ print("", file=f)
+ continue
const_st = set()
nonconst_st = set()
restore_st = set()
- for i in range(index):
+ for i in range(patterns[current_pattern], index):
if blocks[i]["type"] == "code":
for s in blocks[i]["states"]:
const_st.add(s)
@@ -378,27 +472,27 @@ with open(outfile, "w") as f:
assert False
for s in sorted(const_st):
- t = state_types[s]
+ t = state_types[current_pattern][s]
if t.endswith("*"):
- print(" {} const &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
+ print(" {} const &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
else:
- print(" const {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
+ print(" const {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
for s in sorted(nonconst_st):
- t = state_types[s]
- print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
+ t = state_types[current_pattern][s]
+ print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
if len(restore_st):
print("", file=f)
for s in sorted(restore_st):
- t = state_types[s]
+ t = state_types[current_pattern][s]
print(" {} backup_{} = {};".format(t, s, s), file=f)
if block["type"] == "code":
print("", file=f)
print(" do {", file=f)
- print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f)
- print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f)
+ print("#define reject do {{ check_blacklist_{}(); goto rollback_label; }} while(0)".format(current_pattern), file=f)
+ print("#define accept do {{ on_accept(); check_blacklist_{}(); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f)
print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
for line in block["code"]:
@@ -417,11 +511,11 @@ with open(outfile, "w") as f:
if len(restore_st) or len(nonconst_st):
print("", file=f)
for s in sorted(restore_st):
- t = state_types[s]
+ t = state_types[current_pattern][s]
print(" {} = backup_{};".format(s, s), file=f)
for s in sorted(nonconst_st):
if s not in restore_st:
- t = state_types[s]
+ t = state_types[current_pattern][s]
if t.endswith("*"):
print(" {} = nullptr;".format(s), file=f)
else:
@@ -470,17 +564,12 @@ with open(outfile, "w") as f:
else:
assert False
-
+ current_pattern = None
print(" }", file=f)
print("", file=f)
- print(" void block_{}() {{".format(len(blocks)), file=f)
- print(" on_accept();", file=f)
- print(" check_blacklist();", file=f)
- print(" }", file=f)
print("};", file=f)
- print("", file=f)
- print("YOSYS_NAMESPACE_END", file=f)
-
-# pp.pprint(blocks)
+ if genhdr:
+ print("", file=f)
+ print("YOSYS_NAMESPACE_END", file=f)
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index 3add9a9eb..71ce1683d 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -42,7 +42,7 @@ struct dff_map_bit_info_t {
bool consider_wire(RTLIL::Wire *wire, std::map<RTLIL::IdString, dff_map_info_t> &dff_dq_map)
{
- if (/*wire->name[0] == '$' ||*/ dff_dq_map.count(wire->name))
+ if (wire->name[0] == '$' || dff_dq_map.count(wire->name))
return false;
if (wire->port_input)
return false;
@@ -508,7 +508,7 @@ struct ExposePass : public Pass {
}
for (auto &conn : module->connections_)
- conn.first = out_to_in_map(sigmap(conn.first));
+ conn.first = out_to_in_map(conn.first);
}
if (flag_cut)
diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc
index cd75ca860..f64d99dc2 100644
--- a/passes/sat/fmcombine.cc
+++ b/passes/sat/fmcombine.cc
@@ -26,6 +26,8 @@ PRIVATE_NAMESPACE_BEGIN
struct opts_t
{
+ bool initeq = false;
+ bool anyeq = false;
bool fwd = false;
bool bwd = false;
bool nop = false;
@@ -56,7 +58,7 @@ struct FmcombineWorker
return newsig;
}
- void import_prim_cell(Cell *cell, const string &suffix)
+ Cell *import_prim_cell(Cell *cell, const string &suffix)
{
Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
c->parameters = cell->parameters;
@@ -64,6 +66,8 @@ struct FmcombineWorker
for (auto &conn : cell->connections())
c->setPort(conn.first, import_sig(conn.second, suffix));
+
+ return c;
}
void import_hier_cell(Cell *cell)
@@ -102,8 +106,24 @@ struct FmcombineWorker
for (auto cell : original->cells()) {
if (design->module(cell->type) == nullptr) {
- import_prim_cell(cell, "_gold");
- import_prim_cell(cell, "_gate");
+ if (opts.anyeq && cell->type.in("$anyseq", "$anyconst")) {
+ Cell *gold = import_prim_cell(cell, "_gold");
+ for (auto &conn : cell->connections())
+ module->connect(import_sig(conn.second, "_gate"), gold->getPort(conn.first));
+ } else {
+ Cell *gold = import_prim_cell(cell, "_gold");
+ Cell *gate = import_prim_cell(cell, "_gate");
+ if (opts.initeq) {
+ if (cell->type.in("$ff", "$dff", "$dffe",
+ "$dffsr", "$adff", "$dlatch", "$dlatchsr")) {
+ SigSpec gold_q = gold->getPort("\\Q");
+ SigSpec gate_q = gate->getPort("\\Q");
+ SigSpec en = module->Initstate(NEW_ID);
+ SigSpec eq = module->Eq(NEW_ID, gold_q, gate_q);
+ module->addAssume(NEW_ID, eq, en);
+ }
+ }
+ }
} else {
import_hier_cell(cell);
}
@@ -229,6 +249,13 @@ struct FmcombinePass : public Pass {
log("This is useful for formal test benches that check what differences in behavior\n");
log("a slight difference in input causes in a module.\n");
log("\n");
+ log(" -initeq\n");
+ log(" Insert assumptions that initially all FFs in both circuits have the\n");
+ log(" same initial values.\n");
+ log("\n");
+ log(" -anyeq\n");
+ log(" Do not duplicate $anyseq/$anyconst cells.\n");
+ log("\n");
log(" -fwd\n");
log(" Insert forward hint assumptions into the combined module.\n");
log("\n");
@@ -261,6 +288,14 @@ struct FmcombinePass : public Pass {
// filename = args[++argidx];
// continue;
// }
+ if (args[argidx] == "-initeq") {
+ opts.initeq = true;
+ continue;
+ }
+ if (args[argidx] == "-anyeq") {
+ opts.anyeq = true;
+ continue;
+ }
if (args[argidx] == "-fwd") {
opts.fwd = true;
continue;
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index 695a03e15..cbba738f0 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -1169,6 +1169,7 @@ struct SatPass : public Pass {
if (args[argidx] == "-tempinduct-def") {
tempinduct = true;
tempinduct_def = true;
+ enable_undef = true;
continue;
}
if (args[argidx] == "-tempinduct-baseonly") {
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 547115459..5b19d84fb 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -330,20 +330,33 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr)
{
std::string abc_sname = abc_name.substr(1);
- if (abc_sname.substr(0, 5) == "ys__n") {
- bool inv = abc_sname.back() == 'v';
- if (inv) abc_sname.pop_back();
+ bool isnew = false;
+ if (abc_sname.substr(0, 4) == "new_")
+ {
+ abc_sname.erase(0, 4);
+ isnew = true;
+ }
+ if (abc_sname.substr(0, 5) == "ys__n")
+ {
abc_sname.erase(0, 5);
- if (abc_sname.find_last_not_of("012345689") == std::string::npos) {
+ if (std::isdigit(abc_sname.at(0)))
+ {
int sid = std::stoi(abc_sname);
- for (auto sig : signal_list) {
- if (sig.id == sid && sig.bit.wire != nullptr) {
+ size_t postfix_start = abc_sname.find_first_not_of("0123456789");
+ std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : "";
+
+ if (sid < GetSize(signal_list))
+ {
+ auto sig = signal_list.at(sid);
+ if (sig.bit.wire != nullptr)
+ {
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
if (sig.bit.wire->width != 1)
sstr << "[" << sig.bit.offset << "]";
- if (inv)
- sstr << "_inv";
+ if (isnew)
+ sstr << "_new";
+ sstr << postfix;
if (orig_wire != nullptr)
*orig_wire = sig.bit.wire;
return sstr.str();
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 2aa19b348..01842dbf2 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -25,8 +25,7 @@
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
//#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
-//#define ABC_COMMAND_LUT "&st; &sweep; &scorr; &dc2; &retime; &dch -f; &if; &mfs; &ps"
-#define ABC_COMMAND_LUT "&st; &scorr; &dc2; &retime; &dch -f; &if; &ps -l -m"
+#define ABC_COMMAND_LUT "&st; &sweep; &scorr; "/*"&dc2; */"&retime; &dch -f; &ps -l; &if -W 160 -v; &ps -l"
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
@@ -424,6 +423,21 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
Pass::call(design, stringf("write_xaiger -O -map %s/input.sym %s/input.xaig; ", tempdir_name.c_str(), tempdir_name.c_str()));
+#if 0
+ std::string buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig");
+ std::ifstream ifs;
+ ifs.open(buffer);
+ if (ifs.fail())
+ log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
+ buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym");
+ log_assert(!design->module("$__abc9__"));
+ AigerReader reader(design, ifs, "$__abc9__", "" /* clk_name */, buffer.c_str() /* map_filename */, false /* wideports */);
+ reader.parse_xaiger();
+ ifs.close();
+ Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "input.v"));
+ design->remove(design->module("$__abc9__"));
+#endif
+
design->selection_stack.pop_back();
// Now 'unexpose' those wires by undoing
@@ -453,48 +467,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
{
log_header(design, "Executing ABC9.\n");
- std::string buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
- f = fopen(buffer.c_str(), "wt");
- if (f == NULL)
- log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
- fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
- fprintf(f, "GATE ONE 1 Y=CONST1;\n");
- fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
- fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
- if (enabled_gates.empty() || enabled_gates.count("AND"))
- fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
- if (enabled_gates.empty() || enabled_gates.count("NAND"))
- fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
- if (enabled_gates.empty() || enabled_gates.count("OR"))
- fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
- if (enabled_gates.empty() || enabled_gates.count("NOR"))
- fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
- if (enabled_gates.empty() || enabled_gates.count("XOR"))
- fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
- if (enabled_gates.empty() || enabled_gates.count("XNOR"))
- fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
- if (enabled_gates.empty() || enabled_gates.count("ANDNOT"))
- fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ANDNOT_"));
- if (enabled_gates.empty() || enabled_gates.count("ORNOT"))
- fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ORNOT_"));
- if (enabled_gates.empty() || enabled_gates.count("AOI3"))
- fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
- if (enabled_gates.empty() || enabled_gates.count("OAI3"))
- fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
- if (enabled_gates.empty() || enabled_gates.count("AOI4"))
- fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
- if (enabled_gates.empty() || enabled_gates.count("OAI4"))
- fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
- if (enabled_gates.empty() || enabled_gates.count("MUX"))
- fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
- if (map_mux4)
- fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*get_cell_cost("$_MUX_"));
- if (map_mux8)
- fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*get_cell_cost("$_MUX_"));
- if (map_mux16)
- fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_"));
- fclose(f);
-
+ std::string buffer;
if (!lut_costs.empty()) {
buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt");
@@ -536,19 +509,21 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
bool builtin_lib = liberty_file.empty();
- RTLIL::Design *mapped_design = new RTLIL::Design;
//parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_", false, sop_mode);
buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym");
- AigerReader reader(mapped_design, ifs, "\\netlist", "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */);
+ log_assert(!design->module("$__abc9__"));
+ AigerReader reader(design, ifs, "$__abc9__", "" /* clk_name */, buffer.c_str() /* map_filename */, false /* wideports */);
reader.parse_xaiger();
-
ifs.close();
+#if 0
+ Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "output.v"));
+#endif
+
log_header(design, "Re-integrating ABC9 results.\n");
- RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"];
+ RTLIL::Module *mapped_mod = design->module("$__abc9__");
if (mapped_mod == NULL)
- log_error("ABC output file does not contain a module `netlist'.\n");
- Pass::call(mapped_design, "clean");
+ log_error("ABC output file does not contain a module `$__abc9__'.\n");
pool<RTLIL::SigBit> output_bits;
for (auto &it : mapped_mod->wires_) {
@@ -564,7 +539,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
else {
// Attempt another wideports_split here because there
// exists the possibility that different bits of a port
- // could be an input and output, therefore parse_xiager()
+ // could be an input and output, therefore parse_xaiger()
// could not combine it into a wideport
auto r = wideports_split(w->name.str());
wire = module->wire(r.first);
@@ -575,6 +550,33 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
}
}
+ // Remove all AND, NOT, and ABC box instances
+ // in preparation for stitching mapped_mod in
+ pool<IdString> erased_boxes;
+ for (auto it = module->cells_.begin(); it != module->cells_.end(); ) {
+ RTLIL::Cell* cell = it->second;
+ if (cell->type.in("$_AND_", "$_NOT_")) {
+ it = module->cells_.erase(it);
+ continue;
+ }
+ RTLIL::Module* box_module = design->module(cell->type);
+ if (box_module && box_module->attributes.count("\\abc_box_id")) {
+ erased_boxes.insert(it->first);
+ it = module->cells_.erase(it);
+ continue;
+ }
+ ++it;
+ }
+ // Do the same for module connections
+ for (auto &it : module->connections_) {
+ auto &signal = it.first;
+ auto bits = signal.bits();
+ for (auto &b : bits)
+ if (output_bits.count(b))
+ b = module->addWire(NEW_ID);
+ signal = std::move(bits);
+ }
+
std::map<std::string, int> cell_stats;
for (auto c : mapped_mod->cells())
{
@@ -585,30 +587,34 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
RTLIL::SigBit a_bit = c->getPort("\\A").as_bit();
RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit();
if (!lut_costs.empty() || !lut_file.empty()) {
+ RTLIL::Cell* driving_lut = nullptr;
// ABC can return NOT gates that drive POs
- if (a_bit.wire->port_input) {
- // If it's a NOT gate that comes from a primary input directly
- // then implement it using a LUT
- cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
- RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset),
- RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
- 1);
- }
- else {
- // Otherwise, clone the driving LUT to guarantee that we
- // won't increase the max logic depth
+ if (!a_bit.wire->port_input) {
+ // If it's not a NOT gate that that comes from a PI directly,
+ // find the driving LUT and clone that to guarantee that we won't
+ // increase the max logic depth
// (TODO: Optimise by not cloning unless will increase depth)
RTLIL::IdString driver_name;
if (GetSize(a_bit.wire) == 1)
driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
else
driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
- RTLIL::Cell* driver = mapped_mod->cell(driver_name);
- log_assert(driver);
- auto driver_a = driver->getPort("\\A").chunks();
+ driving_lut = mapped_mod->cell(driver_name);
+ }
+
+ if (!driving_lut) {
+ // If a driver couldn't be found (could be from PI,
+ // or from a box) then implement using a LUT
+ cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
+ RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset),
+ RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
+ 1);
+ }
+ else {
+ auto driver_a = driving_lut->getPort("\\A").chunks();
for (auto &chunk : driver_a)
chunk.wire = module->wires_[remap_name(chunk.wire->name)];
- RTLIL::Const driver_lut = driver->getParam("\\LUT");
+ RTLIL::Const driver_lut = driving_lut->getParam("\\LUT");
for (auto &b : driver_lut.bits) {
if (b == RTLIL::State::S0) b = RTLIL::State::S1;
else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
@@ -618,7 +624,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
driver_lut);
}
- cell_stats["$lut"]++;
}
else {
cell = module->addCell(remap_name(c->name), "$_NOT_");
@@ -629,168 +634,21 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
continue;
}
+ }
+ cell_stats[RTLIL::unescape_id(c->type)]++;
- cell_stats[RTLIL::unescape_id(c->type)]++;
- if (c->type == "\\ZERO" || c->type == "\\ONE") {
- RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]);
- conn.second = RTLIL::SigSpec(c->type == "\\ZERO" ? 0 : 1, 1);
- module->connect(conn);
- continue;
- }
- if (c->type == "\\BUF") {
- RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]);
- conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]);
- module->connect(conn);
- continue;
- }
-
- if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" ||
- c->type == "\\XNOR" || c->type == "\\ANDNOT" || c->type == "\\ORNOT") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
- continue;
- }
- if (c->type == "\\MUX") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
- continue;
- }
- if (c->type == "\\MUX4") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX4_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
- cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
- continue;
- }
- if (c->type == "\\MUX8") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX8_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\E", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\E").as_wire()->name)]));
- cell->setPort("\\F", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\F").as_wire()->name)]));
- cell->setPort("\\G", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\G").as_wire()->name)]));
- cell->setPort("\\H", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\H").as_wire()->name)]));
- cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
- cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)]));
- cell->setPort("\\U", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\U").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
- continue;
- }
- if (c->type == "\\MUX16") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX16_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\E", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\E").as_wire()->name)]));
- cell->setPort("\\F", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\F").as_wire()->name)]));
- cell->setPort("\\G", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\G").as_wire()->name)]));
- cell->setPort("\\H", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\H").as_wire()->name)]));
- cell->setPort("\\I", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\I").as_wire()->name)]));
- cell->setPort("\\J", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\J").as_wire()->name)]));
- cell->setPort("\\K", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\K").as_wire()->name)]));
- cell->setPort("\\L", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\L").as_wire()->name)]));
- cell->setPort("\\M", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\M").as_wire()->name)]));
- cell->setPort("\\N", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\N").as_wire()->name)]));
- cell->setPort("\\O", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\O").as_wire()->name)]));
- cell->setPort("\\P", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\P").as_wire()->name)]));
- cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
- cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)]));
- cell->setPort("\\U", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\U").as_wire()->name)]));
- cell->setPort("\\V", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\V").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
- continue;
- }
- if (c->type == "\\AOI3" || c->type == "\\OAI3") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
- continue;
- }
- if (c->type == "\\AOI4" || c->type == "\\OAI4") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
- continue;
- }
- if (c->type == "\\DFF") {
- log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell;
- if (en_sig.size() == 0) {
- cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
- } else {
- log_assert(en_sig.size() == 1);
- cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
- cell->setPort("\\E", en_sig);
- }
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
- cell->setPort("\\C", clk_sig);
+ if (c->type == "$lut") {
+ if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
+ SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
+ SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
+ module->connect(my_y, my_a);
continue;
}
}
else
- cell_stats[RTLIL::unescape_id(c->type)]++;
-
- if (c->type == "\\_const0_" || c->type == "\\_const1_") {
- RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]);
- conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1);
- module->connect(conn);
- continue;
- }
-
- if (c->type == "\\_dff_") {
- log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell;
- if (en_sig.size() == 0) {
- cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
- } else {
- log_assert(en_sig.size() == 1);
- cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
- cell->setPort("\\E", en_sig);
- }
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
- cell->setPort("\\C", clk_sig);
- continue;
- }
-
- if (c->type == "$lut" && GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
- SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
- SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
- module->connect(my_y, my_a);
- continue;
- }
+ log_assert(erased_boxes.count(c->name));
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
+ RTLIL::Cell* cell = module->addCell(remap_name(c->name), c->type);
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->parameters = c->parameters;
for (auto &conn : c->connections()) {
@@ -799,7 +657,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (c.width == 0)
continue;
//log_assert(c.width == 1);
- c.wire = module->wires_[remap_name(c.wire->name)];
+ if (c.wire)
+ c.wire = module->wires_[remap_name(c.wire->name)];
newsig.append(c);
}
cell->setPort(conn.first, newsig);
@@ -836,49 +695,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
for (auto &it : cell_stats)
log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
int in_wires = 0, out_wires = 0;
- //for (auto &si : signal_list)
- // if (si.is_port) {
- // char buffer[100];
- // snprintf(buffer, 100, "\\n%d", si.id);
- // RTLIL::SigSig conn;
- // if (si.type != G(NONE)) {
- // conn.first = si.bit;
- // conn.second = RTLIL::SigSpec(module->wires_[remap_name(buffer)]);
- // out_wires++;
- // } else {
- // conn.first = RTLIL::SigSpec(module->wires_[remap_name(buffer)]);
- // conn.second = si.bit;
- // in_wires++;
- // }
- // module->connect(conn);
- // }
-
- // Go through all AND and NOT output connections,
- // and for those output ports driving wires
- // also driven by mapped_mod, disconnect them
- for (auto cell : module->cells()) {
- if (!cell->type.in("$_AND_", "$_NOT_"))
- continue;
- for (auto &it : cell->connections_) {
- auto port_name = it.first;
- if (!cell->output(port_name)) continue;
- auto &signal = it.second;
- auto bits = signal.bits();
- for (auto &b : bits)
- if (output_bits.count(b))
- b = module->addWire(NEW_ID);
- signal = std::move(bits);
- }
- }
- // Do the same for module connections
- for (auto &it : module->connections_) {
- auto &signal = it.first;
- auto bits = signal.bits();
- for (auto &b : bits)
- if (output_bits.count(b))
- b = module->addWire(NEW_ID);
- signal = std::move(bits);
- }
// Stitch in mapped_mod's inputs/outputs into module
for (auto &it : mapped_mod->wires_) {
@@ -894,7 +710,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
else {
// Attempt another wideports_split here because there
// exists the possibility that different bits of a port
- // could be an input and output, therefore parse_xiager()
+ // could be an input and output, therefore parse_xaiger()
// could not combine it into a wideport
auto r = wideports_split(w->name.str());
wire = module->wire(r.first);
@@ -924,7 +740,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
log("ABC RESULTS: input signals: %8d\n", in_wires);
log("ABC RESULTS: output signals: %8d\n", out_wires);
- delete mapped_design;
+ design->remove(mapped_mod);
}
//else
//{
@@ -1143,6 +959,11 @@ struct Abc9Pass : public Pass {
vector<int> lut_costs;
markgroups = false;
+#if 0
+ cleanup = false;
+ show_tempdir = true;
+#endif
+
map_mux4 = false;
map_mux8 = false;
map_mux16 = false;
@@ -1405,6 +1226,9 @@ struct Abc9Pass : public Pass {
continue;
}
+ if (mod->attributes.count("\\abc_box_id"))
+ continue;
+
assign_map.set(mod);
signal_init.clear();
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index 48390488e..0ad33dc0e 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -102,7 +102,8 @@ struct DffinitPass : public Pass {
if (wire->attributes.count("\\init")) {
Const value = wire->attributes.at("\\init");
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
- init_bits[sigmap(SigBit(wire, i))] = value[i];
+ if (value[i] != State::Sx)
+ init_bits[sigmap(SigBit(wire, i))] = value[i];
}
if (wire->port_output)
for (auto bit : sigmap(wire))
diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc
index 0b7931e48..f5892a60e 100644
--- a/passes/techmap/flowmap.cc
+++ b/passes/techmap/flowmap.cc
@@ -397,7 +397,6 @@ struct FlowGraph
pool<RTLIL::SigBit> x, xi;
NodePrime source_prime = {source, true};
- NodePrime sink_prime = {sink, false};
pool<NodePrime> visited;
vector<NodePrime> worklist = {source_prime};
while (!worklist.empty())
@@ -1382,7 +1381,8 @@ struct FlowmapWorker
vector<RTLIL::SigBit> input_nodes(lut_edges_bw[node].begin(), lut_edges_bw[node].end());
RTLIL::Const lut_table(State::Sx, max(1 << input_nodes.size(), 1 << minlut));
- for (unsigned i = 0; i < (1 << input_nodes.size()); i++)
+ unsigned const mask = 1 << input_nodes.size();
+ for (unsigned i = 0; i < mask; i++)
{
ce.push();
for (size_t n = 0; n < input_nodes.size(); n++)
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 991cc4498..349ccc115 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -94,7 +94,7 @@ int LibertyParser::lexer(std::string &str)
// search for identifiers, numbers, plus or minus.
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
- str = c;
+ str = static_cast<char>(c);
while (1) {
c = f.get();
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index a541b33be..75eedfbcc 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -178,7 +178,17 @@ struct ShregmapTechXilinx7 : ShregmapTech
// Only map if $shiftx exclusively covers the shift register
if (shiftx->type == "$shiftx") {
- if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
+ if (GetSize(taps) > shiftx->getParam("\\A_WIDTH").as_int())
+ return false;
+ // Due to padding the most significant bits of A may be 1'bx,
+ // and if so, discount them
+ if (GetSize(taps) < shiftx->getParam("\\A_WIDTH").as_int()) {
+ const SigSpec A = shiftx->getPort("\\A");
+ const int A_width = shiftx->getParam("\\A_WIDTH").as_int();
+ for (int i = GetSize(taps); i < A_width; ++i)
+ if (A[i] != RTLIL::Sx) return false;
+ }
+ else if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
return false;
}
else if (shiftx->type == "$mux") {
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
index b46147fb9..2aefc091d 100644
--- a/passes/techmap/zinit.cc
+++ b/passes/techmap/zinit.cc
@@ -46,7 +46,7 @@ struct ZinitPass : public Pass {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
- if (args[argidx] == "-singleton") {
+ if (args[argidx] == "-all") {
all_mode = true;
continue;
}
diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc
index 86fb4d6c6..cdd21c3b3 100644
--- a/techlibs/common/prep.cc
+++ b/techlibs/common/prep.cc
@@ -195,9 +195,11 @@ struct PrepPass : public ScriptPass
run(nokeepdc ? "opt" : "opt -keepdc");
if (!ifxmode) {
if (help_mode)
- run("wreduce [-memx]");
- else
+ run("wreduce -keepdc [-memx]");
+ else if (nokeepdc)
run(memxmode ? "wreduce -memx" : "wreduce");
+ else
+ run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc");
}
if (!nomemmode) {
run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : ""));
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 8e43fe058..a424d3089 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -1271,6 +1271,181 @@ endmodule
// --------------------------------------------------------
+module \$specify2 (EN, SRC, DST);
+
+parameter FULL = 0;
+parameter SRC_WIDTH = 1;
+parameter DST_WIDTH = 1;
+
+parameter SRC_DST_PEN = 0;
+parameter SRC_DST_POL = 0;
+
+parameter T_RISE_MIN = 0;
+parameter T_RISE_TYP = 0;
+parameter T_RISE_MAX = 0;
+
+parameter T_FALL_MIN = 0;
+parameter T_FALL_TYP = 0;
+parameter T_FALL_MAX = 0;
+
+input EN;
+input [SRC_WIDTH-1:0] SRC;
+input [DST_WIDTH-1:0] DST;
+
+localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
+
+`ifdef SIMLIB_SPECIFY
+specify
+ if (EN && SD==0 && !FULL) (SRC => DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==0 && FULL) (SRC *> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==1 && !FULL) (SRC +=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==1 && FULL) (SRC +*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==2 && !FULL) (SRC -=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && SD==2 && FULL) (SRC -*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+endspecify
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$specify3 (EN, SRC, DST, DAT);
+
+parameter FULL = 0;
+parameter SRC_WIDTH = 1;
+parameter DST_WIDTH = 1;
+
+parameter EDGE_EN = 0;
+parameter EDGE_POL = 0;
+
+parameter SRC_DST_PEN = 0;
+parameter SRC_DST_POL = 0;
+
+parameter DAT_DST_PEN = 0;
+parameter DAT_DST_POL = 0;
+
+parameter T_RISE_MIN = 0;
+parameter T_RISE_TYP = 0;
+parameter T_RISE_MAX = 0;
+
+parameter T_FALL_MIN = 0;
+parameter T_FALL_TYP = 0;
+parameter T_FALL_MAX = 0;
+
+input EN;
+input [SRC_WIDTH-1:0] SRC;
+input [DST_WIDTH-1:0] DST, DAT;
+
+localparam ED = EDGE_EN ? (EDGE_POL ? 1 : 2) : 0;
+localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
+localparam DD = DAT_DST_PEN ? (DAT_DST_POL ? 1 : 2) : 0;
+
+`ifdef SIMLIB_SPECIFY
+specify
+ // DD=0
+
+ if (EN && DD==0 && SD==0 && ED==0 && !FULL) ( SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==0 && FULL) ( SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==0 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==0 && FULL) ( SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==0 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==0 && FULL) ( SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==0 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ // DD=1
+
+ if (EN && DD==1 && SD==0 && ED==0 && !FULL) ( SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==0 && FULL) ( SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==1 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==0 && FULL) ( SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==1 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==0 && FULL) ( SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==1 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ // DD=2
+
+ if (EN && DD==2 && SD==0 && ED==0 && !FULL) ( SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==0 && FULL) ( SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==2 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==0 && FULL) ( SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+
+ if (EN && DD==2 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==0 && FULL) ( SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+ if (EN && DD==2 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
+endspecify
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$specrule (EN_SRC, EN_DST, SRC, DST);
+
+parameter TYPE = "";
+parameter T_LIMIT = 0;
+parameter T_LIMIT2 = 0;
+
+parameter SRC_WIDTH = 1;
+parameter DST_WIDTH = 1;
+
+parameter SRC_PEN = 0;
+parameter SRC_POL = 0;
+
+parameter DST_PEN = 0;
+parameter DST_POL = 0;
+
+input EN_SRC, EN_DST;
+input [SRC_WIDTH-1:0] SRC;
+input [DST_WIDTH-1:0] DST;
+
+`ifdef SIMLIB_SPECIFY
+specify
+ // TBD
+endspecify
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
module \$assert (A, EN);
input A, EN;
@@ -1863,4 +2038,5 @@ end
endmodule
`endif
+
// --------------------------------------------------------
diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc
index 349605f8c..ee2e86de9 100644
--- a/techlibs/common/synth.cc
+++ b/techlibs/common/synth.cc
@@ -209,6 +209,8 @@ struct SynthPass : public ScriptPass
run("check");
run("opt");
run("wreduce");
+ run("peepopt");
+ run("opt_clean");
if (help_mode)
run("techmap -map +/cmp2lut.v", " (if -lut)");
else
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc
index 4b889d672..c6e12248e 100644
--- a/techlibs/ecp5/synth_ecp5.cc
+++ b/techlibs/ecp5/synth_ecp5.cc
@@ -253,7 +253,7 @@ struct SynthEcp5Pass : public ScriptPass
if (!nodffe)
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
- run("opt_expr -mux_undef");
+ run("opt_expr -undriven -mux_undef");
run("simplemap");
run("ecp5_ffinit");
}
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index 40972766d..b5e10fb20 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -957,10 +957,21 @@ endmodule
(* blackbox *)
module SB_HFOSC(
+ input TRIM0,
+ input TRIM1,
+ input TRIM2,
+ input TRIM3,
+ input TRIM4,
+ input TRIM5,
+ input TRIM6,
+ input TRIM7,
+ input TRIM8,
+ input TRIM9,
input CLKHFPU,
input CLKHFEN,
output CLKHF
);
+parameter TRIM_EN = "0b0";
parameter CLKHF_DIV = "0b00";
endmodule
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index 718f9d9e0..168161a90 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -245,11 +245,13 @@ struct SynthIce40Pass : public ScriptPass
run("proc");
}
- if (flatten && check_label("flatten", "(unless -noflatten)"))
+ if (check_label("flatten", "(unless -noflatten)"))
{
- run("flatten");
- run("tribuf -logic");
- run("deminout");
+ if (flatten) {
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
+ }
}
if (check_label("coarse"))
@@ -259,6 +261,8 @@ struct SynthIce40Pass : public ScriptPass
run("check");
run("opt");
run("wreduce");
+ run("peepopt");
+ run("opt_clean");
run("share");
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
run("opt_expr");
diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc
index d2291b8d4..639cba2c2 100644
--- a/techlibs/intel/synth_intel.cc
+++ b/techlibs/intel/synth_intel.cc
@@ -17,254 +17,243 @@
*
*/
-#include "kernel/register.h"
#include "kernel/celltypes.h"
-#include "kernel/rtlil.h"
#include "kernel/log.h"
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct SynthIntelPass : public ScriptPass {
- SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") { }
+ SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {}
- void help() YS_OVERRIDE
- {
- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
- log("\n");
- log(" synth_intel [options]\n");
- log("\n");
- log("This command runs synthesis for Intel FPGAs.\n");
- log("\n");
- log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
- log(" generate the synthesis netlist for the specified family.\n");
- log(" MAX10 is the default target if no family argument specified.\n");
- log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
- log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
- log("\n");
- log(" -top <module>\n");
- log(" use the specified module as top module (default='top')\n");
- log("\n");
- log(" -vqm <file>\n");
- log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
- log(" output file is omitted if this parameter is not specified.\n");
- log("\n");
- log(" -vpr <file>\n");
- log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
- log(" compatible with the Quartus flow. Writing of an\n");
- log(" output file is omitted if this parameter is not specified.\n");
- log("\n");
- log(" -run <from_label>:<to_label>\n");
- log(" only run the commands between the labels (see below). an empty\n");
- log(" from label is synonymous to 'begin', and empty to label is\n");
- log(" synonymous to the end of the command list.\n");
- log("\n");
- log(" -noiopads\n");
- log(" do not use altsyncram cells in output netlist\n");
- log("\n");
- log(" -nobram\n");
- log(" do not use altsyncram cells in output netlist\n");
- log("\n");
- log(" -noflatten\n");
- log(" do not flatten design before synthesis\n");
- log("\n");
- log(" -retime\n");
- log(" run 'abc' with -dff option\n");
- log("\n");
- log("The following commands are executed by this synthesis command:\n");
- help_script();
- log("\n");
- }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_intel [options]\n");
+ log("\n");
+ log("This command runs synthesis for Intel FPGAs.\n");
+ log("\n");
+ log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
+ log(" generate the synthesis netlist for the specified family.\n");
+ log(" MAX10 is the default target if not family argument specified.\n");
+ log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
+ log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module (default='top')\n");
+ log("\n");
+ log(" -vqm <file>\n");
+ log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
+ log(" output file is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -vpr <file>\n");
+ log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
+ log(" compatible with the Quartus flow. Writing of an\n");
+ log(" output file is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -noiopads\n");
+ log(" do not use altsyncram cells in output netlist\n");
+ log("\n");
+ log(" -nobram\n");
+ log(" do not use altsyncram cells in output netlist\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log(" -retime\n");
+ log(" run 'abc' with -dff option\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
- string top_opt, family_opt, vout_file, blif_file;
- bool retime, flatten, nobram, noiopads;
+ string top_opt, family_opt, vout_file, blif_file;
+ bool retime, flatten, nobram, noiopads;
- void clear_flags() YS_OVERRIDE
- {
- top_opt = "-auto-top";
- family_opt = "max10";
- vout_file = "";
- blif_file = "";
- retime = false;
- flatten = true;
- nobram = false;
- noiopads = false;
- }
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ family_opt = "max10";
+ vout_file = "";
+ blif_file = "";
+ retime = false;
+ flatten = true;
+ nobram = false;
+ noiopads = false;
+ }
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
- {
- string run_from, run_to;
- clear_flags();
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++)
- {
- if (args[argidx] == "-family" && argidx+1 < args.size()) {
- family_opt = args[++argidx];
- continue;
- }
- if (args[argidx] == "-top" && argidx+1 < args.size()) {
- top_opt = "-top " + args[++argidx];
- continue;
- }
- if (args[argidx] == "-vqm" && argidx+1 < args.size()) {
- vout_file = args[++argidx];
- continue;
- }
- if (args[argidx] == "-vpr" && argidx+1 < args.size()) {
- blif_file = args[++argidx];
- continue;
- }
- if (args[argidx] == "-run" && argidx+1 < args.size()) {
- size_t pos = args[argidx+1].find(':');
- if (pos == std::string::npos)
- break;
- run_from = args[++argidx].substr(0, pos);
- run_to = args[argidx].substr(pos+1);
- continue;
- }
- if (args[argidx] == "-noiopads") {
- noiopads = true;
- continue;
- }
- if (args[argidx] == "-nobram") {
- nobram = true;
- continue;
- }
- if (args[argidx] == "-noflatten") {
- flatten = false;
- continue;
- }
- if (args[argidx] == "-retime") {
- retime = true;
- continue;
- }
- break;
- }
- extra_args(args, argidx, design);
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-family" && argidx + 1 < args.size()) {
+ family_opt = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-top" && argidx + 1 < args.size()) {
+ top_opt = "-top " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-vqm" && argidx + 1 < args.size()) {
+ vout_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-vpr" && argidx + 1 < args.size()) {
+ blif_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx + 1 < args.size()) {
+ size_t pos = args[argidx + 1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos + 1);
+ continue;
+ }
+ if (args[argidx] == "-noiopads") {
+ noiopads = true;
+ continue;
+ }
+ if (args[argidx] == "-nobram") {
+ nobram = true;
+ continue;
+ }
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
- if (!design->full_selection())
- log_cmd_error("This command only operates on fully selected designs!\n");
- if (family_opt != "max10" && family_opt !="a10gx" && family_opt != "cyclonev" && family_opt !="cycloneiv" && family_opt !="cycloneive" && family_opt != "cyclone10")
- log_cmd_error("Invalid or no family specified: '%s'\n", family_opt.c_str());
+ if (!design->full_selection())
+ log_cmd_error("This command only operates on fully selected designs!\n");
+ if (family_opt != "max10" && family_opt != "a10gx" && family_opt != "cyclonev" && family_opt != "cycloneiv" &&
+ family_opt != "cycloneive" && family_opt != "cyclone10")
+ log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());
- log_header(design, "Executing SYNTH_INTEL pass.\n");
- log_push();
+ log_header(design, "Executing SYNTH_INTEL pass.\n");
+ log_push();
- run_script(design, run_from, run_to);
+ run_script(design, run_from, run_to);
- log_pop();
- }
+ log_pop();
+ }
- void script() YS_OVERRIDE
- {
- if (check_label("begin"))
- {
- if(check_label("family") && family_opt=="max10")
- run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
- else if(check_label("family") && family_opt=="a10gx")
- run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
- else if(check_label("family") && family_opt=="cyclonev")
- run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
- else if(check_label("family") && family_opt=="cyclone10")
- run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
- else if(check_label("family") && family_opt=="cycloneiv")
- run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
- else
- run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
- // Misc and common cells
- run("read_verilog -sv -lib +/intel/common/m9k_bb.v");
- run("read_verilog -sv -lib +/intel/common/altpll_bb.v");
- run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
- }
+ void script() YS_OVERRIDE
+ {
+ if (check_label("begin")) {
+ if (check_label("family") && family_opt == "max10")
+ run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
+ else if (check_label("family") && family_opt == "a10gx")
+ run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
+ else if (check_label("family") && family_opt == "cyclonev")
+ run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
+ else if (check_label("family") && family_opt == "cyclone10")
+ run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
+ else if (check_label("family") && family_opt == "cycloneiv")
+ run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
+ else
+ run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
+ // Misc and common cells
+ run("read_verilog -sv -lib +/intel/common/m9k_bb.v");
+ run("read_verilog -sv -lib +/intel/common/altpll_bb.v");
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
- if (flatten && check_label("flatten", "(unless -noflatten)"))
- {
- run("proc");
- run("flatten");
- run("tribuf -logic");
- run("deminout");
- }
+ if (flatten && check_label("flatten", "(unless -noflatten)")) {
+ run("proc");
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
+ }
- if (check_label("coarse"))
- {
- run("synth -run coarse");
- }
+ if (check_label("coarse")) {
+ run("synth -run coarse");
+ }
- if (!nobram && check_label("bram", "(skip if -nobram)"))
- {
- run("memory_bram -rules +/intel/common/brams.txt");
- run("techmap -map +/intel/common/brams_map.v");
- }
+ if (!nobram && check_label("bram", "(skip if -nobram)")) {
+ run("memory_bram -rules +/intel/common/brams.txt");
+ run("techmap -map +/intel/common/brams_map.v");
+ }
- if (check_label("fine"))
- {
- run("opt -fast -mux_undef -undriven -fine -full");
- run("memory_map");
- run("opt -undriven -fine");
- run("dffsr2dff");
- run("dff2dffe -direct-match $_DFF_*");
- run("opt -fine");
- run("techmap -map +/techmap.v");
- run("opt -full");
- run("clean -purge");
- run("setundef -undriven -zero");
- if (retime || help_mode)
- run("abc -markgroups -dff", "(only if -retime)");
- }
+ if (check_label("fine")) {
+ run("opt -fast -mux_undef -undriven -fine -full");
+ run("memory_map");
+ run("opt -undriven -fine");
+ run("dffsr2dff");
+ run("dff2dffe -direct-match $_DFF_*");
+ run("opt -fine");
+ run("techmap -map +/techmap.v");
+ run("opt -full");
+ run("clean -purge");
+ run("setundef -undriven -zero");
+ if (retime || help_mode)
+ run("abc -markgroups -dff", "(only if -retime)");
+ }
- if (check_label("map_luts"))
- {
- if(family_opt=="a10gx" || family_opt=="cyclonev")
- run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
- else
- run("abc -lut 4" + string(retime ? " -dff" : ""));
- run("clean");
- }
+ if (check_label("map_luts")) {
+ if (family_opt == "a10gx" || family_opt == "cyclonev")
+ run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
+ else
+ run("abc -lut 4" + string(retime ? " -dff" : ""));
+ run("clean");
+ }
- if (check_label("map_cells"))
- {
- if (!noiopads)
- run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
- if(family_opt=="max10")
- run("techmap -map +/intel/max10/cells_map.v");
- else if(family_opt=="a10gx")
- run("techmap -map +/intel/a10gx/cells_map.v");
- else if(family_opt=="cyclonev")
- run("techmap -map +/intel/cyclonev/cells_map.v");
- else if(family_opt=="cyclone10")
- run("techmap -map +/intel/cyclone10/cells_map.v");
- else if(family_opt=="cycloneiv")
- run("techmap -map +/intel/cycloneiv/cells_map.v");
- else
- run("techmap -map +/intel/cycloneive/cells_map.v");
- run("dffinit -highlow -ff dffeas q power_up");
- run("clean -purge");
- }
+ if (check_label("map_cells")) {
+ if (!noiopads)
+ run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
+ if (family_opt == "max10")
+ run("techmap -map +/intel/max10/cells_map.v");
+ else if (family_opt == "a10gx")
+ run("techmap -map +/intel/a10gx/cells_map.v");
+ else if (family_opt == "cyclonev")
+ run("techmap -map +/intel/cyclonev/cells_map.v");
+ else if (family_opt == "cyclone10")
+ run("techmap -map +/intel/cyclone10/cells_map.v");
+ else if (family_opt == "cycloneiv")
+ run("techmap -map +/intel/cycloneiv/cells_map.v");
+ else
+ run("techmap -map +/intel/cycloneive/cells_map.v");
+ run("dffinit -highlow -ff dffeas q power_up");
+ run("clean -purge");
+ }
- if (check_label("check"))
- {
- run("hierarchy -check");
- run("stat");
- run("check -noinit");
- }
+ if (check_label("check")) {
+ run("hierarchy -check");
+ run("stat");
+ run("check -noinit");
+ }
- if (check_label("vqm"))
- {
- if (!vout_file.empty() || help_mode)
- run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
- help_mode ? "<file-name>" : vout_file.c_str()));
- }
+ if (check_label("vqm")) {
+ if (!vout_file.empty() || help_mode)
+ run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
+ help_mode ? "<file-name>" : vout_file.c_str()));
+ }
- if (check_label("vpr"))
- {
- if (!blif_file.empty() || help_mode)
- {
- run(stringf("opt_clean -purge"));
- run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
- }
- }
- }
+ if (check_label("vpr")) {
+ if (!blif_file.empty() || help_mode) {
+ run(stringf("opt_clean -purge"));
+ run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
+ }
+ }
+ }
} SynthIntelPass;
PRIVATE_NAMESPACE_END
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index d68f03bb4..296edace9 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -30,6 +30,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc.box))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc.lut))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
diff --git a/techlibs/xilinx/abc.box b/techlibs/xilinx/abc.box
new file mode 100644
index 000000000..6e9e1faf6
--- /dev/null
+++ b/techlibs/xilinx/abc.box
@@ -0,0 +1,42 @@
+# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf
+
+# F7BMUX slower than F7AMUX
+# Inputs: I0 I1 S0
+# Outputs: O
+F7BMUX 1 1 3 1
+217 223 296
+
+# Inputs: I0 I1 S0
+# Outputs: O
+MUXF8 2 1 3 1
+104 94 273
+
+# CARRY4 + CARRY4_[ABCD]X
+# Inputs: S0 S1 S2 S3 CYINIT DI0 DI1 DI2 DI3 CI
+# Outputs: O0 O1 O2 O3 CO0 CO1 CO2 CO3
+# (NB: carry chain input/output must be last input/output,
+# swapped with what normally would have been the last
+# output, here: CI <-> S, CO <-> O
+CARRY4 3 1 10 8
+223 - - - 482 - - - - 222
+400 205 - - 598 407 - - - 334
+523 558 226 - 584 556 537 - - 239
+582 618 330 227 642 615 596 438 - 313
+340 - - - 536 379 - - - 271
+433 469 - - 494 465 445 - - 157
+512 548 292 - 592 540 520 356 - 228
+508 528 378 380 580 526 507 398 385 114
+
+# SLICEM/A6LUT
+# Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE
+# Outputs: DPO SPO
+RAM64X1D 4 0 15 2
+- - - - - - - 124 124 124 124 124 124 - -
+124 124 124 124 124 124 - - - - - - 124 - -
+
+# SLICEM/A6LUT + F7[AB]MUX
+# Inputs: A0 A1 A2 A3 A4 A5 A6 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 DPRA6 WCLK WE
+# Outputs: DPO SPO
+RAM128X1D 5 0 17 2
+- - - - - - - - 314 314 314 314 314 314 292 - -
+347 347 347 347 347 347 296 - - - - - - - - - -
diff --git a/techlibs/xilinx/abc.lut b/techlibs/xilinx/abc.lut
new file mode 100644
index 000000000..3a7dc268d
--- /dev/null
+++ b/techlibs/xilinx/abc.lut
@@ -0,0 +1,14 @@
+# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf
+
+# K area delay
+1 1 124
+2 2 124 235
+3 3 124 235 399
+4 3 124 235 399 490
+5 3 124 235 399 490 620
+6 5 124 235 399 490 620 632
+ # F7BMUX
+7 10 296 420 531 695 756 916 928
+ # F8MUX
+ # F8MUX+F7BMUX
+8 20 273 569 693 804 968 1029 1189 1201
diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v
index 09a5f07e8..5c848d4e6 100644
--- a/techlibs/xilinx/arith_map.v
+++ b/techlibs/xilinx/arith_map.v
@@ -180,7 +180,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
// First one
if (i == 0) begin
- CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_part
+ CARRY4 carry4_1st_part
(
.CYINIT(CI),
.CI (1'd0),
@@ -207,7 +207,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
// First one
if (i == 0) begin
- CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_full
+ CARRY4 carry4_1st_full
(
.CYINIT(CI),
.CI (1'd0),
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index 704ab21b1..af6414667 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -17,6 +17,16 @@
*
*/
+// Convert negative-polarity reset to positive-polarity
+(* techmap_celltype = "$_DFF_NN0_" *)
+module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$_DFF_PN0_" *)
+module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$_DFF_NN1_" *)
+module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+(* techmap_celltype = "$_DFF_PN1_" *)
+module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+
module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0;
@@ -78,7 +88,7 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
end else
if (DEPTH > 65 && DEPTH <= 96) begin
wire T0, T1, T2, T3, T4, T5, T6;
- SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
+ SRLC32E #(.INIT(INIT_R[32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4));
if (&_TECHMAP_CONSTMSK_L_)
@@ -91,7 +101,7 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
end else
if (DEPTH > 97 && DEPTH < 128) begin
wire T0, T1, T2, T3, T4, T5, T6, T7, T8;
- SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
+ SRLC32E #(.INIT(INIT_R[32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6));
@@ -105,9 +115,9 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
end
else if (DEPTH == 128) begin
wire T0, T1, T2, T3, T4, T5, T6;
- SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
- SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
- SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
+ SRLC32E #(.INIT(INIT_R[ 32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1));
+ SRLC32E #(.INIT(INIT_R[ 64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
+ SRLC32E #(.INIT(INIT_R[ 96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T6;
@@ -142,5 +152,118 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
endgenerate
endmodule
-`ifndef SRL_ONLY
-`endif
+module \$shiftx (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ parameter [A_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0;
+ parameter [A_WIDTH-1:0] _TECHMAP_CONSTVAL_A_ = 0;
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
+
+ function integer compute_num_leading_X_in_A;
+ integer i, c;
+ begin
+ compute_num_leading_X_in_A = 0;
+ c = 1;
+ for (i = A_WIDTH-1; i >= 0; i=i-1) begin
+ if (!_TECHMAP_CONSTMSK_A_[i] || _TECHMAP_CONSTVAL_A_[i] !== 1'bx)
+ c = 0;
+ compute_num_leading_X_in_A = compute_num_leading_X_in_A + c;
+ end
+ end
+ endfunction
+ localparam num_leading_X_in_A = compute_num_leading_X_in_A();
+
+ generate
+ genvar i, j;
+ // TODO: Check if this opt still necessary
+ if (B_SIGNED) begin
+ if (_TECHMAP_CONSTMSK_B_[B_WIDTH-1] && _TECHMAP_CONSTVAL_B_[B_WIDTH-1] == 1'b0)
+ // Optimisation to remove B_SIGNED if sign bit of B is constant-0
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(0), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH-1'd1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B[B_WIDTH-2:0]), .Y(Y));
+ else
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ // Bit-blast
+ else if (Y_WIDTH > 1) begin
+ for (i = 0; i < Y_WIDTH; i++)
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH-Y_WIDTH+1), .B_WIDTH(B_WIDTH), .Y_WIDTH(1'd1)) bitblast (.A(A[A_WIDTH-Y_WIDTH+i:i]), .B(B), .Y(Y[i]));
+ end
+ // If the LSB of B is constant zero (and Y_WIDTH is 1) then
+ // we can optimise by removing every other entry from A
+ // and popping the constant zero from B
+ else if (_TECHMAP_CONSTMSK_B_[0] && !_TECHMAP_CONSTVAL_B_[0]) begin
+ wire [(A_WIDTH+1)/2-1:0] A_i;
+ for (i = 0; i < (A_WIDTH+1)/2; i++)
+ assign A_i[i] = A[i*2];
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH((A_WIDTH+1'd1)/2'd2), .B_WIDTH(B_WIDTH-1'd1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A_i), .B(B[B_WIDTH-1:1]), .Y(Y));
+ end
+ // Trim off any leading 1'bx -es in A, and resize B accordingly
+ else if (num_leading_X_in_A > 0) begin
+ localparam A_WIDTH_new = A_WIDTH - num_leading_X_in_A;
+ localparam B_WIDTH_new = $clog2(A_WIDTH_new);
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH_new), .B_WIDTH(B_WIDTH_new), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A[A_WIDTH_new-1:0]), .B(B[B_WIDTH_new-1:0]), .Y(Y));
+ end
+ else if (B_WIDTH < 3 || A_WIDTH <= 4) begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ else if (B_WIDTH == 3) begin
+ localparam a_width0 = 2 ** 2;
+ localparam a_widthN = A_WIDTH - a_width0;
+ wire T0, T1;
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_shiftx (.A(A[a_width0-1:0]), .B(B[2-1:0]), .Y(T0));
+ if (a_widthN > 1)
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_shiftx_last (.A(A[A_WIDTH-1:a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T1));
+ else
+ assign T1 = A[A_WIDTH-1];
+ MUXF7 fpga_mux (.I0(T0), .I1(T1), .S(B[B_WIDTH-1]), .O(Y));
+ end
+ else if (B_WIDTH == 4) begin
+ localparam a_width0 = 2 ** 2;
+ localparam num_mux8 = A_WIDTH / a_width0;
+ localparam a_widthN = A_WIDTH - num_mux8*a_width0;
+ wire [4-1:0] T;
+ wire T0, T1;
+ for (i = 0; i < 4; i++)
+ if (i < num_mux8)
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_shiftx (.A(A[i*a_width0+:a_width0]), .B(B[2-1:0]), .Y(T[i]));
+ else if (i == num_mux8 && a_widthN > 0) begin
+ if (a_widthN > 1)
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_shiftx_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i]));
+ else
+ assign T[i] = A[A_WIDTH-1];
+ end
+ else
+ assign T[i] = 1'bx;
+ MUXF7 fpga_mux_0 (.I0(T[0]), .I1(T[1]), .S(B[2]), .O(T0));
+ MUXF7 fpga_mux_1 (.I0(T[2]), .I1(T[3]), .S(B[2]), .O(T1));
+ MUXF8 fpga_mux_2 (.I0(T0), .I1(T1), .S(B[3]), .O(Y));
+ end
+ else begin
+ localparam a_width0 = 2 ** 4;
+ localparam num_mux16 = A_WIDTH / a_width0;
+ localparam a_widthN = A_WIDTH - num_mux16*a_width0;
+ wire [(2**(B_WIDTH-4))-1:0] T;
+ for (i = 0; i < 2 ** (B_WIDTH-4); i++)
+ if (i < num_mux16)
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(4), .Y_WIDTH(Y_WIDTH)) fpga_shiftx (.A(A[i*a_width0+:a_width0]), .B(B[4-1:0]), .Y(T[i]));
+ else if (i == num_mux16 && a_widthN > 0) begin
+ if (a_widthN > 1)
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_shiftx_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i]));
+ else
+ assign T[i] = A[A_WIDTH-1];
+ end
+ else
+ assign T[i] = 1'bx;
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(2**(B_WIDTH-4)), .B_WIDTH(B_WIDTH-4), .Y_WIDTH(Y_WIDTH)) fpga_shiftx (.A(T), .B(B[B_WIDTH-1:4]), .Y(Y));
+ end
+ endgenerate
+endmodule
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index 3a4540b83..7337e0ea7 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -159,10 +159,12 @@ module MUXCY(output O, input CI, DI, S);
assign O = S ? CI : DI;
endmodule
+(* abc_box_id = 1, lib_whitebox *)
module MUXF7(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
+(* abc_box_id = 2, lib_whitebox *)
module MUXF8(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
@@ -171,7 +173,8 @@ module XORCY(output O, input CI, LI);
assign O = CI ^ LI;
endmodule
-module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
+(* abc_box_id = 3, lib_whitebox, abc_carry *)
+module CARRY4((* abc_carry_out *) output [3:0] CO, output [3:0] O, (* abc_carry_in *) input CI, input CYINIT, input [3:0] DI, S);
assign O = S ^ {CO[2:0], CI | CYINIT};
assign CO[0] = S[0] ? CI | CYINIT : DI[0];
assign CO[1] = S[1] ? CO[0] : DI[1];
@@ -202,7 +205,7 @@ endmodule
`endif
-module FDRE (output reg Q, input C, CE, D, R);
+module FDRE ((* abc_flop_q *) output reg Q, input C, CE, input D, R);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -214,7 +217,7 @@ module FDRE (output reg Q, input C, CE, D, R);
endcase endgenerate
endmodule
-module FDSE (output reg Q, input C, CE, D, S);
+module FDSE ((* abc_flop_q *) output reg Q, input C, CE, D, S);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -226,7 +229,7 @@ module FDSE (output reg Q, input C, CE, D, S);
endcase endgenerate
endmodule
-module FDCE (output reg Q, input C, CE, D, CLR);
+module FDCE ((* abc_flop_q *) output reg Q, input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -240,7 +243,7 @@ module FDCE (output reg Q, input C, CE, D, CLR);
endcase endgenerate
endmodule
-module FDPE (output reg Q, input C, CE, D, PRE);
+module FDPE ((* abc_flop_q *) output reg Q, input C, CE, D, PRE);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -254,30 +257,31 @@ module FDPE (output reg Q, input C, CE, D, PRE);
endcase endgenerate
endmodule
-module FDRE_1 (output reg Q, input C, CE, D, R);
+module FDRE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, R);
parameter [0:0] INIT = 1'b0;
initial Q <= INIT;
always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
endmodule
-module FDSE_1 (output reg Q, input C, CE, D, S);
+module FDSE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, S);
parameter [0:0] INIT = 1'b1;
initial Q <= INIT;
always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
endmodule
-module FDCE_1 (output reg Q, input C, CE, D, CLR);
+module FDCE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0;
initial Q <= INIT;
always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
endmodule
-module FDPE_1 (output reg Q, input C, CE, D, PRE);
+module FDPE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1;
initial Q <= INIT;
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
endmodule
+(* abc_box_id = 4 /*, lib_whitebox*/ *)
module RAM64X1D (
output DPO, SPO,
input D, WCLK, WE,
@@ -291,10 +295,13 @@ module RAM64X1D (
reg [63:0] mem = INIT;
assign SPO = mem[a];
assign DPO = mem[dpra];
+`ifndef _ABC
wire clk = WCLK ^ IS_WCLK_INVERTED;
always @(posedge clk) if (WE) mem[a] <= D;
+`endif
endmodule
+(* abc_box_id = 5 /*, lib_whitebox*/ *)
module RAM128X1D (
output DPO, SPO,
input D, WCLK, WE,
@@ -305,12 +312,14 @@ module RAM128X1D (
reg [127:0] mem = INIT;
assign SPO = mem[A];
assign DPO = mem[DPRA];
+`ifndef _ABC
wire clk = WCLK ^ IS_WCLK_INVERTED;
always @(posedge clk) if (WE) mem[A] <= D;
+`endif
endmodule
module SRL16E (
- output Q,
+ (* abc_flop_q *) output Q,
input A0, A1, A2, A3, CE, CLK, D
);
parameter [15:0] INIT = 16'h0000;
@@ -328,7 +337,7 @@ module SRL16E (
endmodule
module SRLC32E (
- output Q,
+ (* abc_flop_q *) output Q,
output Q31,
input [4:0] A,
input CE, CLK, D
diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh
index 8e39b440d..2b384f405 100644
--- a/techlibs/xilinx/cells_xtra.sh
+++ b/techlibs/xilinx/cells_xtra.sh
@@ -116,7 +116,7 @@ function xtract_cell_decl()
xtract_cell_decl PS7 "(* keep *)"
xtract_cell_decl PULLDOWN
xtract_cell_decl PULLUP
- xtract_cell_decl RAM128X1D
+ #xtract_cell_decl RAM128X1D
xtract_cell_decl RAM128X1S
xtract_cell_decl RAM256X1S
xtract_cell_decl RAM32M
@@ -125,7 +125,7 @@ function xtract_cell_decl()
xtract_cell_decl RAM32X1S_1
xtract_cell_decl RAM32X2S
xtract_cell_decl RAM64M
- xtract_cell_decl RAM64X1D
+ #xtract_cell_decl RAM64X1D
xtract_cell_decl RAM64X1S
xtract_cell_decl RAM64X1S_1
xtract_cell_decl RAM64X2S
diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v
index fbcc74682..0ec3d0df0 100644
--- a/techlibs/xilinx/cells_xtra.v
+++ b/techlibs/xilinx/cells_xtra.v
@@ -3655,17 +3655,6 @@ module PULLUP (...);
output O;
endmodule
-module RAM128X1D (...);
- parameter [127:0] INIT = 128'h00000000000000000000000000000000;
- parameter [0:0] IS_WCLK_INVERTED = 1'b0;
- output DPO, SPO;
- input [6:0] A;
- input [6:0] DPRA;
- input D;
- input WCLK;
- input WE;
-endmodule
-
module RAM128X1S (...);
parameter [127:0] INIT = 128'h00000000000000000000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3756,13 +3745,6 @@ module RAM64M (...);
input WE;
endmodule
-module RAM64X1D (...);
- parameter [63:0] INIT = 64'h0000000000000000;
- parameter [0:0] IS_WCLK_INVERTED = 1'b0;
- output DPO, SPO;
- input A0, A1, A2, A3, A4, A5, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5, WCLK, WE;
-endmodule
-
module RAM64X1S (...);
parameter [63:0] INIT = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
diff --git a/techlibs/xilinx/drams.txt b/techlibs/xilinx/drams.txt
index e6635d0e2..91632bcee 100644
--- a/techlibs/xilinx/drams.txt
+++ b/techlibs/xilinx/drams.txt
@@ -26,11 +26,15 @@ bram $__XILINX_RAM128X1D
endbram
match $__XILINX_RAM64X1D
+ min bits 5
+ min wports 1
make_outreg
or_next_if_better
endmatch
match $__XILINX_RAM128X1D
+ min bits 9
+ min wports 1
make_outreg
endmatch
diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v
index c61fd7070..13beaa6ae 100644
--- a/techlibs/xilinx/ff_map.v
+++ b/techlibs/xilinx/ff_map.v
@@ -22,26 +22,21 @@
`ifndef _NO_FFS
-`ifndef _NO_POS_SR
module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
+module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
+module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
+module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
+module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
-`endif
-
-module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
-module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
-
-module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
-module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
-`endif
`endif
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 5820d6d61..cc667b919 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -25,18 +25,9 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
+struct SynthXilinxPass : public ScriptPass
{
- if (label == run_from)
- active = true;
- if (label == run_to)
- active = false;
- return active;
-}
-
-struct SynthXilinxPass : public Pass
-{
- SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
+ SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
void help() YS_OVERRIDE
{
@@ -51,6 +42,10 @@ struct SynthXilinxPass : public Pass
log(" -top <module>\n");
log(" use the specified module as top module\n");
log("\n");
+ log(" -arch {xcup|xcu|xc7|xc6s}\n");
+ log(" run synthesis for the specified Xilinx architecture\n");
+ log(" default: xc7\n");
+ log("\n");
log(" -edif <file>\n");
log(" write the design to the specified edif file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
@@ -63,6 +58,9 @@ struct SynthXilinxPass : public Pass
log(" generate an output netlist (and BLIF file) suitable for VPR\n");
log(" (this feature is experimental and incomplete)\n");
log("\n");
+ log(" -nocarry\n");
+ log(" disable inference of carry chains\n");
+ log("\n");
log(" -nobram\n");
log(" disable inference of block rams\n");
log("\n");
@@ -72,6 +70,9 @@ struct SynthXilinxPass : public Pass
log(" -nosrl\n");
log(" disable inference of shift registers\n");
log("\n");
+ log(" -nomux\n");
+ log(" disable inference of wide multiplexers\n");
+ log("\n");
log(" -run <from_label>:<to_label>\n");
log(" only run the commands between the labels (see below). an empty\n");
log(" from label is synonymous to 'begin', and empty to label is\n");
@@ -88,80 +89,34 @@ struct SynthXilinxPass : public Pass
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
- log("\n");
- log(" begin:\n");
- log(" read_verilog -lib +/xilinx/cells_sim.v\n");
- log(" read_verilog -lib +/xilinx/cells_xtra.v\n");
- log(" read_verilog -lib +/xilinx/brams_bb.v\n");
- log(" hierarchy -check -top <top>\n");
- log("\n");
- log(" flatten: (only if -flatten)\n");
- log(" proc\n");
- log(" flatten\n");
- log("\n");
- log(" coarse:\n");
- log(" synth -run coarse\n");
- log("\n");
- log(" bram: (only executed when '-nobram' is not given)\n");
- log(" memory_bram -rules +/xilinx/brams.txt\n");
- log(" techmap -map +/xilinx/brams_map.v\n");
- log("\n");
- log(" dram: (only executed when '-nodram' is not given)\n");
- log(" memory_bram -rules +/xilinx/drams.txt\n");
- log(" techmap -map +/xilinx/drams_map.v\n");
- log("\n");
- log(" fine:\n");
- log(" opt -fast\n");
- log(" memory_map\n");
- log(" dffsr2dff\n");
- log(" dff2dffe\n");
- log(" techmap -map +/xilinx/arith_map.v\n");
- log(" opt -fast\n");
- log("\n");
- log(" map_cells:\n");
- log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n");
- log(" pmux2shiftx (without '-nosrl' only)\n");
- log(" opt_expr -mux_undef (without '-nosrl' only)\n");
- log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n");
- log(" techmap -map +/xilinx/cells_map.v\n");
- log(" clean\n");
- log("\n");
- log(" map_luts:\n");
- log(" opt -full\n");
- log(" techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n");
- log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n");
- log(" clean\n");
- log(" shregmap -minlen 3 -init -params -enpol any_or_none (without '-nosrl' only)\n");
- log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
- log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n");
- log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n");
- log(" clean\n");
- log("\n");
- log(" check:\n");
- log(" hierarchy -check\n");
- log(" stat\n");
- log(" check -noinit\n");
- log("\n");
- log(" edif: (only if -edif)\n");
- log(" write_edif <file-name>\n");
- log("\n");
- log(" blif: (only if -blif)\n");
- log(" write_blif <file-name>\n");
+ help_script();
log("\n");
}
+
+ std::string top_opt, edif_file, blif_file, abc, arch;
+ bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl, nomux;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ edif_file.clear();
+ blif_file.clear();
+ abc = "abc";
+ flatten = false;
+ retime = false;
+ vpr = false;
+ nocarry = false;
+ nobram = false;
+ nodram = false;
+ nosrl = false;
+ nomux = false;
+ arch = "xc7";
+ }
+
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- std::string top_opt = "-auto-top";
- std::string edif_file;
- std::string blif_file;
std::string run_from, run_to;
- std::string abc = "abc";
- bool flatten = false;
- bool retime = false;
- bool vpr = false;
- bool nobram = false;
- bool nodram = false;
- bool nosrl = false;
+ clear_flags();
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -170,6 +125,10 @@ struct SynthXilinxPass : public Pass
top_opt = "-top " + args[++argidx];
continue;
}
+ if (args[argidx] == "-arch" && argidx+1 < args.size()) {
+ arch = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-edif" && argidx+1 < args.size()) {
edif_file = args[++argidx];
continue;
@@ -198,6 +157,10 @@ struct SynthXilinxPass : public Pass
vpr = true;
continue;
}
+ if (args[argidx] == "-nocarry") {
+ nocarry = true;
+ continue;
+ }
if (args[argidx] == "-nobram") {
nobram = true;
continue;
@@ -209,7 +172,11 @@ struct SynthXilinxPass : public Pass
if (args[argidx] == "-nosrl") {
nosrl = true;
continue;
- }
+ }
+ if (args[argidx] == "-nomux") {
+ nomux = true;
+ continue;
+ }
if (args[argidx] == "-abc9") {
abc = "abc9";
continue;
@@ -218,131 +185,141 @@ struct SynthXilinxPass : public Pass
}
extra_args(args, argidx, design);
+ if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")
+ log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str());
+
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
- bool active = run_from.empty();
-
log_header(design, "Executing SYNTH_XILINX pass.\n");
log_push();
- if (check_label(active, run_from, run_to, "begin"))
- {
- if (vpr) {
- Pass::call(design, "read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
- } else {
- Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v");
- }
+ run_script(design, run_from, run_to);
- Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v");
+ log_pop();
+ }
- if (!nobram) {
- Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v");
- }
+ void script() YS_OVERRIDE
+ {
+ if (check_label("begin")) {
+ if (vpr)
+ run("read_verilog -lib -D_ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
+ else
+ run("read_verilog -lib -D_ABC +/xilinx/cells_sim.v");
+
+ run("read_verilog -lib +/xilinx/cells_xtra.v");
- Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
+ if (!nobram || help_mode)
+ run("read_verilog -lib +/xilinx/brams_bb.v", "(skip if '-nobram')");
+
+ run(stringf("hierarchy -check %s", top_opt.c_str()));
}
- if (flatten && check_label(active, run_from, run_to, "flatten"))
- {
- Pass::call(design, "proc");
- Pass::call(design, "flatten");
+ if (check_label("flatten", "(with '-flatten' only)")) {
+ if (flatten || help_mode) {
+ run("proc");
+ run("flatten");
+ }
}
- if (check_label(active, run_from, run_to, "coarse"))
- {
- Pass::call(design, "synth -run coarse");
+ if (check_label("coarse")) {
+ run("synth -run coarse");
+
+ // shregmap -tech xilinx can cope with $shiftx and $mux
+ // cells for identifying variable-length shift registers,
+ // so attempt to convert $pmux-es to the former
+ // Also: wide multiplexer inference benefits from this too
+ if ((!nosrl && !nomux) || help_mode)
+ run("pmux2shiftx", "(skip if '-nosrl' and '-nomux')");
+
+ // Run a number of peephole optimisations, including one
+ // that optimises $mul cells driving $shiftx's B input
+ // and that aids wide mux analysis
+ run("peepopt");
}
- if (check_label(active, run_from, run_to, "bram"))
- {
- if (!nobram) {
- Pass::call(design, "memory_bram -rules +/xilinx/brams.txt");
- Pass::call(design, "techmap -map +/xilinx/brams_map.v");
+ if (check_label("bram", "(skip if '-nobram')")) {
+ if (!nobram || help_mode) {
+ run("memory_bram -rules +/xilinx/brams.txt");
+ run("techmap -map +/xilinx/brams_map.v");
}
}
- if (check_label(active, run_from, run_to, "dram"))
- {
- if (!nodram) {
- Pass::call(design, "memory_bram -rules +/xilinx/drams.txt");
- Pass::call(design, "techmap -map +/xilinx/drams_map.v");
+ if (check_label("dram", "(skip if '-nodram')")) {
+ if (!nodram || help_mode) {
+ run("memory_bram -rules +/xilinx/drams.txt");
+ run("techmap -map +/xilinx/drams_map.v");
}
}
- if (check_label(active, run_from, run_to, "fine"))
- {
- Pass::call(design, "opt -fast");
- Pass::call(design, "memory_map");
- Pass::call(design, "dffsr2dff");
- Pass::call(design, "dff2dffe");
-
- if (vpr) {
- Pass::call(design, "techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
- } else {
- Pass::call(design, "techmap -map +/xilinx/arith_map.v");
- }
+ if (check_label("fine")) {
+ run("opt -fast -full");
+ run("memory_map");
+ run("dffsr2dff");
+ run("dff2dffe");
+ run("opt -full");
- Pass::call(design, "hierarchy -check");
- Pass::call(design, "opt -fast");
- }
+ if (vpr && !nocarry && !help_mode)
+ run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
+ else if (abc == "abc9" && !nocarry && !help_mode)
+ run("techmap -map +/xilinx/arith_map.v -D _CLB_CARRY", "(skip if '-nocarry')");
+ else if (!nocarry || help_mode)
+ run("techmap -map +/xilinx/arith_map.v", "(skip if '-nocarry')");
- if (check_label(active, run_from, run_to, "map_cells"))
- {
- if (!nosrl) {
+ if (!nosrl || help_mode) {
// shregmap operates on bit-level flops, not word-level,
// so break those down here
- Pass::call(design, "simplemap t:$dff t:$dffe");
- // shregmap -tech xilinx can cope with $shiftx and $mux
- // cells for identifiying variable-length shift registers,
- // so attempt to convert $pmux-es to the former
- Pass::call(design, "pmux2shiftx");
- // pmux2shiftx can leave behind a $pmux with a single entry
- // -- need this to clean that up before shregmap
- Pass::call(design, "opt_expr -mux_undef");
+ run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')");
// shregmap with '-tech xilinx' infers variable length shift regs
- Pass::call(design, "shregmap -tech xilinx -minlen 3");
+ run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
}
- Pass::call(design, "techmap -map +/xilinx/cells_map.v");
- Pass::call(design, "clean");
+ if (!nomux || help_mode)
+ run("techmap -map +/xilinx/cells_map.v");
+
+ run("techmap");
+ run("opt -fast");
}
- if (check_label(active, run_from, run_to, "map_luts"))
- {
- Pass::call(design, "opt -full");
- Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v");
- Pass::call(design, abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
- Pass::call(design, "clean");
+ if (check_label("map_cells")) {
+ run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
+ run("clean");
+ }
+
+ if (check_label("map_luts")) {
+ if (abc == "abc9")
+ run(abc + " -lut +/xilinx/abc.lut -box +/xilinx/abc.box" + string(retime ? " -dff" : ""));
+ else if (help_mode)
+ run(abc + " -luts 2:2,3,6:5,10,20 [-dff]");
+ else
+ run(abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
+ run("clean");
+
// This shregmap call infers fixed length shift registers after abc
// has performed any necessary retiming
- if (!nosrl)
- Pass::call(design, "shregmap -minlen 3 -init -params -enpol any_or_none");
- Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
- Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
+ if (!nosrl || help_mode)
+ run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
+ run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
+ run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
- Pass::call(design, "clean");
+ run("clean");
}
- if (check_label(active, run_from, run_to, "check"))
- {
- Pass::call(design, "hierarchy -check");
- Pass::call(design, "stat");
- Pass::call(design, "check -noinit");
+ if (check_label("check")) {
+ run("hierarchy -check");
+ run("stat -tech xilinx");
+ run("check -noinit");
}
- if (check_label(active, run_from, run_to, "edif"))
- {
- if (!edif_file.empty())
- Pass::call(design, stringf("write_edif -pvector bra %s", edif_file.c_str()));
- }
- if (check_label(active, run_from, run_to, "blif"))
- {
- if (!blif_file.empty())
- Pass::call(design, stringf("write_blif %s", edif_file.c_str()));
+ if (check_label("edif")) {
+ if (!edif_file.empty() || help_mode)
+ run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
}
- log_pop();
+ if (check_label("blif")) {
+ if (!blif_file.empty() || help_mode)
+ run(stringf("write_blif %s", edif_file.c_str()));
+ }
}
} SynthXilinxPass;
diff --git a/tests/memories/firrtl_938.v b/tests/memories/firrtl_938.v
new file mode 100644
index 000000000..af5efcd25
--- /dev/null
+++ b/tests/memories/firrtl_938.v
@@ -0,0 +1,22 @@
+module top
+(
+ input [7:0] data_a,
+ input [6:1] addr_a,
+ input we_a, clk,
+ output reg [7:0] q_a
+);
+ // Declare the RAM variable
+ reg [7:0] ram[63:0];
+
+ // Port A
+ always @ (posedge clk)
+ begin
+ if (we_a)
+ begin
+ ram[addr_a] <= data_a;
+ q_a <= data_a;
+ end
+ q_a <= ram[addr_a];
+ end
+
+endmodule
diff --git a/tests/simple/dff_init.v b/tests/simple/dff_init.v
index be947042e..375ea5c4d 100644
--- a/tests/simple/dff_init.v
+++ b/tests/simple/dff_init.v
@@ -40,3 +40,15 @@ module dff1a_test(n1, n1_inv, clk);
n1 <= n1_inv;
assign n1_inv = ~n1;
endmodule
+
+module dff_test_997 (y, clk, wire4);
+// https://github.com/YosysHQ/yosys/issues/997
+ output wire [1:0] y;
+ input clk;
+ input signed wire4;
+ reg [1:0] reg10 = 0;
+ always @(posedge clk) begin
+ reg10 <= wire4;
+ end
+ assign y = reg10;
+endmodule
diff --git a/tests/simple/forloops.v b/tests/simple/forloops.v
new file mode 100644
index 000000000..8665222d8
--- /dev/null
+++ b/tests/simple/forloops.v
@@ -0,0 +1,25 @@
+module forloops01 (input clk, a, b, output reg [3:0] p, q, x, y);
+ integer k;
+ always @(posedge clk) begin
+ for (k=0; k<2; k=k+1)
+ p[2*k +: 2] = {a, b} ^ {2{k}};
+ x <= k + {a, b};
+ end
+ always @* begin
+ for (k=0; k<4; k=k+1)
+ q[k] = {~a, ~b, a, b} >> k[1:0];
+ y = k - {a, b};
+ end
+endmodule
+
+module forloops02 (input clk, a, b, output reg [3:0] q, x, output [3:0] y);
+ integer k;
+ always @* begin
+ for (k=0; k<4; k=k+1)
+ q[k] = {~a, ~b, a, b} >> k[1:0];
+ end
+ always @* begin
+ x = k + {a, b};
+ end
+ assign y = k - {a, b};
+endmodule
diff --git a/tests/simple/localparam_attr.v b/tests/simple/localparam_attr.v
new file mode 100644
index 000000000..2ef76c71c
--- /dev/null
+++ b/tests/simple/localparam_attr.v
@@ -0,0 +1,11 @@
+module uut_localparam_attr (I, O);
+
+(* LOCALPARAM_ATTRIBUTE = "attribute_content" *)
+localparam WIDTH = 1;
+
+input wire [WIDTH-1:0] I;
+output wire [WIDTH-1:0] O;
+
+assign O = I;
+
+endmodule
diff --git a/tests/simple/mem2reg.v b/tests/simple/mem2reg.v
index 9839fd4a8..100426785 100644
--- a/tests/simple/mem2reg.v
+++ b/tests/simple/mem2reg.v
@@ -92,3 +92,25 @@ module mem2reg_test5(input ctrl, output out);
assign out = bar[foo[0]];
endmodule
+// ------------------------------------------------------
+
+module mem2reg_test6 (din, dout);
+ input wire [3:0] din;
+ output reg [3:0] dout;
+
+ reg [1:0] din_array [1:0];
+ reg [1:0] dout_array [1:0];
+
+ always @* begin
+ din_array[0] = din[0 +: 2];
+ din_array[1] = din[2 +: 2];
+
+ dout_array[0] = din_array[0];
+ dout_array[1] = din_array[1];
+
+ {dout_array[0][1], dout_array[0][0]} = dout_array[0][0] + dout_array[1][0];
+
+ dout[0 +: 2] = dout_array[0];
+ dout[2 +: 2] = dout_array[1];
+ end
+endmodule
diff --git a/tests/simple/param_attr.v b/tests/simple/param_attr.v
new file mode 100644
index 000000000..34d63a34e
--- /dev/null
+++ b/tests/simple/param_attr.v
@@ -0,0 +1,11 @@
+module uut_param_attr (I, O);
+
+(* PARAMETER_ATTRIBUTE = "attribute_content" *)
+parameter WIDTH = 1;
+
+input wire [WIDTH-1:0] I;
+output wire [WIDTH-1:0] O;
+
+assign O = I;
+
+endmodule
diff --git a/tests/simple/peepopt.v b/tests/simple/peepopt.v
new file mode 100644
index 000000000..b27b9fe57
--- /dev/null
+++ b/tests/simple/peepopt.v
@@ -0,0 +1,9 @@
+module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output [W-1:0] o);
+assign o = i[s*W+:W];
+endmodule
+
+module peepopt_muldiv_0(input [1:0] i, output [1:0] o);
+wire [3:0] t;
+assign t = i * 3;
+assign o = t / 3;
+endmodule
diff --git a/tests/simple/wandwor.v b/tests/simple/wandwor.v
new file mode 100644
index 000000000..34404aa26
--- /dev/null
+++ b/tests/simple/wandwor.v
@@ -0,0 +1,36 @@
+module wandwor_test0 (A, B, C, D, X, Y, Z);
+ input A, B, C, D;
+ output wor X;
+ output wand Y;
+ output Z;
+
+ assign X = A, X = B, Y = C, Y = D;
+ foo foo_0 (C, D, X);
+ foo foo_1 (A, B, Y);
+ foo foo_2 (X, Y, Z);
+endmodule
+
+module wandwor_test1 (A, B, C, D, X, Y, Z);
+ input [3:0] A, B, C, D;
+ output wor [3:0] X;
+ output wand [3:0] Y;
+ output Z;
+
+ bar bar_inst (
+ .I0({A, B}),
+ .I1({B, A}),
+ .O({X, Y})
+ );
+
+ assign X = C, X = D;
+ assign Y = C, Y = D;
+ assign Z = ^{X,Y};
+endmodule
+
+module foo(input I0, I1, output O);
+ assign O = I0 ^ I1;
+endmodule
+
+module bar(input [7:0] I0, I1, output [7:0] O);
+ assign O = I0 + I1;
+endmodule
diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl
index 50d693513..ba61a4476 100644
--- a/tests/simple/xfirrtl
+++ b/tests/simple/xfirrtl
@@ -16,6 +16,7 @@ operators.v $pow
partsel.v drops modules
process.v drops modules
realexpr.v drops modules
+retime.v Initial value (11110101) for (retime_test.ff) not supported
scopes.v original verilog issues ( -x where x isn't declared signed)
sincos.v $adff
specify.v no code (empty module generates error
diff --git a/tests/simple_abc9/abc.box b/tests/simple_abc9/abc.box
new file mode 100644
index 000000000..a8801d807
--- /dev/null
+++ b/tests/simple_abc9/abc.box
@@ -0,0 +1,2 @@
+MUXF8 1 0 3 1
+1 1 1
diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v
index f37d975ff..2752ff8cc 100644
--- a/tests/simple_abc9/abc9.v
+++ b/tests/simple_abc9/abc9.v
@@ -142,3 +142,111 @@ assign b = ~a;
(* keep *) reg d;
always @* d <= &c;
endmodule
+
+// Citation: https://github.com/alexforencich/verilog-ethernet
+module abc9_test021(clk, rst, s_eth_hdr_valid, s_eth_hdr_ready, s_eth_dest_mac, s_eth_src_mac, s_eth_type, s_eth_payload_axis_tdata, s_eth_payload_axis_tkeep, s_eth_payload_axis_tvalid, s_eth_payload_axis_tready, s_eth_payload_axis_tlast, s_eth_payload_axis_tid, s_eth_payload_axis_tdest, s_eth_payload_axis_tuser, m_eth_hdr_valid, m_eth_hdr_ready, m_eth_dest_mac, m_eth_src_mac, m_eth_type, m_eth_payload_axis_tdata, m_eth_payload_axis_tkeep, m_eth_payload_axis_tvalid, m_eth_payload_axis_tready, m_eth_payload_axis_tlast, m_eth_payload_axis_tid, m_eth_payload_axis_tdest, m_eth_payload_axis_tuser);
+ input clk;
+ output [47:0] m_eth_dest_mac;
+ input m_eth_hdr_ready;
+ output m_eth_hdr_valid;
+ output [7:0] m_eth_payload_axis_tdata;
+ output [7:0] m_eth_payload_axis_tdest;
+ output [7:0] m_eth_payload_axis_tid;
+ output m_eth_payload_axis_tkeep;
+ output m_eth_payload_axis_tlast;
+ input m_eth_payload_axis_tready;
+ output m_eth_payload_axis_tuser;
+ output m_eth_payload_axis_tvalid;
+ output [47:0] m_eth_src_mac;
+ output [15:0] m_eth_type;
+ input rst;
+ input [191:0] s_eth_dest_mac;
+ output [3:0] s_eth_hdr_ready;
+ input [3:0] s_eth_hdr_valid;
+ input [31:0] s_eth_payload_axis_tdata;
+ input [31:0] s_eth_payload_axis_tdest;
+ input [31:0] s_eth_payload_axis_tid;
+ input [3:0] s_eth_payload_axis_tkeep;
+ input [3:0] s_eth_payload_axis_tlast;
+ output [3:0] s_eth_payload_axis_tready;
+ input [3:0] s_eth_payload_axis_tuser;
+ input [3:0] s_eth_payload_axis_tvalid;
+ input [191:0] s_eth_src_mac;
+ input [63:0] s_eth_type;
+ (* keep *)
+ wire [0:0] grant, request;
+ wire a;
+ not u0 (
+ a,
+ grant[0]
+ );
+ and u1 (
+ request[0],
+ s_eth_hdr_valid[0],
+ a
+ );
+ (* keep *)
+ MUXF8 u2 (
+ .I0(1'bx),
+ .I1(1'bx),
+ .O(o),
+ .S(1'bx)
+ );
+ arbiter arb_inst (
+ .acknowledge(acknowledge),
+ .clk(clk),
+ .grant(grant),
+ .grant_encoded(grant_encoded),
+ .grant_valid(grant_valid),
+ .request(request),
+ .rst(rst)
+ );
+endmodule
+
+module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encoded);
+ input [3:0] acknowledge;
+ input clk;
+ output [3:0] grant;
+ output [1:0] grant_encoded;
+ output grant_valid;
+ input [3:0] request;
+ input rst;
+endmodule
+
+(* abc_box_id=1 *)
+module MUXF8(input I0, I1, S, output O);
+endmodule
+
+// Citation: https://github.com/alexforencich/verilog-ethernet
+// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test022" abc9.v -q
+// returns before b4321a31
+// Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [7] is used but has no
+// driver.
+// Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [3] is used but has no
+// driver.
+module abc9_test022
+(
+ input wire clk,
+ input wire i,
+ output wire [7:0] m_eth_payload_axis_tkeep
+);
+ reg [7:0] m_eth_payload_axis_tkeep_reg = 8'd0;
+ assign m_eth_payload_axis_tkeep = m_eth_payload_axis_tkeep_reg;
+ always @(posedge clk)
+ m_eth_payload_axis_tkeep_reg <= i ? 8'hff : 8'h0f;
+endmodule
+
+// Citation: https://github.com/riscv/riscv-bitmanip
+// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test023" abc9.v -q
+// returns before 14233843
+// Warning: Wire abc9_test023.\dout [1] is used but has no driver.
+module abc9_test023 #(
+ parameter integer N = 2,
+ parameter integer M = 2
+) (
+ input [7:0] din,
+ output [M-1:0] dout
+);
+ wire [2*M-1:0] mask = {M{1'b1}};
+ assign dout = (mask << din[N-1:0]) >> M;
+endmodule
diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh
index 97f284378..4935d41ad 100755
--- a/tests/simple_abc9/run-test.sh
+++ b/tests/simple_abc9/run-test.sh
@@ -19,4 +19,4 @@ fi
cp ../simple/*.v .
DOLLAR='?'
-exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-p 'hierarchy; synth -run coarse; techmap; opt -full; abc9 -lut 4; stat; check -assert; select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
+exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-p 'hierarchy; synth -run coarse; opt -full; techmap; abc9 -lut 4 -box ../abc.box; stat; check -assert; select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
diff --git a/tests/svinterfaces/runone.sh b/tests/svinterfaces/runone.sh
index 0adecc797..54cf5f2ec 100755
--- a/tests/svinterfaces/runone.sh
+++ b/tests/svinterfaces/runone.sh
@@ -11,12 +11,12 @@ echo "" > $STDERRFILE
echo -n "Test: ${TESTNAME} -> "
-$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE >> $STDERRFILE
-$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE >> $STDERRFILE
+set -e
-rm -f a.out reference_result.txt dut_result.txt
+$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE 2>> $STDERRFILE
+$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE 2>> $STDERRFILE
-set -e
+rm -f a.out reference_result.txt dut_result.txt
iverilog -g2012 ${TESTNAME}_syn.v
iverilog -g2012 ${TESTNAME}_ref_syn.v
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index 86a90793e..920474a84 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -132,13 +132,13 @@ do
fn=$(basename $fn)
bn=$(basename $bn)
+ rm -f ${bn}_ref.fir
if [[ "$ext" == "v" ]]; then
egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
else
"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn}
frontend="verilog -noblackbox"
fi
- rm -f ${bn}_ref.fir
if [ ! -f ../${bn}_tb.v ]; then
"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v
@@ -147,7 +147,8 @@ do
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.v $libs \
- "$toolsdir"/../../techlibs/common/simlib.v
+ "$toolsdir"/../../techlibs/common/simlib.v \
+ "$toolsdir"/../../techlibs/common/simcells.v
if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
test_count=0
diff --git a/tests/various/chparam.sh b/tests/various/chparam.sh
new file mode 100644
index 000000000..9bb8d81db
--- /dev/null
+++ b/tests/various/chparam.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+trap 'echo "ERROR in chparam.sh" >&2; exit 1' ERR
+
+cat > chparam1.sv << "EOT"
+module top #(
+ parameter [31:0] X = 0
+) (
+ input [31:0] din,
+ output [31:0] dout
+);
+ assign dout = X-din;
+endmodule
+
+module top_props #(
+ parameter [31:0] X = 0
+) (
+ input [31:0] dout
+);
+ always @* assert (dout != X);
+endmodule
+
+bind top top_props #(.X(123456789)) props (.*);
+EOT
+
+cat > chparam2.sv << "EOT"
+module top #(
+ parameter [31:0] X = 0
+) (
+ input [31:0] din,
+ output [31:0] dout
+);
+ assign dout = X-din;
+ always @* assert (dout != 123456789);
+endmodule
+EOT
+
+if ../../yosys -q -p 'verific -sv chparam1.sv'; then
+ ../../yosys -q -p 'verific -sv chparam1.sv; hierarchy -chparam X 123123123 -top top; prep -flatten' \
+ -p 'sat -verify -prove-asserts -show-ports -set din[0] 1' \
+ -p 'sat -falsify -prove-asserts -show-ports -set din[0] 0'
+
+ ../../yosys -q -p 'verific -sv chparam2.sv; hierarchy -chparam X 123123123 -top top; prep -flatten' \
+ -p 'sat -verify -prove-asserts -show-ports -set din[0] 1' \
+ -p 'sat -falsify -prove-asserts -show-ports -set din[0] 0'
+fi
+../../yosys -q -p 'read_verilog -sv chparam2.sv; hierarchy -chparam X 123123123 -top top; prep -flatten' \
+ -p 'sat -verify -prove-asserts -show-ports -set din[0] 1' \
+ -p 'sat -falsify -prove-asserts -show-ports -set din[0] 0'
+
+rm chparam1.sv
+rm chparam2.sv
diff --git a/tests/various/opt_rmdff.v b/tests/various/opt_rmdff.v
new file mode 100644
index 000000000..b1c06703c
--- /dev/null
+++ b/tests/various/opt_rmdff.v
@@ -0,0 +1,50 @@
+module opt_rmdff_test (input C, input D, input E, output [29:0] Q);
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove0 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[0])); // EN is never active
+(* init = "1'b1" *) wire Q1; assign Q[1] = Q1;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove1 (.CLK(C), .D(D), .EN(1'b0), .Q(Q1)); // EN is never active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove2 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[2])); // EN is don't care
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep3 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[3])); // EN is always active
+(* init = "1'b0" *) wire Q4; assign Q[4] = Q4;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) keep4 (.CLK(C), .D(D), .EN(1'b1), .Q(Q4)); // EN is always active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove5 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[5])); // EN is never active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove6 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[6])); // EN is don't care
+(* init = "1'b0" *) wire Q7; assign Q[7] = Q7;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(0)) keep7 (.CLK(C), .D(D), .EN(E), .Q(Q7)); // EN is non constant
+
+\$_DFFE_PP_ remove8 (.C(C), .D(D), .E(1'b0), .Q(Q[8])); // EN is never active
+(* init = "1'b1" *) wire Q9; assign Q[9] = Q9;
+\$_DFFE_PP_ remove9 (.C(C), .D(D), .E(1'b0), .Q(Q9)); // EN is never active
+\$_DFFE_PP_ remove10 (.C(C), .D(D), .E(1'bx), .Q(Q[10])); // EN is don't care
+\$_DFFE_PP_ keep11 (.C(C), .D(D), .E(1'b1), .Q(Q[11])); // EN is always active
+(* init = "1'b0" *) wire Q12; assign Q[12] = Q12;
+\$_DFFE_PP_ keep12 (.C(C), .D(D), .E(1'b1), .Q(Q12)); // EN is always active
+
+\$_DFFE_NN_ remove13 (.C(C), .D(D), .E(1'b1), .Q(Q[13])); // EN is never active
+(* init = "1'b1" *) wire Q14; assign Q[14] = Q14;
+\$_DFFE_NN_ remove14 (.C(C), .D(D), .E(1'b1), .Q(Q14)); // EN is never active
+\$_DFFE_NN_ remove15 (.C(C), .D(D), .E(1'bx), .Q(Q[15])); // EN is don't care
+\$_DFFE_NN_ keep16 (.C(C), .D(D), .E(1'b0), .Q(Q[16])); // EN is always active
+(* init = "1'b0" *) wire Q17; assign Q[17] = Q17;
+\$_DFFE_NN_ keep17 (.C(C), .D(D), .E(1'b0), .Q(Q17)); // EN is always active
+
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove18 (.CLK(1'b0), .D(D), .EN(E), .Q(Q[18])); // CLK is constant
+(* init = "1'b1" *) wire Q19; assign Q[19] = Q19;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove19 (.CLK(1'b1), .D(D), .EN(E), .Q(Q19)); // CLK is constant
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove20 (.CLK(C), .D(1'bx), .EN(E), .Q(Q[20])); // D is undriven, Q has no initial value
+(* init = "1'b0" *) wire Q21; assign Q[21] = Q21;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep21 (.CLK(C), .D(1'bx), .EN(E), .Q(Q21)); // D is undriven, Q has initial value
+//\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) remove22 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q[22])); // D is constant, no initial Q value, EN is always active
+// // (TODO, Q starts with 1'bx and becomes 1'b0)
+(* init = "1'b0" *) wire Q23; assign Q[23] = Q23;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) noenable23 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q23)); // D is constant, initial Q value same as D, EN is always active
+(* init = "1'b1" *) wire Q24; assign Q[24] = Q24;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) keep24 (.CLK(C), .D(1'b0), .EN(1'b0), .Q(Q24)); // D is constant, initial Q value NOT same as D, EN is always active
+(* init = "1'b1" *) wire Q25; assign Q[25] = Q25;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove25 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q25)); // D is constant, EN is never active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove26 (.CLK(C), .D(Q[26]), .EN(1'b1), .Q(Q[26])); // D is Q, EN is always active
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove27 (.CLK(C), .D(Q[27]), .EN(1'b1), .Q(Q[27])); // D is Q, EN is never active, but no initial value
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove28 (.CLK(C), .D(Q[28]), .EN(E), .Q(Q[28])); // EN is nonconst, but no initial value
+(* init = "1'b1" *) wire Q29; assign Q[29] = Q29;
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep29 (.CLK(C), .D(Q[29]), .EN(1'b1), .Q(Q29)); // EN is always active, but with initial value
+
+endmodule
diff --git a/tests/various/opt_rmdff.ys b/tests/various/opt_rmdff.ys
new file mode 100644
index 000000000..081f81782
--- /dev/null
+++ b/tests/various/opt_rmdff.ys
@@ -0,0 +1,26 @@
+read_verilog -icells opt_rmdff.v
+prep
+design -stash gold
+read_verilog -icells opt_rmdff.v
+proc
+opt_rmdff
+
+select -assert-count 0 c:remove*
+select -assert-min 7 c:keep*
+select -assert-count 0 t:$dffe 7:$_DFFE_* %u c:noenable* %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+equiv_make gold gate equiv
+hierarchy -top equiv
+equiv_simple -undef
+equiv_status -assert
+
+design -load gold
+stat
+
+design -load gate
+stat
diff --git a/tests/various/specify.v b/tests/various/specify.v
new file mode 100644
index 000000000..afc421da8
--- /dev/null
+++ b/tests/various/specify.v
@@ -0,0 +1,30 @@
+module test (
+ input EN, CLK,
+ input [3:0] D,
+ output reg [3:0] Q
+);
+ always @(posedge CLK)
+ if (EN) Q <= D;
+
+ specify
+ if (EN) (CLK *> (Q : D)) = (1, 2:3:4);
+ $setup(D, posedge CLK &&& EN, 5);
+ $hold(posedge CLK, D &&& EN, 6);
+ endspecify
+endmodule
+
+module test2 (
+ input A, B,
+ output Q
+);
+ xor (Q, A, B);
+ specify
+ //specparam T_rise = 1;
+ //specparam T_fall = 2;
+ `define T_rise 1
+ `define T_fall 2
+ (A => Q) = (`T_rise,`T_fall);
+ //(B => Q) = (`T_rise+`T_fall)/2.0;
+ (B => Q) = 1.5;
+ endspecify
+endmodule
diff --git a/tests/various/specify.ys b/tests/various/specify.ys
new file mode 100644
index 000000000..a5ca07219
--- /dev/null
+++ b/tests/various/specify.ys
@@ -0,0 +1,56 @@
+read_verilog -specify specify.v
+prep
+cd test
+select t:$specify2 -assert-count 0
+select t:$specify3 -assert-count 1
+select t:$specrule -assert-count 2
+cd test2
+select t:$specify2 -assert-count 2
+select t:$specify3 -assert-count 0
+select t:$specrule -assert-count 0
+cd
+write_verilog specify.out
+design -stash gold
+
+read_verilog -specify specify.out
+prep
+cd test
+select t:$specify2 -assert-count 0
+select t:$specify3 -assert-count 1
+select t:$specrule -assert-count 2
+cd test2
+select t:$specify2 -assert-count 2
+select t:$specify3 -assert-count 0
+select t:$specrule -assert-count 0
+cd
+design -stash gate
+
+design -copy-from gold -as gold test
+design -copy-from gate -as gate test
+rename -hide
+rename -enumerate -pattern A_% t:$specify3
+rename -enumerate -pattern B_% t:$specrule r:TYPE=$setup %i
+rename -enumerate -pattern C_% t:$specrule r:TYPE=$hold %i
+select n:A_* -assert-count 2
+select n:B_* -assert-count 2
+select n:C_* -assert-count 2
+equiv_make gold gate equiv
+hierarchy -top equiv
+equiv_struct
+equiv_induct -seq 5
+equiv_status -assert
+design -reset
+
+design -copy-from gold -as gold test2
+design -copy-from gate -as gate test2
+rename -hide
+rename -enumerate -pattern A_% t:$specify2 r:T_RISE_TYP=1 %i
+rename -enumerate -pattern B_% t:$specify2 n:A_* %d
+select n:A_* -assert-count 2
+select n:B_* -assert-count 2
+equiv_make gold gate equiv
+hierarchy -top equiv
+equiv_struct
+equiv_induct -seq 5
+equiv_status -assert
+design -reset