aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG3
-rw-r--r--Makefile85
-rw-r--r--README.md4
-rw-r--r--backends/aiger/xaiger.cc4
-rw-r--r--backends/cxxrtl/Makefile.inc2
-rw-r--r--backends/cxxrtl/cxxrtl.cc1769
-rw-r--r--backends/cxxrtl/cxxrtl.h1141
-rw-r--r--backends/firrtl/firrtl.cc80
-rw-r--r--backends/json/json.cc44
-rw-r--r--backends/smt2/Makefile.inc14
-rw-r--r--backends/smt2/smtbmc.py21
-rw-r--r--backends/verilog/verilog_backend.cc2
-rw-r--r--frontends/aiger/aigerparse.cc2
-rw-r--r--frontends/ast/ast.cc2
-rw-r--r--frontends/ast/genrtlil.cc20
-rw-r--r--frontends/ast/simplify.cc43
-rw-r--r--frontends/ilang/ilang_lexer.l13
-rw-r--r--frontends/ilang/ilang_parser.y11
-rw-r--r--frontends/verilog/verilog_parser.y4
-rw-r--r--kernel/hashlib.h72
-rw-r--r--kernel/log.h7
-rw-r--r--kernel/register.cc7
-rw-r--r--kernel/rtlil.cc52
-rw-r--r--kernel/rtlil.h4
-rw-r--r--kernel/yosys.cc15
-rw-r--r--kernel/yosys.h8
-rw-r--r--libs/sha1/sha1.h6
-rw-r--r--libs/subcircuit/subcircuit.cc3
-rw-r--r--manual/command-reference-manual.tex2498
-rw-r--r--misc/yosys-config.in8
-rw-r--r--passes/cmds/bugpoint.cc28
-rw-r--r--passes/cmds/check.cc45
-rw-r--r--passes/cmds/connect.cc26
-rw-r--r--passes/cmds/connwrappers.cc22
-rw-r--r--passes/cmds/copy.cc4
-rw-r--r--passes/cmds/delete.cc43
-rw-r--r--passes/cmds/design.cc39
-rw-r--r--passes/cmds/rename.cc222
-rw-r--r--passes/cmds/scatter.cc28
-rw-r--r--passes/cmds/select.cc25
-rw-r--r--passes/cmds/setattr.cc36
-rw-r--r--passes/cmds/setundef.cc49
-rw-r--r--passes/cmds/show.cc94
-rw-r--r--passes/cmds/splice.cc32
-rw-r--r--passes/cmds/splitnets.cc3
-rw-r--r--passes/cmds/stat.cc46
-rw-r--r--passes/hierarchy/submod.cc45
-rw-r--r--passes/memory/memory_bram.cc48
-rw-r--r--passes/memory/memory_collect.cc9
-rw-r--r--passes/memory/memory_map.cc119
-rw-r--r--passes/memory/memory_unpack.cc13
-rw-r--r--passes/opt/opt_clean.cc6
-rw-r--r--passes/opt/opt_expr.cc181
-rw-r--r--passes/opt/opt_merge.cc4
-rw-r--r--passes/sat/Makefile.inc1
-rw-r--r--passes/sat/qbfsat.cc550
-rw-r--r--passes/techmap/Makefile.inc7
-rw-r--r--passes/techmap/abc.cc10
-rw-r--r--passes/techmap/abc9.cc4
-rw-r--r--passes/techmap/abc9_exe.cc12
-rw-r--r--passes/techmap/abc9_ops.cc3
-rw-r--r--passes/techmap/dffinit.cc8
-rw-r--r--passes/techmap/dfflibmap.cc54
-rw-r--r--passes/techmap/dffsr2dff.cc213
-rw-r--r--passes/techmap/extract.cc79
-rw-r--r--passes/techmap/hilomap.cc8
-rw-r--r--passes/techmap/techmap.cc2
-rw-r--r--passes/techmap/zinit.cc72
-rw-r--r--passes/tests/test_autotb.cc20
-rw-r--r--techlibs/achronix/synth_achronix.cc1
-rw-r--r--techlibs/anlogic/synth_anlogic.cc1
-rw-r--r--techlibs/common/gen_fine_ffs.py9
-rw-r--r--techlibs/common/simcells.v36
-rw-r--r--techlibs/common/simlib.v2
-rw-r--r--techlibs/ecp5/brams.txt62
-rw-r--r--techlibs/ecp5/dsp_map.v2
-rw-r--r--techlibs/ecp5/lutrams.txt9
-rw-r--r--techlibs/ecp5/synth_ecp5.cc5
-rw-r--r--techlibs/efinix/synth_efinix.cc1
-rw-r--r--techlibs/gowin/synth_gowin.cc1
-rw-r--r--techlibs/ice40/brams.txt60
-rw-r--r--techlibs/ice40/synth_ice40.cc5
-rw-r--r--techlibs/intel/Makefile.inc1
-rw-r--r--techlibs/intel/synth_intel.cc1
-rw-r--r--techlibs/intel_alm/Makefile.inc23
-rw-r--r--techlibs/intel_alm/common/alm_map.v56
-rw-r--r--techlibs/intel_alm/common/alm_sim.v482
-rw-r--r--techlibs/intel_alm/common/arith_alm_map.v64
-rw-r--r--techlibs/intel_alm/common/bram_m10k.txt33
-rw-r--r--techlibs/intel_alm/common/bram_m10k_map.v31
-rw-r--r--techlibs/intel_alm/common/bram_m20k.txt33
-rw-r--r--techlibs/intel_alm/common/bram_m20k_map.v31
-rw-r--r--techlibs/intel_alm/common/dff_map.v124
-rw-r--r--techlibs/intel_alm/common/dff_sim.v48
-rw-r--r--techlibs/intel_alm/common/lutram_mlab.txt20
-rw-r--r--techlibs/intel_alm/common/lutram_mlab_map.v29
-rw-r--r--techlibs/intel_alm/common/megafunction_bb.v108
-rw-r--r--techlibs/intel_alm/common/quartus_rename.v19
-rw-r--r--techlibs/intel_alm/cyclone10gx/quartus_rename.v54
-rw-r--r--techlibs/intel_alm/cyclonev/quartus_rename.v54
-rw-r--r--techlibs/intel_alm/synth_intel_alm.cc241
-rw-r--r--techlibs/sf2/synth_sf2.cc1
-rw-r--r--techlibs/xilinx/synth_xilinx.cc3
-rw-r--r--tests/arch/common/blockram.v42
-rw-r--r--tests/arch/common/blockrom.v31
-rw-r--r--tests/arch/ecp5/memories.ys330
-rw-r--r--tests/arch/ice40/lutram.ys15
-rw-r--r--tests/arch/ice40/memories.ys168
-rw-r--r--tests/arch/intel_alm/add_sub.ys8
-rw-r--r--tests/arch/intel_alm/adffs.ys48
-rw-r--r--tests/arch/intel_alm/counter.ys13
-rw-r--r--tests/arch/intel_alm/dffs.ys22
-rw-r--r--tests/arch/intel_alm/fsm.ys18
-rw-r--r--tests/arch/intel_alm/logic.ys11
-rw-r--r--tests/arch/intel_alm/mux.ys45
-rwxr-xr-xtests/arch/intel_alm/run-test.sh20
-rw-r--r--tests/arch/intel_alm/shifter.ys10
-rw-r--r--tests/arch/intel_alm/tribuf.ys13
-rw-r--r--tests/opt/opt_expr.ys28
-rw-r--r--tests/opt/opt_expr_alu.ys124
-rw-r--r--tests/select/.gitignore1
-rw-r--r--tests/select/unset.ys10
-rw-r--r--tests/select/unset2.ys10
-rw-r--r--tests/svtypes/typedef_package.sv11
-rw-r--r--tests/techmap/dffinit.ys25
-rw-r--r--tests/techmap/zinit.ys151
-rw-r--r--tests/various/.gitignore1
-rw-r--r--tests/various/bug1876.ys60
-rw-r--r--tests/various/design.ys9
-rw-r--r--tests/various/design2.ys9
-rw-r--r--tests/various/global_scope.ys18
-rw-r--r--tests/various/plugin.cc15
-rw-r--r--tests/various/plugin.sh6
133 files changed, 9826 insertions, 1250 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 18f82bdd1..df8e14b26 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -63,6 +63,9 @@ Yosys 0.9 .. Yosys 0.9-dev
- Improved support of $readmem[hb] Memory Content File inclusion
- Added "opt_lut_ins" pass
- Added "logger" pass
+ - Removed "dffsr2dff" (use opt_rmdff instead)
+ - Added "design -delete"
+ - Added "select -unset"
Yosys 0.8 .. Yosys 0.9
----------------------
diff --git a/Makefile b/Makefile
index c6a8844ec..b3cfd71f9 100644
--- a/Makefile
+++ b/Makefile
@@ -42,6 +42,7 @@ SANITIZER =
# SANITIZER = undefined
# SANITIZER = cfi
+PROGRAM_PREFIX :=
OS := $(shell uname -s)
PREFIX ?= /usr/local
@@ -51,16 +52,20 @@ ifneq ($(wildcard Makefile.conf),)
include Makefile.conf
endif
+ifeq ($(ENABLE_PYOSYS),1)
+ENABLE_LIBYOSYS := 1
+endif
+
BINDIR := $(PREFIX)/bin
-LIBDIR := $(PREFIX)/lib
-DATDIR := $(PREFIX)/share/yosys
+LIBDIR := $(PREFIX)/lib/$(PROGRAM_PREFIX)yosys
+DATDIR := $(PREFIX)/share/$(PROGRAM_PREFIX)yosys
EXE =
OBJS =
GENFILES =
EXTRA_OBJS =
EXTRA_TARGETS =
-TARGETS = yosys$(EXE) yosys-config
+TARGETS = $(PROGRAM_PREFIX)yosys$(EXE) $(PROGRAM_PREFIX)yosys-config
PRETTY = 1
SMALL = 0
@@ -143,7 +148,10 @@ define newline
endef
ifneq ($(wildcard Makefile.conf),)
+# don't echo Makefile.conf contents when invoked to print source versions
+ifeq ($(findstring echo-,$(MAKECMDGOALS)),)
$(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$,;' < Makefile.conf | tr -d '\n' | sed 's,\$$--\$$$$,,')))
+endif
include Makefile.conf
endif
@@ -245,7 +253,7 @@ LDFLAGS += $(EMCCFLAGS)
LDLIBS =
EXE = .js
-TARGETS := $(filter-out yosys-config,$(TARGETS))
+TARGETS := $(filter-out $(PROGRAM_PREFIX)yosys-config,$(TARGETS))
EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip
ifeq ($(ENABLE_ABC),1)
@@ -459,7 +467,7 @@ LDLIBS += -lpthread
endif
else
ifeq ($(ABCEXTERNAL),)
-TARGETS += yosys-abc$(EXE)
+TARGETS += $(PROGRAM_PREFIX)yosys-abc$(EXE)
endif
endif
endif
@@ -509,8 +517,8 @@ endef
ifeq ($(PRETTY), 1)
P_STATUS = 0
P_OFFSET = 0
-P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | $(AWK) 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
-P_SHOW = [$(shell $(AWK) "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
+P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) $(PROGRAM_PREFIX)yosys$(EXE) | $(AWK) 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
+P_SHOW = [$(shell $(AWK) "BEGIN { N=$(words $(OBJS) $(PROGRAM_PREFIX)yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@";
Q = @
S = -s
@@ -529,6 +537,7 @@ $(eval $(call add_include_file,kernel/register.h))
$(eval $(call add_include_file,kernel/celltypes.h))
$(eval $(call add_include_file,kernel/celledges.h))
$(eval $(call add_include_file,kernel/consteval.h))
+$(eval $(call add_include_file,kernel/constids.inc))
$(eval $(call add_include_file,kernel/sigtools.h))
$(eval $(call add_include_file,kernel/modtools.h))
$(eval $(call add_include_file,kernel/macc.h))
@@ -541,12 +550,13 @@ $(eval $(call add_include_file,libs/json11/json11.hpp))
$(eval $(call add_include_file,passes/fsm/fsmdata.h))
$(eval $(call add_include_file,frontends/ast/ast.h))
$(eval $(call add_include_file,backends/ilang/ilang_backend.h))
+$(eval $(call add_include_file,backends/cxxrtl/cxxrtl.h))
OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
OBJS += kernel/cellaigs.o kernel/celledges.o
kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
-kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"'
+kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"'
OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o
OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o
@@ -599,7 +609,7 @@ include techlibs/common/Makefile.inc
endif
ifeq ($(LINK_ABC),1)
-OBJS += yosys-libabc.a
+OBJS += $(PROGRAM_PREFIX)yosys-libabc.a
endif
top-all: $(TARGETS) $(EXTRA_TARGETS)
@@ -611,14 +621,14 @@ ifeq ($(CONFIG),emcc)
yosys.js: $(filter-out yosysjs-$(YOSYS_VER).zip,$(EXTRA_TARGETS))
endif
-yosys$(EXE): $(OBJS)
- $(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
+$(PROGRAM_PREFIX)yosys$(EXE): $(OBJS)
+ $(P) $(LD) -o $(PROGRAM_PREFIX)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)
+ $(P) $(LD) -o libyosys.so -shared -Wl,-install_name,$(DESTDIR)$(LIBDIR)/libyosys.so $(LDFLAGS) $^ $(LDLIBS)
else
- $(P) $(LD) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
+ $(P) $(LD) -o libyosys.so -shared -Wl,-soname,$(DESTDIR)$(LIBDIR)/libyosys.so $(LDFLAGS) $^ $(LDLIBS)
endif
%.o: %.cc
@@ -654,11 +664,11 @@ CXXFLAGS_NOVERIFIC = $(CXXFLAGS)
LDLIBS_NOVERIFIC = $(LDLIBS)
endif
-yosys-config: misc/yosys-config.in
+$(PROGRAM_PREFIX)yosys-config: misc/yosys-config.in
$(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC)))#;' \
-e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LDFLAGS@#$(strip $(LDFLAGS) $(PLUGIN_LDFLAGS))#;' -e 's#@LDLIBS@#$(strip $(LDLIBS_NOVERIFIC))#;' \
- -e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > yosys-config
- $(Q) chmod +x yosys-config
+ -e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > $(PROGRAM_PREFIX)yosys-config
+ $(Q) chmod +x $(PROGRAM_PREFIX)yosys-config
abc/abc-$(ABCREV)$(EXE) abc/libabc-$(ABCREV).a:
$(P)
@@ -685,11 +695,11 @@ ifeq ($(ABCREV),default)
.PHONY: abc/libabc-$(ABCREV).a
endif
-yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
- $(P) cp abc/abc-$(ABCREV)$(EXE) yosys-abc$(EXE)
+$(PROGRAM_PREFIX)yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
+ $(P) cp abc/abc-$(ABCREV)$(EXE) $(PROGRAM_PREFIX)yosys-abc$(EXE)
-yosys-libabc.a: abc/libabc-$(ABCREV).a
- $(P) cp abc/libabc-$(ABCREV).a yosys-libabc.a
+$(PROGRAM_PREFIX)yosys-libabc.a: abc/libabc-$(ABCREV).a
+ $(P) cp abc/libabc-$(ABCREV).a $(PROGRAM_PREFIX)yosys-libabc.a
ifneq ($(SEED),)
SEEDOPT="-S $(SEED)"
@@ -730,6 +740,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/arch/efinix && bash run-test.sh $(SEEDOPT)
+cd tests/arch/anlogic && bash run-test.sh $(SEEDOPT)
+cd tests/arch/gowin && bash run-test.sh $(SEEDOPT)
+ +cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT)
+cd tests/rpc && bash run-test.sh
+cd tests/memfile && bash run-test.sh
@echo ""
@@ -769,14 +780,14 @@ clean-unit-test:
install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
$(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR)
-ifneq ($(filter yosys,$(TARGETS)),)
- $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/yosys
+ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),)
+ $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys
endif
-ifneq ($(filter yosys-abc,$(TARGETS)),)
- $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/yosys-abc
+ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc,$(TARGETS)),)
+ $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc
endif
-ifneq ($(filter yosys-filterlib,$(TARGETS)),)
- $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/yosys-filterlib
+ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib,$(TARGETS)),)
+ $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib
endif
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
@@ -785,9 +796,9 @@ ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so
ifeq ($(ENABLE_PYOSYS),1)
- $(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
- $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/
- $(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/
+ $(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
+ $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so
+ $(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/
endif
endif
@@ -797,14 +808,14 @@ uninstall:
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so
ifeq ($(ENABLE_PYOSYS),1)
- $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/libyosys.so
- $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/__init__.py
- $(INSTALL_SUDO) rmdir $(PYTHON_DESTDIR)/pyosys
+ $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so
+ $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py
+ $(INSTALL_SUDO) rmdir $(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
endif
endif
update-manual: $(TARGETS) $(EXTRA_TARGETS)
- cd manual && ../yosys -p 'help -write-tex-command-reference-manual'
+ cd manual && ../$(PROGRAM_PREFIX)yosys -p 'help -write-tex-command-reference-manual'
manual: $(TARGETS) $(EXTRA_TARGETS)
cd manual && bash appnotes.sh
@@ -830,13 +841,13 @@ clean:
clean-abc:
$(MAKE) -C abc DEP= clean
- rm -f yosys-abc$(EXE) yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a
+ rm -f $(PROGRAM_PREFIX)yosys-abc$(EXE) $(PROGRAM_PREFIX)yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a
mrproper: clean
git clean -xdf
coverage:
- ./yosys -qp 'help; help -all'
+ ./$(PROGRAM_PREFIX)yosys -qp 'help; help -all'
rm -rf coverage.info coverage_html
lcov --capture -d . --no-external -o coverage.info
genhtml coverage.info --output-directory coverage_html
@@ -862,9 +873,9 @@ ifeq ($(CONFIG),mxe)
mxebin: $(TARGETS) $(EXTRA_TARGETS)
rm -rf yosys-win32-mxebin-$(YOSYS_VER){,.zip}
mkdir -p yosys-win32-mxebin-$(YOSYS_VER)
- cp -r yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/
+ cp -r $(PROGRAM_PREFIX)yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/
ifeq ($(ENABLE_ABC),1)
- cp -r yosys-abc.exe abc/lib/x86/pthreadVC2.dll yosys-win32-mxebin-$(YOSYS_VER)/
+ cp -r $(PROGRAM_PREFIX)yosys-abc.exe abc/lib/x86/pthreadVC2.dll yosys-win32-mxebin-$(YOSYS_VER)/
endif
echo -en 'This is Yosys $(YOSYS_VER) for Win32.\r\n' > yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
echo -en 'Documentation at http://www.clifford.at/yosys/.\r\n' >> yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
diff --git a/README.md b/README.md
index ce7b26411..0a81d8bb9 100644
--- a/README.md
+++ b/README.md
@@ -443,8 +443,8 @@ Verilog Attributes and non-standard features
- The ``wiretype`` attribute is added by the verilog parser for wires of a
typedef'd type to indicate the type identifier.
-- Various ``enum_{width}_{value}`` attributes are added to wires of an
- enumerated type to give a map of possible enum items to their values.
+- Various ``enum_value_{value}`` attributes are added to wires of an enumerated type
+ to give a map of possible enum items to their values.
- The ``enum_base_type`` attribute is added to enum items to indicate which
enum they belong to (enums -- anonymous and otherwise -- are
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 3b51d8685..3c7c745fe 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -280,6 +280,10 @@ struct XAigerWriter
if (abc9_flop)
continue;
}
+ else {
+ if (cell->type == ID($__ABC9_DELAY))
+ log_error("Cell type '%s' not recognised. Check that '+/abc9_model.v' has been read.\n", cell->type.c_str());
+ }
bool cell_known = inst_module || cell->known();
for (const auto &c : cell->connections()) {
diff --git a/backends/cxxrtl/Makefile.inc b/backends/cxxrtl/Makefile.inc
new file mode 100644
index 000000000..f93e65f85
--- /dev/null
+++ b/backends/cxxrtl/Makefile.inc
@@ -0,0 +1,2 @@
+
+OBJS += backends/cxxrtl/cxxrtl.o
diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc
new file mode 100644
index 000000000..e4fa430f3
--- /dev/null
+++ b/backends/cxxrtl/cxxrtl.cc
@@ -0,0 +1,1769 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2019-2020 whitequark <whitequark@whitequark.org>
+ *
+ * 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/rtlil.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/utils.h"
+#include "kernel/celltypes.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+// [[CITE]]
+// Peter Eades; Xuemin Lin; W. F. Smyth, "A Fast Effective Heuristic For The Feedback Arc Set Problem"
+// Information Processing Letters, Vol. 47, pp 319-323, 1993
+// https://pdfs.semanticscholar.org/c7ed/d9acce96ca357876540e19664eb9d976637f.pdf
+
+// A topological sort (on a cell/wire graph) is always possible in a fully flattened RTLIL design without
+// processes or logic loops where every wire has a single driver. Logic loops are illegal in RTLIL and wires
+// with multiple drivers can be split by the `splitnets` pass; however, interdependencies between processes
+// or module instances can create strongly connected components without introducing evaluation nondeterminism.
+// We wish to support designs with such benign SCCs (as well as designs with multiple drivers per wire), so
+// we sort the graph in a way that minimizes feedback arcs. If there are no feedback arcs in the sorted graph,
+// then a more efficient evaluation method is possible, since eval() will always immediately converge.
+template<class T>
+struct Scheduler {
+ struct Vertex {
+ T *data;
+ Vertex *prev, *next;
+ pool<Vertex*, hash_ptr_ops> preds, succs;
+
+ Vertex() : data(NULL), prev(this), next(this) {}
+ Vertex(T *data) : data(data), prev(NULL), next(NULL) {}
+
+ bool empty() const
+ {
+ log_assert(data == NULL);
+ if (next == this) {
+ log_assert(prev == next);
+ return true;
+ }
+ return false;
+ }
+
+ void link(Vertex *list)
+ {
+ log_assert(prev == NULL && next == NULL);
+ next = list;
+ prev = list->prev;
+ list->prev->next = this;
+ list->prev = this;
+ }
+
+ void unlink()
+ {
+ log_assert(prev->next == this && next->prev == this);
+ prev->next = next;
+ next->prev = prev;
+ next = prev = NULL;
+ }
+
+ int delta() const
+ {
+ return succs.size() - preds.size();
+ }
+ };
+
+ std::vector<Vertex*> vertices;
+ Vertex *sources = new Vertex;
+ Vertex *sinks = new Vertex;
+ dict<int, Vertex*> bins;
+
+ ~Scheduler()
+ {
+ delete sources;
+ delete sinks;
+ for (auto bin : bins)
+ delete bin.second;
+ for (auto vertex : vertices)
+ delete vertex;
+ }
+
+ Vertex *add(T *data)
+ {
+ Vertex *vertex = new Vertex(data);
+ vertices.push_back(vertex);
+ return vertex;
+ }
+
+ void relink(Vertex *vertex)
+ {
+ if (vertex->succs.empty())
+ vertex->link(sinks);
+ else if (vertex->preds.empty())
+ vertex->link(sources);
+ else {
+ int delta = vertex->delta();
+ if (!bins.count(delta))
+ bins[delta] = new Vertex;
+ vertex->link(bins[delta]);
+ }
+ }
+
+ Vertex *remove(Vertex *vertex)
+ {
+ vertex->unlink();
+ for (auto pred : vertex->preds) {
+ if (pred == vertex)
+ continue;
+ log_assert(pred->succs[vertex]);
+ pred->unlink();
+ pred->succs.erase(vertex);
+ relink(pred);
+ }
+ for (auto succ : vertex->succs) {
+ if (succ == vertex)
+ continue;
+ log_assert(succ->preds[vertex]);
+ succ->unlink();
+ succ->preds.erase(vertex);
+ relink(succ);
+ }
+ vertex->preds.clear();
+ vertex->succs.clear();
+ return vertex;
+ }
+
+ std::vector<Vertex*> schedule()
+ {
+ std::vector<Vertex*> s1, s2r;
+ for (auto vertex : vertices)
+ relink(vertex);
+ bool bins_empty = false;
+ while (!(sinks->empty() && sources->empty() && bins_empty)) {
+ while (!sinks->empty())
+ s2r.push_back(remove(sinks->next));
+ while (!sources->empty())
+ s1.push_back(remove(sources->next));
+ // Choosing u in this implementation isn't O(1), but the paper handwaves which data structure they suggest
+ // using to get O(1) relinking *and* find-max-key ("it is clear"... no it isn't), so this code uses a very
+ // naive implementation of find-max-key.
+ bins_empty = true;
+ bins.template sort<std::greater<int>>();
+ for (auto bin : bins) {
+ if (!bin.second->empty()) {
+ bins_empty = false;
+ s1.push_back(remove(bin.second->next));
+ break;
+ }
+ }
+ }
+ s1.insert(s1.end(), s2r.rbegin(), s2r.rend());
+ return s1;
+ }
+};
+
+static bool is_unary_cell(RTLIL::IdString type)
+{
+ return type.in(
+ ID($not), ID($logic_not), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool),
+ ID($pos), ID($neg));
+}
+
+static bool is_binary_cell(RTLIL::IdString type)
+{
+ return type.in(
+ ID($and), ID($or), ID($xor), ID($xnor), ID($logic_and), ID($logic_or),
+ ID($shl), ID($sshl), ID($shr), ID($sshr), ID($shift), ID($shiftx),
+ ID($eq), ID($ne), ID($eqx), ID($nex), ID($gt), ID($ge), ID($lt), ID($le),
+ ID($add), ID($sub), ID($mul), ID($div), ID($mod));
+}
+
+static bool is_elidable_cell(RTLIL::IdString type)
+{
+ return is_unary_cell(type) || is_binary_cell(type) || type.in(
+ ID($mux), ID($concat), ID($slice));
+}
+
+static bool is_sync_ff_cell(RTLIL::IdString type)
+{
+ return type.in(
+ ID($dff), ID($dffe));
+}
+
+static bool is_ff_cell(RTLIL::IdString type)
+{
+ return is_sync_ff_cell(type) || type.in(
+ ID($adff), ID($dffsr), ID($dlatch), ID($dlatchsr), ID($sr));
+}
+
+static bool is_internal_cell(RTLIL::IdString type)
+{
+ return type[0] == '$' && !type.begins_with("$paramod\\");
+}
+
+struct FlowGraph {
+ struct Node {
+ enum class Type {
+ CONNECT,
+ CELL,
+ PROCESS
+ };
+
+ Type type;
+ RTLIL::SigSig connect = {};
+ const RTLIL::Cell *cell = NULL;
+ const RTLIL::Process *process = NULL;
+ };
+
+ std::vector<Node*> nodes;
+ dict<const RTLIL::Wire*, pool<Node*, hash_ptr_ops>> wire_defs, wire_uses;
+ dict<const RTLIL::Wire*, bool> wire_def_elidable, wire_use_elidable;
+
+ ~FlowGraph()
+ {
+ for (auto node : nodes)
+ delete node;
+ }
+
+ void add_defs(Node *node, const RTLIL::SigSpec &sig, bool elidable)
+ {
+ for (auto chunk : sig.chunks())
+ if (chunk.wire)
+ wire_defs[chunk.wire].insert(node);
+ // Only defs of an entire wire in the right order can be elided.
+ if (sig.is_wire())
+ wire_def_elidable[sig.as_wire()] = elidable;
+ }
+
+ void add_uses(Node *node, const RTLIL::SigSpec &sig)
+ {
+ for (auto chunk : sig.chunks())
+ if (chunk.wire) {
+ wire_uses[chunk.wire].insert(node);
+ // Only a single use of an entire wire in the right order can be elided.
+ // (But the use can include other chunks.)
+ if (!wire_use_elidable.count(chunk.wire))
+ wire_use_elidable[chunk.wire] = true;
+ else
+ wire_use_elidable[chunk.wire] = false;
+ }
+ }
+
+ bool is_elidable(const RTLIL::Wire *wire) const
+ {
+ if (wire_def_elidable.count(wire) && wire_use_elidable.count(wire))
+ return wire_def_elidable.at(wire) && wire_use_elidable.at(wire);
+ return false;
+ }
+
+ // Connections
+ void add_connect_defs_uses(Node *node, const RTLIL::SigSig &conn)
+ {
+ add_defs(node, conn.first, /*elidable=*/true);
+ add_uses(node, conn.second);
+ }
+
+ Node *add_node(const RTLIL::SigSig &conn)
+ {
+ Node *node = new Node;
+ node->type = Node::Type::CONNECT;
+ node->connect = conn;
+ nodes.push_back(node);
+ add_connect_defs_uses(node, conn);
+ return node;
+ }
+
+ // Cells
+ void add_cell_defs_uses(Node *node, const RTLIL::Cell *cell)
+ {
+ log_assert(cell->known());
+ for (auto conn : cell->connections()) {
+ if (cell->output(conn.first)) {
+ if (is_sync_ff_cell(cell->type) || (cell->type == ID($memrd) && cell->getParam(ID(CLK_ENABLE)).as_bool()))
+ /* non-combinatorial outputs do not introduce defs */;
+ else if (is_elidable_cell(cell->type))
+ add_defs(node, conn.second, /*elidable=*/true);
+ else if (is_internal_cell(cell->type))
+ add_defs(node, conn.second, /*elidable=*/false);
+ else {
+ // Unlike outputs of internal cells (which generate code that depends on the ability to set the output
+ // wire bits), outputs of user cells are normal wires, and the wires connected to them can be elided.
+ add_defs(node, conn.second, /*elidable=*/true);
+ }
+ }
+ if (cell->input(conn.first))
+ add_uses(node, conn.second);
+ }
+ }
+
+ Node *add_node(const RTLIL::Cell *cell)
+ {
+ Node *node = new Node;
+ node->type = Node::Type::CELL;
+ node->cell = cell;
+ nodes.push_back(node);
+ add_cell_defs_uses(node, cell);
+ return node;
+ }
+
+ // Processes
+ void add_case_defs_uses(Node *node, const RTLIL::CaseRule *case_)
+ {
+ for (auto &action : case_->actions) {
+ add_defs(node, action.first, /*elidable=*/false);
+ add_uses(node, action.second);
+ }
+ for (auto sub_switch : case_->switches) {
+ add_uses(node, sub_switch->signal);
+ for (auto sub_case : sub_switch->cases) {
+ for (auto &compare : sub_case->compare)
+ add_uses(node, compare);
+ add_case_defs_uses(node, sub_case);
+ }
+ }
+ }
+
+ void add_process_defs_uses(Node *node, const RTLIL::Process *process)
+ {
+ add_case_defs_uses(node, &process->root_case);
+ for (auto sync : process->syncs)
+ for (auto action : sync->actions) {
+ if (sync->type == RTLIL::STp || sync->type == RTLIL::STn || sync->type == RTLIL::STe)
+ /* sync actions do not introduce feedback */;
+ else
+ add_defs(node, action.first, /*elidable=*/false);
+ add_uses(node, action.second);
+ }
+ }
+
+ Node *add_node(const RTLIL::Process *process)
+ {
+ Node *node = new Node;
+ node->type = Node::Type::PROCESS;
+ node->process = process;
+ nodes.push_back(node);
+ add_process_defs_uses(node, process);
+ return node;
+ }
+};
+
+struct CxxrtlWorker {
+ bool split_intf = false;
+ std::string intf_filename;
+ std::string design_ns = "cxxrtl_design";
+ std::ostream *impl_f = nullptr;
+ std::ostream *intf_f = nullptr;
+
+ bool elide_internal = false;
+ bool elide_public = false;
+ bool localize_internal = false;
+ bool localize_public = false;
+ bool run_splitnets = false;
+
+ std::ostringstream f;
+ std::string indent;
+ int temporary = 0;
+
+ dict<const RTLIL::Module*, SigMap> sigmaps;
+ pool<const RTLIL::Wire*> sync_wires;
+ dict<RTLIL::SigBit, RTLIL::SyncType> sync_types;
+ pool<const RTLIL::Memory*> writable_memories;
+ dict<const RTLIL::Cell*, pool<const RTLIL::Cell*>> transparent_for;
+ dict<const RTLIL::Cell*, dict<RTLIL::Wire*, RTLIL::IdString>> cell_wire_defs;
+ dict<const RTLIL::Wire*, FlowGraph::Node> elided_wires;
+ dict<const RTLIL::Module*, std::vector<FlowGraph::Node>> schedule;
+ pool<const RTLIL::Wire*> localized_wires;
+
+ void inc_indent() {
+ indent += "\t";
+ }
+ void dec_indent() {
+ indent.resize(indent.size() - 1);
+ }
+
+ // RTLIL allows any characters in names other than whitespace. This presents an issue for generating C++ code
+ // because C++ identifiers may be only alphanumeric, cannot clash with C++ keywords, and cannot clash with cxxrtl
+ // identifiers. This issue can be solved with a name mangling scheme. We choose a name mangling scheme that results
+ // in readable identifiers, does not depend on an up-to-date list of C++ keywords, and is easy to apply. Its rules:
+ // 1. All generated identifiers start with `_`.
+ // 1a. Generated identifiers for public names (beginning with `\`) start with `p_`.
+ // 1b. Generated identifiers for internal names (beginning with `$`) start with `i_`.
+ // 2. An underscore is escaped with another underscore, i.e. `__`.
+ // 3. Any other non-alnum character is escaped with underscores around its lowercase hex code, e.g. `@` as `_40_`.
+ std::string mangle_name(const RTLIL::IdString &name)
+ {
+ std::string mangled;
+ bool first = true;
+ for (char c : name.str()) {
+ if (first) {
+ first = false;
+ if (c == '\\')
+ mangled += "p_";
+ else if (c == '$')
+ mangled += "i_";
+ else
+ log_assert(false);
+ } else {
+ if (isalnum(c)) {
+ mangled += c;
+ } else if (c == '_') {
+ mangled += "__";
+ } else {
+ char l = c & 0xf, h = (c >> 4) & 0xf;
+ mangled += '_';
+ mangled += (h < 10 ? '0' + h : 'a' + h - 10);
+ mangled += (l < 10 ? '0' + l : 'a' + l - 10);
+ mangled += '_';
+ }
+ }
+ }
+ return mangled;
+ }
+
+ std::string mangle_module_name(const RTLIL::IdString &name)
+ {
+ // Class namespace.
+ return mangle_name(name);
+ }
+
+ std::string mangle_memory_name(const RTLIL::IdString &name)
+ {
+ // Class member namespace.
+ return "memory_" + mangle_name(name);
+ }
+
+ std::string mangle_cell_name(const RTLIL::IdString &name)
+ {
+ // Class member namespace.
+ return "cell_" + mangle_name(name);
+ }
+
+ std::string mangle_wire_name(const RTLIL::IdString &name)
+ {
+ // Class member namespace.
+ return mangle_name(name);
+ }
+
+ std::string mangle(const RTLIL::Module *module)
+ {
+ return mangle_module_name(module->name);
+ }
+
+ std::string mangle(const RTLIL::Memory *memory)
+ {
+ return mangle_memory_name(memory->name);
+ }
+
+ std::string mangle(const RTLIL::Cell *cell)
+ {
+ return mangle_cell_name(cell->name);
+ }
+
+ std::string mangle(const RTLIL::Wire *wire)
+ {
+ return mangle_wire_name(wire->name);
+ }
+
+ std::string mangle(RTLIL::SigBit sigbit)
+ {
+ log_assert(sigbit.wire != NULL);
+ if (sigbit.wire->width == 1)
+ return mangle(sigbit.wire);
+ return mangle(sigbit.wire) + "_" + std::to_string(sigbit.offset);
+ }
+
+ std::string fresh_temporary()
+ {
+ return stringf("tmp_%d", temporary++);
+ }
+
+ void dump_attrs(const RTLIL::AttrObject *object)
+ {
+ for (auto attr : object->attributes) {
+ f << indent << "// " << attr.first.str() << ": ";
+ if (attr.second.flags & RTLIL::CONST_FLAG_STRING) {
+ f << attr.second.decode_string();
+ } else {
+ f << attr.second.as_int(/*is_signed=*/attr.second.flags & RTLIL::CONST_FLAG_SIGNED);
+ }
+ f << "\n";
+ }
+ }
+
+ void dump_const_init(const RTLIL::Const &data, int width, int offset = 0, bool fixed_width = false)
+ {
+ f << "{";
+ while (width > 0) {
+ const int CHUNK_SIZE = 32;
+ uint32_t chunk = data.extract(offset, width > CHUNK_SIZE ? CHUNK_SIZE : width).as_int();
+ if (fixed_width)
+ f << stringf("0x%08xu", chunk);
+ else
+ f << stringf("%#xu", chunk);
+ if (width > CHUNK_SIZE)
+ f << ',';
+ offset += CHUNK_SIZE;
+ width -= CHUNK_SIZE;
+ }
+ f << "}";
+ }
+
+ void dump_const_init(const RTLIL::Const &data)
+ {
+ dump_const_init(data, data.size());
+ }
+
+ void dump_const(const RTLIL::Const &data, int width, int offset = 0, bool fixed_width = false)
+ {
+ f << "value<" << width << ">";
+ dump_const_init(data, width, offset, fixed_width);
+ }
+
+ void dump_const(const RTLIL::Const &data)
+ {
+ dump_const(data, data.size());
+ }
+
+ bool dump_sigchunk(const RTLIL::SigChunk &chunk, bool is_lhs)
+ {
+ if (chunk.wire == NULL) {
+ dump_const(chunk.data, chunk.width, chunk.offset);
+ return false;
+ } else {
+ if (!is_lhs && elided_wires.count(chunk.wire)) {
+ const FlowGraph::Node &node = elided_wires[chunk.wire];
+ switch (node.type) {
+ case FlowGraph::Node::Type::CONNECT:
+ dump_connect_elided(node.connect);
+ break;
+ case FlowGraph::Node::Type::CELL:
+ if (is_elidable_cell(node.cell->type)) {
+ dump_cell_elided(node.cell);
+ } else {
+ f << mangle(node.cell) << "." << mangle_wire_name(cell_wire_defs[node.cell][chunk.wire]) << ".curr";
+ }
+ break;
+ default:
+ log_assert(false);
+ }
+ } else if (localized_wires[chunk.wire]) {
+ f << mangle(chunk.wire);
+ } else {
+ f << mangle(chunk.wire) << (is_lhs ? ".next" : ".curr");
+ }
+ if (chunk.width == chunk.wire->width && chunk.offset == 0)
+ return false;
+ else if (chunk.width == 1)
+ f << ".slice<" << chunk.offset << ">()";
+ else
+ f << ".slice<" << chunk.offset+chunk.width-1 << "," << chunk.offset << ">()";
+ return true;
+ }
+ }
+
+ bool dump_sigspec(const RTLIL::SigSpec &sig, bool is_lhs)
+ {
+ if (sig.empty()) {
+ f << "value<0>()";
+ return false;
+ } else if (sig.is_chunk()) {
+ return dump_sigchunk(sig.as_chunk(), is_lhs);
+ } else {
+ dump_sigchunk(*sig.chunks().rbegin(), is_lhs);
+ for (auto it = sig.chunks().rbegin() + 1; it != sig.chunks().rend(); ++it) {
+ f << ".concat(";
+ dump_sigchunk(*it, is_lhs);
+ f << ")";
+ }
+ return true;
+ }
+ }
+
+ void dump_sigspec_lhs(const RTLIL::SigSpec &sig)
+ {
+ dump_sigspec(sig, /*is_lhs=*/true);
+ }
+
+ void dump_sigspec_rhs(const RTLIL::SigSpec &sig)
+ {
+ // In the contexts where we want template argument deduction to occur for `template<size_t Bits> ... value<Bits>`,
+ // it is necessary to have the argument to already be a `value<N>`, since template argument deduction and implicit
+ // type conversion are mutually exclusive. In these contexts, we use dump_sigspec_rhs() to emit an explicit
+ // type conversion, but only if the expression needs it.
+ bool is_complex = dump_sigspec(sig, /*is_lhs=*/false);
+ if (is_complex)
+ f << ".val()";
+ }
+
+ void collect_sigspec_rhs(const RTLIL::SigSpec &sig, std::vector<RTLIL::IdString> &cells)
+ {
+ for (auto chunk : sig.chunks()) {
+ if (!chunk.wire || !elided_wires.count(chunk.wire))
+ continue;
+
+ const FlowGraph::Node &node = elided_wires[chunk.wire];
+ switch (node.type) {
+ case FlowGraph::Node::Type::CONNECT:
+ collect_connect(node.connect, cells);
+ break;
+ case FlowGraph::Node::Type::CELL:
+ collect_cell(node.cell, cells);
+ break;
+ default:
+ log_assert(false);
+ }
+ }
+ }
+
+ void dump_connect_elided(const RTLIL::SigSig &conn)
+ {
+ dump_sigspec_rhs(conn.second);
+ }
+
+ bool is_connect_elided(const RTLIL::SigSig &conn)
+ {
+ return conn.first.is_wire() && elided_wires.count(conn.first.as_wire());
+ }
+
+ void collect_connect(const RTLIL::SigSig &conn, std::vector<RTLIL::IdString> &cells)
+ {
+ if (!is_connect_elided(conn))
+ return;
+
+ collect_sigspec_rhs(conn.second, cells);
+ }
+
+ void dump_connect(const RTLIL::SigSig &conn)
+ {
+ if (is_connect_elided(conn))
+ return;
+
+ f << indent << "// connection\n";
+ f << indent;
+ dump_sigspec_lhs(conn.first);
+ f << " = ";
+ dump_connect_elided(conn);
+ f << ";\n";
+ }
+
+ void dump_cell_elided(const RTLIL::Cell *cell)
+ {
+ // Unary cells
+ if (is_unary_cell(cell->type)) {
+ f << cell->type.substr(1) << '_' <<
+ (cell->getParam(ID(A_SIGNED)).as_bool() ? 's' : 'u') <<
+ "<" << cell->getParam(ID(Y_WIDTH)).as_int() << ">(";
+ dump_sigspec_rhs(cell->getPort(ID(A)));
+ f << ")";
+ // Binary cells
+ } else if (is_binary_cell(cell->type)) {
+ f << cell->type.substr(1) << '_' <<
+ (cell->getParam(ID(A_SIGNED)).as_bool() ? 's' : 'u') <<
+ (cell->getParam(ID(B_SIGNED)).as_bool() ? 's' : 'u') <<
+ "<" << cell->getParam(ID(Y_WIDTH)).as_int() << ">(";
+ dump_sigspec_rhs(cell->getPort(ID(A)));
+ f << ", ";
+ dump_sigspec_rhs(cell->getPort(ID(B)));
+ f << ")";
+ // Muxes
+ } else if (cell->type == ID($mux)) {
+ f << "(";
+ dump_sigspec_rhs(cell->getPort(ID(S)));
+ f << " ? ";
+ dump_sigspec_rhs(cell->getPort(ID(B)));
+ f << " : ";
+ dump_sigspec_rhs(cell->getPort(ID(A)));
+ f << ")";
+ // Concats
+ } else if (cell->type == ID($concat)) {
+ dump_sigspec_rhs(cell->getPort(ID(B)));
+ f << ".concat(";
+ dump_sigspec_rhs(cell->getPort(ID(A)));
+ f << ").val()";
+ // Slices
+ } else if (cell->type == ID($slice)) {
+ dump_sigspec_rhs(cell->getPort(ID(A)));
+ f << ".slice<";
+ f << cell->getParam(ID(OFFSET)).as_int() + cell->getParam(ID(Y_WIDTH)).as_int() - 1;
+ f << ",";
+ f << cell->getParam(ID(OFFSET)).as_int();
+ f << ">().val()";
+ } else {
+ log_assert(false);
+ }
+ }
+
+ bool is_cell_elided(const RTLIL::Cell *cell)
+ {
+ return is_elidable_cell(cell->type) && cell->hasPort(ID(Y)) && cell->getPort(ID(Y)).is_wire() &&
+ elided_wires.count(cell->getPort(ID(Y)).as_wire());
+ }
+
+ void collect_cell(const RTLIL::Cell *cell, std::vector<RTLIL::IdString> &cells)
+ {
+ if (!is_cell_elided(cell))
+ return;
+
+ cells.push_back(cell->name);
+ for (auto port : cell->connections())
+ if (port.first != ID(Y))
+ collect_sigspec_rhs(port.second, cells);
+ }
+
+ void dump_cell(const RTLIL::Cell *cell)
+ {
+ if (is_cell_elided(cell))
+ return;
+ if (cell->type == ID($meminit))
+ return; // Handled elsewhere.
+
+ std::vector<RTLIL::IdString> elided_cells;
+ if (is_elidable_cell(cell->type)) {
+ for (auto port : cell->connections())
+ if (port.first != ID(Y))
+ collect_sigspec_rhs(port.second, elided_cells);
+ }
+ if (elided_cells.empty()) {
+ dump_attrs(cell);
+ f << indent << "// cell " << cell->name.str() << "\n";
+ } else {
+ f << indent << "// cells";
+ for (auto elided_cell : elided_cells)
+ f << " " << elided_cell.str();
+ f << "\n";
+ }
+
+ // Elidable cells
+ if (is_elidable_cell(cell->type)) {
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(Y)));
+ f << " = ";
+ dump_cell_elided(cell);
+ f << ";\n";
+ // Parallel (one-hot) muxes
+ } else if (cell->type == ID($pmux)) {
+ int width = cell->getParam(ID(WIDTH)).as_int();
+ int s_width = cell->getParam(ID(S_WIDTH)).as_int();
+ bool first = true;
+ for (int part = 0; part < s_width; part++) {
+ f << (first ? indent : " else ");
+ first = false;
+ f << "if (";
+ dump_sigspec_rhs(cell->getPort(ID(S)).extract(part));
+ f << ") {\n";
+ inc_indent();
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(Y)));
+ f << " = ";
+ dump_sigspec_rhs(cell->getPort(ID(B)).extract(part * width, width));
+ f << ";\n";
+ dec_indent();
+ f << indent << "}";
+ }
+ f << " else {\n";
+ inc_indent();
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(Y)));
+ f << " = ";
+ dump_sigspec_rhs(cell->getPort(ID(A)));
+ f << ";\n";
+ dec_indent();
+ f << indent << "}\n";
+ // Flip-flops
+ } else if (is_ff_cell(cell->type)) {
+ if (cell->hasPort(ID(CLK)) && cell->getPort(ID(CLK)).is_wire()) {
+ // Edge-sensitive logic
+ RTLIL::SigBit clk_bit = cell->getPort(ID(CLK))[0];
+ clk_bit = sigmaps[clk_bit.wire->module](clk_bit);
+ f << indent << "if (" << (cell->getParam(ID(CLK_POLARITY)).as_bool() ? "posedge_" : "negedge_")
+ << mangle(clk_bit) << ") {\n";
+ inc_indent();
+ if (cell->type == ID($dffe)) {
+ f << indent << "if (";
+ dump_sigspec_rhs(cell->getPort(ID(EN)));
+ f << " == value<1> {" << cell->getParam(ID(EN_POLARITY)).as_bool() << "u}) {\n";
+ inc_indent();
+ }
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(Q)));
+ f << " = ";
+ dump_sigspec_rhs(cell->getPort(ID(D)));
+ f << ";\n";
+ if (cell->type == ID($dffe)) {
+ dec_indent();
+ f << indent << "}\n";
+ }
+ dec_indent();
+ f << indent << "}\n";
+ } else if (cell->hasPort(ID(EN))) {
+ // Level-sensitive logic
+ f << indent << "if (";
+ dump_sigspec_rhs(cell->getPort(ID(EN)));
+ f << " == value<1> {" << cell->getParam(ID(EN_POLARITY)).as_bool() << "u}) {\n";
+ inc_indent();
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(Q)));
+ f << " = ";
+ dump_sigspec_rhs(cell->getPort(ID(D)));
+ f << ";\n";
+ dec_indent();
+ f << indent << "}\n";
+ }
+ if (cell->hasPort(ID(ARST))) {
+ // Asynchronous reset (entire coarse cell at once)
+ f << indent << "if (";
+ dump_sigspec_rhs(cell->getPort(ID(ARST)));
+ f << " == value<1> {" << cell->getParam(ID(ARST_POLARITY)).as_bool() << "u}) {\n";
+ inc_indent();
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(Q)));
+ f << " = ";
+ dump_const(cell->getParam(ID(ARST_VALUE)));
+ f << ";\n";
+ dec_indent();
+ f << indent << "}\n";
+ }
+ if (cell->hasPort(ID(SET))) {
+ // Asynchronous set (for individual bits)
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(Q)));
+ f << " = ";
+ dump_sigspec_lhs(cell->getPort(ID(Q)));
+ f << ".update(";
+ dump_const(RTLIL::Const(RTLIL::S1, cell->getParam(ID(WIDTH)).as_int()));
+ f << ", ";
+ dump_sigspec_rhs(cell->getPort(ID(SET)));
+ f << (cell->getParam(ID(SET_POLARITY)).as_bool() ? "" : ".bit_not()") << ");\n";
+ }
+ if (cell->hasPort(ID(CLR))) {
+ // Asynchronous clear (for individual bits; priority over set)
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(Q)));
+ f << " = ";
+ dump_sigspec_lhs(cell->getPort(ID(Q)));
+ f << ".update(";
+ dump_const(RTLIL::Const(RTLIL::S0, cell->getParam(ID(WIDTH)).as_int()));
+ f << ", ";
+ dump_sigspec_rhs(cell->getPort(ID(CLR)));
+ f << (cell->getParam(ID(CLR_POLARITY)).as_bool() ? "" : ".bit_not()") << ");\n";
+ }
+ // Memory ports
+ } else if (cell->type.in(ID($memrd), ID($memwr))) {
+ if (cell->getParam(ID(CLK_ENABLE)).as_bool()) {
+ RTLIL::SigBit clk_bit = cell->getPort(ID(CLK))[0];
+ clk_bit = sigmaps[clk_bit.wire->module](clk_bit);
+ f << indent << "if (" << (cell->getParam(ID(CLK_POLARITY)).as_bool() ? "posedge_" : "negedge_")
+ << mangle(clk_bit) << ") {\n";
+ inc_indent();
+ }
+ RTLIL::Memory *memory = cell->module->memories[cell->getParam(ID(MEMID)).decode_string()];
+ std::string valid_index_temp = fresh_temporary();
+ f << indent << "auto " << valid_index_temp << " = memory_index(";
+ dump_sigspec_rhs(cell->getPort(ID(ADDR)));
+ f << ", " << memory->start_offset << ", " << memory->size << ");\n";
+ if (cell->type == ID($memrd)) {
+ bool has_enable = cell->getParam(ID(CLK_ENABLE)).as_bool() && !cell->getPort(ID(EN)).is_fully_ones();
+ if (has_enable) {
+ f << indent << "if (";
+ dump_sigspec_rhs(cell->getPort(ID(EN)));
+ f << ") {\n";
+ inc_indent();
+ }
+ // The generated code has two bounds checks; one in an assertion, and another that guards the read.
+ // This is done so that the code does not invoke undefined behavior under any conditions, but nevertheless
+ // loudly crashes if an illegal condition is encountered. The assert may be turned off with -NDEBUG not
+ // just for release builds, but also to make sure the simulator (which is presumably embedded in some
+ // larger program) will never crash the code that calls into it.
+ //
+ // If assertions are disabled, out of bounds reads are defined to return zero.
+ f << indent << "assert(" << valid_index_temp << ".valid && \"out of bounds read\");\n";
+ f << indent << "if(" << valid_index_temp << ".valid) {\n";
+ inc_indent();
+ if (writable_memories[memory]) {
+ std::string addr_temp = fresh_temporary();
+ f << indent << "const value<" << cell->getPort(ID(ADDR)).size() << "> &" << addr_temp << " = ";
+ dump_sigspec_rhs(cell->getPort(ID(ADDR)));
+ f << ";\n";
+ std::string lhs_temp = fresh_temporary();
+ f << indent << "value<" << memory->width << "> " << lhs_temp << " = "
+ << mangle(memory) << "[" << valid_index_temp << ".index];\n";
+ std::vector<const RTLIL::Cell*> memwr_cells(transparent_for[cell].begin(), transparent_for[cell].end());
+ std::sort(memwr_cells.begin(), memwr_cells.end(),
+ [](const RTLIL::Cell *a, const RTLIL::Cell *b) {
+ return a->getParam(ID(PRIORITY)).as_int() < b->getParam(ID(PRIORITY)).as_int();
+ });
+ for (auto memwr_cell : memwr_cells) {
+ f << indent << "if (" << addr_temp << " == ";
+ dump_sigspec_rhs(memwr_cell->getPort(ID(ADDR)));
+ f << ") {\n";
+ inc_indent();
+ f << indent << lhs_temp << " = " << lhs_temp;
+ f << ".update(";
+ dump_sigspec_rhs(memwr_cell->getPort(ID(DATA)));
+ f << ", ";
+ dump_sigspec_rhs(memwr_cell->getPort(ID(EN)));
+ f << ");\n";
+ dec_indent();
+ f << indent << "}\n";
+ }
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(DATA)));
+ f << " = " << lhs_temp << ";\n";
+ } else {
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(DATA)));
+ f << " = " << mangle(memory) << "[" << valid_index_temp << ".index];\n";
+ }
+ dec_indent();
+ f << indent << "} else {\n";
+ inc_indent();
+ f << indent;
+ dump_sigspec_lhs(cell->getPort(ID(DATA)));
+ f << " = value<" << memory->width << "> {};\n";
+ dec_indent();
+ f << indent << "}\n";
+ if (has_enable) {
+ dec_indent();
+ f << indent << "}\n";
+ }
+ } else /*if (cell->type == ID($memwr))*/ {
+ log_assert(writable_memories[memory]);
+ // See above for rationale of having both the assert and the condition.
+ //
+ // If assertions are disabled, out of bounds writes are defined to do nothing.
+ f << indent << "assert(" << valid_index_temp << ".valid && \"out of bounds write\");\n";
+ f << indent << "if (" << valid_index_temp << ".valid) {\n";
+ inc_indent();
+ f << indent << mangle(memory) << ".update(" << valid_index_temp << ".index, ";
+ dump_sigspec_rhs(cell->getPort(ID(DATA)));
+ f << ", ";
+ dump_sigspec_rhs(cell->getPort(ID(EN)));
+ f << ", " << cell->getParam(ID(PRIORITY)).as_int() << ");\n";
+ dec_indent();
+ f << indent << "}\n";
+ }
+ if (cell->getParam(ID(CLK_ENABLE)).as_bool()) {
+ dec_indent();
+ f << indent << "}\n";
+ }
+ // Internal cells
+ } else if (is_internal_cell(cell->type)) {
+ log_cmd_error("Unsupported internal cell `%s'.\n", cell->type.c_str());
+ // User cells
+ } else {
+ log_assert(cell->known());
+ for (auto conn : cell->connections())
+ if (cell->input(conn.first)) {
+ f << indent << mangle(cell) << "." << mangle_wire_name(conn.first) << ".next = ";
+ dump_sigspec_rhs(conn.second);
+ f << ";\n";
+ }
+ f << indent << mangle(cell) << ".eval();\n";
+ for (auto conn : cell->connections()) {
+ if (conn.second.is_wire()) {
+ RTLIL::Wire *wire = conn.second.as_wire();
+ if (elided_wires.count(wire) && cell_wire_defs[cell].count(wire))
+ continue;
+ }
+ if (cell->output(conn.first)) {
+ if (conn.second.empty())
+ continue; // ignore disconnected ports
+ f << indent;
+ dump_sigspec_lhs(conn.second);
+ f << " = " << mangle(cell) << "." << mangle_wire_name(conn.first) << ".curr;\n";
+ }
+ }
+ }
+ }
+
+ void dump_assign(const RTLIL::SigSig &sigsig)
+ {
+ f << indent;
+ dump_sigspec_lhs(sigsig.first);
+ f << " = ";
+ dump_sigspec_rhs(sigsig.second);
+ f << ";\n";
+ }
+
+ void dump_case_rule(const RTLIL::CaseRule *rule)
+ {
+ for (auto action : rule->actions)
+ dump_assign(action);
+ for (auto switch_ : rule->switches)
+ dump_switch_rule(switch_);
+ }
+
+ void dump_switch_rule(const RTLIL::SwitchRule *rule)
+ {
+ // The switch attributes are printed before the switch condition is captured.
+ dump_attrs(rule);
+ std::string signal_temp = fresh_temporary();
+ f << indent << "const value<" << rule->signal.size() << "> &" << signal_temp << " = ";
+ dump_sigspec(rule->signal, /*is_lhs=*/false);
+ f << ";\n";
+
+ bool first = true;
+ for (auto case_ : rule->cases) {
+ // The case attributes (for nested cases) are printed before the if/else if/else statement.
+ dump_attrs(rule);
+ f << indent;
+ if (!first)
+ f << "} else ";
+ first = false;
+ if (!case_->compare.empty()) {
+ f << "if (";
+ bool first = true;
+ for (auto &compare : case_->compare) {
+ if (!first)
+ f << " || ";
+ first = false;
+ if (compare.is_fully_def()) {
+ f << signal_temp << " == ";
+ dump_sigspec(compare, /*is_lhs=*/false);
+ } else if (compare.is_fully_const()) {
+ RTLIL::Const compare_mask, compare_value;
+ for (auto bit : compare.as_const()) {
+ switch (bit) {
+ case RTLIL::S0:
+ case RTLIL::S1:
+ compare_mask.bits.push_back(RTLIL::S1);
+ compare_value.bits.push_back(bit);
+ break;
+
+ case RTLIL::Sx:
+ case RTLIL::Sz:
+ case RTLIL::Sa:
+ compare_mask.bits.push_back(RTLIL::S0);
+ compare_value.bits.push_back(RTLIL::S0);
+ break;
+
+ default:
+ log_assert(false);
+ }
+ }
+ f << "and_uu<" << compare.size() << ">(" << signal_temp << ", ";
+ dump_const(compare_mask);
+ f << ") == ";
+ dump_const(compare_value);
+ } else {
+ log_assert(false);
+ }
+ }
+ f << ") ";
+ }
+ f << "{\n";
+ inc_indent();
+ dump_case_rule(case_);
+ dec_indent();
+ }
+ f << indent << "}\n";
+ }
+
+ void dump_process(const RTLIL::Process *proc)
+ {
+ dump_attrs(proc);
+ f << indent << "// process " << proc->name.str() << "\n";
+ // The case attributes (for root case) are always empty.
+ log_assert(proc->root_case.attributes.empty());
+ dump_case_rule(&proc->root_case);
+ for (auto sync : proc->syncs) {
+ RTLIL::SigBit sync_bit = sync->signal[0];
+ sync_bit = sigmaps[sync_bit.wire->module](sync_bit);
+
+ pool<std::string> events;
+ switch (sync->type) {
+ case RTLIL::STp:
+ events.insert("posedge_" + mangle(sync_bit));
+ break;
+ case RTLIL::STn:
+ events.insert("negedge_" + mangle(sync_bit));
+ case RTLIL::STe:
+ events.insert("posedge_" + mangle(sync_bit));
+ events.insert("negedge_" + mangle(sync_bit));
+ break;
+
+ case RTLIL::ST0:
+ case RTLIL::ST1:
+ case RTLIL::STa:
+ case RTLIL::STg:
+ case RTLIL::STi:
+ log_assert(false);
+ }
+ if (!events.empty()) {
+ f << indent << "if (";
+ bool first = true;
+ for (auto &event : events) {
+ if (!first)
+ f << " || ";
+ first = false;
+ f << event;
+ }
+ f << ") {\n";
+ inc_indent();
+ for (auto action : sync->actions)
+ dump_assign(action);
+ dec_indent();
+ f << indent << "}\n";
+ }
+ }
+ }
+
+ void dump_wire(const RTLIL::Wire *wire, bool is_local)
+ {
+ if (elided_wires.count(wire))
+ return;
+
+ if (is_local) {
+ if (!localized_wires.count(wire))
+ return;
+
+ dump_attrs(wire);
+ f << indent << "value<" << wire->width << "> " << mangle(wire) << ";\n";
+ } else {
+ if (localized_wires.count(wire))
+ return;
+
+ dump_attrs(wire);
+ f << indent << "wire<" << wire->width << "> " << mangle(wire);
+ if (wire->attributes.count(ID(init))) {
+ f << " ";
+ dump_const_init(wire->attributes.at(ID(init)));
+ }
+ f << ";\n";
+ if (sync_wires[wire]) {
+ for (auto sync_type : sync_types) {
+ if (sync_type.first.wire == wire) {
+ if (sync_type.second != RTLIL::STn)
+ f << indent << "bool posedge_" << mangle(sync_type.first) << " = false;\n";
+ if (sync_type.second != RTLIL::STp)
+ f << indent << "bool negedge_" << mangle(sync_type.first) << " = false;\n";
+ }
+ }
+ }
+ }
+ }
+
+ void dump_memory(RTLIL::Module *module, const RTLIL::Memory *memory)
+ {
+ vector<const RTLIL::Cell*> init_cells;
+ for (auto cell : module->cells())
+ if (cell->type == ID($meminit) && cell->getParam(ID(MEMID)).decode_string() == memory->name.str())
+ init_cells.push_back(cell);
+
+ std::sort(init_cells.begin(), init_cells.end(), [](const RTLIL::Cell *a, const RTLIL::Cell *b) {
+ int a_addr = a->getPort(ID(ADDR)).as_int(), b_addr = b->getPort(ID(ADDR)).as_int();
+ int a_prio = a->getParam(ID(PRIORITY)).as_int(), b_prio = b->getParam(ID(PRIORITY)).as_int();
+ return a_prio > b_prio || (a_prio == b_prio && a_addr < b_addr);
+ });
+
+ dump_attrs(memory);
+ f << indent << "memory<" << memory->width << "> " << mangle(memory)
+ << " { " << memory->size << "u";
+ if (init_cells.empty()) {
+ f << " };\n";
+ } else {
+ f << ",\n";
+ inc_indent();
+ for (auto cell : init_cells) {
+ dump_attrs(cell);
+ RTLIL::Const data = cell->getPort(ID(DATA)).as_const();
+ size_t width = cell->getParam(ID(WIDTH)).as_int();
+ size_t words = cell->getParam(ID(WORDS)).as_int();
+ f << indent << "memory<" << memory->width << ">::init<" << words << "> { "
+ << stringf("%#x", cell->getPort(ID(ADDR)).as_int()) << ", {";
+ inc_indent();
+ for (size_t n = 0; n < words; n++) {
+ if (n % 4 == 0)
+ f << "\n" << indent;
+ else
+ f << " ";
+ dump_const(data, width, n * width, /*fixed_width=*/true);
+ f << ",";
+ }
+ dec_indent();
+ f << "\n" << indent << "}},\n";
+ }
+ dec_indent();
+ f << indent << "};\n";
+ }
+ }
+
+ void dump_module_intf(RTLIL::Module *module)
+ {
+ dump_attrs(module);
+ f << "struct " << mangle(module) << " : public module {\n";
+ inc_indent();
+ for (auto wire : module->wires())
+ dump_wire(wire, /*is_local=*/false);
+ f << "\n";
+ bool has_memories = false;
+ for (auto memory : module->memories) {
+ dump_memory(module, memory.second);
+ has_memories = true;
+ }
+ if (has_memories)
+ f << "\n";
+ bool has_cells = false;
+ for (auto cell : module->cells()) {
+ if (is_internal_cell(cell->type))
+ continue;
+ f << indent << mangle_module_name(cell->type) << " " << mangle(cell) << ";\n";
+ has_cells = true;
+ }
+ if (has_cells)
+ f << "\n";
+ f << indent << "void eval() override;\n";
+ f << indent << "bool commit() override;\n";
+ dec_indent();
+ f << "}; // struct " << mangle(module) << "\n";
+ f << "\n";
+ }
+
+ void dump_module_impl(RTLIL::Module *module)
+ {
+ f << "void " << mangle(module) << "::eval() {\n";
+ inc_indent();
+ for (auto wire : module->wires())
+ dump_wire(wire, /*is_local=*/true);
+ for (auto node : schedule[module]) {
+ switch (node.type) {
+ case FlowGraph::Node::Type::CONNECT:
+ dump_connect(node.connect);
+ break;
+ case FlowGraph::Node::Type::CELL:
+ dump_cell(node.cell);
+ break;
+ case FlowGraph::Node::Type::PROCESS:
+ dump_process(node.process);
+ break;
+ }
+ }
+ for (auto sync_type : sync_types) {
+ if (sync_type.first.wire->module == module) {
+ if (sync_type.second != RTLIL::STn)
+ f << indent << "posedge_" << mangle(sync_type.first) << " = false;\n";
+ if (sync_type.second != RTLIL::STp)
+ f << indent << "negedge_" << mangle(sync_type.first) << " = false;\n";
+ }
+ }
+ dec_indent();
+ f << "}\n";
+ f << "\n";
+
+ f << "bool " << mangle(module) << "::commit() {\n";
+ inc_indent();
+ f << indent << "bool changed = false;\n";
+ for (auto wire : module->wires()) {
+ if (elided_wires.count(wire) || localized_wires.count(wire))
+ continue;
+ if (sync_wires[wire]) {
+ std::string wire_prev = mangle(wire) + "_prev";
+ std::string wire_curr = mangle(wire) + ".curr";
+ std::string wire_edge = mangle(wire) + "_edge";
+ f << indent << "value<" << wire->width << "> " << wire_prev << " = " << wire_curr << ";\n";
+ f << indent << "if (" << mangle(wire) << ".commit()) {\n";
+ inc_indent();
+ f << indent << "value<" << wire->width << "> " << wire_edge << " = "
+ << wire_prev << ".bit_xor(" << wire_curr << ");\n";
+ for (auto sync_type : sync_types) {
+ if (sync_type.first.wire != wire)
+ continue;
+ if (sync_type.second != RTLIL::STn) {
+ f << indent << "if (" << wire_edge << ".slice<" << sync_type.first.offset << ">().val() && "
+ << wire_curr << ".slice<" << sync_type.first.offset << ">().val())\n";
+ inc_indent();
+ f << indent << "posedge_" << mangle(sync_type.first) << " = true;\n";
+ dec_indent();
+ }
+ if (sync_type.second != RTLIL::STp) {
+ f << indent << "if (" << wire_edge << ".slice<" << sync_type.first.offset << ">().val() && "
+ << "!" << wire_curr << ".slice<" << sync_type.first.offset << ">().val())\n";
+ inc_indent();
+ f << indent << "negedge_" << mangle(sync_type.first) << " = true;\n";
+ dec_indent();
+ }
+ f << indent << "changed = true;\n";
+ }
+ dec_indent();
+ f << indent << "}\n";
+ } else {
+ f << indent << "changed |= " << mangle(wire) << ".commit();\n";
+ }
+ }
+ for (auto memory : module->memories) {
+ if (!writable_memories[memory.second])
+ continue;
+ f << indent << "changed |= " << mangle(memory.second) << ".commit();\n";
+ }
+ for (auto cell : module->cells()) {
+ if (is_internal_cell(cell->type))
+ continue;
+ f << indent << "changed |= " << mangle(cell) << ".commit();\n";
+ }
+ f << indent << "return changed;\n";
+ dec_indent();
+ f << "}\n";
+ f << "\n";
+ }
+
+ void dump_design(RTLIL::Design *design)
+ {
+ TopoSort<RTLIL::Module*> topo_design;
+ for (auto module : design->modules()) {
+ if (module->get_blackbox_attribute() || !design->selected_module(module))
+ continue;
+ topo_design.node(module);
+
+ for (auto cell : module->cells()) {
+ if (is_internal_cell(cell->type))
+ continue;
+ log_assert(design->has(cell->type));
+ topo_design.edge(design->module(cell->type), module);
+ }
+ }
+ log_assert(topo_design.sort());
+
+ if (split_intf) {
+ // The only thing more depraved than include guards, is mangling filenames to turn them into include guards.
+ std::string include_guard = design_ns + "_header";
+ std::transform(include_guard.begin(), include_guard.end(), include_guard.begin(), ::toupper);
+
+ f << "#ifndef " << include_guard << "\n";
+ f << "#define " << include_guard << "\n";
+ f << "\n";
+ f << "#include <backends/cxxrtl/cxxrtl.h>\n";
+ f << "\n";
+ f << "using namespace cxxrtl;\n";
+ f << "\n";
+ f << "namespace " << design_ns << " {\n";
+ f << "\n";
+ for (auto module : topo_design.sorted) {
+ if (!design->selected_module(module))
+ continue;
+ dump_module_intf(module);
+ }
+ f << "} // namespace " << design_ns << "\n";
+ f << "\n";
+ f << "#endif\n";
+ *intf_f << f.str(); f.str("");
+ }
+
+ if (split_intf)
+ f << "#include \"" << intf_filename << "\"\n";
+ else
+ f << "#include <backends/cxxrtl/cxxrtl.h>\n";
+ f << "\n";
+ f << "using namespace cxxrtl_yosys;\n";
+ f << "\n";
+ f << "namespace " << design_ns << " {\n";
+ f << "\n";
+ for (auto module : topo_design.sorted) {
+ if (!design->selected_module(module))
+ continue;
+ if (!split_intf)
+ dump_module_intf(module);
+ dump_module_impl(module);
+ }
+ f << "} // namespace " << design_ns << "\n";
+ *impl_f << f.str(); f.str("");
+ }
+
+ // Edge-type sync rules require us to emit edge detectors, which require coordination between
+ // eval and commit phases. To do this we need to collect them upfront.
+ //
+ // Note that the simulator commit phase operates at wire granularity but edge-type sync rules
+ // operate at wire bit granularity; it is possible to have code similar to:
+ // wire [3:0] clocks;
+ // always @(posedge clocks[0]) ...
+ // To handle this we track edge sensitivity both for wires and wire bits.
+ void register_edge_signal(SigMap &sigmap, RTLIL::SigSpec signal, RTLIL::SyncType type)
+ {
+ signal = sigmap(signal);
+ log_assert(signal.is_wire() && signal.is_bit());
+ log_assert(type == RTLIL::STp || type == RTLIL::STn || type == RTLIL::STe);
+
+ RTLIL::SigBit sigbit = signal[0];
+ if (!sync_types.count(sigbit))
+ sync_types[sigbit] = type;
+ else if (sync_types[sigbit] != type)
+ sync_types[sigbit] = RTLIL::STe;
+ sync_wires.insert(signal.as_wire());
+ }
+
+ void analyze_design(RTLIL::Design *design)
+ {
+ bool has_feedback_arcs = false;
+ for (auto module : design->modules()) {
+ if (!design->selected_module(module))
+ continue;
+
+ FlowGraph flow;
+ SigMap &sigmap = sigmaps[module];
+ sigmap.set(module);
+
+ for (auto conn : module->connections())
+ flow.add_node(conn);
+
+ dict<const RTLIL::Cell*, FlowGraph::Node*> memrw_cell_nodes;
+ dict<std::pair<RTLIL::SigBit, const RTLIL::Memory*>,
+ pool<const RTLIL::Cell*>> memwr_per_domain;
+ for (auto cell : module->cells()) {
+ FlowGraph::Node *node = flow.add_node(cell);
+
+ // Various DFF cells are treated like posedge/negedge processes, see above for details.
+ if (cell->type.in(ID($dff), ID($dffe), ID($adff), ID($dffsr))) {
+ if (cell->getPort(ID(CLK)).is_wire())
+ register_edge_signal(sigmap, cell->getPort(ID(CLK)),
+ cell->parameters[ID(CLK_POLARITY)].as_bool() ? RTLIL::STp : RTLIL::STn);
+ }
+ // Similar for memory port cells.
+ if (cell->type.in(ID($memrd), ID($memwr))) {
+ if (cell->getParam(ID(CLK_ENABLE)).as_bool()) {
+ if (cell->getPort(ID(CLK)).is_wire())
+ register_edge_signal(sigmap, cell->getPort(ID(CLK)),
+ cell->parameters[ID(CLK_POLARITY)].as_bool() ? RTLIL::STp : RTLIL::STn);
+ }
+ memrw_cell_nodes[cell] = node;
+ }
+ // Optimize access to read-only memories.
+ if (cell->type == ID($memwr))
+ writable_memories.insert(module->memories[cell->getParam(ID(MEMID)).decode_string()]);
+ // Collect groups of memory write ports in the same domain.
+ if (cell->type == ID($memwr) && cell->getParam(ID(CLK_ENABLE)).as_bool() && cell->getPort(ID(CLK)).is_wire()) {
+ RTLIL::SigBit clk_bit = sigmap(cell->getPort(ID(CLK)))[0];
+ const RTLIL::Memory *memory = module->memories[cell->getParam(ID(MEMID)).decode_string()];
+ memwr_per_domain[{clk_bit, memory}].insert(cell);
+ }
+ // Handling of packed memories is delegated to the `memory_unpack` pass, so we can rely on the presence
+ // of RTLIL memory objects and $memrd/$memwr/$meminit cells.
+ if (cell->type.in(ID($mem)))
+ log_assert(false);
+ }
+ for (auto cell : module->cells()) {
+ // Collect groups of memory write ports read by every transparent read port.
+ if (cell->type == ID($memrd) && cell->getParam(ID(CLK_ENABLE)).as_bool() && cell->getPort(ID(CLK)).is_wire() &&
+ cell->getParam(ID(TRANSPARENT)).as_bool()) {
+ RTLIL::SigBit clk_bit = sigmap(cell->getPort(ID(CLK)))[0];
+ const RTLIL::Memory *memory = module->memories[cell->getParam(ID(MEMID)).decode_string()];
+ for (auto memwr_cell : memwr_per_domain[{clk_bit, memory}]) {
+ transparent_for[cell].insert(memwr_cell);
+ // Our implementation of transparent $memrd cells reads \EN, \ADDR and \DATA from every $memwr cell
+ // in the same domain, which isn't directly visible in the netlist. Add these uses explicitly.
+ flow.add_uses(memrw_cell_nodes[cell], memwr_cell->getPort(ID(EN)));
+ flow.add_uses(memrw_cell_nodes[cell], memwr_cell->getPort(ID(ADDR)));
+ flow.add_uses(memrw_cell_nodes[cell], memwr_cell->getPort(ID(DATA)));
+ }
+ }
+ }
+
+ for (auto proc : module->processes) {
+ flow.add_node(proc.second);
+
+ for (auto sync : proc.second->syncs)
+ switch (sync->type) {
+ // Edge-type sync rules require pre-registration.
+ case RTLIL::STp:
+ case RTLIL::STn:
+ case RTLIL::STe:
+ register_edge_signal(sigmap, sync->signal, sync->type);
+ break;
+
+ // Level-type sync rules require no special handling.
+ case RTLIL::ST0:
+ case RTLIL::ST1:
+ case RTLIL::STa:
+ break;
+
+ // Handling of init-type sync rules is delegated to the `proc_init` pass, so we can use the wire
+ // attribute regardless of input.
+ case RTLIL::STi:
+ log_assert(false);
+
+ case RTLIL::STg:
+ log_cmd_error("Global clock is not supported.\n");
+ }
+ }
+
+ for (auto wire : module->wires()) {
+ if (!flow.is_elidable(wire)) continue;
+ if (wire->port_id != 0) continue;
+ if (wire->get_bool_attribute(ID(keep))) continue;
+ if (wire->name.begins_with("$") && !elide_internal) continue;
+ if (wire->name.begins_with("\\") && !elide_public) continue;
+ if (sync_wires[wire]) continue;
+ log_assert(flow.wire_defs[wire].size() == 1);
+ elided_wires[wire] = **flow.wire_defs[wire].begin();
+ }
+
+ // Elided wires that are outputs of internal cells are always connected to a well known port (Y).
+ // For user cells, there could be multiple of them, and we need a way to look up the port name
+ // knowing only the wire.
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections())
+ if (conn.second.is_wire() && elided_wires.count(conn.second.as_wire()))
+ cell_wire_defs[cell][conn.second.as_wire()] = conn.first;
+
+ dict<FlowGraph::Node*, pool<const RTLIL::Wire*>, hash_ptr_ops> node_defs;
+ for (auto wire_def : flow.wire_defs)
+ for (auto node : wire_def.second)
+ node_defs[node].insert(wire_def.first);
+
+ Scheduler<FlowGraph::Node> scheduler;
+ dict<FlowGraph::Node*, Scheduler<FlowGraph::Node>::Vertex*, hash_ptr_ops> node_map;
+ for (auto node : flow.nodes)
+ node_map[node] = scheduler.add(node);
+ for (auto node_def : node_defs) {
+ auto vertex = node_map[node_def.first];
+ for (auto wire : node_def.second)
+ for (auto succ_node : flow.wire_uses[wire]) {
+ auto succ_vertex = node_map[succ_node];
+ vertex->succs.insert(succ_vertex);
+ succ_vertex->preds.insert(vertex);
+ }
+ }
+
+ auto eval_order = scheduler.schedule();
+ pool<FlowGraph::Node*, hash_ptr_ops> evaluated;
+ pool<const RTLIL::Wire*> feedback_wires;
+ for (auto vertex : eval_order) {
+ auto node = vertex->data;
+ schedule[module].push_back(*node);
+ // Any wire that is an output of node vo and input of node vi where vo is scheduled later than vi
+ // is a feedback wire. Feedback wires indicate apparent logic loops in the design, which may be
+ // caused by a true logic loop, but usually are a benign result of dependency tracking that works
+ // on wire, not bit, level. Nevertheless, feedback wires cannot be localized.
+ evaluated.insert(node);
+ for (auto wire : node_defs[node])
+ for (auto succ_node : flow.wire_uses[wire])
+ if (evaluated[succ_node]) {
+ feedback_wires.insert(wire);
+ // Feedback wires may never be elided because feedback requires state, but the point of elision
+ // (and localization) is to eliminate state.
+ elided_wires.erase(wire);
+ }
+ }
+
+ if (!feedback_wires.empty()) {
+ has_feedback_arcs = true;
+ log("Module `%s` contains feedback arcs through wires:\n", module->name.c_str());
+ for (auto wire : feedback_wires) {
+ log(" %s\n", wire->name.c_str());
+ }
+ }
+
+ for (auto wire : module->wires()) {
+ if (feedback_wires[wire]) continue;
+ if (wire->port_id != 0) continue;
+ if (wire->get_bool_attribute(ID(keep))) continue;
+ if (wire->name.begins_with("$") && !localize_internal) continue;
+ if (wire->name.begins_with("\\") && !localize_public) continue;
+ if (sync_wires[wire]) continue;
+ // Outputs of FF/$memrd cells and LHS of sync actions do not end up in defs.
+ if (flow.wire_defs[wire].size() != 1) continue;
+ localized_wires.insert(wire);
+ }
+ }
+ if (has_feedback_arcs) {
+ log("Feedback arcs require delta cycles during evaluation.\n");
+ }
+ }
+
+ void check_design(RTLIL::Design *design, bool &has_sync_init, bool &has_packed_mem)
+ {
+ has_sync_init = has_packed_mem = false;
+
+ for (auto module : design->modules()) {
+ if (module->get_blackbox_attribute())
+ continue;
+
+ if (!design->selected_whole_module(module))
+ if (design->selected_module(module))
+ log_cmd_error("Can't handle partially selected module `%s`!\n", id2cstr(module->name));
+ if (!design->selected_module(module))
+ continue;
+
+ for (auto proc : module->processes)
+ for (auto sync : proc.second->syncs)
+ if (sync->type == RTLIL::STi)
+ has_sync_init = true;
+
+ for (auto cell : module->cells())
+ if (cell->type == ID($mem))
+ has_packed_mem = true;
+ }
+ }
+
+ void prepare_design(RTLIL::Design *design)
+ {
+ bool has_sync_init, has_packed_mem;
+ check_design(design, has_sync_init, has_packed_mem);
+ if (has_sync_init) {
+ // We're only interested in proc_init, but it depends on proc_prune and proc_clean, so call those
+ // in case they weren't already. (This allows `yosys foo.v -o foo.cc` to work.)
+ Pass::call(design, "proc_prune");
+ Pass::call(design, "proc_clean");
+ Pass::call(design, "proc_init");
+ }
+ if (has_packed_mem)
+ Pass::call(design, "memory_unpack");
+ // Recheck the design if it was modified.
+ if (has_sync_init || has_packed_mem)
+ check_design(design, has_sync_init, has_packed_mem);
+ log_assert(!(has_sync_init || has_packed_mem));
+
+ if (run_splitnets) {
+ Pass::call(design, "splitnets -driver");
+ Pass::call(design, "opt_clean -purge");
+ }
+ log("\n");
+ analyze_design(design);
+ }
+};
+
+struct CxxrtlBackend : public Backend {
+ static const int DEFAULT_OPT_LEVEL = 5;
+
+ CxxrtlBackend() : Backend("cxxrtl", "convert design to C++ RTL simulation") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_cxxrtl [options] [filename]\n");
+ log("\n");
+ log("Write C++ code for simulating the design. The generated code requires a driver\n");
+ log("that instantiates the design, toggles its clock, and interacts with its ports.\n");
+ log("\n");
+ log("The following driver may be used as an example for a design with a single clock\n");
+ log("driving rising edge triggered flip-flops:\n");
+ log("\n");
+ log(" #include \"top.cc\"\n");
+ log("\n");
+ log(" int main() {\n");
+ log(" cxxrtl_design::p_top top;\n");
+ log(" top.step();\n");
+ log(" while (1) {\n");
+ log(" /* user logic */\n");
+ log(" top.p_clk.next = value<1> {0u};\n");
+ log(" top.step();\n");
+ log(" top.p_clk.next = value<1> {1u};\n");
+ log(" top.step();\n");
+ log(" }\n");
+ log(" }\n");
+ log("\n");
+ log("Note that CXXRTL simulations, just like the hardware they are simulating, are\n");
+ log("subject to race conditions. If, in then example above, the user logic would run\n");
+ log("simultaneously with the rising edge of the clock, the design would malfunction.\n");
+ log("\n");
+ log("The following options are supported by this backend:\n");
+ log("\n");
+ log(" -header\n");
+ log(" generate separate interface (.h) and implementation (.cc) files.\n");
+ log(" if specified, the backend must be called with a filename, and filename\n");
+ log(" of the interface is derived from filename of the implementation.\n");
+ log(" otherwise, interface and implementation are generated together.\n");
+ log("\n");
+ log(" -namespace <ns-name>\n");
+ log(" place the generated code into namespace <ns-name>. if not specified,\n");
+ log(" \"cxxrtl_design\" is used.\n");
+ log("\n");
+ log(" -O <level>\n");
+ log(" set the optimization level. the default is -O%d. higher optimization\n", DEFAULT_OPT_LEVEL);
+ log(" levels dramatically decrease compile and run time, and highest level\n");
+ log(" possible for a design should be used.\n");
+ log("\n");
+ log(" -O0\n");
+ log(" no optimization.\n");
+ log("\n");
+ log(" -O1\n");
+ log(" elide internal wires if possible.\n");
+ log("\n");
+ log(" -O2\n");
+ log(" like -O1, and localize internal wires if possible.\n");
+ log("\n");
+ log(" -O3\n");
+ log(" like -O2, and elide public wires not marked (*keep*) if possible.\n");
+ log("\n");
+ log(" -O4\n");
+ log(" like -O3, and localize public wires not marked (*keep*) if possible.\n");
+ log("\n");
+ log(" -O5\n");
+ log(" like -O4, and run `splitnets -driver; opt_clean -purge` first.\n");
+ log("\n");
+ }
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ int opt_level = DEFAULT_OPT_LEVEL;
+ CxxrtlWorker worker;
+
+ log_header(design, "Executing CXXRTL backend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-O" && argidx+1 < args.size()) {
+ opt_level = std::stoi(args[++argidx]);
+ continue;
+ }
+ if (args[argidx].substr(0, 2) == "-O" && args[argidx].size() == 3 && isdigit(args[argidx][2])) {
+ opt_level = std::stoi(args[argidx].substr(2));
+ continue;
+ }
+ if (args[argidx] == "-header") {
+ worker.split_intf = true;
+ continue;
+ }
+ if (args[argidx] == "-namespace" && argidx+1 < args.size()) {
+ worker.design_ns = args[++argidx];
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ switch (opt_level) {
+ case 5:
+ worker.run_splitnets = true;
+ case 4:
+ worker.localize_public = true;
+ case 3:
+ worker.elide_public = true;
+ case 2:
+ worker.localize_internal = true;
+ case 1:
+ worker.elide_internal = true;
+ case 0:
+ break;
+ default:
+ log_cmd_error("Invalid optimization level %d.\n", opt_level);
+ }
+
+ std::ofstream intf_f;
+ if (worker.split_intf) {
+ if (filename == "<stdout>")
+ log_cmd_error("Option -header must be used with a filename.\n");
+
+ worker.intf_filename = filename.substr(0, filename.rfind('.')) + ".h";
+ intf_f.open(worker.intf_filename, std::ofstream::trunc);
+ if (intf_f.fail())
+ log_cmd_error("Can't open file `%s' for writing: %s\n",
+ worker.intf_filename.c_str(), strerror(errno));
+
+ worker.intf_f = &intf_f;
+ }
+ worker.impl_f = f;
+
+ worker.prepare_design(design);
+ worker.dump_design(design);
+ }
+} CxxrtlBackend;
+
+PRIVATE_NAMESPACE_END
diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h
new file mode 100644
index 000000000..fd390db79
--- /dev/null
+++ b/backends/cxxrtl/cxxrtl.h
@@ -0,0 +1,1141 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2019-2020 whitequark <whitequark@whitequark.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted.
+ *
+ * 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.
+ *
+ */
+
+// This file is included by the designs generated with `write_cxxrtl`. It is not used in Yosys itself.
+
+#ifndef CXXRTL_H
+#define CXXRTL_H
+
+#include <cstddef>
+#include <cstdint>
+#include <cassert>
+#include <limits>
+#include <type_traits>
+#include <tuple>
+#include <vector>
+#include <algorithm>
+#include <sstream>
+
+// The cxxrtl support library implements compile time specialized arbitrary width arithmetics, as well as provides
+// composite lvalues made out of bit slices and concatenations of lvalues. This allows the `write_cxxrtl` pass
+// to perform a straightforward translation of RTLIL structures to readable C++, relying on the C++ compiler
+// to unwrap the abstraction and generate efficient code.
+namespace cxxrtl {
+
+// All arbitrary-width values in cxxrtl are backed by arrays of unsigned integers called chunks. The chunk size
+// is the same regardless of the value width to simplify manipulating values via FFI interfaces, e.g. driving
+// and introspecting the simulation in Python.
+//
+// It is practical to use chunk sizes between 32 bits and platform register size because when arithmetics on
+// narrower integer types is legalized by the C++ compiler, it inserts code to clear the high bits of the register.
+// However, (a) most of our operations do not change those bits in the first place because of invariants that are
+// invisible to the compiler, (b) we often operate on non-power-of-2 values and have to clear the high bits anyway.
+// Therefore, using relatively wide chunks and clearing the high bits explicitly and only when we know they may be
+// clobbered results in simpler generated code.
+template<typename T>
+struct chunk_traits {
+ static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
+ "chunk type must be an unsigned integral type");
+ using type = T;
+ static constexpr size_t bits = std::numeric_limits<T>::digits;
+ static constexpr T mask = std::numeric_limits<T>::max();
+};
+
+template<class T>
+struct expr_base;
+
+template<size_t Bits>
+struct value : public expr_base<value<Bits>> {
+ static constexpr size_t bits = Bits;
+
+ using chunk = chunk_traits<uint32_t>;
+ static constexpr chunk::type msb_mask = (Bits % chunk::bits == 0) ? chunk::mask
+ : chunk::mask >> (chunk::bits - (Bits % chunk::bits));
+
+ static constexpr size_t chunks = (Bits + chunk::bits - 1) / chunk::bits;
+ chunk::type data[chunks] = {};
+
+ value() = default;
+ template<typename... Init>
+ explicit constexpr value(Init ...init) : data{init...} {}
+
+ value(const value<Bits> &) = default;
+ value(value<Bits> &&) = default;
+ value<Bits> &operator=(const value<Bits> &) = default;
+
+ // A (no-op) helper that forces the cast to value<>.
+ const value<Bits> &val() const {
+ return *this;
+ }
+
+ std::string str() const {
+ std::stringstream ss;
+ ss << *this;
+ return ss.str();
+ }
+
+ // Operations with compile-time parameters.
+ //
+ // These operations are used to implement slicing, concatenation, and blitting.
+ // The trunc, zext and sext operations add or remove most significant bits (i.e. on the left);
+ // the rtrunc and rzext operations add or remove least significant bits (i.e. on the right).
+ template<size_t NewBits>
+ value<NewBits> trunc() const {
+ static_assert(NewBits <= Bits, "trunc() may not increase width");
+ value<NewBits> result;
+ for (size_t n = 0; n < result.chunks; n++)
+ result.data[n] = data[n];
+ result.data[result.chunks - 1] &= result.msb_mask;
+ return result;
+ }
+
+ template<size_t NewBits>
+ value<NewBits> zext() const {
+ static_assert(NewBits >= Bits, "zext() may not decrease width");
+ value<NewBits> result;
+ for (size_t n = 0; n < chunks; n++)
+ result.data[n] = data[n];
+ return result;
+ }
+
+ template<size_t NewBits>
+ value<NewBits> sext() const {
+ static_assert(NewBits >= Bits, "sext() may not decrease width");
+ value<NewBits> result;
+ for (size_t n = 0; n < chunks; n++)
+ result.data[n] = data[n];
+ if (is_neg()) {
+ result.data[chunks - 1] |= ~msb_mask;
+ for (size_t n = chunks; n < result.chunks; n++)
+ result.data[n] = chunk::mask;
+ result.data[result.chunks - 1] &= result.msb_mask;
+ }
+ return result;
+ }
+
+ template<size_t NewBits>
+ value<NewBits> rtrunc() const {
+ static_assert(NewBits <= Bits, "rtrunc() may not increase width");
+ value<NewBits> result;
+ constexpr size_t shift_chunks = (Bits - NewBits) / chunk::bits;
+ constexpr size_t shift_bits = (Bits - NewBits) % chunk::bits;
+ chunk::type carry = 0;
+ if (shift_chunks + result.chunks < chunks) {
+ carry = (shift_bits == 0) ? 0
+ : data[shift_chunks + result.chunks] << (chunk::bits - shift_bits);
+ }
+ for (size_t n = result.chunks; n > 0; n--) {
+ result.data[n - 1] = carry | (data[shift_chunks + n - 1] >> shift_bits);
+ carry = (shift_bits == 0) ? 0
+ : data[shift_chunks + n - 1] << (chunk::bits - shift_bits);
+ }
+ return result;
+ }
+
+ template<size_t NewBits>
+ value<NewBits> rzext() const {
+ static_assert(NewBits >= Bits, "rzext() may not decrease width");
+ value<NewBits> result;
+ constexpr size_t shift_chunks = (NewBits - Bits) / chunk::bits;
+ constexpr size_t shift_bits = (NewBits - Bits) % chunk::bits;
+ chunk::type carry = 0;
+ for (size_t n = 0; n < chunks; n++) {
+ result.data[shift_chunks + n] = (data[n] << shift_bits) | carry;
+ carry = (shift_bits == 0) ? 0
+ : data[n] >> (chunk::bits - shift_bits);
+ }
+ if (carry != 0)
+ result.data[result.chunks - 1] = carry;
+ return result;
+ }
+
+ // Bit blit operation, i.e. a partial read-modify-write.
+ template<size_t Stop, size_t Start>
+ value<Bits> blit(const value<Stop - Start + 1> &source) const {
+ static_assert(Stop >= Start, "blit() may not reverse bit order");
+ constexpr chunk::type start_mask = ~(chunk::mask << (Start % chunk::bits));
+ constexpr chunk::type stop_mask = (Stop % chunk::bits + 1 == chunk::bits) ? 0
+ : (chunk::mask << (Stop % chunk::bits + 1));
+ value<Bits> masked = *this;
+ if (Start / chunk::bits == Stop / chunk::bits) {
+ masked.data[Start / chunk::bits] &= stop_mask | start_mask;
+ } else {
+ masked.data[Start / chunk::bits] &= start_mask;
+ for (size_t n = Start / chunk::bits + 1; n < Stop / chunk::bits; n++)
+ masked.data[n] = 0;
+ masked.data[Stop / chunk::bits] &= stop_mask;
+ }
+ value<Bits> shifted = source
+ .template rzext<Stop + 1>()
+ .template zext<Bits>();
+ return masked.bit_or(shifted);
+ }
+
+ // Helpers for selecting extending or truncating operation depending on whether the result is wider or narrower
+ // than the operand. In C++17 these can be replaced with `if constexpr`.
+ template<size_t NewBits, typename = void>
+ struct zext_cast {
+ value<NewBits> operator()(const value<Bits> &val) {
+ return val.template zext<NewBits>();
+ }
+ };
+
+ template<size_t NewBits>
+ struct zext_cast<NewBits, typename std::enable_if<(NewBits < Bits)>::type> {
+ value<NewBits> operator()(const value<Bits> &val) {
+ return val.template trunc<NewBits>();
+ }
+ };
+
+ template<size_t NewBits, typename = void>
+ struct sext_cast {
+ value<NewBits> operator()(const value<Bits> &val) {
+ return val.template sext<NewBits>();
+ }
+ };
+
+ template<size_t NewBits>
+ struct sext_cast<NewBits, typename std::enable_if<(NewBits < Bits)>::type> {
+ value<NewBits> operator()(const value<Bits> &val) {
+ return val.template trunc<NewBits>();
+ }
+ };
+
+ template<size_t NewBits>
+ value<NewBits> zcast() const {
+ return zext_cast<NewBits>()(*this);
+ }
+
+ template<size_t NewBits>
+ value<NewBits> scast() const {
+ return sext_cast<NewBits>()(*this);
+ }
+
+ // Operations with run-time parameters (offsets, amounts, etc).
+ //
+ // These operations are used for computations.
+ bool bit(size_t offset) const {
+ return data[offset / chunk::bits] & (1 << (offset % chunk::bits));
+ }
+
+ void set_bit(size_t offset, bool value = true) {
+ size_t offset_chunks = offset / chunk::bits;
+ size_t offset_bits = offset % chunk::bits;
+ data[offset_chunks] &= ~(1 << offset_bits);
+ data[offset_chunks] |= value ? 1 << offset_bits : 0;
+ }
+
+ bool is_zero() const {
+ for (size_t n = 0; n < chunks; n++)
+ if (data[n] != 0)
+ return false;
+ return true;
+ }
+
+ explicit operator bool() const {
+ return !is_zero();
+ }
+
+ bool is_neg() const {
+ return data[chunks - 1] & (1 << ((Bits - 1) % chunk::bits));
+ }
+
+ bool operator ==(const value<Bits> &other) const {
+ for (size_t n = 0; n < chunks; n++)
+ if (data[n] != other.data[n])
+ return false;
+ return true;
+ }
+
+ bool operator !=(const value<Bits> &other) const {
+ return !(*this == other);
+ }
+
+ value<Bits> bit_not() const {
+ value<Bits> result;
+ for (size_t n = 0; n < chunks; n++)
+ result.data[n] = ~data[n];
+ result.data[chunks - 1] &= msb_mask;
+ return result;
+ }
+
+ value<Bits> bit_and(const value<Bits> &other) const {
+ value<Bits> result;
+ for (size_t n = 0; n < chunks; n++)
+ result.data[n] = data[n] & other.data[n];
+ return result;
+ }
+
+ value<Bits> bit_or(const value<Bits> &other) const {
+ value<Bits> result;
+ for (size_t n = 0; n < chunks; n++)
+ result.data[n] = data[n] | other.data[n];
+ return result;
+ }
+
+ value<Bits> bit_xor(const value<Bits> &other) const {
+ value<Bits> result;
+ for (size_t n = 0; n < chunks; n++)
+ result.data[n] = data[n] ^ other.data[n];
+ return result;
+ }
+
+ value<Bits> update(const value<Bits> &val, const value<Bits> &mask) const {
+ return bit_and(mask.bit_not()).bit_or(val.bit_and(mask));
+ }
+
+ template<size_t AmountBits>
+ value<Bits> shl(const value<AmountBits> &amount) const {
+ // Ensure our early return is correct by prohibiting values larger than 4 Gbit.
+ static_assert(Bits <= chunk::mask, "shl() of unreasonably large values is not supported");
+ // Detect shifts definitely large than Bits early.
+ for (size_t n = 1; n < amount.chunks; n++)
+ if (amount.data[n] != 0)
+ return {};
+ // Past this point we can use the least significant chunk as the shift size.
+ size_t shift_chunks = amount.data[0] / chunk::bits;
+ size_t shift_bits = amount.data[0] % chunk::bits;
+ if (shift_chunks >= chunks)
+ return {};
+ value<Bits> result;
+ chunk::type carry = 0;
+ for (size_t n = 0; n < chunks - shift_chunks; n++) {
+ result.data[shift_chunks + n] = (data[n] << shift_bits) | carry;
+ carry = (shift_bits == 0) ? 0
+ : data[n] >> (chunk::bits - shift_bits);
+ }
+ return result;
+ }
+
+ template<size_t AmountBits, bool Signed = false>
+ value<Bits> shr(const value<AmountBits> &amount) const {
+ // Ensure our early return is correct by prohibiting values larger than 4 Gbit.
+ static_assert(Bits <= chunk::mask, "shr() of unreasonably large values is not supported");
+ // Detect shifts definitely large than Bits early.
+ for (size_t n = 1; n < amount.chunks; n++)
+ if (amount.data[n] != 0)
+ return {};
+ // Past this point we can use the least significant chunk as the shift size.
+ size_t shift_chunks = amount.data[0] / chunk::bits;
+ size_t shift_bits = amount.data[0] % chunk::bits;
+ if (shift_chunks >= chunks)
+ return {};
+ value<Bits> result;
+ chunk::type carry = 0;
+ for (size_t n = 0; n < chunks - shift_chunks; n++) {
+ result.data[chunks - shift_chunks - 1 - n] = carry | (data[chunks - 1 - n] >> shift_bits);
+ carry = (shift_bits == 0) ? 0
+ : data[chunks - 1 - n] << (chunk::bits - shift_bits);
+ }
+ if (Signed && is_neg()) {
+ for (size_t n = chunks - shift_chunks; n < chunks; n++)
+ result.data[n] = chunk::mask;
+ if (shift_bits != 0)
+ result.data[chunks - shift_chunks] |= chunk::mask << (chunk::bits - shift_bits);
+ }
+ return result;
+ }
+
+ template<size_t AmountBits>
+ value<Bits> sshr(const value<AmountBits> &amount) const {
+ return shr<AmountBits, /*Signed=*/true>(amount);
+ }
+
+ size_t ctpop() const {
+ size_t count = 0;
+ for (size_t n = 0; n < chunks; n++) {
+ // This loop implements the population count idiom as recognized by LLVM and GCC.
+ for (chunk::type x = data[n]; x != 0; count++)
+ x = x & (x - 1);
+ }
+ return count;
+ }
+
+ size_t ctlz() const {
+ size_t count = 0;
+ for (size_t n = 0; n < chunks; n++) {
+ chunk::type x = data[chunks - 1 - n];
+ if (x == 0) {
+ count += (n == 0 ? Bits % chunk::bits : chunk::bits);
+ } else {
+ // This loop implements the find first set idiom as recognized by LLVM.
+ for (; x != 0; count++)
+ x >>= 1;
+ }
+ }
+ return count;
+ }
+
+ template<bool Invert, bool CarryIn>
+ std::pair<value<Bits>, bool /*CarryOut*/> alu(const value<Bits> &other) const {
+ value<Bits> result;
+ bool carry = CarryIn;
+ for (size_t n = 0; n < result.chunks; n++) {
+ result.data[n] = data[n] + (Invert ? ~other.data[n] : other.data[n]) + carry;
+ carry = (result.data[n] < data[n]) ||
+ (result.data[n] == data[n] && carry);
+ }
+ result.data[result.chunks - 1] &= result.msb_mask;
+ return {result, carry};
+ }
+
+ value<Bits> add(const value<Bits> &other) const {
+ return alu</*Invert=*/false, /*CarryIn=*/false>(other).first;
+ }
+
+ value<Bits> sub(const value<Bits> &other) const {
+ return alu</*Invert=*/true, /*CarryIn=*/true>(other).first;
+ }
+
+ value<Bits> neg() const {
+ return value<Bits> { 0u }.sub(*this);
+ }
+
+ bool ucmp(const value<Bits> &other) const {
+ bool carry;
+ std::tie(std::ignore, carry) = alu</*Invert=*/true, /*CarryIn=*/true>(other);
+ return !carry; // a.ucmp(b) ≡ a u< b
+ }
+
+ bool scmp(const value<Bits> &other) const {
+ value<Bits> result;
+ bool carry;
+ std::tie(result, carry) = alu</*Invert=*/true, /*CarryIn=*/true>(other);
+ bool overflow = (is_neg() == !other.is_neg()) && (is_neg() != result.is_neg());
+ return result.is_neg() ^ overflow; // a.scmp(b) ≡ a s< b
+ }
+};
+
+// Expression template for a slice, usable as lvalue or rvalue, and composable with other expression templates here.
+template<class T, size_t Stop, size_t Start>
+struct slice_expr : public expr_base<slice_expr<T, Stop, Start>> {
+ static_assert(Stop >= Start, "slice_expr() may not reverse bit order");
+ static_assert(Start < T::bits && Stop < T::bits, "slice_expr() must be within bounds");
+ static constexpr size_t bits = Stop - Start + 1;
+
+ T &expr;
+
+ slice_expr(T &expr) : expr(expr) {}
+ slice_expr(const slice_expr<T, Stop, Start> &) = delete;
+
+ operator value<bits>() const {
+ return static_cast<const value<T::bits> &>(expr)
+ .template rtrunc<T::bits - Start>()
+ .template trunc<bits>();
+ }
+
+ slice_expr<T, Stop, Start> &operator=(const value<bits> &rhs) {
+ // Generic partial assignment implemented using a read-modify-write operation on the sliced expression.
+ expr = static_cast<const value<T::bits> &>(expr)
+ .template blit<Stop, Start>(rhs);
+ return *this;
+ }
+
+ // A helper that forces the cast to value<>, which allows deduction to work.
+ value<bits> val() const {
+ return static_cast<const value<bits> &>(*this);
+ }
+};
+
+// Expression template for a concatenation, usable as lvalue or rvalue, and composable with other expression templates here.
+template<class T, class U>
+struct concat_expr : public expr_base<concat_expr<T, U>> {
+ static constexpr size_t bits = T::bits + U::bits;
+
+ T &ms_expr;
+ U &ls_expr;
+
+ concat_expr(T &ms_expr, U &ls_expr) : ms_expr(ms_expr), ls_expr(ls_expr) {}
+ concat_expr(const concat_expr<T, U> &) = delete;
+
+ operator value<bits>() const {
+ value<bits> ms_shifted = static_cast<const value<T::bits> &>(ms_expr)
+ .template rzext<bits>();
+ value<bits> ls_extended = static_cast<const value<U::bits> &>(ls_expr)
+ .template zext<bits>();
+ return ms_shifted.bit_or(ls_extended);
+ }
+
+ concat_expr<T, U> &operator=(const value<bits> &rhs) {
+ ms_expr = rhs.template rtrunc<T::bits>();
+ ls_expr = rhs.template trunc<U::bits>();
+ return *this;
+ }
+
+ // A helper that forces the cast to value<>, which allows deduction to work.
+ value<bits> val() const {
+ return static_cast<const value<bits> &>(*this);
+ }
+};
+
+// Base class for expression templates, providing helper methods for operations that are valid on both rvalues and lvalues.
+//
+// Note that expression objects (slices and concatenations) constructed in this way should NEVER be captured because
+// they refer to temporaries that will, in general, only live until the end of the statement. For example, both of
+// these snippets perform use-after-free:
+//
+// const auto &a = val.slice<7,0>().slice<1>();
+// value<1> b = a;
+//
+// auto &&c = val.slice<7,0>().slice<1>();
+// c = value<1>{1u};
+//
+// An easy way to write code using slices and concatenations safely is to follow two simple rules:
+// * Never explicitly name any type except `value<W>` or `const value<W> &`.
+// * Never use a `const auto &` or `auto &&` in any such expression.
+// Then, any code that compiles will be well-defined.
+template<class T>
+struct expr_base {
+ template<size_t Stop, size_t Start = Stop>
+ slice_expr<const T, Stop, Start> slice() const {
+ return {*static_cast<const T *>(this)};
+ }
+
+ template<size_t Stop, size_t Start = Stop>
+ slice_expr<T, Stop, Start> slice() {
+ return {*static_cast<T *>(this)};
+ }
+
+ template<class U>
+ concat_expr<const T, typename std::remove_reference<const U>::type> concat(const U &other) const {
+ return {*static_cast<const T *>(this), other};
+ }
+
+ template<class U>
+ concat_expr<T, typename std::remove_reference<U>::type> concat(U &&other) {
+ return {*static_cast<T *>(this), other};
+ }
+};
+
+template<size_t Bits>
+std::ostream &operator<<(std::ostream &os, const value<Bits> &val) {
+ auto old_flags = os.flags(std::ios::right);
+ auto old_width = os.width(0);
+ auto old_fill = os.fill('0');
+ os << val.bits << '\'' << std::hex;
+ for (size_t n = val.chunks - 1; n != (size_t)-1; n--) {
+ if (n == val.chunks - 1 && Bits % value<Bits>::chunk::bits != 0)
+ os.width((Bits % value<Bits>::chunk::bits + 3) / 4);
+ else
+ os.width((value<Bits>::chunk::bits + 3) / 4);
+ os << val.data[n];
+ }
+ os.fill(old_fill);
+ os.width(old_width);
+ os.flags(old_flags);
+ return os;
+}
+
+template<size_t Bits>
+struct wire {
+ static constexpr size_t bits = Bits;
+
+ value<Bits> curr;
+ value<Bits> next;
+
+ wire() = default;
+ constexpr wire(const value<Bits> &init) : curr(init), next(init) {}
+ template<typename... Init>
+ explicit constexpr wire(Init ...init) : curr{init...}, next{init...} {}
+
+ wire(const wire<Bits> &) = delete;
+ wire(wire<Bits> &&) = default;
+ wire<Bits> &operator=(const wire<Bits> &) = delete;
+
+ bool commit() {
+ if (curr != next) {
+ curr = next;
+ return true;
+ }
+ return false;
+ }
+};
+
+template<size_t Bits>
+std::ostream &operator<<(std::ostream &os, const wire<Bits> &val) {
+ os << val.curr;
+ return os;
+}
+
+template<size_t Width>
+struct memory {
+ std::vector<value<Width>> data;
+
+ size_t depth() const {
+ return data.size();
+ }
+
+ memory() = delete;
+ explicit memory(size_t depth) : data(depth) {}
+
+ memory(const memory<Width> &) = delete;
+ memory<Width> &operator=(const memory<Width> &) = delete;
+
+ // The only way to get the compiler to put the initializer in .rodata and do not copy it on stack is to stuff it
+ // into a plain array. You'd think an std::initializer_list would work here, but it doesn't, because you can't
+ // construct an initializer_list in a constexpr (or something) and so if you try to do that the whole thing is
+ // first copied on the stack (probably overflowing it) and then again into `data`.
+ template<size_t Size>
+ struct init {
+ size_t offset;
+ value<Width> data[Size];
+ };
+
+ template<size_t... InitSize>
+ explicit memory(size_t depth, const init<InitSize> &...init) : data(depth) {
+ data.resize(depth);
+ // This utterly reprehensible construct is the most reasonable way to apply a function to every element
+ // of a parameter pack, if the elements all have different types and so cannot be cast to an initializer list.
+ auto _ = {std::move(std::begin(init.data), std::end(init.data), data.begin() + init.offset)...};
+ }
+
+ // An operator for direct memory reads. May be used at any time during the simulation.
+ const value<Width> &operator [](size_t index) const {
+ assert(index < data.size());
+ return data[index];
+ }
+
+ // An operator for direct memory writes. May only be used before the simulation is started. If used
+ // after the simulation is started, the design may malfunction.
+ value<Width> &operator [](size_t index) {
+ assert(index < data.size());
+ return data[index];
+ }
+
+ // A simple way to make a writable memory would be to use an array of wires instead of an array of values.
+ // However, there are two significant downsides to this approach: first, it has large overhead (2× space
+ // overhead, and O(depth) time overhead during commit); second, it does not simplify handling write port
+ // priorities. Although in principle write ports could be ordered or conditionally enabled in generated
+ // code based on their priorities and selected addresses, the feedback arc set problem is computationally
+ // expensive, and the heuristic based algorithms are not easily modified to guarantee (rather than prefer)
+ // a particular write port evaluation order.
+ //
+ // The approach used here instead is to queue writes into a buffer during the eval phase, then perform
+ // the writes during the commit phase in the priority order. This approach has low overhead, with both space
+ // and time proportional to the amount of write ports. Because virtually every memory in a practical design
+ // has at most two write ports, linear search is used on every write, being the fastest and simplest approach.
+ struct write {
+ size_t index;
+ value<Width> val;
+ value<Width> mask;
+ int priority;
+ };
+ std::vector<write> write_queue;
+
+ void update(size_t index, const value<Width> &val, const value<Width> &mask, int priority = 0) {
+ assert(index < data.size());
+ write_queue.emplace_back(write { index, val, mask, priority });
+ }
+
+ bool commit() {
+ bool changed = false;
+ std::sort(write_queue.begin(), write_queue.end(),
+ [](const write &a, const write &b) { return a.priority < b.priority; });
+ for (const write &entry : write_queue) {
+ value<Width> elem = data[entry.index];
+ elem = elem.update(entry.val, entry.mask);
+ changed |= (data[entry.index] != elem);
+ data[entry.index] = elem;
+ }
+ write_queue.clear();
+ return changed;
+ }
+};
+
+struct module {
+ module() {}
+ virtual ~module() {}
+
+ module(const module &) = delete;
+ module &operator=(const module &) = delete;
+
+ virtual void eval() = 0;
+ virtual bool commit() = 0;
+
+ size_t step() {
+ size_t deltas = 0;
+ do {
+ eval();
+ deltas++;
+ } while (commit());
+ return deltas;
+ }
+};
+
+} // namespace cxxrtl
+
+// Definitions of internal Yosys cells. Other than the functions in this namespace, cxxrtl is fully generic
+// and indepenent of Yosys implementation details.
+//
+// The `write_cxxrtl` pass translates internal cells (cells with names that start with `$`) to calls of these
+// functions. All of Yosys arithmetic and logical cells perform sign or zero extension on their operands,
+// whereas basic operations on arbitrary width values require operands to be of the same width. These functions
+// bridge the gap by performing the necessary casts. They are named similar to `cell_A[B]`, where A and B are `u`
+// if the corresponding operand is unsigned, and `s` if it is signed.
+namespace cxxrtl_yosys {
+
+using namespace cxxrtl;
+
+// std::max isn't constexpr until C++14 for no particular reason (it's an oversight), so we define our own.
+template<class T>
+constexpr T max(const T &a, const T &b) {
+ return a > b ? a : b;
+}
+
+// Logic operations
+template<size_t BitsY, size_t BitsA>
+value<BitsY> not_u(const value<BitsA> &a) {
+ return a.template zcast<BitsY>().bit_not();
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> not_s(const value<BitsA> &a) {
+ return a.template scast<BitsY>().bit_not();
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> logic_not_u(const value<BitsA> &a) {
+ return value<BitsY> { a ? 0u : 1u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> logic_not_s(const value<BitsA> &a) {
+ return value<BitsY> { a ? 0u : 1u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_and_u(const value<BitsA> &a) {
+ return value<BitsY> { a.bit_not().is_zero() ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_and_s(const value<BitsA> &a) {
+ return value<BitsY> { a.bit_not().is_zero() ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_or_u(const value<BitsA> &a) {
+ return value<BitsY> { a ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_or_s(const value<BitsA> &a) {
+ return value<BitsY> { a ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_xor_u(const value<BitsA> &a) {
+ return value<BitsY> { (a.ctpop() % 2) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_xor_s(const value<BitsA> &a) {
+ return value<BitsY> { (a.ctpop() % 2) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_xnor_u(const value<BitsA> &a) {
+ return value<BitsY> { (a.ctpop() % 2) ? 0u : 1u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_xnor_s(const value<BitsA> &a) {
+ return value<BitsY> { (a.ctpop() % 2) ? 0u : 1u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_bool_u(const value<BitsA> &a) {
+ return value<BitsY> { a ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> reduce_bool_s(const value<BitsA> &a) {
+ return value<BitsY> { a ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> and_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template zcast<BitsY>().bit_and(b.template zcast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> and_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template scast<BitsY>().bit_and(b.template scast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> or_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template zcast<BitsY>().bit_or(b.template zcast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> or_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template scast<BitsY>().bit_or(b.template scast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> xor_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template zcast<BitsY>().bit_xor(b.template zcast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> xor_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template scast<BitsY>().bit_xor(b.template scast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> xnor_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template zcast<BitsY>().bit_xor(b.template zcast<BitsY>()).bit_not();
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> xnor_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template scast<BitsY>().bit_xor(b.template scast<BitsY>()).bit_not();
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> logic_and_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return value<BitsY> { (bool(a) & bool(b)) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> logic_and_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return value<BitsY> { (bool(a) & bool(b)) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> logic_or_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return value<BitsY> { (bool(a) | bool(b)) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> logic_or_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return value<BitsY> { (bool(a) | bool(b)) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shl_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template zcast<BitsY>().template shl(b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shl_su(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template scast<BitsY>().template shl(b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> sshl_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template zcast<BitsY>().template shl(b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> sshl_su(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template scast<BitsY>().template shl(b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shr_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template shr(b).template zcast<BitsY>();
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shr_su(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template shr(b).template scast<BitsY>();
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> sshr_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template shr(b).template zcast<BitsY>();
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> sshr_su(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template shr(b).template scast<BitsY>();
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shift_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return shr_uu<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shift_su(const value<BitsA> &a, const value<BitsB> &b) {
+ return shr_su<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shift_us(const value<BitsA> &a, const value<BitsB> &b) {
+ return b.is_neg() ? shl_uu<BitsY>(a, b.template sext<BitsB + 1>().neg()) : shr_uu<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shift_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return b.is_neg() ? shl_su<BitsY>(a, b.template sext<BitsB + 1>().neg()) : shr_su<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shiftx_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return shift_uu<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shiftx_su(const value<BitsA> &a, const value<BitsB> &b) {
+ return shift_su<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shiftx_us(const value<BitsA> &a, const value<BitsB> &b) {
+ return shift_us<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> shiftx_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return shift_ss<BitsY>(a, b);
+}
+
+// Comparison operations
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> eq_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY>{ a.template zext<BitsExt>() == b.template zext<BitsExt>() ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> eq_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY>{ a.template sext<BitsExt>() == b.template sext<BitsExt>() ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> ne_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY>{ a.template zext<BitsExt>() != b.template zext<BitsExt>() ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> ne_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY>{ a.template sext<BitsExt>() != b.template sext<BitsExt>() ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> eqx_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return eq_uu<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> eqx_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return eq_ss<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> nex_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return ne_uu<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> nex_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return ne_ss<BitsY>(a, b);
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> gt_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY> { b.template zext<BitsExt>().ucmp(a.template zext<BitsExt>()) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> gt_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY> { b.template sext<BitsExt>().scmp(a.template sext<BitsExt>()) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> ge_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY> { !a.template zext<BitsExt>().ucmp(b.template zext<BitsExt>()) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> ge_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY> { !a.template sext<BitsExt>().scmp(b.template sext<BitsExt>()) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> lt_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY> { a.template zext<BitsExt>().ucmp(b.template zext<BitsExt>()) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> lt_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY> { a.template sext<BitsExt>().scmp(b.template sext<BitsExt>()) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> le_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY> { !b.template zext<BitsExt>().ucmp(a.template zext<BitsExt>()) ? 1u : 0u };
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> le_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t BitsExt = max(BitsA, BitsB);
+ return value<BitsY> { !b.template sext<BitsExt>().scmp(a.template sext<BitsExt>()) ? 1u : 0u };
+}
+
+// Arithmetic operations
+template<size_t BitsY, size_t BitsA>
+value<BitsY> pos_u(const value<BitsA> &a) {
+ return a.template zcast<BitsY>();
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> pos_s(const value<BitsA> &a) {
+ return a.template scast<BitsY>();
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> neg_u(const value<BitsA> &a) {
+ return a.template zcast<BitsY>().neg();
+}
+
+template<size_t BitsY, size_t BitsA>
+value<BitsY> neg_s(const value<BitsA> &a) {
+ return a.template scast<BitsY>().neg();
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> add_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template zcast<BitsY>().add(b.template zcast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> add_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template scast<BitsY>().add(b.template scast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> sub_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template zcast<BitsY>().sub(b.template zcast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> sub_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return a.template scast<BitsY>().sub(b.template scast<BitsY>());
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> mul_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ value<BitsY> product;
+ value<BitsY> multiplicand = a.template zcast<BitsY>();
+ const value<BitsB> &multiplier = b;
+ uint32_t multiplicand_shift = 0;
+ for (size_t step = 0; step < BitsB; step++) {
+ if (multiplier.bit(step)) {
+ multiplicand = multiplicand.shl(value<32> { multiplicand_shift });
+ product = product.add(multiplicand);
+ multiplicand_shift = 0;
+ }
+ multiplicand_shift++;
+ }
+ return product;
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> mul_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ value<BitsB + 1> ub = b.template sext<BitsB + 1>();
+ if (ub.is_neg()) ub = ub.neg();
+ value<BitsY> y = mul_uu<BitsY>(a.template scast<BitsY>(), ub);
+ return b.is_neg() ? y.neg() : y;
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+std::pair<value<BitsY>, value<BitsY>> divmod_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ constexpr size_t Bits = max(BitsY, max(BitsA, BitsB));
+ value<Bits> quotient;
+ value<Bits> dividend = a.template zext<Bits>();
+ value<Bits> divisor = b.template zext<Bits>();
+ if (dividend.ucmp(divisor))
+ return {/*quotient=*/value<BitsY> { 0u }, /*remainder=*/dividend.template trunc<BitsY>()};
+ uint32_t divisor_shift = dividend.ctlz() - divisor.ctlz();
+ divisor = divisor.shl(value<32> { divisor_shift });
+ for (size_t step = 0; step <= divisor_shift; step++) {
+ quotient = quotient.shl(value<1> { 1u });
+ if (!dividend.ucmp(divisor)) {
+ dividend = dividend.sub(divisor);
+ quotient.set_bit(0, true);
+ }
+ divisor = divisor.shr(value<1> { 1u });
+ }
+ return {quotient.template trunc<BitsY>(), /*remainder=*/dividend.template trunc<BitsY>()};
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+std::pair<value<BitsY>, value<BitsY>> divmod_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ value<BitsA + 1> ua = a.template sext<BitsA + 1>();
+ value<BitsB + 1> ub = b.template sext<BitsB + 1>();
+ if (ua.is_neg()) ua = ua.neg();
+ if (ub.is_neg()) ub = ub.neg();
+ value<BitsY> y, r;
+ std::tie(y, r) = divmod_uu<BitsY>(ua, ub);
+ if (a.is_neg() != b.is_neg()) y = y.neg();
+ if (a.is_neg()) r = r.neg();
+ return {y, r};
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> div_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return divmod_uu<BitsY>(a, b).first;
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> div_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return divmod_ss<BitsY>(a, b).first;
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> mod_uu(const value<BitsA> &a, const value<BitsB> &b) {
+ return divmod_uu<BitsY>(a, b).second;
+}
+
+template<size_t BitsY, size_t BitsA, size_t BitsB>
+value<BitsY> mod_ss(const value<BitsA> &a, const value<BitsB> &b) {
+ return divmod_ss<BitsY>(a, b).second;
+}
+
+// Memory helper
+struct memory_index {
+ bool valid;
+ size_t index;
+
+ template<size_t BitsAddr>
+ memory_index(const value<BitsAddr> &addr, size_t offset, size_t depth) {
+ static_assert(value<BitsAddr>::chunks <= 1, "memory address is too wide");
+ size_t offset_index = addr.data[0];
+
+ valid = (offset_index >= offset && offset_index < offset + depth);
+ index = offset_index - offset;
+ }
+};
+
+} // namespace cxxrtl_yosys
+
+#endif
diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index 1f750b359..fd7f20cc6 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -42,6 +42,13 @@ static const FDirection FD_OUT = 0x2;
static const FDirection FD_INOUT = 0x3;
static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width
+std::string getFileinfo(const RTLIL::AttrObject *design_entity)
+{
+ std::string src(design_entity->get_src_attribute());
+ std::string fileinfo_str = src.empty() ? "" : "@[" + src + "]";
+ return fileinfo_str;
+}
+
// Get a port direction with respect to a specific module.
FDirection getPortFDirection(IdString id, Module *module)
{
@@ -192,9 +199,10 @@ struct FirrtlWorker
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(""){}
+ memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
const char *atLine() {
if (srcLine == "") {
@@ -329,7 +337,8 @@ struct FirrtlWorker
log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
return;
}
- wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str()));
+ std::string cellFileinfo = getFileinfo(cell);
+ wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str(), cellFileinfo.c_str()));
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (it->second.size() > 0) {
@@ -370,7 +379,7 @@ struct FirrtlWorker
// as part of the coalesced subfield assignments for this wire.
register_reverse_wire_map(sourceExpr, *sinkSig);
} else {
- wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str()));
+ wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str(), cellFileinfo.c_str()));
}
}
}
@@ -394,12 +403,15 @@ struct FirrtlWorker
void run()
{
- f << stringf(" module %s:\n", make_id(module->name));
+ std::string moduleFileinfo = getFileinfo(module);
+ f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo.c_str());
vector<string> port_decls, wire_decls, cell_exprs, wire_exprs;
for (auto wire : module->wires())
{
const auto wireName = make_id(wire->name);
+ std::string wireFileinfo = getFileinfo(wire);
+
// If a wire has initial data, issue a warning since FIRRTL doesn't currently support it.
if (wire->attributes.count(ID::init)) {
log_warning("Initial value (%s) for (%s.%s) not supported\n",
@@ -410,12 +422,12 @@ struct FirrtlWorker
{
if (wire->port_input && wire->port_output)
log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
- port_decls.push_back(stringf(" %s %s: UInt<%d>\n", wire->port_input ? "input" : "output",
- wireName, wire->width));
+ port_decls.push_back(stringf(" %s %s: UInt<%d> %s\n", wire->port_input ? "input" : "output",
+ wireName, wire->width, wireFileinfo.c_str()));
}
else
{
- wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", wireName, wire->width));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", wireName, wire->width, wireFileinfo.c_str()));
}
}
@@ -423,7 +435,7 @@ struct FirrtlWorker
{
static Const ndef(0, 0);
- // Is this cell is a module instance?
+ // Is this cell is a module instance?
if (cell->type[0] != '$')
{
process_instance(cell, wire_exprs);
@@ -441,11 +453,12 @@ struct FirrtlWorker
string primop;
bool always_uint = false;
string y_id = make_id(cell->name);
+ std::string cellFileinfo = getFileinfo(cell);
if (cell->type.in(ID($not), ID($logic_not), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor)))
{
string a_expr = make_expr(cell->getPort(ID::A));
- wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), y_width, cellFileinfo.c_str()));
if (a_signed) {
a_expr = "asSInt(" + a_expr + ")";
@@ -464,16 +477,16 @@ struct FirrtlWorker
firrtl_is_signed = true; // Result of "neg" is signed (an SInt).
firrtl_width = a_width;
} else if (cell->type == ID($logic_not)) {
- primop = "eq";
- a_expr = stringf("%s, UInt(0)", a_expr.c_str());
- }
+ primop = "eq";
+ a_expr = stringf("%s, UInt(0)", a_expr.c_str());
+ }
else if (cell->type == ID($reduce_and)) primop = "andr";
else if (cell->type == ID($reduce_or)) primop = "orr";
else if (cell->type == ID($reduce_xor)) primop = "xorr";
else if (cell->type == ID($reduce_xnor)) {
- primop = "not";
- a_expr = stringf("xorr(%s)", a_expr.c_str());
- }
+ primop = "not";
+ a_expr = stringf("xorr(%s)", a_expr.c_str());
+ }
else if (cell->type == ID($reduce_bool)) {
primop = "neq";
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
@@ -485,18 +498,19 @@ struct FirrtlWorker
if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str());
- cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue;
}
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($xnor), ID($and), ID($or), ID($eq), ID($eqx),
- ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl),
- ID($logic_and), ID($logic_or), ID($pow)))
+ ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl),
+ ID($logic_and), ID($logic_or), ID($pow)))
{
string a_expr = make_expr(cell->getPort(ID::A));
string b_expr = make_expr(cell->getPort(ID::B));
- wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+ std::string cellFileinfo = getFileinfo(cell);
+ wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), y_width, cellFileinfo.c_str()));
if (a_signed) {
a_expr = "asSInt(" + a_expr + ")";
@@ -579,7 +593,7 @@ struct FirrtlWorker
primop = "eq";
always_uint = true;
firrtl_width = 1;
- }
+ }
else if ((cell->type == ID($ne)) | (cell->type == ID($nex))) {
primop = "neq";
always_uint = true;
@@ -712,7 +726,7 @@ struct FirrtlWorker
if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str());
- cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue;
@@ -724,11 +738,11 @@ struct FirrtlWorker
string a_expr = make_expr(cell->getPort(ID::A));
string b_expr = make_expr(cell->getPort(ID::B));
string s_expr = make_expr(cell->getPort(ID::S));
- wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), width));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), width, cellFileinfo.c_str()));
string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
- cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue;
@@ -867,9 +881,9 @@ struct FirrtlWorker
string expr = make_expr(cell->getPort(ID::D));
string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")";
- wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", y_id.c_str(), width, clk_expr.c_str()));
+ wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s %s\n", y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.c_str()));
- cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
register_reverse_wire_map(y_id, cell->getPort(ID::Q));
continue;
@@ -959,6 +973,7 @@ struct FirrtlWorker
for (auto wire : module->wires())
{
string expr;
+ std::string wireFileinfo = getFileinfo(wire);
if (wire->port_input)
continue;
@@ -1017,14 +1032,20 @@ struct FirrtlWorker
if (is_valid) {
if (make_unconn_id) {
- wire_decls.push_back(stringf(" wire %s: UInt<1>\n", unconn_id.c_str()));
+ wire_decls.push_back(stringf(" wire %s: UInt<1> %s\n", unconn_id.c_str(), wireFileinfo.c_str()));
+ // `invalid` is a firrtl construction for simulation so we will not
+ // tag it with a @[fileinfo] tag as it doesn't directly correspond to
+ // a specific line of verilog code.
wire_decls.push_back(stringf(" %s is invalid\n", unconn_id.c_str()));
}
- wire_exprs.push_back(stringf(" %s <= %s\n", make_id(wire->name), expr.c_str()));
+ wire_exprs.push_back(stringf(" %s <= %s %s\n", make_id(wire->name), expr.c_str(), wireFileinfo.c_str()));
} else {
if (make_unconn_id) {
unconn_id.clear();
}
+ // `invalid` is a firrtl construction for simulation so we will not
+ // tag it with a @[fileinfo] tag as it doesn't directly correspond to
+ // a specific line of verilog code.
wire_decls.push_back(stringf(" %s is invalid\n", make_id(wire->name)));
}
}
@@ -1123,7 +1144,8 @@ struct FirrtlBackend : public Backend {
if (top == nullptr)
top = last;
- *f << stringf("circuit %s:\n", make_id(top->name));
+ std::string circuitFileinfo = getFileinfo(top);
+ *f << stringf("circuit %s: %s\n", make_id(top->name), circuitFileinfo.c_str());
for (auto module : design->modules())
{
diff --git a/backends/json/json.cc b/backends/json/json.cc
index 6c924ff99..1da23bb7d 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -303,8 +303,13 @@ struct JsonBackend : public Backend {
log("The general syntax of the JSON output created by this command is as follows:\n");
log("\n");
log(" {\n");
+ log(" \"creator\": \"Yosys <version info>\",\n");
log(" \"modules\": {\n");
log(" <module_name>: {\n");
+ log(" \"attributes\": {\n");
+ log(" <attribute_name>: <attribute_value>,\n");
+ log(" ...\n");
+ log(" },\n");
log(" \"ports\": {\n");
log(" <port_name>: <port_details>,\n");
log(" ...\n");
@@ -329,13 +334,19 @@ struct JsonBackend : public Backend {
log(" {\n");
log(" \"direction\": <\"input\" | \"output\" | \"inout\">,\n");
log(" \"bits\": <bit_vector>\n");
+ log(" \"offset\": <the lowest bit index in use, if non-0>\n");
+ log(" \"upto\": <1 if the port bit indexing is MSB-first>\n");
log(" }\n");
log("\n");
+ log("The \"offset\" and \"upto\" fields are skipped if their value would be 0.");
+ log("They don't affect connection semantics, and are only used to preserve original");
+ log("HDL bit indexing.");
log("And <cell_details> is:\n");
log("\n");
log(" {\n");
log(" \"hide_name\": <1 | 0>,\n");
log(" \"type\": <cell_type>,\n");
+ log(" \"model\": <AIG model name, if -aig option used>,\n");
log(" \"parameters\": {\n");
log(" <parameter_name>: <parameter_value>,\n");
log(" ...\n");
@@ -359,6 +370,8 @@ struct JsonBackend : public Backend {
log(" {\n");
log(" \"hide_name\": <1 | 0>,\n");
log(" \"bits\": <bit_vector>\n");
+ log(" \"offset\": <the lowest bit index in use, if non-0>\n");
+ log(" \"upto\": <1 if the port bit indexing is MSB-first>\n");
log(" }\n");
log("\n");
log("The \"hide_name\" fields are set to 1 when the name of this cell or net is\n");
@@ -386,9 +399,15 @@ struct JsonBackend : public Backend {
log("\n");
log("Translates to the following JSON output:\n");
log("\n");
+
log(" {\n");
+ log(" \"creator\": \"Yosys 0.9+2406 (git sha1 fb1168d8, clang 9.0.1 -fPIC -Os)\",\n");
log(" \"modules\": {\n");
log(" \"test\": {\n");
+ log(" \"attributes\": {\n");
+ log(" \"cells_not_processed\": \"00000000000000000000000000000001\",\n");
+ log(" \"src\": \"test.v:1.1-4.10\"\n");
+ log(" },\n");
log(" \"ports\": {\n");
log(" \"x\": {\n");
log(" \"direction\": \"input\",\n");
@@ -404,33 +423,34 @@ struct JsonBackend : public Backend {
log(" \"hide_name\": 0,\n");
log(" \"type\": \"foo\",\n");
log(" \"parameters\": {\n");
- log(" \"Q\": 1337,\n");
- log(" \"P\": 42\n");
+ log(" \"P\": \"00000000000000000000000000101010\",\n");
+ log(" \"Q\": \"00000000000000000000010100111001\"\n");
log(" },\n");
log(" \"attributes\": {\n");
- log(" \"keep\": 1,\n");
- log(" \"src\": \"test.v:2\"\n");
+ log(" \"keep\": \"00000000000000000000000000000001\",\n");
+ log(" \"module_not_derived\": \"00000000000000000000000000000001\",\n");
+ log(" \"src\": \"test.v:3.1-3.55\"\n");
log(" },\n");
log(" \"connections\": {\n");
- log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ],\n");
+ log(" \"A\": [ 3, 2 ],\n");
log(" \"B\": [ 2, 3 ],\n");
- log(" \"A\": [ 3, 2 ]\n");
+ log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ]\n");
log(" }\n");
log(" }\n");
log(" },\n");
log(" \"netnames\": {\n");
- log(" \"y\": {\n");
+ log(" \"x\": {\n");
log(" \"hide_name\": 0,\n");
- log(" \"bits\": [ 3 ],\n");
+ log(" \"bits\": [ 2 ],\n");
log(" \"attributes\": {\n");
- log(" \"src\": \"test.v:1\"\n");
+ log(" \"src\": \"test.v:1.19-1.20\"\n");
log(" }\n");
log(" },\n");
- log(" \"x\": {\n");
+ log(" \"y\": {\n");
log(" \"hide_name\": 0,\n");
- log(" \"bits\": [ 2 ],\n");
+ log(" \"bits\": [ 3 ],\n");
log(" \"attributes\": {\n");
- log(" \"src\": \"test.v:1\"\n");
+ log(" \"src\": \"test.v:1.22-1.23\"\n");
log(" }\n");
log(" }\n");
log(" }\n");
diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc
index 68394a909..fb01308bd 100644
--- a/backends/smt2/Makefile.inc
+++ b/backends/smt2/Makefile.inc
@@ -6,23 +6,23 @@ ifneq ($(CONFIG),emcc)
# MSYS targets support yosys-smtbmc, but require a launcher script
ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
-TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py
+TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc.exe $(PROGRAM_PREFIX)yosys-smtbmc-script.py
# Needed to find the Python interpreter for yosys-smtbmc scripts.
# Override if necessary, it is only used for msys2 targets.
PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
-yosys-smtbmc-script.py: backends/smt2/smtbmc.py
- $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \
+$(PROGRAM_PREFIX)yosys-smtbmc-script.py: backends/smt2/smtbmc.py
+ $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' \
-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
-yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
+$(PROGRAM_PREFIX)yosys-smtbmc.exe: misc/launcher.c $(PROGRAM_PREFIX)yosys-smtbmc-script.py
$(P) $(CXX) -DGUI=0 -O -s -o $@ $<
# Other targets
else
-TARGETS += yosys-smtbmc
+TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc
-yosys-smtbmc: backends/smt2/smtbmc.py
- $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
+$(PROGRAM_PREFIX)yosys-smtbmc: backends/smt2/smtbmc.py
+ $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' < $< > $@.new
$(Q) chmod +x $@.new
$(Q) mv $@.new $@
endif
diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py
index 630464419..d3015b066 100644
--- a/backends/smt2/smtbmc.py
+++ b/backends/smt2/smtbmc.py
@@ -49,12 +49,12 @@ presat = False
smtcinit = False
smtctop = None
noinit = False
+binarymode = False
so = SmtOpts()
def usage():
- print("""
-yosys-smtbmc [options] <yosys_smt2_output>
+ print(os.path.basename(sys.argv[0]) + """ [options] <yosys_smt2_output>
-t <num_steps>
-t <skip_steps>:<num_steps>
@@ -150,6 +150,9 @@ yosys-smtbmc [options] <yosys_smt2_output>
add <num_steps> time steps at the end of the trace
when creating a counter example (this additional time
steps will still be constrained by assumptions)
+
+ --binary
+ dump anyconst values as raw bit strings
""" + so.helpmsg())
sys.exit(1)
@@ -158,7 +161,7 @@ try:
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts +
["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat",
"dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=",
- "smtc-init", "smtc-top=", "noinit"])
+ "smtc-init", "smtc-top=", "noinit", "binary"])
except:
usage()
@@ -229,6 +232,8 @@ for o, a in opts:
covermode = True
elif o == "-m":
topmod = a
+ elif o == "--binary":
+ binarymode = True
elif so.handle(o, a):
pass
else:
@@ -1089,9 +1094,15 @@ def print_anyconsts_worker(mod, state, path):
for fun, info in smt.modinfo[mod].anyconsts.items():
if info[1] is None:
- print_msg("Value for anyconst in %s (%s): %d" % (path, info[0], smt.bv2int(smt.get("(|%s| %s)" % (fun, state)))))
+ if not binarymode:
+ print_msg("Value for anyconst in %s (%s): %d" % (path, info[0], smt.bv2int(smt.get("(|%s| %s)" % (fun, state)))))
+ else:
+ print_msg("Value for anyconst in %s (%s): %s" % (path, info[0], smt.bv2bin(smt.get("(|%s| %s)" % (fun, state)))))
else:
- print_msg("Value for anyconst %s.%s (%s): %d" % (path, info[1], info[0], smt.bv2int(smt.get("(|%s| %s)" % (fun, state)))))
+ if not binarymode:
+ print_msg("Value for anyconst %s.%s (%s): %d" % (path, info[1], info[0], smt.bv2int(smt.get("(|%s| %s)" % (fun, state)))))
+ else:
+ print_msg("Value for anyconst %s.%s (%s): %s" % (path, info[1], info[0], smt.bv2bin(smt.get("(|%s| %s)" % (fun, state)))))
def print_anyconsts(state):
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 5467e250b..11b2ae10f 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -1984,7 +1984,7 @@ struct VerilogBackend : public Backend {
extra_args(f, filename, args, argidx);
if (extmem)
{
- if (filename.empty())
+ if (filename == "<stdout>")
log_cmd_error("Option -extmem must be used with a filename.\n");
extmem_prefix = filename.substr(0, filename.rfind('.'));
}
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index cbce0c990..92cf92fa8 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -30,7 +30,9 @@
#include <libkern/OSByteOrder.h>
#define __builtin_bswap32 OSSwapInt32
#endif
+#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
+#endif
#include <inttypes.h>
#include "kernel/yosys.h"
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 2b6002548..245a53611 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -1153,6 +1153,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire)
{
current_ast = ast;
+ current_ast_mod = nullptr;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
flag_no_dump_ptr = no_dump_ptr;
@@ -1219,6 +1220,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
}
design->add(process_module(*it, defer));
+ current_ast_mod = nullptr;
}
else if ((*it)->type == AST_PACKAGE) {
// process enum/other declarations
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index c0539252c..ab368fdb0 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -1326,20 +1326,25 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
{
if (width_hint < 0)
detectSignWidth(width_hint, sign_hint);
+ is_signed = sign_hint;
RTLIL::SigSpec cond = children[0]->genRTLIL();
RTLIL::SigSpec sig;
- if (cond.is_fully_const()) {
+
+ if (cond.is_fully_def())
+ {
if (cond.as_bool()) {
sig = children[1]->genRTLIL(width_hint, sign_hint);
- widthExtend(this, sig, sig.size(), children[1]->is_signed);
- }
- else {
+ log_assert(is_signed == children[1]->is_signed);
+ } else {
sig = children[2]->genRTLIL(width_hint, sign_hint);
- widthExtend(this, sig, sig.size(), children[2]->is_signed);
+ log_assert(is_signed == children[2]->is_signed);
}
+
+ widthExtend(this, sig, sig.size(), is_signed);
}
- else {
+ else
+ {
RTLIL::SigSpec val1 = children[1]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec val2 = children[2]->genRTLIL(width_hint, sign_hint);
@@ -1347,7 +1352,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
cond = uniop2rtlil(this, ID($reduce_bool), 1, cond, false);
int width = max(val1.size(), val2.size());
- is_signed = children[1]->is_signed && children[2]->is_signed;
+ log_assert(is_signed == children[1]->is_signed);
+ log_assert(is_signed == children[2]->is_signed);
widthExtend(this, val1, width, is_signed);
widthExtend(this, val2, width, is_signed);
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index b87af0f8c..372dcf95c 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -420,9 +420,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
current_scope[node->str] = node;
for (auto enode : node->children) {
log_assert(enode->type==AST_ENUM_ITEM);
- if (current_scope.count(enode->str) == 0) {
+ if (current_scope.count(enode->str) == 0)
current_scope[enode->str] = enode;
- }
+ else
+ log_file_error(filename, location.first_line, "enum item %s already exists\n", enode->str.c_str());
}
}
}
@@ -441,6 +442,29 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
+ // create name resolution entries for all objects with names
+ if (type == AST_PACKAGE) {
+ //add names to package scope
+ for (size_t i = 0; i < children.size(); i++) {
+ AstNode *node = children[i];
+ // these nodes appear at the top level in a package and can define names
+ if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_TYPEDEF) {
+ current_scope[node->str] = node;
+ }
+ if (node->type == AST_ENUM) {
+ current_scope[node->str] = node;
+ for (auto enode : node->children) {
+ log_assert(enode->type==AST_ENUM_ITEM);
+ if (current_scope.count(enode->str) == 0)
+ current_scope[enode->str] = enode;
+ else
+ log_file_error(filename, location.first_line, "enum item %s already exists in package\n", enode->str.c_str());
+ }
+ }
+ }
+ }
+
+
auto backup_current_block = current_block;
auto backup_current_block_child = current_block_child;
auto backup_current_top_block = current_top_block;
@@ -907,9 +931,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
);
}
//start building attribute string
- std::string enum_item_str = "\\enum_";
- enum_item_str.append(std::to_string(width));
- enum_item_str.append("_");
+ std::string enum_item_str = "\\enum_value_";
//get enum item value
if(enum_item->children[0]->type != AST_CONSTANT){
log_error("expected const, got %s for %s (%s)\n",
@@ -917,8 +939,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
enum_item->str.c_str(), enum_node->str.c_str()
);
}
- int val = enum_item->children[0]->asInt(is_signed);
- enum_item_str.append(std::to_string(val));
+ RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed);
+ enum_item_str.append(val.as_string());
//set attribute for available val to enum item name mappings
attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str);
}
@@ -1147,7 +1169,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// annotate identifiers using scope resolution and create auto-wires as needed
if (type == AST_IDENTIFIER) {
if (current_scope.count(str) == 0) {
- for (auto node : current_ast_mod->children) {
+ AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod;
+ for (auto node : current_scope_ast->children) {
//log("looking at mod scope child %s\n", type2str(node->type).c_str());
switch (node->type) {
case AST_PARAMETER:
@@ -1181,7 +1204,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
if (current_scope.count(str) == 0) {
- if (flag_autowire || str == "\\$global_clock") {
+ if (current_ast_mod == nullptr) {
+ log_file_error(filename, location.first_line, "Identifier `%s' is implicitly declared outside of a module.\n", str.c_str());
+ } else if (flag_autowire || str == "\\$global_clock") {
AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
auto_wire->str = str;
current_ast_mod->children.push_back(auto_wire);
diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l
index 4fd0ae855..62f53d18e 100644
--- a/frontends/ilang/ilang_lexer.l
+++ b/frontends/ilang/ilang_lexer.l
@@ -29,6 +29,7 @@
#pragma clang diagnostic ignored "-Wdeprecated-register"
#endif
+#include <cstdlib>
#include "frontends/ilang/ilang_frontend.h"
#include "ilang_parser.tab.hh"
@@ -88,7 +89,16 @@ USING_YOSYS_NAMESPACE
"."[0-9]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
[0-9]+'[01xzm-]* { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; }
--?[0-9]+ { rtlil_frontend_ilang_yylval.integer = atoi(yytext); return TOK_INT; }
+-?[0-9]+ {
+ char *end = nullptr;
+ long value = strtol(yytext, &end, 10);
+ if (end != yytext + strlen(yytext))
+ return TOK_INVALID; // literal out of range of long
+ if (value < INT_MIN || value > INT_MAX)
+ return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms)
+ rtlil_frontend_ilang_yylval.integer = value;
+ return TOK_INT;
+}
\" { BEGIN(STRING); }
<STRING>\\. { yymore(); }
@@ -136,4 +146,3 @@ USING_YOSYS_NAMESPACE
void *rtlil_frontend_ilang_avoid_input_warnings() {
return (void*)&yyinput;
}
-
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index 4e0b62edd..0522fa72a 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -169,7 +169,7 @@ wire_stmt:
current_wire->attributes = attrbuf;
attrbuf.clear();
} wire_options TOK_ID EOL {
- if (current_module->wires_.count($4) != 0)
+ if (current_module->wire($4) != nullptr)
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of wire %s.", $4).c_str());
current_module->rename(current_wire, $4);
free($4);
@@ -179,6 +179,9 @@ wire_options:
wire_options TOK_WIDTH TOK_INT {
current_wire->width = $3;
} |
+ wire_options TOK_WIDTH TOK_INVALID {
+ rtlil_frontend_ilang_yyerror("ilang error: invalid wire width");
+ } |
wire_options TOK_UPTO {
current_wire->upto = true;
} |
@@ -229,7 +232,7 @@ memory_options:
cell_stmt:
TOK_CELL TOK_ID TOK_ID EOL {
- if (current_module->cells_.count($3) != 0)
+ if (current_module->cell($3) != nullptr)
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell %s.", $3).c_str());
current_cell = current_module->addCell($3, $2);
current_cell->attributes = attrbuf;
@@ -424,9 +427,9 @@ sigspec:
delete $1;
} |
TOK_ID {
- if (current_module->wires_.count($1) == 0)
+ if (current_module->wire($1) == nullptr)
rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
- $$ = new RTLIL::SigSpec(current_module->wires_[$1]);
+ $$ = new RTLIL::SigSpec(current_module->wire($1));
free($1);
} |
sigspec '[' TOK_INT ']' {
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 3bffa3986..76373c2e4 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -521,7 +521,8 @@ package_body:
package_body_stmt:
typedef_decl |
- localparam_decl;
+ localparam_decl |
+ param_decl;
interface:
TOK_INTERFACE {
@@ -1735,7 +1736,6 @@ single_cell:
ast_stack.back()->children.push_back(new AstNode(AST_CELLARRAY, $2, astbuf2));
} '(' cell_port_list ')'{
SET_AST_NODE_LOC(astbuf2, @1, @$);
- SET_AST_NODE_LOC(astbuf3, @1, @$);
};
prim_list:
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
index e7cb312ed..996bda38e 100644
--- a/kernel/hashlib.h
+++ b/kernel/hashlib.h
@@ -314,11 +314,11 @@ class dict
int do_insert(const K &key, int &hash)
{
if (hashtable.empty()) {
- entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
+ entries.emplace_back(std::pair<K, T>(key, T()), -1);
do_rehash();
hash = do_hash(key);
} else {
- entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
+ entries.emplace_back(std::pair<K, T>(key, T()), hashtable[hash]);
hashtable[hash] = entries.size() - 1;
}
return entries.size() - 1;
@@ -327,11 +327,25 @@ class dict
int do_insert(const std::pair<K, T> &value, int &hash)
{
if (hashtable.empty()) {
- entries.push_back(entry_t(value, -1));
+ entries.emplace_back(value, -1);
do_rehash();
hash = do_hash(value.first);
} else {
- entries.push_back(entry_t(value, hashtable[hash]));
+ entries.emplace_back(value, hashtable[hash]);
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+ int do_insert(std::pair<K, T> &&rvalue, int &hash)
+ {
+ if (hashtable.empty()) {
+ auto key = rvalue.first;
+ entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), -1);
+ do_rehash();
+ hash = do_hash(key);
+ } else {
+ entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), hashtable[hash]);
hashtable[hash] = entries.size() - 1;
}
return entries.size() - 1;
@@ -441,6 +455,56 @@ public:
return std::pair<iterator, bool>(iterator(this, i), true);
}
+ std::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)
+ {
+ int hash = do_hash(rvalue.first);
+ int i = do_lookup(rvalue.first, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::forward<std::pair<K, T>>(rvalue), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K const &key, T const &value)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(key, value), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K const &key, T &&rvalue)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(key, std::forward<T>(rvalue)), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K &&rkey, T const &value)
+ {
+ int hash = do_hash(rkey);
+ int i = do_lookup(rkey, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(std::forward<K>(rkey), value), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)
+ {
+ int hash = do_hash(rkey);
+ int i = do_lookup(rkey, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(std::forward<K>(rkey), std::forward<T>(rvalue)), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
int erase(const K &key)
{
int hash = do_hash(key);
diff --git a/kernel/log.h b/kernel/log.h
index cd0e8185c..5478482ac 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -29,18 +29,25 @@
#if defined(__GNUC__) && !defined( __clang__) && ( __GNUC__ == 4 && __GNUC_MINOR__ <= 8)
#include <boost/xpressive/xpressive.hpp>
#define YS_REGEX_TYPE boost::xpressive::sregex
+ #define YS_REGEX_MATCH_TYPE boost::xpressive::smatch
#define YS_REGEX_NS boost::xpressive
#define YS_REGEX_COMPILE(param) boost::xpressive::sregex::compile(param, \
boost::xpressive::regex_constants::nosubs | \
boost::xpressive::regex_constants::optimize)
+ #define YS_REGEX_COMPILE_WITH_SUBS(param) boost::xpressive::sregex::compile(param, \
+ boost::xpressive::regex_constants::optimize)
# else
#include <regex>
#define YS_REGEX_TYPE std::regex
+ #define YS_REGEX_MATCH_TYPE std::smatch
#define YS_REGEX_NS std
#define YS_REGEX_COMPILE(param) std::regex(param, \
std::regex_constants::nosubs | \
std::regex_constants::optimize | \
std::regex_constants::egrep)
+ #define YS_REGEX_COMPILE_WITH_SUBS(param) std::regex(param, \
+ std::regex_constants::optimize | \
+ std::regex_constants::egrep)
#endif
#ifndef _WIN32
diff --git a/kernel/register.cc b/kernel/register.cc
index af8c1b8e8..925d0d776 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -485,20 +485,21 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
filename = arg;
+ //Accommodate heredocs with EOT marker spaced out from "<<", e.g. "<< EOT" vs. "<<EOT"
if (filename == "<<" && argidx+1 < args.size())
filename += args[++argidx];
if (filename.compare(0, 2, "<<") == 0) {
- if (Frontend::current_script_file == NULL)
- log_error("Unexpected here document '%s' outside of script!\n", filename.c_str());
if (filename.size() <= 2)
log_error("Missing EOT marker in here document!\n");
std::string eot_marker = filename.substr(2);
+ if (Frontend::current_script_file == nullptr)
+ filename = "<stdin>";
last_here_document.clear();
while (1) {
std::string buffer;
char block[4096];
while (1) {
- if (fgets(block, 4096, Frontend::current_script_file) == NULL)
+ if (fgets(block, 4096, Frontend::current_script_file == nullptr? stdin : Frontend::current_script_file) == nullptr)
log_error("Unexpected end of file in here document '%s'!\n", filename.c_str());
buffer += block;
if (buffer.size() > 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r'))
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 00c116115..6996a02c4 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -42,11 +42,58 @@ int RTLIL::IdString::last_created_idx_ptr_;
#endif
#define X(_id) IdString RTLIL::ID::_id;
-#include "constids.inc"
+#include "kernel/constids.inc"
#undef X
dict<std::string, std::string> RTLIL::constpad;
+const pool<IdString> &RTLIL::builtin_ff_cell_types() {
+ static const pool<IdString> res = {
+ ID($sr),
+ ID($ff),
+ ID($dff),
+ ID($dffe),
+ ID($dffsr),
+ ID($adff),
+ ID($dlatch),
+ ID($dlatchsr),
+ ID($_DFFE_NN_),
+ ID($_DFFE_NP_),
+ ID($_DFFE_PN_),
+ ID($_DFFE_PP_),
+ ID($_DFFSR_NNN_),
+ ID($_DFFSR_NNP_),
+ ID($_DFFSR_NPN_),
+ ID($_DFFSR_NPP_),
+ ID($_DFFSR_PNN_),
+ ID($_DFFSR_PNP_),
+ ID($_DFFSR_PPN_),
+ ID($_DFFSR_PPP_),
+ ID($_DFF_NN0_),
+ ID($_DFF_NN1_),
+ ID($_DFF_NP0_),
+ ID($_DFF_NP1_),
+ ID($_DFF_N_),
+ ID($_DFF_PN0_),
+ ID($_DFF_PN1_),
+ ID($_DFF_PP0_),
+ ID($_DFF_PP1_),
+ ID($_DFF_P_),
+ ID($_DLATCHSR_NNN_),
+ ID($_DLATCHSR_NNP_),
+ ID($_DLATCHSR_NPN_),
+ ID($_DLATCHSR_NPP_),
+ ID($_DLATCHSR_PNN_),
+ ID($_DLATCHSR_PNP_),
+ ID($_DLATCHSR_PPN_),
+ ID($_DLATCHSR_PPP_),
+ ID($_DLATCH_N_),
+ ID($_DLATCH_P_),
+ ID($_FF_),
+ };
+ return res;
+}
+
RTLIL::Const::Const()
{
flags = RTLIL::CONST_FLAG_NONE;
@@ -550,6 +597,7 @@ void RTLIL::Design::remove(RTLIL::Module *module)
}
log_assert(modules_.at(module->name) == module);
+ log_assert(refcount_modules_ == 0);
modules_.erase(module->name);
delete module;
}
@@ -720,6 +768,8 @@ void RTLIL::Module::makeblackbox()
delete it->second;
processes.clear();
+ connections_.clear();
+
remove(delwires);
set_bool_attribute(ID::blackbox);
}
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 7279835ea..17f038e36 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -377,12 +377,14 @@ namespace RTLIL
namespace ID {
#define X(_id) extern IdString _id;
-#include "constids.inc"
+#include "kernel/constids.inc"
#undef X
};
extern dict<std::string, std::string> constpad;
+ const pool<IdString> &builtin_ff_cell_types();
+
static inline std::string escape_id(const std::string &str) {
if (str.size() > 0 && str[0] != '\\' && str[0] != '$')
return "\\" + str;
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 380f7030b..01131601f 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -516,7 +516,7 @@ void yosys_setup()
already_setup = true;
#define X(_id) RTLIL::ID::_id = "\\" # _id;
-#include "constids.inc"
+#include "kernel/constids.inc"
#undef X
#ifdef WITH_PYTHON
@@ -835,7 +835,7 @@ std::string proc_share_dirname()
std::string proc_share_path = proc_self_path + "share/";
if (check_file_exists(proc_share_path, true))
return proc_share_path;
- proc_share_path = proc_self_path + "../share/yosys/";
+ proc_share_path = proc_self_path + "../share/" + proc_program_prefix()+ "yosys/";
if (check_file_exists(proc_share_path, true))
return proc_share_path;
# ifdef YOSYS_DATDIR
@@ -848,6 +848,15 @@ std::string proc_share_dirname()
}
#endif
+std::string proc_program_prefix()
+{
+ std::string program_prefix;
+#ifdef YOSYS_PROGRAM_PREFIX
+ program_prefix = YOSYS_PROGRAM_PREFIX;
+#endif
+ return program_prefix;
+}
+
bool fgetline(FILE *f, std::string &buffer)
{
buffer = "";
@@ -1034,6 +1043,8 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig
command = "verilog";
else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0)
command = "ilang";
+ else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".cc") == 0)
+ command = "cxxrtl";
else if (filename.size() > 4 && filename.compare(filename.size()-4, std::string::npos, ".aig") == 0)
command = "aiger";
else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".blif") == 0)
diff --git a/kernel/yosys.h b/kernel/yosys.h
index 16e0aaf1c..ed48eec09 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -117,6 +117,10 @@ extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *p
# define PATH_MAX MAX_PATH
# define isatty _isatty
# define fileno _fileno
+# else
+// mingw includes `wingdi.h` which defines a TRANSPARENT macro
+// that conflicts with X(TRANSPARENT) entry in kernel/constids.inc
+# undef TRANSPARENT
# endif
#endif
@@ -207,6 +211,7 @@ namespace RTLIL {
struct SigSpec;
struct Wire;
struct Cell;
+ struct Memory;
struct Module;
struct Design;
struct Monitor;
@@ -229,6 +234,7 @@ using RTLIL::Design;
namespace hashlib {
template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
+ template<> struct hash_ops<RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
@@ -236,6 +242,7 @@ namespace hashlib {
template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
+ template<> struct hash_ops<const RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
@@ -321,6 +328,7 @@ namespace ID = RTLIL::ID;
RTLIL::Design *yosys_get_design();
std::string proc_self_dirname();
std::string proc_share_dirname();
+std::string proc_program_prefix();
const char *create_prompt(RTLIL::Design *design, int recursion_counter);
std::vector<std::string> glob_filename(const std::string &filename_pattern);
void rewrite_filename(std::string &filename);
diff --git a/libs/sha1/sha1.h b/libs/sha1/sha1.h
index 9f526376e..b1346b548 100644
--- a/libs/sha1/sha1.h
+++ b/libs/sha1/sha1.h
@@ -35,9 +35,9 @@ public:
static std::string from_file(const std::string &filename);
private:
- static const unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */
- static const unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
- static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4;
+ static constexpr unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */
+ static constexpr unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
+ static constexpr unsigned int BLOCK_BYTES = BLOCK_INTS * 4;
uint32_t digest[DIGEST_INTS];
std::string buffer;
diff --git a/libs/subcircuit/subcircuit.cc b/libs/subcircuit/subcircuit.cc
index e8361a67e..4068dc09a 100644
--- a/libs/subcircuit/subcircuit.cc
+++ b/libs/subcircuit/subcircuit.cc
@@ -316,7 +316,7 @@ class SubCircuit::SolverWorker
// helper functions for handling permutations
- static const int maxPermutationsLimit = 1000000;
+ static constexpr int maxPermutationsLimit = 1000000;
static int numberOfPermutations(const std::vector<std::string> &list)
{
@@ -1689,4 +1689,3 @@ void SubCircuit::Solver::clearConfig()
{
worker->clearConfig();
}
-
diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex
index 4925defe3..988f034b4 100644
--- a/manual/command-reference-manual.tex
+++ b/manual/command-reference-manual.tex
@@ -116,20 +116,26 @@ library to a target architecture.
-g type1,type2,...
Map to the specified list of gate types. Supported gates types are:
- AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4.
+ AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX,
+ NMUX, AOI3, OAI3, AOI4, OAI4.
(The NOT gate is always added to this list automatically.)
The following aliases can be used to reference common sets of gate types:
simple: AND OR XOR MUX
- cmos2: NAND NOR
- cmos3: NAND NOR AOI3 OAI3
- cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4
- gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT
- aig: AND NAND OR NOR ANDNOT ORNOT
+ cmos2: NAND NOR
+ cmos3: NAND NOR AOI3 OAI3
+ cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4
+ cmos: NAND NOR AOI3 OAI3 AOI4 OAI4 NMUX MUX XOR XNOR
+ gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT
+ aig: AND NAND OR NOR ANDNOT ORNOT
+
+ The alias 'all' represent the full set of all gate types.
Prefix a gate type with a '-' to remove it from the list. For example
the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.
+ The default is 'all,-NMUX,-AOI3,-OAI3,-AOI4,-OAI4'.
+
-dff
also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many
clock domains are automatically partitioned in clock domains and each
@@ -156,6 +162,11 @@ library to a target architecture.
this attribute is a unique integer for each ABC process started. This
is useful for debugging the partitioning of clock domains.
+ -dress
+ run the 'dress' command after all other ABC commands. This aims to
+ preserve naming by an equivalence check between the original and post-ABC
+ netlists (experimental).
+
When neither -liberty nor -lut is used, the Yosys standard cell library is
loaded into ABC before the ABC script is executed.
@@ -163,12 +174,251 @@ Note that this is a logic optimization pass within Yosys that is calling ABC
internally. This is not going to "run ABC on your design". It will instead run
ABC on logic snippets extracted from your design. You will not get any useful
output when passing an ABC script that writes a file. Instead write your full
-design as BLIF file with write_blif and the load that into ABC externally if
+design as BLIF file with write_blif and then load that into ABC externally if
+you want to use ABC to convert your design into another format.
+
+[1] http://www.eecs.berkeley.edu/~alanmi/abc/
+\end{lstlisting}
+
+\section{abc9 -- use ABC9 for technology mapping}
+\label{cmd:abc9}
+\begin{lstlisting}[numbers=left,frame=single]
+ abc9 [options] [selection]
+
+This script pass performs a sequence of commands to facilitate the use of the ABC
+tool [1] for technology mapping of the current design to a target FPGA
+architecture. Only fully-selected modules are supported.
+
+ -run <from_label>:<to_label>
+ only run the commands between the labels (see below). an empty
+ from label is synonymous to 'begin', and empty to label is
+ synonymous to the end of the command list.
+
+ -exe <command>
+ use the specified command instead of "<yosys-bindir>/yosys-abc" to execute ABC.
+ This can e.g. be used to call a specific version of ABC or a wrapper.
+
+ -script <file>
+ use the specified ABC script file instead of the default script.
+
+ if <file> starts with a plus sign (+), then the rest of the filename
+ string is interpreted as the command string to be passed to ABC. The
+ leading plus sign is removed and all commas (,) in the string are
+ replaced with blanks before the string is passed to ABC.
+
+ if no -script parameter is given, the following scripts are used:
+ &scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -v; &mfs
+
+ -fast
+ use different default scripts that are slightly faster (at the cost
+ of output quality):
+ &if {C} {W} {D} {R} -v
+
+ -D <picoseconds>
+ set delay target. the string {D} in the default scripts above is
+ replaced by this option when used, and an empty string otherwise
+ (indicating best possible delay).
+
+ -lut <width>
+ generate netlist using luts of (max) the specified width.
+
+ -lut <w1>:<w2>
+ generate netlist using luts of (max) the specified width <w2>. All
+ luts with width <= <w1> have constant cost. for luts larger than <w1>
+ the area cost doubles with each additional input bit. the delay cost
+ is still constant for all lut widths.
+
+ -lut <file>
+ pass this file with lut library to ABC.
+
+ -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..
+ generate netlist using luts. Use the specified costs for luts with 1,
+ 2, 3, .. inputs.
+
+ -maxlut <width>
+ when auto-generating the lut library, discard all luts equal to or
+ greater than this size (applicable when neither -lut nor -luts is
+ specified).
+
+ -dff
+ also pass $_ABC9_FF_ cells through to ABC. modules with many clock
+ domains are marked as such and automatically partitioned by ABC.
+
+ -nocleanup
+ when this option is used, the temporary files created by this pass
+ are not removed. this is useful for debugging.
+
+ -showtmp
+ print the temp dir name in log. usually this is suppressed so that the
+ command output is identical across runs.
+
+ -box <file>
+ pass this file with box library to ABC.
+
+Note that this is a logic optimization pass within Yosys that is calling ABC
+internally. This is not going to "run ABC on your design". It will instead run
+ABC on logic snippets extracted from your design. You will not get any useful
+output when passing an ABC script that writes a file. Instead write your full
+design as an XAIGER file with `write_xaiger' and then load that into ABC
+externally if you want to use ABC to convert your design into another format.
+
+[1] http://www.eecs.berkeley.edu/~alanmi/abc/
+
+
+ pre:
+ abc9_ops -check
+ scc -set_attr abc9_scc_id {}
+ abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff] (option for -dff)
+ abc9_ops -prep_lut <maxlut> (skip if -lut or -luts)
+ abc9_ops -prep_box [-dff] (skip if -box)
+ select -set abc9_holes A:abc9_holes
+ flatten -wb @abc9_holes
+ techmap @abc9_holes
+ abc9_ops -prep_dff (only if -dff)
+ opt -purge @abc9_holes
+ aigmap
+ wbflip @abc9_holes
+
+ map:
+ foreach module in selection
+ abc9_ops -write_lut <abc-temp-dir>/input.lut (skip if '-lut' or '-luts')
+ abc9_ops -write_box <abc-temp-dir>/input.box
+ write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig
+ abc9_exe [options] -cwd <abc-temp-dir> [-lut <abc-temp-dir>/input.lut] -box <abc-temp-dir>/input.box
+ read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig
+ abc9_ops -reintegrate
+\end{lstlisting}
+
+\section{abc9\_exe -- use ABC9 for technology mapping}
+\label{cmd:abc9_exe}
+\begin{lstlisting}[numbers=left,frame=single]
+ abc9_exe [options]
+
+
+This pass uses the ABC tool [1] for technology mapping of the top module
+(according to the (* top *) attribute or if only one module is currently selected)
+to a target FPGA architecture.
+
+ -exe <command>
+ use the specified command instead of "<yosys-bindir>/yosys-abc" to execute ABC.
+ This can e.g. be used to call a specific version of ABC or a wrapper.
+
+ -script <file>
+ use the specified ABC script file instead of the default script.
+
+ if <file> starts with a plus sign (+), then the rest of the filename
+ string is interpreted as the command string to be passed to ABC. The
+ leading plus sign is removed and all commas (,) in the string are
+ replaced with blanks before the string is passed to ABC.
+
+ if no -script parameter is given, the following scripts are used:
+ &scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -v; &mfs
+
+ -fast
+ use different default scripts that are slightly faster (at the cost
+ of output quality):
+ &if {C} {W} {D} {R} -v
+
+ -D <picoseconds>
+ set delay target. the string {D} in the default scripts above is
+ replaced by this option when used, and an empty string otherwise
+ (indicating best possible delay).
+
+ -lut <width>
+ generate netlist using luts of (max) the specified width.
+
+ -lut <w1>:<w2>
+ generate netlist using luts of (max) the specified width <w2>. All
+ luts with width <= <w1> have constant cost. for luts larger than <w1>
+ the area cost doubles with each additional input bit. the delay cost
+ is still constant for all lut widths.
+
+ -lut <file>
+ pass this file with lut library to ABC.
+
+ -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..
+ generate netlist using luts. Use the specified costs for luts with 1,
+ 2, 3, .. inputs.
+
+ -showtmp
+ print the temp dir name in log. usually this is suppressed so that the
+ command output is identical across runs.
+
+ -box <file>
+ pass this file with box library to ABC.
+
+ -cwd <dir>
+ use this as the current working directory, inside which the 'input.xaig'
+ file is expected. temporary files will be created in this directory, and
+ the mapped result will be written to 'output.aig'.
+
+Note that this is a logic optimization pass within Yosys that is calling ABC
+internally. This is not going to "run ABC on your design". It will instead run
+ABC on logic snippets extracted from your design. You will not get any useful
+output when passing an ABC script that writes a file. Instead write your full
+design as BLIF file with write_blif and then load that into ABC externally if
you want to use ABC to convert your design into another format.
[1] http://www.eecs.berkeley.edu/~alanmi/abc/
\end{lstlisting}
+\section{abc9\_ops -- helper functions for ABC9}
+\label{cmd:abc9_ops}
+\begin{lstlisting}[numbers=left,frame=single]
+ abc9_ops [options] [selection]
+
+This pass contains a set of supporting operations for use during ABC technology
+mapping, and is expected to be called in conjunction with other operations from
+the `abc9' script pass. Only fully-selected modules are supported.
+
+ -check
+ check that the design is valid, e.g. (* abc9_box_id *) values are unique,
+ (* abc9_carry *) is only given for one input/output port, etc.
+
+ -prep_delays
+ insert `$__ABC9_DELAY' blackbox cells into the design to account for
+ certain required times.
+
+ -mark_scc
+ for an arbitrarily chosen cell in each unique SCC of each selected module
+ (tagged with an (* abc9_scc_id = <int> *) attribute), temporarily mark all
+ wires driven by this cell's outputs with a (* keep *) attribute in order
+ to break the SCC. this temporary attribute will be removed on -reintegrate.
+
+ -prep_xaiger
+ prepare the design for XAIGER output. this includes computing the
+ topological ordering of ABC9 boxes, as well as preparing the
+ '<module-name>$holes' module that contains the logic behaviour of ABC9
+ whiteboxes.
+
+ -dff
+ consider flop cells (those instantiating modules marked with (* abc9_flop *))
+ during -prep_{delays,xaiger,box}.
+
+ -prep_dff
+ compute the clock domain and initial value of each flop in the design.
+ process the '$holes' module to support clock-enable functionality.
+
+ -prep_lut <maxlut>
+ pre-compute the lut library by analysing all modules marked with
+ (* abc9_lut=<area> *).
+
+ -write_lut <dst>
+ write the pre-computed lut library to <dst>.
+
+ -prep_box
+ pre-compute the box library by analysing all modules marked with
+ (* abc9_box *).
+
+ -write_box <dst>
+ write the pre-computed box library to <dst>.
+
+ -reintegrate
+ for each selected module, re-intergrate the module '<module-name>$abc9'
+ by first recovering ABC9 boxes, and then stitching in the remaining primary
+ inputs and outputs.
+\end{lstlisting}
+
\section{add -- add objects to the design}
\label{cmd:add}
\begin{lstlisting}[numbers=left,frame=single]
@@ -189,6 +439,17 @@ than the object to be created.
Like 'add -input', but also connect the signal between instances of the
selected modules.
+
+
+ add {-assert|-assume|-live|-fair|-cover} <name1> [-if <name2>]
+
+Add an $assert, $assume, etc. cell connected to a wire named name1, with its
+enable signal optionally connected to a wire named name2 (default: 1'b1).
+
+
+ add -mod <name[s]>
+
+Add module[s] with the specified name[s].
\end{lstlisting}
\section{aigmap -- map logic to and-inverter-graph circuit}
@@ -201,6 +462,10 @@ $_NOT_ cells.
-nand
Enable creation of $_NAND_ cells
+
+ -select
+ Overwrite replaced cells in the current selection with new $_AND_,
+ $_NOT_, and $_NAND_, cells
\end{lstlisting}
\section{alumacc -- extract ALU and MACC cells}
@@ -212,7 +477,23 @@ This pass translates arithmetic operations like $add, $mul, $lt, etc. to $alu
and $macc cells.
\end{lstlisting}
-\section{assertpmux -- convert internal signals to module ports}
+\section{anlogic\_eqn -- Anlogic: Calculate equations for luts}
+\label{cmd:anlogic_eqn}
+\begin{lstlisting}[numbers=left,frame=single]
+ anlogic_eqn [selection]
+
+Calculate equations for luts since bitstream generator depends on it.
+\end{lstlisting}
+
+\section{anlogic\_fixcarry -- Anlogic: fix carry chain}
+\label{cmd:anlogic_fixcarry}
+\begin{lstlisting}[numbers=left,frame=single]
+ anlogic_fixcarry [options] [selection]
+
+Add Anlogic adders to fix carry chain if needed.
+\end{lstlisting}
+
+\section{assertpmux -- adds asserts for parallel muxes}
\label{cmd:assertpmux}
\begin{lstlisting}[numbers=left,frame=single]
assertpmux [options] [selection]
@@ -225,8 +506,8 @@ This command adds asserts to the design that assert that all parallel muxes
-always
usually the $pmux condition is only checked when the $pmux output
- is used be the mux tree it drives. this option will deactivate this
- additional constrained and check the $pmux condition always.
+ is used by the mux tree it drives. this option will deactivate this
+ additional constraint and check the $pmux condition always.
\end{lstlisting}
\section{async2sync -- convert async FF inputs to sync circuits}
@@ -242,7 +523,7 @@ a reset deasserts with the clock edge, then the FF output will still drive the
reset value in the next cycle regardless of the data-in value at the time of
the clock edge.
-Currently only $adff cells are supported by this pass.
+Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.
\end{lstlisting}
\section{attrmap -- renaming attributes}
@@ -250,7 +531,7 @@ Currently only $adff cells are supported by this pass.
\begin{lstlisting}[numbers=left,frame=single]
attrmap [options] [selection]
-This command renames attributes and/or mapps key/value pairs to
+This command renames attributes and/or maps key/value pairs to
other key/value pairs.
-tocase <name>
@@ -307,7 +588,16 @@ Move or copy attributes on wires to the cells driving them.
multiple times.
\end{lstlisting}
-\section{blackbox -- change type of cells in the design}
+\section{autoname -- automatically assign names to objects}
+\label{cmd:autoname}
+\begin{lstlisting}[numbers=left,frame=single]
+ autoname [selection]
+
+Assign auto-generated public names to objects with private names (the ones
+with $-prefix).
+\end{lstlisting}
+
+\section{blackbox -- convert modules into blackbox modules}
\label{cmd:blackbox}
\begin{lstlisting}[numbers=left,frame=single]
blackbox [options] [selection]
@@ -316,6 +606,58 @@ Convert modules into blackbox modules (remove contents and set the blackbox
module attribute).
\end{lstlisting}
+\section{bugpoint -- minimize testcases}
+\label{cmd:bugpoint}
+\begin{lstlisting}[numbers=left,frame=single]
+ bugpoint [options]
+
+This command minimizes testcases that crash Yosys. It removes an arbitrary part
+of the design and recursively invokes Yosys with a given script, repeating these
+steps while it can find a smaller design that still causes a crash. Once this
+command finishes, it replaces the current design with the smallest testcase it
+was able to produce.
+
+It is possible to specify the kinds of design part that will be removed. If none
+are specified, all parts of design will be removed.
+
+ -yosys <filename>
+ use this Yosys binary. if not specified, `yosys` is used.
+
+ -script <filename>
+ use this script to crash Yosys. required.
+
+ -grep <string>
+ only consider crashes that place this string in the log file.
+
+ -fast
+ run `proc_clean; clean -purge` after each minimization step. converges
+ faster, but produces larger testcases, and may fail to produce any
+ testcase at all if the crash is related to dangling wires.
+
+ -clean
+ run `proc_clean; clean -purge` before checking testcase and after
+ finishing. produces smaller and more useful testcases, but may fail to
+ produce any testcase at all if the crash is related to dangling wires.
+
+ -modules
+ try to remove modules.
+
+ -ports
+ try to remove module ports.
+
+ -cells
+ try to remove cells.
+
+ -connections
+ try to reconnect ports to 'x.
+
+ -assigns
+ try to remove process assigns from cases.
+
+ -updates
+ try to remove process updates from syncs.
+\end{lstlisting}
+
\section{cd -- a shortcut for 'select -module <name>'}
\label{cmd:cd}
\begin{lstlisting}[numbers=left,frame=single]
@@ -354,14 +696,24 @@ This pass identifies the following problems in the current design:
- used wires that do not have a driver
-When called with -noinit then this command also checks for wires which have
-the 'init' attribute set.
+Options:
+
+ -noinit
+ Also check for wires which have the 'init' attribute set.
-When called with -initdrv then this command also checks for wires which have
-the 'init' attribute set and aren't driven by a FF cell type.
+ -initdrv
+ Also check for wires that have the 'init' attribute set and are not
+ driven by an FF cell type.
-When called with -assert then the command will produce an error if any
-problems are found in the current design.
+ -mapped
+ Also check for internal cells that have not been mapped to cells of the
+ target architecture.
+
+ -allow-tbuf
+ Modify the -mapped behavior to still allow $_TBUF_ cells.
+
+ -assert
+ Produce a runtime error if any problems are found in the current design.
\end{lstlisting}
\section{chformal -- change formal constraints of the design}
@@ -370,7 +722,7 @@ problems are found in the current design.
chformal [types] [mode] [options] [selection]
Make changes to the formal constraints of the design. The [types] options
-the type of constraint to operate on. If none of the folling options is given,
+the type of constraint to operate on. If none of the following options are given,
the command will operate on all constraint types:
-assert $assert cells, representing assert(...) constraints
@@ -397,7 +749,7 @@ Exactly one of the following modes must be specified:
-assume2assert
-live2fair
-fair2live
- change the roles of cells as indicated. this options can be combined
+ change the roles of cells as indicated. these options can be combined
\end{lstlisting}
\section{chparam -- re-evaluate modules with new parameters}
@@ -452,6 +804,32 @@ implicit global clock. This is useful for formal verification of designs with
multiple clocks.
\end{lstlisting}
+\section{clkbufmap -- insert global buffers on clock networks}
+\label{cmd:clkbufmap}
+\begin{lstlisting}[numbers=left,frame=single]
+ clkbufmap [options] [selection]
+
+Inserts global buffers between nets connected to clock inputs and their drivers.
+
+In the absence of any selection, all wires without the 'clkbuf_inhibit'
+attribute will be considered for global buffer insertion.
+Alternatively, to consider all wires without the 'buffer_type' attribute set to
+'none' or 'bufr' one would specify:
+ 'w:* a:buffer_type=none a:buffer_type=bufr %u %d'
+as the selection.
+
+ -buf <celltype> <portname_out>:<portname_in>
+ Specifies the cell type to use for the global buffers
+ and its port names. The first port will be connected to
+ the clock network sinks, and the second will be connected
+ to the actual clock source. This option is required.
+
+ -inpad <celltype> <portname_out>:<portname_in>
+ If specified, a PAD cell of the given type is inserted on
+ clock nets that are also top module's inputs (in addition
+ to the global buffer).
+\end{lstlisting}
+
\section{connect -- create or remove connections}
\label{cmd:connect}
\begin{lstlisting}[numbers=left,frame=single]
@@ -483,6 +861,50 @@ be selected or an active module must be set using the 'cd' command.
This command does not operate on module with processes.
\end{lstlisting}
+\section{connect\_rpc -- connect to RPC frontend}
+\label{cmd:connect_rpc}
+\begin{lstlisting}[numbers=left,frame=single]
+ connect_rpc -exec <command> [args...]
+ connect_rpc -path <path>
+
+Load modules using an out-of-process frontend.
+
+ -exec <command> [args...]
+ run <command> with arguments [args...]. send requests on stdin, read
+ responses from stdout.
+
+ -path <path>
+ connect to Unix domain socket at <path>. (Unix)
+ connect to bidirectional byte-type named pipe at <path>. (Windows)
+
+A simple JSON-based, newline-delimited protocol is used for communicating with
+the frontend. Yosys requests data from the frontend by sending exactly 1 line
+of JSON. Frontend responds with data or error message by replying with exactly
+1 line of JSON as well.
+
+ -> {"method": "modules"}
+ <- {"modules": ["<module-name>", ...]}
+ <- {"error": "<error-message>"}
+ request for the list of modules that can be derived by this frontend.
+ the 'hierarchy' command will call back into this frontend if a cell
+ with type <module-name> is instantiated in the design.
+
+ -> {"method": "derive", "module": "<module-name">, "parameters": {
+ "<param-name>": {"type": "[unsigned|signed|string|real]",
+ "value": "<param-value>"}, ...}}
+ <- {"frontend": "[ilang|verilog|...]","source": "<source>"}}
+ <- {"error": "<error-message>"}
+ request for the module <module-name> to be derived for a specific set of
+ parameters. <param-name> starts with \ for named parameters, and with $
+ for unnamed parameters, which are numbered starting at 1.<param-value>
+ for integer parameters is always specified as a binary string of unlimited
+ precision. the <source> returned by the frontend is hygienically parsed
+ by a built-in Yosys <frontend>, allowing the RPC frontend to return any
+ convenient representation of the module. the derived module is cached,
+ so the response should be the same whenever the same set of parameters
+ is provided.
+\end{lstlisting}
+
\section{connwrappers -- match width of input-output port pairs}
\label{cmd:connwrappers}
\begin{lstlisting}[numbers=left,frame=single]
@@ -504,6 +926,14 @@ the driving cell.
The options -signed, -unsigned, and -port can be specified multiple times.
\end{lstlisting}
+\section{coolrunner2\_fixup -- insert necessary buffer cells for CoolRunner-II architecture}
+\label{cmd:coolrunner2_fixup}
+\begin{lstlisting}[numbers=left,frame=single]
+ coolrunner2_fixup [options] [selection]
+
+Insert necessary buffer cells for CoolRunner-II architecture.
+\end{lstlisting}
+
\section{coolrunner2\_sop -- break \$sop cells into ANDTERM/ORTERM cells}
\label{cmd:coolrunner2_sop}
\begin{lstlisting}[numbers=left,frame=single]
@@ -568,6 +998,26 @@ Hint: Use the following AWK command to consolidate Yosys coverage files:
Coverage counters are only available in Yosys for Linux.
\end{lstlisting}
+\section{cutpoint -- adds formal cut points to the design}
+\label{cmd:cutpoint}
+\begin{lstlisting}[numbers=left,frame=single]
+ cutpoint [options] [selection]
+
+This command adds formal cut points to the design.
+
+ -undef
+ set cupoint nets to undef (x). the default behavior is to create a
+ $anyseq cell and drive the cutpoint net from that
+\end{lstlisting}
+
+\section{debug -- run command with debug log messages enabled}
+\label{cmd:debug}
+\begin{lstlisting}[numbers=left,frame=single]
+ debug cmd
+
+Execute the specified command with debug log messages enabled
+\end{lstlisting}
+
\section{delete -- delete objects in the design}
\label{cmd:delete}
\begin{lstlisting}[numbers=left,frame=single]
@@ -614,6 +1064,11 @@ Save the current design under the given name and then clear the current design.
Push the current design to the stack and then clear the current design.
+ design -push-copy
+
+Push the current design to the stack without clearing the current design.
+
+
design -pop
Reset the current design and pop the last design from the stack.
@@ -649,6 +1104,14 @@ The Verilog front-end remembers defined macros and top-level declarations
between calls to 'read_verilog'. This command resets this memory.
\end{lstlisting}
+\section{determine\_init -- Determine the init value of cells}
+\label{cmd:determine_init}
+\begin{lstlisting}[numbers=left,frame=single]
+ determine_init [selection]
+
+Determine the init value of cells that doesn't allow unknown init value.
+\end{lstlisting}
+
\section{dff2dffe -- transform \$dff cells to \$dffe cells}
\label{cmd:dff2dffe}
\begin{lstlisting}[numbers=left,frame=single]
@@ -660,7 +1123,11 @@ $_DFF_P_, $_DFF_N_ and $_MUX_.
-unmap
operate in the opposite direction: replace $dffe cells with combinations
- of $dff and $mux cells. the options below are ignore in unmap mode.
+ of $dff and $mux cells. the options below are ignored in unmap mode.
+
+ -unmap-mince N
+ Same as -unmap but only unmap $dffe where the clock enable port
+ signal is used by less $dffe than the specified number
-direct <internal_gate_type> <external_gate_type>
map directly to external gate type. <internal_gate_type> can
@@ -686,6 +1153,10 @@ $_DFF_P_, $_DFF_N_ and $_MUX_.
Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before
dff2dffe for SR over CE priority.
+
+ -match-init
+ Disallow merging synchronous set/reset that has polarity opposite of the
+ output wire's init attribute (if any).
\end{lstlisting}
\section{dffinit -- set INIT param on FF cells}
@@ -704,6 +1175,16 @@ drives. (This is primarily used in FPGA flows.)
use the string values "high" and "low" to represent a single-bit
initial value of 1 or 0. (multi-bit values are not supported in this
mode.)
+
+ -strinit <string for high> <string for low>
+ use string values in the command line to represent a single-bit
+ initial value of 1 or 0. (multi-bit values are not supported in this
+ mode.)
+
+ -noreinit
+ fail if the FF cell has already a defined initial value set in other
+ passes and the initial value of the net it drives is not equal to
+ the already defined initial value.
\end{lstlisting}
\section{dfflibmap -- technology mapping of flip-flops}
@@ -722,15 +1203,6 @@ to the internal cell types that best match the cells found in the given
liberty file.
\end{lstlisting}
-\section{dffsr2dff -- convert DFFSR cells to simpler FF cell types}
-\label{cmd:dffsr2dff}
-\begin{lstlisting}[numbers=left,frame=single]
- dffsr2dff [options] [selection]
-
-This pass converts DFFSR cells ($dffsr, $_DFFSR_???_) and ADFF cells ($adff,
-$_DFF_???_) to simpler FF cell types when any of the set/reset inputs is unused.
-\end{lstlisting}
-
\section{dump -- print parts of the design in ilang format}
\label{cmd:dump}
\begin{lstlisting}[numbers=left,frame=single]
@@ -766,6 +1238,29 @@ Print all commands to log before executing them.
Do not print all commands to log before executing them. (default)
\end{lstlisting}
+\section{ecp5\_ffinit -- ECP5: handle FF init values}
+\label{cmd:ecp5_ffinit}
+\begin{lstlisting}[numbers=left,frame=single]
+ ecp5_ffinit [options] [selection]
+
+Remove init values for FF output signals when equal to reset value.
+If reset is not used, set the reset value to the init value, otherwise
+unmap out the reset (if not an async reset).
+\end{lstlisting}
+
+\section{ecp5\_gsr -- ECP5: handle GSR}
+\label{cmd:ecp5_gsr}
+\begin{lstlisting}[numbers=left,frame=single]
+ ecp5_gsr [options] [selection]
+
+Trim active low async resets connected to GSR and resolve GSR parameter,
+if a GSR or SGSR primitive is used in the design.
+
+If any cell has the GSR parameter set to "AUTO", this will be resolved
+to "ENABLED" if a GSR primitive is present and the (* nogsr *) attribute
+is not set, otherwise it will be resolved to "DISABLED".
+\end{lstlisting}
+
\section{edgetypes -- list all types of edges in selection}
\label{cmd:edgetypes}
\begin{lstlisting}[numbers=left,frame=single]
@@ -775,6 +1270,22 @@ This command lists all unique types of 'edges' found in the selection. An 'edge'
is a 4-tuple of source and sink cell type and port name.
\end{lstlisting}
+\section{efinix\_fixcarry -- Efinix: fix carry chain}
+\label{cmd:efinix_fixcarry}
+\begin{lstlisting}[numbers=left,frame=single]
+ efinix_fixcarry [options] [selection]
+
+Add Efinix adders to fix carry chain if needed.
+\end{lstlisting}
+
+\section{efinix\_gbuf -- Efinix: insert global clock buffers}
+\label{cmd:efinix_gbuf}
+\begin{lstlisting}[numbers=left,frame=single]
+ efinix_gbuf [options] [selection]
+
+Add Efinix global clock buffers to top module as needed.
+\end{lstlisting}
+
\section{equiv\_add -- add a \$equiv cell}
\label{cmd:equiv_add}
\begin{lstlisting}[numbers=left,frame=single]
@@ -872,6 +1383,65 @@ This creates a miter module for further analysis of the selected $equiv cells.
Create compare logic that handles undefs correctly
\end{lstlisting}
+\section{equiv\_opt -- prove equivalence for optimized circuit}
+\label{cmd:equiv_opt}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_opt [options] [command]
+
+This command uses temporal induction to check circuit equivalence before and
+after an optimization pass.
+
+ -run <from_label>:<to_label>
+ only run the commands between the labels (see below). an empty
+ from label is synonymous to the start of the command list, and empty to
+ label is synonymous to the end of the command list.
+
+ -map <filename>
+ expand the modules in this file before proving equivalence. this is
+ useful for handling architecture-specific primitives.
+
+ -blacklist <file>
+ Do not match cells or signals that match the names in the file
+ (passed to equiv_make).
+
+ -assert
+ produce an error if the circuits are not equivalent.
+
+ -multiclock
+ run clk2fflogic before equivalence checking.
+
+ -async2sync
+ run async2sync before equivalence checking.
+
+ -undef
+ enable modelling of undef states during equiv_induct.
+
+The following commands are executed by this verification command:
+
+ run_pass:
+ hierarchy -auto-top
+ design -save preopt
+ [command]
+ design -stash postopt
+
+ prepare:
+ design -copy-from preopt -as gold A:top
+ design -copy-from postopt -as gate A:top
+
+ techmap: (only with -map)
+ techmap -wb -D EQUIV -autoproc -map <filename> ...
+
+ prove:
+ clk2fflogic (only with -multiclock)
+ async2sync (only with -async2sync)
+ equiv_make -blacklist <filename> ... gold gate equiv
+ equiv_induct [-undef] equiv
+ equiv_status [-assert] equiv
+
+ restore:
+ design -load preopt
+\end{lstlisting}
+
\section{equiv\_purge -- purge equivalence checking module}
\label{cmd:equiv_purge}
\begin{lstlisting}[numbers=left,frame=single]
@@ -984,6 +1554,37 @@ inputs.
then all output ports of the current module are used.
\end{lstlisting}
+\section{exec -- execute commands in the operating system shell}
+\label{cmd:exec}
+\begin{lstlisting}[numbers=left,frame=single]
+ exec [options] -- [command]
+
+Execute a command in the operating system shell. All supplied arguments are
+concatenated and passed as a command to popen(3). Whitespace is not guaranteed
+to be preserved, even if quoted. stdin and stderr are not connected, while stdout is
+logged unless the "-q" option is specified.
+
+
+ -q
+ Suppress stdout and stderr from subprocess
+
+ -expect-return <int>
+ Generate an error if popen() does not return specified value.
+ May only be specified once; the final specified value is controlling
+ if specified multiple times.
+
+ -expect-stdout <regex>
+ Generate an error if the specified regex does not match any line
+ in subprocess's stdout. May be specified multiple times.
+
+ -not-expect-stdout <regex>
+ Generate an error if the specified regex matches any line
+ in subprocess's stdout. May be specified multiple times.
+
+
+ Example: exec -q -expect-return 0 -- echo "bananapie" | grep "nana"
+\end{lstlisting}
+
\section{expose -- convert internal signals to module ports}
\label{cmd:expose}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1117,7 +1718,16 @@ counter cells. Use a target-specific 'techmap' map file to convert those cells
to the actual target cells.
-maxwidth N
- Only extract counters up to N bits wide
+ Only extract counters up to N bits wide (default 64)
+
+ -minwidth N
+ Only extract counters at least N bits wide (default 2)
+
+ -allow_arst yes|no
+ Allow counters to have async reset (default yes)
+
+ -dir up|down|both
+ Look for up-counters, down-counters, or both (default down)
-pout X,Y,...
Only allow parallel output from the counter to the listed cell types
@@ -1165,10 +1775,30 @@ parts of the design to AND/OR/XOR cells, and run extract_reduce a second time.
cell will remain, driving its original loads.
\end{lstlisting}
+\section{extractinv -- extract explicit inverter cells for invertible cell pins}
+\label{cmd:extractinv}
+\begin{lstlisting}[numbers=left,frame=single]
+ extractinv [options] [selection]
+
+Searches the design for all cells with invertible pins controlled by a cell
+parameter (eg. IS_CLK_INVERTED on many Xilinx cells) and removes the parameter.
+If the parameter was set to 1, inserts an explicit inverter cell in front of
+the pin instead. Normally used for output to ISE, which does not support the
+inversion parameters.
+
+To mark a cell port as invertible, use (* invertible_pin = "param_name" *)
+on the wire in the blackbox module. The parameter value should have
+the same width as the port, and will be effectively XORed with it.
+
+ -inv <celltype> <portname_out>:<portname_in>
+ Specifies the cell type to use for the inverters and its port names.
+ This option is required.
+\end{lstlisting}
+
\section{flatten -- flatten design}
\label{cmd:flatten}
\begin{lstlisting}[numbers=left,frame=single]
- flatten [selection]
+ flatten [options] [selection]
This pass flattens the design by replacing cells by their implementation. This
pass is very similar to the 'techmap' pass. The only difference is that this
@@ -1176,6 +1806,105 @@ pass is using the current design as mapping library.
Cells and/or modules with the 'keep_hierarchy' attribute set will not be
flattened by this command.
+
+ -wb
+ Ignore the 'whitebox' attribute on cell implementations.
+\end{lstlisting}
+
+\section{flowmap -- pack LUTs with FlowMap}
+\label{cmd:flowmap}
+\begin{lstlisting}[numbers=left,frame=single]
+ flowmap [options] [selection]
+
+This pass uses the FlowMap technology mapping algorithm to pack logic gates
+into k-LUTs with optimal depth. It allows mapping any circuit elements that can
+be evaluated with the `eval` pass, including cells with multiple output ports
+and multi-bit input and output ports.
+
+ -maxlut k
+ perform technology mapping for a k-LUT architecture. if not specified,
+ defaults to 3.
+
+ -minlut n
+ only produce n-input or larger LUTs. if not specified, defaults to 1.
+
+ -cells <cell>[,<cell>,...]
+ map specified cells. if not specified, maps $_NOT_, $_AND_, $_OR_,
+ $_XOR_ and $_MUX_, which are the outputs of the `simplemap` pass.
+
+ -relax
+ perform depth relaxation and area minimization.
+
+ -r-alpha n, -r-beta n, -r-gamma n
+ parameters of depth relaxation heuristic potential function.
+ if not specified, alpha=8, beta=2, gamma=1.
+
+ -optarea n
+ optimize for area by trading off at most n logic levels for fewer LUTs.
+ n may be zero, to optimize for area without increasing depth.
+ implies -relax.
+
+ -debug
+ dump intermediate graphs.
+
+ -debug-relax
+ explain decisions performed during depth relaxation.
+\end{lstlisting}
+
+\section{fmcombine -- combine two instances of a cell into one}
+\label{cmd:fmcombine}
+\begin{lstlisting}[numbers=left,frame=single]
+ fmcombine [options] module_name gold_cell gate_cell
+
+This pass takes two cells, which are instances of the same module, and replaces
+them with one instance of a special 'combined' module, that effectively
+contains two copies of the original module, plus some formal properties.
+
+This is useful for formal test benches that check what differences in behavior
+a slight difference in input causes in a module.
+
+ -initeq
+ Insert assumptions that initially all FFs in both circuits have the
+ same initial values.
+
+ -anyeq
+ Do not duplicate $anyseq/$anyconst cells.
+
+ -fwd
+ Insert forward hint assumptions into the combined module.
+
+ -bwd
+ Insert backward hint assumptions into the combined module.
+ (Backward hints are logically equivalend to fordward hits, but
+ some solvers are faster with bwd hints, or even both -bwd and -fwd.)
+
+ -nop
+ Don't insert hint assumptions into the combined module.
+ (This should not provide any speedup over the original design, but
+ strangely sometimes it does.)
+
+If none of -fwd, -bwd, and -nop is given, then -fwd is used as default.
+\end{lstlisting}
+
+\section{fminit -- set init values/sequences for formal}
+\label{cmd:fminit}
+\begin{lstlisting}[numbers=left,frame=single]
+ fminit [options] <selection>
+
+This pass creates init constraints (for example for reset sequences) in a formal
+model.
+
+ -seq <signal> <sequence>
+ Set sequence using comma-separated list of values, use 'z for
+ unconstrained bits. The last value is used for the remainder of the
+ trace.
+
+ -set <signal> <value>
+ Add constant value constraint
+
+ -posedge <signal>
+ -negedge <signal>
+ Set clock for init sequences
\end{lstlisting}
\section{freduce -- perform functional reduction}
@@ -1393,15 +2122,16 @@ Merge GP_INV cells with GP_DFF* and GP_DLATCH* cells.
In parametric designs, a module might exists in several variations with
different parameter values. This pass looks at all modules in the current
design an re-runs the language frontends for the parametric modules as
-needed.
+needed. It also resolves assignments to wired logic data types (wand/wor),
+resolves positional module parameters, unroll array instances, and more.
-check
also check the design hierarchy. this generates an error when
an unknown module is used as cell type.
-simcheck
- like -check, but also thow an error if blackbox modules are
- instantiated, and throw an error if the design has no top module
+ like -check, but also throw an error if blackbox modules are
+ instantiated, and throw an error if the design has no top module.
-purge_lib
by default the hierarchy command will not remove library (blackbox)
@@ -1414,20 +2144,23 @@ needed.
-keep_positionals
per default this pass also converts positional arguments in cells
- to arguments using port names. this option disables this behavior.
+ to arguments using port names. This option disables this behavior.
-keep_portwidths
per default this pass adjusts the port width on cells that are
- module instances when the width does not match the module port. this
+ module instances when the width does not match the module port. This
option disables this behavior.
+ -nodefaults
+ do not resolve input port default values
+
-nokeep_asserts
per default this pass sets the "keep" attribute on all modules
- that directly or indirectly contain one or more $assert cells. this
- option disables this behavior.
+ that directly or indirectly contain one or more formal properties.
+ This option disables this behavior.
-top <module>
- use the specified top module to built a design hierarchy. modules
+ use the specified top module to build the design hierarchy. Modules
outside this tree (unused modules) are removed.
when the -top option is used, the 'top' attribute will be set on the
@@ -1437,6 +2170,12 @@ needed.
-auto-top
automatically determine the top of the design hierarchy and mark it.
+ -chparam name value
+ elaborate the top module using this parameter value. Modules on which
+ this parameter does not exist may cause a warning message to be output.
+ This option can be specified multiple times to override multiple
+ parameters. String values must be passed in double quotes (").
+
In -generate mode this pass generates blackbox modules for the given cell
types (wildcards supported). For this the design is searched for cells that
match the given types and then the given port declarations are used to
@@ -1483,6 +2222,33 @@ all commands executed in an interactive session, but not the commands
from executed scripts.
\end{lstlisting}
+\section{ice40\_braminit -- iCE40: perform SB\_RAM40\_4K initialization from file}
+\label{cmd:ice40_braminit}
+\begin{lstlisting}[numbers=left,frame=single]
+ ice40_braminit
+
+This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE
+parameter and converts it into the required INIT_x attributes
+\end{lstlisting}
+
+\section{ice40\_dsp -- iCE40: map multipliers}
+\label{cmd:ice40_dsp}
+\begin{lstlisting}[numbers=left,frame=single]
+ ice40_dsp [options] [selection]
+
+Map multipliers ($mul/SB_MAC16) and multiply-accumulate ($mul/SB_MAC16 + $add)
+cells into iCE40 DSP resources.
+Currently, only the 16x16 multiply mode is supported and not the 2 x 8x8 mode.
+
+Pack input registers (A, B, {C,D}; with optional hold), pipeline registers
+({F,J,K,G}, H), output registers (O -- full 32-bits or lower 16-bits only; with
+optional hold), and post-adder into into the SB_MAC16 resource.
+
+Multiply-accumulate operations using the post-adder with feedback on the {C,D}
+input will be folded into the DSP. In this scenario only, resetting the
+the accumulator to an arbitrary value can be inferred to use the {C,D} input.
+\end{lstlisting}
+
\section{ice40\_ffinit -- iCE40: handle FF init values}
\label{cmd:ice40_ffinit}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1514,9 +2280,24 @@ This command executes the following script:
opt_rmdff
opt_clean
while <changed design>
+\end{lstlisting}
+
+\section{ice40\_wrapcarry -- iCE40: wrap carries}
+\label{cmd:ice40_wrapcarry}
+\begin{lstlisting}[numbers=left,frame=single]
+ ice40_wrapcarry [selection]
-When called with the option -unlut, this command will transform all already
-mapped SB_LUT4 cells back to logic.
+Wrap manually instantiated SB_CARRY cells, along with their associated SB_LUT4s,
+into an internal $__ICE40_CARRY_WRAPPER cell for preservation across technology
+mapping.
+
+Attributes on both cells will have their names prefixed with 'SB_CARRY.' or
+'SB_LUT4.' and attached to the wrapping cell.
+A (* keep *) attribute on either cell will be logically OR-ed together.
+
+ -unwrap
+ unwrap $__ICE40_CARRY_WRAPPER cells back into SB_CARRYs and SB_LUT4s,
+ including restoring their attributes.
\end{lstlisting}
\section{insbuf -- insert buffer cells for connected wires}
@@ -1561,6 +2342,11 @@ the resulting cells to more sophisticated PAD cells.
of the tristate driver and the 2nd portname is the internal output
buffering the external signal.
+ -ignore <celltype> <portname>[:<portname>]*
+ Skips mapping inputs/outputs that are already connected to given
+ ports of the given cell. Can be used multiple times. This is in
+ addition to the cells specified as mapping targets.
+
-widthparam <param_name>
Use the specified parameter name to set the port width.
@@ -1588,6 +2374,10 @@ Write a JSON netlist of all selected objects.
-aig
also include AIG models for the different gate types
+ -compat-int
+ emit 32-bit or smaller fully-defined parameter values directly
+ as JSON numbers (for compatibility with old parsers)
+
See 'help write_json' for a description of the JSON format used.
\end{lstlisting}
@@ -1615,6 +2405,44 @@ logfiles.
do not append a newline
\end{lstlisting}
+\section{logger -- set logger properties}
+\label{cmd:logger}
+\begin{lstlisting}[numbers=left,frame=single]
+ logger [options]
+
+This command sets global logger properties, also available using command line
+options.
+
+ -[no]time
+ enable/disable display of timestamp in log output.
+
+ -[no]stderr
+ enable/disable logging errors to stderr.
+
+ -warn regex
+ print a warning for all log messages matching the regex.
+
+ -nowarn regex
+ if a warning message matches the regex, it is printed as regular
+ message instead.
+
+ -werror regex
+ if a warning message matches the regex, it is printed as error
+ message instead and the tool terminates with a nonzero return code.
+
+ -[no]debug
+ globally enable/disable debug log messages.
+
+ -experimental <feature>
+ do not print warnings for the specified experimental feature
+
+ -expect <type> <regex> <expected_count>
+ expect log,warning or error to appear. In case of error return code is 0.
+
+ -expect-no-warnings
+ gives error in case there is at least one warning that is not expected.
+\end{lstlisting}
+
\section{ls -- list modules or objects in modules}
\label{cmd:ls}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1661,6 +2489,7 @@ is used then the $macc cell is mapped to $add, $sub, etc. cells instead.
This pass calls all the other memory_* passes in a useful order:
+ opt_mem
memory_dff [-nordff] (-memx implies -nordff)
opt_clean
memory_share
@@ -1683,8 +2512,13 @@ This pass converts the multi-port $mem memory cells into block ram instances.
The given rules file describes the available resources and how they should be
used.
-The rules file contains a set of block ram description and a sequence of match
-rules. A block ram description looks like this:
+The rules file contains configuration options, a set of block ram description
+and a sequence of match rules.
+
+The option 'attr_icase' configures how attribute values are matched. The value 0
+means case-sensitive, 1 means case-insensitive.
+
+A block ram description looks like this:
bram RAMB1024X32 # name of BRAM cell
init 1 # set to '1' if BRAM can be initialized
@@ -1745,6 +2579,13 @@ It is possible to match against the following values with min/max rules:
dcells ....... number of cells in 'data-direction'
cells ........ total number of cells (acells*dcells*dups)
+A match containing the command 'attribute' followed by a list of space
+separated 'name[=string_value]' values requires that the memory contains any
+one of the given attribute name and string values (where specified), or name
+and integer 1 value (if no string_value given, since Verilog will interpret
+'(* attr *)' as '(* attr=1 *)').
+A name prefixed with '!' indicates that the attribute must not exist.
+
The interface for the created bram instances is derived from the bram
description. Use 'techmap' to convert the created bram instances into
instances of the actual bram cells of your target architecture.
@@ -1788,10 +2629,22 @@ interface and yields a synchronous memory port.
\section{memory\_map -- translate multiport memories to basic cells}
\label{cmd:memory_map}
\begin{lstlisting}[numbers=left,frame=single]
- memory_map [selection]
+ memory_map [options] [selection]
This pass converts multiport memory cells as generated by the memory_collect
pass to word-wide DFFs and address decoders.
+
+ -attr !<name>
+ do not map memories that have attribute <name> set.
+
+ -attr <name>[=<value>]
+ for memories that have attribute <name> set, only map them if its value
+ is a string <value> (if specified), or an integer 1 (otherwise). if this
+ option is specified multiple times, map the memory if the attribute is
+ to any of the values.
+
+ -iattr
+ for -attr, ignore case of <value>.
\end{lstlisting}
\section{memory\_memx -- emulate vlog sim behavior for mem ports}
@@ -1872,7 +2725,7 @@ detected.
also create an 'assert' cell that checks if trigger is always low.
-flatten
- call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.
+ call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.
miter -assert [options] module [miter_name]
@@ -1886,7 +2739,70 @@ module is modified.
keep module output ports.
-flatten
- call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.
+ call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.
+\end{lstlisting}
+
+\section{mutate -- generate or apply design mutations}
+\label{cmd:mutate}
+\begin{lstlisting}[numbers=left,frame=single]
+ mutate -list N [options] [selection]
+
+Create a list of N mutations using an even sampling.
+
+ -o filename
+ Write list to this file instead of console output
+
+ -s filename
+ Write a list of all src tags found in the design to the specified file
+
+ -seed N
+ RNG seed for selecting mutations
+
+ -none
+ Include a "none" mutation in the output
+
+ -ctrl name width value
+ Add -ctrl options to the output. Use 'value' for first mutation, then
+ simply count up from there.
+
+ -mode name
+ -module name
+ -cell name
+ -port name
+ -portbit int
+ -ctrlbit int
+ -wire name
+ -wirebit int
+ -src string
+ Filter list of mutation candidates to those matching
+ the given parameters.
+
+ -cfg option int
+ Set a configuration option. Options available:
+ weight_pq_w weight_pq_b weight_pq_c weight_pq_s
+ weight_pq_mw weight_pq_mb weight_pq_mc weight_pq_ms
+ weight_cover pick_cover_prcnt
+
+
+ mutate -mode MODE [options]
+
+Apply the given mutation.
+
+ -ctrl name width value
+ Add a control signal with the given name and width. The mutation is
+ activated if the control signal equals the given value.
+
+ -module name
+ -cell name
+ -port name
+ -portbit int
+ -ctrlbit int
+ Mutation parameters, as generated by 'mutate -list N'.
+
+ -wire name
+ -wirebit int
+ -src string
+ Ignored. (They are generated by -list for documentation purposes.)
\end{lstlisting}
\section{muxcover -- cover trees of MUX cells with wider MUXes}
@@ -1896,14 +2812,43 @@ module is modified.
Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells
- -mux4, -mux8, -mux16
- Use the specified types of MUXes. If none of those options are used,
- the effect is the same as if all of them where used.
+ -mux4[=cost], -mux8[=cost], -mux16[=cost]
+ Cover $_MUX_ trees using the specified types of MUXes (with optional
+ integer costs). If none of these options are given, the effect is the
+ same as if all of them are.
+ Default costs: $_MUX4_ = 220, $_MUX8_ = 460,
+ $_MUX16_ = 940
+
+ -mux2=cost
+ Use the specified cost for $_MUX_ cells when making covering decisions.
+ Default cost: $_MUX_ = 100
+
+ -dmux=cost
+ Use the specified cost for $_MUX_ cells used in decoders.
+ Default cost: 90
-nodecode
Do not insert decoder logic. This reduces the number of possible
substitutions, but guarantees that the resulting circuit is not
less efficient than the original circuit.
+
+ -nopartial
+ Do not consider mappings that use $_MUX<N>_ to select from less
+ than <N> different signals.
+\end{lstlisting}
+
+\section{muxpack -- \$mux/\$pmux cascades to \$pmux}
+\label{cmd:muxpack}
+\begin{lstlisting}[numbers=left,frame=single]
+ muxpack [selection]
+
+This pass converts cascaded chains of $pmux cells (e.g. those create from case
+constructs) and $mux cells (e.g. those created by if-else constructs) into
+$pmux cells.
+
+This optimisation is conservative --- it will only pack $mux or $pmux cells
+whose select lines are driven by '$eq' cells with other such cells if it can be
+certain that their select inputs are mutually exclusive.
\end{lstlisting}
\section{nlutmap -- map to LUTs of different sizes}
@@ -1925,6 +2870,17 @@ Excess logic that does not fit into the specified LUTs is mapped back
to generic logic gates ($_AND_, etc.).
\end{lstlisting}
+\section{onehot -- optimize \$eq cells for onehot signals}
+\label{cmd:onehot}
+\begin{lstlisting}[numbers=left,frame=single]
+ onehot [options] [selection]
+
+This pass optimizes $eq cells that compare one-hot signals against constants
+
+ -v, -vv
+ verbose output
+\end{lstlisting}
+
\section{opt -- perform simple optimizations}
\label{cmd:opt}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1941,7 +2897,8 @@ passes in the following order:
opt_muxtree
opt_reduce [-fine] [-full]
opt_merge [-share_all]
- opt_rmdff [-keepdc]
+ opt_share (-full only)
+ opt_rmdff [-keepdc] [-sat]
opt_clean [-purge]
opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]
while <changed design>
@@ -1951,7 +2908,7 @@ When called with -fast the following script is used instead:
do
opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]
opt_merge [-share_all]
- opt_rmdff [-keepdc]
+ opt_rmdff [-keepdc] [-sat]
opt_clean [-purge]
while <changed design in opt_rmdff>
@@ -1990,7 +2947,7 @@ overall gate count of the circuit
opt_expr [options] [selection]
This pass performs const folding on internal cell types with constant inputs.
-It also performs some simple expression rewritring.
+It also performs some simple expression rewriting.
-mux_undef
remove 'undef' inputs from $mux, $pmux and $_MUX_ cells
@@ -2017,6 +2974,47 @@ It also performs some simple expression rewritring.
replaced by 'a'. the -keepdc option disables all such optimizations.
\end{lstlisting}
+\section{opt\_lut -- optimize LUT cells}
+\label{cmd:opt_lut}
+\begin{lstlisting}[numbers=left,frame=single]
+ opt_lut [options] [selection]
+
+This pass combines cascaded $lut cells with unused inputs.
+
+ -dlogic <type>:<cell-port>=<LUT-input>[:<cell-port>=<LUT-input>...]
+ preserve connections to dedicated logic cell <type> that has ports
+ <cell-port> connected to LUT inputs <LUT-input>. this includes
+ the case where both LUT and dedicated logic input are connected to
+ the same constant.
+
+ -limit N
+ only perform the first N combines, then stop. useful for debugging.
+\end{lstlisting}
+
+\section{opt\_lut\_ins -- discard unused LUT inputs}
+\label{cmd:opt_lut_ins}
+\begin{lstlisting}[numbers=left,frame=single]
+ opt_lut_ins [options] [selection]
+
+This pass removes unused inputs from LUT cells (that is, inputs that can not
+influence the output signal given this LUT's value). While such LUTs cannot
+be directly emitted by ABC, they can be a result of various post-ABC
+transformations, such as mapping wide LUTs (not all sub-LUTs will use the
+full set of inputs) or optimizations such as xilinx_dffopt.
+
+ -tech <technology>
+ Instead of generic $lut cells, operate on LUT cells specific
+ to the given technology. Valid values are: xilinx, ecp5, gowin.
+\end{lstlisting}
+
+\section{opt\_mem -- optimize memories}
+\label{cmd:opt_mem}
+\begin{lstlisting}[numbers=left,frame=single]
+ opt_mem [options] [selection]
+
+This pass performs various optimizations on memories in the design.
+\end{lstlisting}
+
\section{opt\_merge -- consolidate identical cells}
\label{cmd:opt_merge}
\begin{lstlisting}[numbers=left,frame=single]
@@ -2067,10 +3065,65 @@ input with the original control signals OR'ed together.
\section{opt\_rmdff -- remove DFFs with constant inputs}
\label{cmd:opt_rmdff}
\begin{lstlisting}[numbers=left,frame=single]
- opt_rmdff [-keepdc] [selection]
+ opt_rmdff [-keepdc] [-sat] [selection]
This pass identifies flip-flops with constant inputs and replaces them with
a constant driver.
+
+ -sat
+ additionally invoke SAT solver to detect and remove flip-flops (with
+ non-constant inputs) that can also be replaced with a constant driver
+\end{lstlisting}
+
+\section{opt\_share -- merge mutually exclusive cells of the same type that share an input signal}
+\label{cmd:opt_share}
+\begin{lstlisting}[numbers=left,frame=single]
+ opt_share [selection]
+
+This pass identifies mutually exclusive cells of the same type that:
+ (a) share an input signal,
+ (b) drive the same $mux, $_MUX_, or $pmux multiplexing cell,
+
+allowing the cell to be merged and the multiplexer to be moved from
+multiplexing its output to multiplexing the non-shared input signals.
+\end{lstlisting}
+
+\section{paramap -- renaming cell parameters}
+\label{cmd:paramap}
+\begin{lstlisting}[numbers=left,frame=single]
+ paramap [options] [selection]
+
+This command renames cell parameters and/or maps key/value pairs to
+other key/value pairs.
+
+ -tocase <name>
+ Match attribute names case-insensitively and set it to the specified
+ name.
+
+ -rename <old_name> <new_name>
+ Rename attributes as specified
+
+ -map <old_name>=<old_value> <new_name>=<new_value>
+ Map key/value pairs as indicated.
+
+ -imap <old_name>=<old_value> <new_name>=<new_value>
+ Like -map, but use case-insensitive match for <old_value> when
+ it is a string value.
+
+ -remove <name>=<value>
+ Remove attributes matching this pattern.
+
+For example, mapping Diamond-style ECP5 "init" attributes to Yosys-style:
+
+ paramap -tocase INIT t:LUT4
+\end{lstlisting}
+
+\section{peepopt -- collection of peephole optimizers}
+\label{cmd:peepopt}
+\begin{lstlisting}[numbers=left,frame=single]
+ peepopt [options] [selection]
+
+This pass applies a collection of peephole optimizers to the current design.
\end{lstlisting}
\section{plugin -- load and list loaded plugins}
@@ -2090,12 +3143,51 @@ Load and list loaded plugins.
List loaded plugins
\end{lstlisting}
+\section{pmux2shiftx -- transform \$pmux cells to \$shiftx cells}
+\label{cmd:pmux2shiftx}
+\begin{lstlisting}[numbers=left,frame=single]
+ pmux2shiftx [options] [selection]
+
+This pass transforms $pmux cells to $shiftx cells.
+
+ -v, -vv
+ verbose output
+
+ -min_density <percentage>
+ specifies the minimum density for the shifter
+ default: 50
+
+ -min_choices <int>
+ specified the minimum number of choices for a control signal
+ default: 3
+
+ -onehot ignore|pmux|shiftx
+ select strategy for one-hot encoded control signals
+ default: pmux
+
+ -norange
+ disable $sub inference for "range decoders"
+\end{lstlisting}
+
\section{pmuxtree -- transform \$pmux cells to trees of \$mux cells}
\label{cmd:pmuxtree}
\begin{lstlisting}[numbers=left,frame=single]
- pmuxtree [options] [selection]
+ pmuxtree [selection]
+
+This pass transforms $pmux cells to trees of $mux cells.
+\end{lstlisting}
+
+\section{portlist -- list (top-level) ports}
+\label{cmd:portlist}
+\begin{lstlisting}[numbers=left,frame=single]
+ portlist [options] [selection]
+
+This command lists all module ports found in the selected modules.
-This pass transforms $pmux cells to a trees of $mux cells.
+If no selection is provided then it lists the ports on the top module.
+
+ -m
+ print verilog blackbox module definitions instead of port lists
\end{lstlisting}
\section{prep -- generic synthesis script}
@@ -2153,7 +3245,7 @@ The following commands are executed by this synthesis command:
opt_clean
check
opt -keepdc
- wreduce [-memx]
+ wreduce -keepdc [-memx]
memory_dff [-nordff]
memory_memx (if -memx)
opt_clean
@@ -2174,6 +3266,7 @@ This pass calls all the other proc_* passes in the most common order.
proc_clean
proc_rmdead
+ proc_prune
proc_init
proc_arst
proc_mux
@@ -2214,7 +3307,10 @@ flip-flop cells with asynchronous resets.
\section{proc\_clean -- remove empty parts of processes}
\label{cmd:proc_clean}
\begin{lstlisting}[numbers=left,frame=single]
- proc_clean [selection]
+ proc_clean [options] [selection]
+
+ -quiet
+ do not print any messages.
This pass removes empty parts of processes and ultimately removes a process
if it contains only empty structures.
@@ -2261,6 +3357,15 @@ and case statements) to trees of multiplexer cells.
'case' expressions and 'if' conditions.
\end{lstlisting}
+\section{proc\_prune -- remove redundant assignments}
+\label{cmd:proc_prune}
+\begin{lstlisting}[numbers=left,frame=single]
+ proc_prune [selection]
+
+This pass identifies assignments in processes that are always overwritten by
+a later assignment to the same signal and removes them.
+\end{lstlisting}
+
\section{proc\_rmdead -- eliminate dead trees in decision trees}
\label{cmd:proc_rmdead}
\begin{lstlisting}[numbers=left,frame=single]
@@ -2328,12 +3433,45 @@ Unset global Verilog/SystemVerilog defines.
read -incdir <directory>
Add directory to global Verilog/SystemVerilog include directories.
+
+
+ read -verific
+ read -noverific
+
+Subsequent calls to 'read' will either use or not use Verific. Calling 'read'
+with -verific will result in an error on Yosys binaries that are built without
+Verific support. The default is to use Verific if it is available.
+\end{lstlisting}
+
+\section{read\_aiger -- read AIGER file}
+\label{cmd:read_aiger}
+\begin{lstlisting}[numbers=left,frame=single]
+ read_aiger [options] [filename]
+
+Load module from an AIGER file into the current design.
+
+ -module_name <module_name>
+ name of module to be created (default: <filename>)
+
+ -clk_name <wire_name>
+ if specified, AIGER latches to be transformed into $_DFF_P_ cells
+ clocked by wire of this name. otherwise, $_FF_ cells will be used
+
+ -map <filename>
+ read file with port and latch symbols
+
+ -wideports
+ merge ports that match the pattern 'name[int]' into a single
+ multi-bit port 'name'
+
+ -xaiger
+ read XAIGER extensions
\end{lstlisting}
\section{read\_blif -- read BLIF file}
\label{cmd:read_blif}
\begin{lstlisting}[numbers=left,frame=single]
- read_blif [filename]
+ read_blif [options] [filename]
Load modules from a BLIF file into the current design.
@@ -2352,6 +3490,17 @@ Load modules from a BLIF file into the current design.
Load modules from an ilang file to the current design. (ilang is a text
representation of a design in yosys's internal format.)
+
+ -nooverwrite
+ ignore re-definitions of modules. (the default behavior is to
+ create an error message if the existing module is not a blackbox
+ module, and overwrite the existing module if it is a blackbox module.)
+
+ -overwrite
+ overwrite existing modules with the same name
+
+ -lib
+ only create empty blackbox modules
\end{lstlisting}
\section{read\_json -- read JSON file}
@@ -2411,12 +3560,24 @@ Verilog-2005 is supported.
enable support for SystemVerilog assertions and some Yosys extensions
replace the implicit -D SYNTHESIS with -D FORMAL
+ -noassert
+ ignore assert() statements
+
+ -noassume
+ ignore assume() statements
+
-norestrict
- ignore restrict() assertions
+ ignore restrict() statements
-assume-asserts
treat all assert() statements like assume() statements
+ -assert-assumes
+ treat all assume() statements like assert() statements
+
+ -debug
+ alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug
+
-dump_ast1
dump abstract syntax tree (before simplification)
@@ -2426,7 +3587,10 @@ Verilog-2005 is supported.
-no_dump_ptr
do not include hex memory addresses in dump (easier to diff dumps)
- -dump_vlog
+ -dump_vlog1
+ dump ast as Verilog code (before simplification)
+
+ -dump_vlog2
dump ast as Verilog code (after simplification)
-dump_rtlil
@@ -2475,8 +3639,21 @@ Verilog-2005 is supported.
-nodpi
disable DPI-C support
+ -noblackbox
+ do not automatically add a (* blackbox *) attribute to an
+ empty module.
+
-lib
only create empty blackbox modules. This implies -DBLACKBOX.
+ modules with the (* whitebox *) attribute will be preserved.
+ (* lib_whitebox *) will be treated like (* whitebox *).
+
+ -nowb
+ delete (* whitebox *) and (* lib_whitebox *) attributes from
+ all modules.
+
+ -specify
+ parse and import specify blocks
-noopt
don't perform basic optimizations (such as const folding) in the
@@ -2485,6 +3662,9 @@ Verilog-2005 is supported.
-icells
interpret cell types starting with '$' as internal cell types
+ -pwires
+ add a wire for each module parameter
+
-nooverwrite
ignore re-definitions of modules. (the default behavior is to
create an error message if the existing module is not a black box
@@ -2537,6 +3717,25 @@ Rename the specified object. Note that selection patterns are not supported
by this command.
+
+ rename -output old_name new_name
+
+Like above, but also make the wire an output. This will fail if the object is
+not a wire.
+
+
+ rename -src [selection]
+
+Assign names auto-generated from the src attribute to all selected wires and
+cells with private names.
+
+
+ rename -wire [selection]
+
+Assign auto-generated names based on the wires they drive to all selected
+cells with private names. Ignores cells driving privatly named wires.
+
+
rename -enumerate [-pattern <pattern>] [selection]
Assign short auto-generated names to all selected wires and cells with private
@@ -2544,11 +3743,13 @@ names. The -pattern option can be used to set the pattern for the new names.
The character % in the pattern is replaced with a integer number. The default
pattern is '_%_'.
+
rename -hide [selection]
Assign private names (the ones with $-prefix) to all selected wires and cells
with public names. This ignores all selected ports.
+
rename -top new_name
Rename top module.
@@ -2778,20 +3979,61 @@ design.
that are part of a found logic loop
\end{lstlisting}
-\section{script -- execute commands from script file}
+\section{scratchpad -- get/set values in the scratchpad}
+\label{cmd:scratchpad}
+\begin{lstlisting}[numbers=left,frame=single]
+ scratchpad [options]
+
+This pass allows to read and modify values from the scratchpad of the current
+design. Options:
+
+ -get <identifier>
+ print the value saved in the scratchpad under the given identifier.
+
+ -set <identifier> <value>
+ save the given value in the scratchpad under the given identifier.
+
+ -unset <identifier>
+ remove the entry for the given identifier from the scratchpad.
+
+ -copy <identifier_from> <identifier_to>
+ copy the value of the first identifier to the second identifier.
+
+ -assert <identifier> <value>
+ assert that the entry for the given identifier is set to the given value.
+
+ -assert-set <identifier>
+ assert that the entry for the given identifier exists.
+
+ -assert-unset <identifier>
+ assert that the entry for the given identifier does not exist.
+
+The identifier may not contain whitespace. By convention, it is usually prefixed
+by the name of the pass that uses it, e.g. 'opt.did_something'. If the value
+contains whitespace, it must be enclosed in double quotes.
+\end{lstlisting}
+
+\section{script -- execute commands from file or wire}
\label{cmd:script}
\begin{lstlisting}[numbers=left,frame=single]
script <filename> [<from_label>:<to_label>]
+ script -scriptwire [selection]
-This command executes the yosys commands in the specified file.
+This command executes the yosys commands in the specified file (default
+behaviour), or commands embedded in the constant text value connected to the
+selected wires.
-The 2nd argument can be used to only execute the section of the
-file between the specified labels. An empty from label is synonymous
-for the beginning of the file and an empty to label is synonymous
-for the end of the file.
+In the default (file) case, the 2nd argument can be used to only execute the
+section of the file between the specified labels. An empty from label is
+synonymous with the beginning of the file and an empty to label is synonymous
+with the end of the file.
If only one label is specified (without ':') then only the block
marked with that label (until the next label) is executed.
+
+In "-scriptwire" mode, the commands on the selected wire(s) will be executed
+in the scope of (and thus, relative to) the wires' owning module(s). This
+'-module' mode can be exited by using the 'cd' command.
\end{lstlisting}
\section{select -- modify and view the list of selected objects}
@@ -2807,7 +4049,7 @@ of the design to operate on. This command can be used to modify and view this
list of selected objects.
Note that many commands support an optional [selection] argument that can be
-used to YS_OVERRIDE the global selection for the command. The syntax of this
+used to override the global selection for the command. The syntax of this
optional argument is identical to the syntax of the <selection> argument
described here.
@@ -2897,6 +4139,10 @@ matching module names, or one of the following:
all modules with an attribute matching the given pattern
in addition to = also <, <=, >=, and > are supported
+ N:<pattern>
+ all modules with a name matching the given pattern
+ (i.e. 'N:' is optional as it is the default matching rule)
+
An <obj_pattern> can be an object name, wildcard expression, or one of
the following:
@@ -3062,11 +4308,25 @@ This command replaces undef (x) constants with defined (0/1) constants.
replace with $anyconst drivers (for formal)
-random <seed>
- replace with random bits using the specified integer als seed
+ replace with random bits using the specified integer as seed
value for the random number generator.
-init
also create/update init values for flip-flops
+
+ -params
+ replace undef in cell parameters
+\end{lstlisting}
+
+\section{sf2\_iobs -- SF2: insert IO buffers}
+\label{cmd:sf2_iobs}
+\begin{lstlisting}[numbers=left,frame=single]
+ sf2_iobs [options] [selection]
+
+Add SF2 I/O buffers and global buffers to top module as needed.
+
+ -clkbuf
+ Insert PAD->global_net clock buffers
\end{lstlisting}
\section{share -- perform sat-based resource sharing}
@@ -3182,7 +4442,7 @@ to a graphics file (usually SVG or PostScript).
assigned to each unique value of this attribute.
-width
- annotate busses with a label indicating the width of the bus.
+ annotate buses with a label indicating the width of the bus.
-signed
mark ports (A, B) that are declared as signed (using the [AB]_SIGNED
@@ -3204,6 +4464,10 @@ to a graphics file (usually SVG or PostScript).
-notitle
do not add the module name as graph title to the dot file
+ -nobg
+ don't run viewer in the background, IE wait for the viewer tool to
+ exit before returning
+
When no <format> is specified, 'dot' is used. When no <format> and <viewer> is
specified, 'xdot' is used to display the schematic (POSIX systems only).
@@ -3404,6 +4668,10 @@ design.
-liberty <liberty_file>
use cell area information from the provided liberty file
+ -tech <technology>
+ print area estemate for the specified technology. Currently supported
+ values for <technology>: xilinx, cmos
+
-width
annotate internal cell types with their word width.
e.g. $add_8 for an 8 bit wide $add cell.
@@ -3412,7 +4680,7 @@ design.
\section{submod -- moving part of a module to a new submodule}
\label{cmd:submod}
\begin{lstlisting}[numbers=left,frame=single]
- submod [-copy] [selection]
+ submod [options] [selection]
This pass identifies all cells with the 'submod' attribute and moves them to
a newly created module. The value of the attribute is used as name for the
@@ -3424,16 +4692,29 @@ be useful for analyzing or reverse-engineering a design.
This pass only operates on completely selected modules with no processes
or memories.
+ -copy
+ by default the cells are 'moved' from the source module and the source
+ module will use an instance of the new module after this command is
+ finished. call with -copy to not modify the source module.
+
+ -name <name>
+ don't use the 'submod' attribute but instead use the selection. only
+ objects from one module might be selected. the value of the -name option
+ is used as the value of the 'submod' attribute instead.
- submod -name <name> [-copy] [selection]
+ -hidden
+ instead of creating submodule ports with public names, create ports with
+ private names so that a subsequent 'flatten; clean' call will restore the
+ original module with original public names.
+\end{lstlisting}
-As above, but don't use the 'submod' attribute but instead use the selection.
-Only objects from one module might be selected. The value of the -name option
-is used as the value of the 'submod' attribute above.
+\section{supercover -- add hi/lo cover cells for each wire bit}
+\label{cmd:supercover}
+\begin{lstlisting}[numbers=left,frame=single]
+ supercover [options] [selection]
-By default the cells are 'moved' from the source module and the source module
-will use an instance of the new module after this command is finished. Call
-with -copy to not modify the source module.
+This command adds two cover cells for each bit of each selected wire, one
+checking for a hi signal level and one checking for lo level.
\end{lstlisting}
\section{synth -- generic synthesis script}
@@ -3457,6 +4738,9 @@ on partly selected designs.
-encfile <file>
passed to 'fsm_recode' via 'fsm'
+ -lut <k>
+ perform synthesis for a k-LUT architecture.
+
-nofsm
do not run FSM optimization
@@ -3478,6 +4762,12 @@ on partly selected designs.
from label is synonymous to 'begin', and empty to label is
synonymous to the end of the command list.
+ -abc9
+ use new ABC9 flow (EXPERIMENTAL)
+
+ -flowmap
+ use FlowMap LUT techmapping instead of ABC
+
The following commands are executed by this synthesis command:
@@ -3486,16 +4776,19 @@ The following commands are executed by this synthesis command:
coarse:
proc
- flatten (if -flatten)
+ flatten (if -flatten)
opt_expr
opt_clean
check
opt
wreduce
- alumacc
- share
+ peepopt
+ opt_clean
+ techmap -map +/cmp2lut.v -map +/cmp2lcu.v (if -lut)
+ alumacc (unless -noalumacc)
+ share (unless -noshare)
opt
- fsm
+ fsm (unless -nofsm)
opt -fast
memory -nomap
opt_clean
@@ -3505,9 +4798,13 @@ The following commands are executed by this synthesis command:
memory_map
opt -full
techmap
+ techmap -map +/gate2lut.v (if -noabc and -lut)
+ clean; opt_lut (if -noabc and -lut)
+ flowmap -maxlut K (if -flowmap and -lut)
opt -fast
- abc -fast
- opt -fast
+ abc -fast (unless -noabc, unless -lut)
+ abc -fast -lut k (unless -noabc, if -lut)
+ opt -fast (unless -noabc)
check:
hierarchy -check
@@ -3538,7 +4835,7 @@ This command runs synthesis for Achronix Speedster eFPGAs. This work is still ex
do not flatten design before synthesis
-retime
- run 'abc' with -dff option
+ run 'abc' with '-dff -D 1' options
The following commands are executed by this synthesis command:
@@ -3560,14 +4857,13 @@ The following commands are executed by this synthesis command:
opt -fast -mux_undef -undriven -fine -full
memory_map
opt -undriven -fine
- dffsr2dff
dff2dffe -direct-match $_DFF_*
opt -fine
techmap -map +/techmap.v
opt -full
clean -purge
setundef -undriven -zero
- abc -markgroups -dff (only if -retime)
+ abc -markgroups -dff -D 1 (only if -retime)
map_luts:
abc -lut 4
@@ -3587,6 +4883,99 @@ The following commands are executed by this synthesis command:
write_verilog -nodec -attr2comment -defparam -renameprefix syn_ <file-name>
\end{lstlisting}
+\section{synth\_anlogic -- synthesis for Anlogic FPGAs}
+\label{cmd:synth_anlogic}
+\begin{lstlisting}[numbers=left,frame=single]
+ synth_anlogic [options]
+
+This command runs synthesis for Anlogic FPGAs.
+
+ -top <module>
+ use the specified module as top module
+
+ -edif <file>
+ write the design to the specified EDIF file. writing of an output file
+ is omitted if this parameter is not specified.
+
+ -json <file>
+ write the design to the specified JSON file. writing of an output file
+ is omitted if this parameter is not specified.
+
+ -run <from_label>:<to_label>
+ only run the commands between the labels (see below). an empty
+ from label is synonymous to 'begin', and empty to label is
+ synonymous to the end of the command list.
+
+ -noflatten
+ do not flatten design before synthesis
+
+ -retime
+ run 'abc' with '-dff -D 1' options
+
+ -nolutram
+ do not use EG_LOGIC_DRAM16X4 cells in output netlist
+
+
+The following commands are executed by this synthesis command:
+
+ begin:
+ read_verilog -lib +/anlogic/cells_sim.v +/anlogic/eagle_bb.v
+ hierarchy -check -top <top>
+
+ flatten: (unless -noflatten)
+ proc
+ flatten
+ tribuf -logic
+ deminout
+
+ coarse:
+ synth -run coarse
+
+ map_lutram: (skip if -nolutram)
+ memory_bram -rules +/anlogic/lutrams.txt
+ techmap -map +/anlogic/lutrams_map.v
+ setundef -zero -params t:EG_LOGIC_DRAM16X4
+
+ map_ffram:
+ opt -fast -mux_undef -undriven -fine
+ memory_map
+ opt -undriven -fine
+
+ map_gates:
+ techmap -map +/techmap.v -map +/anlogic/arith_map.v
+ opt -fast
+ abc -dff -D 1 (only if -retime)
+
+ map_ffs:
+ techmap -D NO_LUT -map +/anlogic/cells_map.v
+ dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit
+ opt_expr -mux_undef
+ simplemap
+
+ map_luts:
+ abc -lut 4:6
+ clean
+
+ map_cells:
+ techmap -map +/anlogic/cells_map.v
+ clean
+
+ map_anlogic:
+ anlogic_fixcarry
+ anlogic_eqn
+
+ check:
+ hierarchy -check
+ stat
+ check -noinit
+
+ edif:
+ write_edif <file-name>
+
+ json:
+ write_json <file-name>
+\end{lstlisting}
+
\section{synth\_coolrunner2 -- synthesis for Xilinx Coolrunner-II CPLDs}
\label{cmd:synth_coolrunner2}
\begin{lstlisting}[numbers=left,frame=single]
@@ -3612,7 +5001,7 @@ place-and-route.
do not flatten design before synthesis
-retime
- run 'abc' with -dff option
+ run 'abc' with '-dff -D 1' options
The following commands are executed by this synthesis command:
@@ -3630,9 +5019,12 @@ The following commands are executed by this synthesis command:
synth -run coarse
fine:
+ extract_counter -dir up -allow_arst no
+ techmap -map +/coolrunner2/cells_counter_map.v
+ clean
opt -fast -full
- techmap
- techmap -map +/coolrunner2/cells_latch.v
+ techmap -map +/techmap.v -map +/coolrunner2/cells_latch.v
+ opt -fast
dfflibmap -prepare -liberty +/coolrunner2/xc2_dff.lib
map_tff:
@@ -3653,9 +5045,11 @@ The following commands are executed by this synthesis command:
dffinit -ff LDCP Q INIT
dffinit -ff LDCP_N Q INIT
coolrunner2_sop
+ clean
iopadmap -bits -inpad IBUF O:I -outpad IOBUFE I:IO -inoutpad IOBUFE O:IO -toutpad IOBUFE E:I:IO -tinoutpad IOBUFE E:O:I:IO
attrmvcp -attr src -attr LOC t:IOBUFE n:*
attrmvcp -attr src -attr LOC -driven t:IBUF n:*
+ coolrunner2_fixup
splitnets
clean
@@ -3694,7 +5088,7 @@ This command runs synthesis for eASIC platform.
do not flatten design before synthesis
-retime
- run 'abc' with -dff option
+ run 'abc' with '-dff -D 1' options
The following commands are executed by this synthesis command:
@@ -3717,7 +5111,7 @@ The following commands are executed by this synthesis command:
opt -undriven -fine
techmap
opt -fast
- abc -dff (only if -retime)
+ abc -dff -D 1 (only if -retime)
opt_clean (only if -retime)
map:
@@ -3765,7 +5159,7 @@ This command runs synthesis for ECP5 FPGAs.
do not flatten design before synthesis
-retime
- run 'abc' with -dff option
+ run 'abc' with '-dff -D 1' options
-noccu2
do not use CCU2 cells in output netlist
@@ -3774,69 +5168,105 @@ This command runs synthesis for ECP5 FPGAs.
do not use flipflops with CE in output netlist
-nobram
- do not use BRAM cells in output netlist
+ do not use block RAM cells in output netlist
- -nodram
- do not use distributed RAM cells in output netlist
+ -nolutram
+ do not use LUT RAM cells in output netlist
- -nomux
+ -nowidelut
do not use PFU muxes to implement LUTs larger than LUT4s
+ -asyncprld
+ use async PRLD mode to implement DLATCH and DFFSR (EXPERIMENTAL)
+
-abc2
run two passes of 'abc' for slightly improved logic density
+ -abc9
+ use new ABC9 flow (EXPERIMENTAL)
+
-vpr
generate an output netlist (and BLIF file) suitable for VPR
(this feature is experimental and incomplete)
+ -nodsp
+ do not map multipliers to MULT18X18D
+
The following commands are executed by this synthesis command:
begin:
- read_verilog -lib +/ecp5/cells_sim.v
+ read_verilog -lib -specify +/ecp5/cells_sim.v +/ecp5/cells_bb.v
hierarchy -check -top <top>
- flatten: (unless -noflatten)
+ coarse:
proc
flatten
tribuf -logic
deminout
+ opt_expr
+ opt_clean
+ check
+ opt
+ wreduce
+ peepopt
+ opt_clean
+ share
+ techmap -map +/cmp2lut.v -D LUT_WIDTH=4
+ opt_expr
+ opt_clean
+ techmap -map +/mul2dsp.v -map +/ecp5/dsp_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=$__MUL18X18 (unless -nodsp)
+ chtype -set $mul t:$__soft_mul (unless -nodsp)
+ alumacc
+ opt
+ fsm
+ opt -fast
+ memory -nomap
+ opt_clean
- coarse:
- synth -run coarse
-
- bram: (skip if -nobram)
+ map_bram: (skip if -nobram)
+ memory_bram -rules +/ecp5/brams.txt
+ techmap -map +/ecp5/brams_map.v
- dram: (skip if -nodram)
- memory_bram -rules +/ecp5/dram.txt
- techmap -map +/ecp5/drams_map.v
+ map_lutram: (skip if -nolutram)
+ memory_bram -rules +/ecp5/lutrams.txt
+ techmap -map +/ecp5/lutrams_map.v
- fine:
+ map_ffram:
opt -fast -mux_undef -undriven -fine
- memory_map
+ memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block -attr syn_ramstyle=auto -attr syn_ramstyle=registers -attr syn_romstyle=auto -attr syn_romstyle=logic
opt -undriven -fine
+
+ map_gates:
techmap -map +/techmap.v -map +/ecp5/arith_map.v
- abc -dff (only if -retime)
+ opt -fast
+ abc -dff -D 1 (only if -retime)
map_ffs:
- dffsr2dff
dff2dffs
opt_clean
dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*
- techmap -D NO_LUT -map +/ecp5/cells_map.v
- opt_expr -mux_undef
+ techmap -D NO_LUT [-D ASYNC_PRLD] -map +/ecp5/cells_map.v
+ opt_expr -undriven -mux_undef
simplemap
+ ecp5_ffinit
+ ecp5_gsr
+ attrmvcp -copy -attr syn_useioff
+ opt_clean
map_luts:
abc (only if -abc2)
- abc -lut 4:7
+ techmap -map +/ecp5/latches_map.v
+ abc -lut 4:7 -dress
clean
map_cells:
techmap -map +/ecp5/cells_map.v (with -D NO_LUT in vpr mode)
+ opt_lut_ins -tech ecp5
clean
check:
+ autoname
hierarchy -check
stat
check -noinit
@@ -3853,6 +5283,98 @@ The following commands are executed by this synthesis command:
write_json <file-name>
\end{lstlisting}
+\section{synth\_efinix -- synthesis for Efinix FPGAs}
+\label{cmd:synth_efinix}
+\begin{lstlisting}[numbers=left,frame=single]
+ synth_efinix [options]
+
+This command runs synthesis for Efinix FPGAs.
+
+ -top <module>
+ use the specified module as top module
+
+ -edif <file>
+ write the design to the specified EDIF file. writing of an output file
+ is omitted if this parameter is not specified.
+
+ -json <file>
+ write the design to the specified JSON file. writing of an output file
+ is omitted if this parameter is not specified.
+
+ -run <from_label>:<to_label>
+ only run the commands between the labels (see below). an empty
+ from label is synonymous to 'begin', and empty to label is
+ synonymous to the end of the command list.
+
+ -noflatten
+ do not flatten design before synthesis
+
+ -retime
+ run 'abc' with '-dff -D 1' options
+
+ -nobram
+ do not use EFX_RAM_5K cells in output netlist
+
+
+The following commands are executed by this synthesis command:
+
+ begin:
+ read_verilog -lib +/efinix/cells_sim.v
+ hierarchy -check -top <top>
+
+ flatten: (unless -noflatten)
+ proc
+ flatten
+ tribuf -logic
+ deminout
+
+ coarse:
+ synth -run coarse
+ memory_bram -rules +/efinix/brams.txt
+ techmap -map +/efinix/brams_map.v
+ setundef -zero -params t:EFX_RAM_5K
+
+ map_ffram:
+ opt -fast -mux_undef -undriven -fine
+ memory_map
+ opt -undriven -fine
+
+ map_gates:
+ techmap -map +/techmap.v -map +/efinix/arith_map.v
+ opt -fast
+ abc -dff -D 1 (only if -retime)
+
+ map_ffs:
+ techmap -D NO_LUT -map +/efinix/cells_map.v
+ dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit
+ opt_expr -mux_undef
+ simplemap
+
+ map_luts:
+ abc -lut 4
+ clean
+
+ map_cells:
+ techmap -map +/efinix/cells_map.v
+ clean
+
+ map_gbuf:
+ efinix_gbuf
+ efinix_fixcarry
+ clean
+
+ check:
+ hierarchy -check
+ stat
+ check -noinit
+
+ edif:
+ write_edif <file-name>
+
+ json:
+ write_json <file-name>
+\end{lstlisting}
+
\section{synth\_gowin -- synthesis for Gowin FPGAs}
\label{cmd:synth_gowin}
\begin{lstlisting}[numbers=left,frame=single]
@@ -3872,8 +5394,26 @@ This command runs synthesis for Gowin FPGAs. This work is experimental.
from label is synonymous to 'begin', and empty to label is
synonymous to the end of the command list.
+ -nodffe
+ do not use flipflops with CE in output netlist
+
+ -nobram
+ do not use BRAM cells in output netlist
+
+ -nolutram
+ do not use distributed RAM cells in output netlist
+
+ -noflatten
+ do not flatten design before synthesis
+
-retime
- run 'abc' with -dff option
+ run 'abc' with '-dff -D 1' options
+
+ -nowidelut
+ do not use muxes to implement LUTs larger than LUT4s
+
+ -noiopads
+ do not emit IOB at top level ports
The following commands are executed by this synthesis command:
@@ -3882,7 +5422,7 @@ The following commands are executed by this synthesis command:
read_verilog -lib +/gowin/cells_sim.v
hierarchy -check -top <top>
- flatten:
+ flatten: (unless -noflatten)
proc
flatten
tribuf -logic
@@ -3891,25 +5431,45 @@ The following commands are executed by this synthesis command:
coarse:
synth -run coarse
- fine:
+ map_bram: (skip if -nobram)
+ memory_bram -rules +/gowin/brams.txt
+ techmap -map +/gowin/brams_map.v
+
+ map_lutram: (skip if -nolutram)
+ memory_bram -rules +/gowin/lutrams.txt
+ techmap -map +/gowin/lutrams_map.v
+ determine_init
+
+ map_ffram:
opt -fast -mux_undef -undriven -fine
memory_map
opt -undriven -fine
- techmap
- clean -purge
- splitnets -ports
- setundef -undriven -zero
- abc -dff (only if -retime)
+
+ map_gates:
+ techmap -map +/techmap.v -map +/gowin/arith_map.v
+ opt -fast
+ abc -dff -D 1 (only if -retime)
+ splitnets
+
+ map_ffs:
+ dff2dffs -match-init
+ opt_clean
+ dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*
+ techmap -map +/gowin/cells_map.v
+ opt_expr -mux_undef
+ simplemap
map_luts:
- abc -lut 4
+ abc -lut 4:8
clean
map_cells:
techmap -map +/gowin/cells_map.v
- hilomap -hicell VCC V -locell GND G
- iopadmap -inpad IBUF O:I -outpad OBUF I:O
- clean -purge
+ opt_lut_ins -tech gowin
+ setundef -undriven -params -zero
+ hilomap -singleton -hicell VCC V -locell GND G
+ iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O -toutpad TBUF OEN:I:O -tinoutpad IOBUF OEN:O:I:IO (unless -noiopads)
+ clean
check:
hierarchy -check
@@ -3917,7 +5477,7 @@ The following commands are executed by this synthesis command:
check -noinit
vout:
- write_verilog -nodec -attr2comment -defparam -renameprefix gen <file-name>
+ write_verilog -decimal -attr2comment -defparam -renameprefix gen <file-name>
\end{lstlisting}
\section{synth\_greenpak4 -- synthesis for GreenPAK4 FPGAs}
@@ -3949,7 +5509,7 @@ place-and-route.
do not flatten design before synthesis
-retime
- run 'abc' with -dff option
+ run 'abc' with '-dff -D 1' options
The following commands are executed by this synthesis command:
@@ -3972,11 +5532,10 @@ The following commands are executed by this synthesis command:
opt -fast -mux_undef -undriven -fine
memory_map
opt -undriven -fine
- techmap
- techmap -map +/greenpak4/cells_latch.v
+ techmap -map +/techmap.v -map +/greenpak4/cells_latch.v
dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib
opt -fast
- abc -dff (only if -retime)
+ abc -dff -D 1 (only if -retime)
map_luts:
nlutmap -assert -luts 0,6,8,2 (for -part SLG46140V)
@@ -4014,6 +5573,10 @@ The following commands are executed by this synthesis command:
This command runs synthesis for iCE40 FPGAs.
+ -device < hx | lp | u >
+ relevant only for '-abc9' flow, optimise timing for the specified device.
+ default: hx
+
-top <module>
use the specified module as top module
@@ -4038,7 +5601,7 @@ This command runs synthesis for iCE40 FPGAs.
do not flatten design before synthesis
-retime
- run 'abc' with -dff option
+ run 'abc' with '-dff -D 1' options
-nocarry
do not use SB_CARRY cells in output netlist
@@ -4046,9 +5609,19 @@ This command runs synthesis for iCE40 FPGAs.
-nodffe
do not use SB_DFFE* cells in output netlist
+ -dffe_min_ce_use <min_ce_use>
+ do not use SB_DFFE* cells if the resulting CE line would go to less
+ than min_ce_use SB_DFFE* in output netlist
+
-nobram
do not use SB_RAM40_4K* cells in output netlist
+ -dsp
+ use iCE40 UltraPlus DSP cells for large arithmetic
+
+ -noabc
+ use built-in Yosys LUT techmapping instead of abc
+
-abc2
run two passes of 'abc' for slightly improved logic density
@@ -4056,38 +5629,74 @@ This command runs synthesis for iCE40 FPGAs.
generate an output netlist (and BLIF file) suitable for VPR
(this feature is experimental and incomplete)
+ -abc9
+ use new ABC9 flow (EXPERIMENTAL)
+
+ -flowmap
+ use FlowMap LUT techmapping instead of abc (EXPERIMENTAL)
+
The following commands are executed by this synthesis command:
begin:
- read_verilog -lib +/ice40/cells_sim.v
+ read_verilog -D ICE40_HX -lib -specify +/ice40/cells_sim.v
hierarchy -check -top <top>
+ proc
flatten: (unless -noflatten)
- proc
flatten
tribuf -logic
deminout
coarse:
- synth -run coarse
+ opt_expr
+ opt_clean
+ check
+ opt
+ wreduce
+ peepopt
+ opt_clean
+ share
+ techmap -map +/cmp2lut.v -D LUT_WIDTH=4
+ opt_expr
+ opt_clean
+ memory_dff
+ wreduce t:$mul
+ techmap -map +/mul2dsp.v -map +/ice40/dsp_map.v -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=16 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_Y_MINWIDTH=11 -D DSP_NAME=$__MUL16X16 (if -dsp)
+ select a:mul2dsp (if -dsp)
+ setattr -unset mul2dsp (if -dsp)
+ opt_expr -fine (if -dsp)
+ wreduce (if -dsp)
+ select -clear (if -dsp)
+ ice40_dsp (if -dsp)
+ chtype -set $mul t:$__soft_mul (if -dsp)
+ alumacc
+ opt
+ fsm
+ opt -fast
+ memory -nomap
+ opt_clean
- bram: (skip if -nobram)
+ map_bram: (skip if -nobram)
memory_bram -rules +/ice40/brams.txt
techmap -map +/ice40/brams_map.v
+ ice40_braminit
- fine:
+ map_ffram:
opt -fast -mux_undef -undriven -fine
- memory_map
+ memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block -attr syn_ramstyle=auto -attr syn_ramstyle=registers -attr syn_romstyle=auto -attr syn_romstyle=logic
opt -undriven -fine
+
+ map_gates:
+ ice40_wrapcarry
techmap -map +/techmap.v -map +/ice40/arith_map.v
- abc -dff (only if -retime)
+ opt -fast
+ abc -dff -D 1 (only if -retime)
ice40_opt
map_ffs:
- dffsr2dff
dff2dffe -direct-match $_DFF_*
- techmap -D NO_LUT -map +/ice40/cells_map.v
+ techmap -D NO_LUT -D NO_ADDER -map +/ice40/cells_map.v
opt_expr -mux_undef
simplemap
ice40_ffinit
@@ -4098,14 +5707,21 @@ The following commands are executed by this synthesis command:
abc (only if -abc2)
ice40_opt (only if -abc2)
techmap -map +/ice40/latches_map.v
- abc -lut 4
+ simplemap (if -noabc or -flowmap)
+ techmap -map +/gate2lut.v -D LUT_WIDTH=4 (only if -noabc)
+ flowmap -maxlut 4 (only if -flowmap)
+ abc -dress -lut 4 (skip if -noabc)
+ ice40_wrapcarry -unwrap
+ techmap -D NO_LUT -map +/ice40/cells_map.v
clean
+ opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0
map_cells:
techmap -map +/ice40/cells_map.v (with -D NO_LUT in vpr mode)
clean
check:
+ autoname
hierarchy -check
stat
check -noinit
@@ -4129,11 +5745,11 @@ The following commands are executed by this synthesis command:
This command runs synthesis for Intel FPGAs.
- -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>
+ -family <max10 | arria10gx | cyclone10lp | cyclonev | cycloneiv | cycloneive>
generate the synthesis netlist for the specified family.
- MAX10 is the default target if not family argument specified.
- For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.
- Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.
+ MAX10 is the default target if no family argument specified.
+ For Cyclone IV GX devices, use cycloneiv argument; for Cyclone IV E, use cycloneive.
+ Cyclone V and Arria 10 GX devices are experimental.
-top <module>
use the specified module as top module (default='top')
@@ -4141,6 +5757,8 @@ This command runs synthesis for Intel FPGAs.
-vqm <file>
write the design to the specified Verilog Quartus Mapping File. Writing of an
output file is omitted if this parameter is not specified.
+ Note that this backend has not been tested and is likely incompatible
+ with recent versions of Quartus.
-vpr <file>
write BLIF files for VPR flow experiments. The synthesized BLIF output file is not
@@ -4152,17 +5770,17 @@ This command runs synthesis for Intel FPGAs.
from label is synonymous to 'begin', and empty to label is
synonymous to the end of the command list.
- -noiopads
- do not use altsyncram cells in output netlist
+ -iopads
+ use IO pad cells in output netlist
-nobram
- do not use altsyncram cells in output netlist
+ do not use block RAM cells in output netlist
-noflatten
do not flatten design before synthesis
-retime
- run 'abc' with -dff option
+ run 'abc' with '-dff -D 1' options
The following commands are executed by this synthesis command:
@@ -4183,29 +5801,28 @@ The following commands are executed by this synthesis command:
coarse:
synth -run coarse
- bram: (skip if -nobram)
- memory_bram -rules +/intel/common/brams.txt
- techmap -map +/intel/common/brams_map.v
+ map_bram: (skip if -nobram)
+ memory_bram -rules +/intel/common/brams_m9k.txt (if applicable for family)
+ techmap -map +/intel/common/brams_map_m9k.v (if applicable for family)
- fine:
+ map_ffram:
opt -fast -mux_undef -undriven -fine -full
memory_map
opt -undriven -fine
- dffsr2dff
dff2dffe -direct-match $_DFF_*
opt -fine
techmap -map +/techmap.v
opt -full
clean -purge
setundef -undriven -zero
- abc -markgroups -dff (only if -retime)
+ abc -markgroups -dff -D 1 (only if -retime)
map_luts:
abc -lut 4
clean
map_cells:
- iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I (unless -noiopads)
+ iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I (if -iopads)
techmap -map +/intel/max10/cells_map.v
dffinit -highlow -ff dffeas q power_up
clean -purge
@@ -4221,6 +5838,104 @@ The following commands are executed by this synthesis command:
vpr:
opt_clean -purge
write_blif <file-name>
+
+
+WARNING: THE 'synth_intel' COMMAND IS EXPERIMENTAL.
+\end{lstlisting}
+
+\section{synth\_sf2 -- synthesis for SmartFusion2 and IGLOO2 FPGAs}
+\label{cmd:synth_sf2}
+\begin{lstlisting}[numbers=left,frame=single]
+ synth_sf2 [options]
+
+This command runs synthesis for SmartFusion2 and IGLOO2 FPGAs.
+
+ -top <module>
+ use the specified module as top module
+
+ -edif <file>
+ write the design to the specified EDIF file. writing of an output file
+ is omitted if this parameter is not specified.
+
+ -vlog <file>
+ write the design to the specified Verilog file. writing of an output file
+ is omitted if this parameter is not specified.
+
+ -json <file>
+ write the design to the specified JSON file. writing of an output file
+ is omitted if this parameter is not specified.
+
+ -run <from_label>:<to_label>
+ only run the commands between the labels (see below). an empty
+ from label is synonymous to 'begin', and empty to label is
+ synonymous to the end of the command list.
+
+ -noflatten
+ do not flatten design before synthesis
+
+ -noiobs
+ run synthesis in "block mode", i.e. do not insert IO buffers
+
+ -clkbuf
+ insert direct PAD->global_net buffers
+
+ -retime
+ run 'abc' with '-dff -D 1' options
+
+
+The following commands are executed by this synthesis command:
+
+ begin:
+ read_verilog -lib +/sf2/cells_sim.v
+ hierarchy -check -top <top>
+
+ flatten: (unless -noflatten)
+ proc
+ flatten
+ tribuf -logic
+ deminout
+
+ coarse:
+ synth -run coarse
+
+ fine:
+ opt -fast -mux_undef -undriven -fine
+ memory_map
+ opt -undriven -fine
+ techmap -map +/techmap.v -map +/sf2/arith_map.v
+ opt -fast
+ abc -dff -D 1 (only if -retime)
+
+ map_ffs:
+ techmap -D NO_LUT -map +/sf2/cells_map.v
+ opt_expr -mux_undef
+ simplemap
+
+ map_luts:
+ abc -lut 4
+ clean
+
+ map_cells:
+ techmap -map +/sf2/cells_map.v
+ clean
+
+ map_iobs:
+ sf2_iobs [-clkbuf] (unless -noiobs)
+ clean
+
+ check:
+ hierarchy -check
+ stat
+ check -noinit
+
+ edif:
+ write_edif -gndvccy <file-name>
+
+ vlog:
+ write_verilog <file-name>
+
+ json:
+ write_json <file-name>
\end{lstlisting}
\section{synth\_xilinx -- synthesis for Xilinx FPGAs}
@@ -4235,6 +5950,26 @@ compatible with 7-Series Xilinx devices.
-top <module>
use the specified module as top module
+ -family <family>
+ run synthesis for the specified Xilinx architecture
+ generate the synthesis netlist for the specified family.
+ supported values:
+ - xcup: Ultrascale Plus
+ - xcu: Ultrascale
+ - xc7: Series 7 (default)
+ - xc6s: Spartan 6
+ - xc6v: Virtex 6
+ - xc5v: Virtex 5 (EXPERIMENTAL)
+ - xc4v: Virtex 4 (EXPERIMENTAL)
+ - xc3sda: Spartan 3A DSP (EXPERIMENTAL)
+ - xc3sa: Spartan 3A (EXPERIMENTAL)
+ - xc3se: Spartan 3E (EXPERIMENTAL)
+ - xc3s: Spartan 3 (EXPERIMENTAL)
+ - xc2vp: Virtex 2 Pro (EXPERIMENTAL)
+ - xc2v: Virtex 2 (EXPERIMENTAL)
+ - xcve: Virtex E, Spartan 2E (EXPERIMENTAL)
+ - xcv: Virtex, Spartan 2 (EXPERIMENTAL)
+
-edif <file>
write the design to the specified edif file. writing of an output file
is omitted if this parameter is not specified.
@@ -4247,6 +5982,42 @@ compatible with 7-Series Xilinx devices.
generate an output netlist (and BLIF file) suitable for VPR
(this feature is experimental and incomplete)
+ -ise
+ generate an output netlist suitable for ISE
+
+ -nobram
+ do not use block RAM cells in output netlist
+
+ -nolutram
+ do not use distributed RAM cells in output netlist
+
+ -nosrl
+ do not use distributed SRL cells in output netlist
+
+ -nocarry
+ do not use XORCY/MUXCY/CARRY4 cells in output netlist
+
+ -nowidelut
+ do not use MUXF[5-9] resources to implement LUTs larger than native for the target
+
+ -nodsp
+ do not use DSP48*s to implement multipliers and associated logic
+
+ -noiopad
+ disable I/O buffer insertion (useful for hierarchical or
+ out-of-context flows)
+
+ -noclkbuf
+ disable automatic clock buffer insertion
+
+ -uram
+ infer URAM288s for large memories (xcup only)
+
+ -widemux <int>
+ enable inference of hard multiplexer resources (MUXF[78]) for muxes at or
+ above this number of inputs (minimum value 2, recommended value >= 5).
+ default: 0 (no inference)
+
-run <from_label>:<to_label>
only run the commands between the labels (see below). an empty
from label is synonymous to 'begin', and empty to label is
@@ -4255,67 +6026,125 @@ compatible with 7-Series Xilinx devices.
-flatten
flatten design before synthesis
+ -dff
+ run 'abc'/'abc9' with -dff option
+
-retime
- run 'abc' with -dff option
+ run 'abc' with '-D 1' option to enable flip-flop retiming.
+ implies -dff.
+
+ -abc9
+ use new ABC9 flow (EXPERIMENTAL)
The following commands are executed by this synthesis command:
begin:
- read_verilog -lib +/xilinx/cells_sim.v
+ read_verilog -lib -specify +/xilinx/cells_sim.v
read_verilog -lib +/xilinx/cells_xtra.v
- read_verilog -lib +/xilinx/brams_bb.v
- hierarchy -check -top <top>
+ hierarchy -check -auto-top
- flatten: (only if -flatten)
+ prepare:
proc
- flatten
+ flatten (with '-flatten')
+ tribuf -logic
+ deminout
+ opt_expr
+ opt_clean
+ check
+ opt
+ wreduce [-keepdc] (option for '-widemux')
+ peepopt
+ opt_clean
+ muxpack ('-widemux' only)
+ pmux2shiftx (skip if '-nosrl' and '-widemux=0')
+ clean (skip if '-nosrl' and '-widemux=0')
+
+ map_dsp: (skip if '-nodsp')
+ memory_dff
+ techmap -map +/mul2dsp.v -map +/xilinx/{family}_dsp_map.v {options}
+ select a:mul2dsp
+ setattr -unset mul2dsp
+ opt_expr -fine
+ wreduce
+ select -clear
+ xilinx_dsp -family <family>
+ chtype -set $mul t:$__soft_mul
coarse:
- synth -run coarse
+ techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=[46]
+ alumacc
+ share
+ opt
+ fsm
+ opt -fast
+ memory -nomap
+ opt_clean
- bram:
- memory_bram -rules +/xilinx/brams.txt
- techmap -map +/xilinx/brams_map.v
+ map_uram: (only if '-uram')
+ memory_bram -rules +/xilinx/{family}_urams.txt
+ techmap -map +/xilinx/{family}_urams_map.v
- dram:
- memory_bram -rules +/xilinx/drams.txt
- techmap -map +/xilinx/drams_map.v
+ map_bram: (skip if '-nobram')
+ memory_bram -rules +/xilinx/{family}_brams.txt
+ techmap -map +/xilinx/{family}_brams_map.v
- fine:
+ map_lutram: (skip if '-nolutram')
+ memory_bram -rules +/xilinx/lut[46]_lutrams.txt
+ techmap -map +/xilinx/lutrams_map.v
+
+ map_ffram:
+ simplemap t:$dff t:$adff t:$mux
+ dff2dffs [-match-init] (-match-init for xc6s only)
opt -fast -full
memory_map
- dffsr2dff
- dff2dffe
+
+ fine:
+ dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*
+ muxcover <internal options> ('-widemux' only)
opt -full
- techmap -map +/techmap.v -map +/xilinx/arith_map.v
+ xilinx_srl -variable -minlen 3 (skip if '-nosrl')
+ techmap -map +/techmap.v -D LUT_SIZE=[46] [-map +/xilinx/mux_map.v] -map +/xilinx/arith_map.v
opt -fast
- map_luts:
- abc -luts 2:2,3,6:5,10,20 [-dff]
+ map_cells:
+ iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top (skip if '-noiopad')
+ techmap -map +/techmap.v -map +/xilinx/cells_map.v
clean
- map_cells:
- techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode)
- dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT
+ map_ffs:
+ techmap -map +/xilinx/{family}_ff_map.v ('-abc9' only)
+
+ map_luts:
+ opt_expr -mux_undef
+ abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1] (option for 'nowidelut', '-dff', '-retime')
+ clean
+ xilinx_srl -fixed -minlen 3 (skip if '-nosrl')
+ techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v -map +/xilinx/{family}_ff_map.v -D LUT_WIDTH=[46]
+ xilinx_dffopt [-lut4]
+ opt_lut_ins -tech xilinx
+
+ finalize:
+ clkbufmap -buf BUFG O:I (skip if '-noclkbuf')
+ extractinv -inv INV O:I (only if '-ise')
clean
check:
hierarchy -check
- stat
+ stat -tech xilinx
check -noinit
- edif: (only if -edif)
- write_edif <file-name>
+ edif:
+ write_edif -pvector bra
- blif: (only if -blif)
- write_blif <file-name>
+ blif:
+ write_blif
\end{lstlisting}
\section{tcl -- execute a TCL script file}
\label{cmd:tcl}
\begin{lstlisting}[numbers=left,frame=single]
- tcl <filename>
+ tcl <filename> [args]
This command executes the tcl commands in the specified file.
Use 'yosys cmd' to run the yosys command 'cmd' from tcl.
@@ -4324,6 +6153,9 @@ The tcl command 'yosys -import' can be used to import all yosys
commands directly as tcl commands to the tcl shell. Yosys commands
'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'
in order to avoid a name collision with the built in commands.
+
+If any arguments are specified, these arguments are provided to the script via
+the standard $argc and $argv variables.
\end{lstlisting}
\section{techmap -- generic technology mapper}
@@ -4349,7 +6181,8 @@ file.
instead of inlining them.
-max_iter <number>
- only run the specified number of iterations.
+ only run the specified number of iterations on each module.
+ default: unlimited
-recursive
instead of the iterative breadth-first algorithm use a recursive
@@ -4359,6 +6192,9 @@ file.
-autoproc
Automatically call "proc" on implementations that contain processes.
+ -wb
+ Ignore the 'whitebox' attribute on cell implementations.
+
-assert
this option will cause techmap to exit with an error if it can't map
a selected cell. only cell types that end on an underscore are accepted
@@ -4383,6 +6219,11 @@ When a module in the map file has the 'techmap_wrap' attribute set, techmap
will create a wrapper for the cell and then run the command string that the
attribute is set to on the wrapper module.
+When a port on a module in the map file has the 'techmap_autopurge' attribute
+set, and that port is not connected in the instantiation that is mapped, then
+then a cell port connected only to such wires will be omitted in the mapped
+version of the circuit.
+
All wires in the modules from the map file matching the pattern _TECHMAP_*
or *._TECHMAP_* are special wires that are used to pass instructions from
the mapping module to the techmap command. At the moment the following special
@@ -4421,6 +6262,13 @@ wires are supported:
It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.
+ _TECHMAP_REMOVEINIT_<port-name>_
+ When this wire is set to a constant value, the init attribute of the wire(s)
+ connected to this port will be consumed. This wire must have the same
+ width as the given port, and for every bit that is set to 1 in the value,
+ the corresponding init attribute bit will be changed to 1'bx. If all
+ bits of an init attribute are left as x, it will be removed.
+
In addition to this special wires, techmap also supports special parameters in
modules in the map file:
@@ -4434,6 +6282,13 @@ modules in the map file:
former has a 1-bit for each constant input bit and the latter has the
value for this bit. The unused bits of the latter are set to undef (x).
+ _TECHMAP_WIREINIT_<port-name>_
+ When a parameter with this name exists, it will be set to the initial
+ value of the wire(s) connected to the given port, as specified by the init
+ attribute. If the attribute doesn't exist, x will be filled for the
+ missing bits. To remove the init attribute bits used, use the
+ _TECHMAP_REMOVEINIT_*_ wires.
+
_TECHMAP_BITS_CONNMAP_
_TECHMAP_CONNMAP_<port-name>_
For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it
@@ -4449,6 +6304,12 @@ constant value.
A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name
and attributes of the cell that is being replaced.
+A cell with a name of the form `_TECHMAP_REPLACE_.<suffix>` in the map file will
+be named thus but with the `_TECHMAP_REPLACE_' prefix substituted with the name
+of the cell being replaced.
+Similarly, a wire named in the form `_TECHMAP_REPLACE_.<suffix>` will cause a
+new wire alias to be created and named as above but with the `_TECHMAP_REPLACE_'
+prefix also substituted.
See 'help extract' for a pass that does the opposite thing.
@@ -4465,7 +6326,7 @@ Execute the specified command, optionally writing the commands output to the
specified logfile(s).
-q
- Do not print output to the normal destination (console and/or log file)
+ Do not print output to the normal destination (console and/or log file).
-o logfile
Write output to this file, truncate if exists.
@@ -4474,7 +6335,7 @@ specified logfile(s).
Write output to this file, append if exists.
+INT, -INT
- Add/subract INT from the -v setting for this command.
+ Add/subtract INT from the -v setting for this command.
\end{lstlisting}
\section{test\_abcloop -- automatically test handling of loops in abc command}
@@ -4511,8 +6372,16 @@ The attribute 'gentb_constant' can be used to force a signal to a constant
value after initialization. This can e.g. be used to force a reset signal
low in order to explore more inner states in a state machine.
+The attribute 'gentb_skip' can be attached to modules to suppress testbench
+generation.
+
-n <int>
number of iterations the test bench should run (default = 1000)
+
+ -seed <int>
+ seed used for pseudo-random number generation (default = 0).
+ a value of 0 will cause an arbitrary seed to be chosen, based on
+ the current system time.
\end{lstlisting}
\section{test\_cell -- automatically test the implementation of a cell type}
@@ -4574,6 +6443,29 @@ cell types. Use for example 'all /$add' for all cell types except $add.
create a Verilog test bench to test simlib and write_verilog
\end{lstlisting}
+\section{test\_pmgen -- test pass for pmgen}
+\label{cmd:test_pmgen}
+\begin{lstlisting}[numbers=left,frame=single]
+ test_pmgen -reduce_chain [options] [selection]
+
+Demo for recursive pmgen patterns. Map chains of AND/OR/XOR to $reduce_*.
+
+
+ test_pmgen -reduce_tree [options] [selection]
+
+Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.
+
+
+ test_pmgen -eqpmux [options] [selection]
+
+Demo for recursive pmgen patterns. Optimize EQ/NE/PMUX circuits.
+
+
+ test_pmgen -generate [options] <pattern_name>
+
+Create modules that match the specified pattern.
+\end{lstlisting}
+
\section{torder -- print cells in topological order}
\label{cmd:torder}
\begin{lstlisting}[numbers=left,frame=single]
@@ -4656,12 +6548,18 @@ Like -sv, but define FORMAL instead of SYNTHESIS.
Load the specified VHDL files into Verific.
- verific -work <libname> {-sv|-vhdl|...} <hdl-file>
+ verific [-work <libname>] {-sv|-vhdl|...} <hdl-file>
Load the specified Verilog/SystemVerilog/VHDL file into the specified library.
(default library when -work is not present: "work")
+ verific [-L <libname>] {-sv|-vhdl|...} <hdl-file>
+
+Look up external definitions in the specified library.
+(-L may be used more than once)
+
+
verific -vlog-incdir <directory>..
Add Verilog include directories.
@@ -4715,6 +6613,16 @@ Import options:
-autocover
Generate automatic cover statements for all asserts
+ -fullinit
+ Keep all register initializations, even those for non-FF registers.
+
+ -chparam name value
+ Elaborate the specified top modules (all modules when -all given) using
+ this parameter value. Modules on which this parameter does not exist will
+ cause Verific to produce a VERI-1928 or VHDL-1676 message. This option
+ can be specified multiple times to override multiple parameters.
+ String values must be passed in double quotes (").
+
-v, -vv
Verbose log messages. (-vv is even more verbose than -v.)
@@ -4743,7 +6651,12 @@ bindings (for Yosys and/or Verific developers):
-d <dump_file>
Dump the Verific netlist as a verilog file.
-Visit http://verific.com/ for more information on Verific.
+
+Use Symbiotic EDA Suite if you need Yosys+Verifc.
+https://www.symbioticeda.com/seda-suite
+
+Contact office@symbioticeda.com for free evaluation
+binaries of Symbiotic EDA Suite.
\end{lstlisting}
\section{verilog\_defaults -- set default options for read\_verilog}
@@ -4779,6 +6692,21 @@ Define and undefine verilog preprocessor macros.
-Uname[=definition]
undefine the preprocessor symbol 'name'
+
+ -reset
+ clear list of defined preprocessor symbols
+
+ -list
+ list currently defined preprocessor symbols
+\end{lstlisting}
+
+\section{wbflip -- flip the whitebox attribute}
+\label{cmd:wbflip}
+\begin{lstlisting}[numbers=left,frame=single]
+ wbflip [selection]
+
+Flip the whitebox attribute on selected cells. I.e. if it's set, unset it, and
+vice-versa. Blackbox cells are not effected by this command.
\end{lstlisting}
\section{wreduce -- reduce the word size of operations if possible}
@@ -4798,6 +6726,9 @@ Options:
-memx
Do not change the width of memory address ports. Use this options in
flows that use the 'memory_memx' pass.
+
+ -keepdc
+ Do not optimize explicit don't-care values.
\end{lstlisting}
\section{write\_aiger -- write design to AIGER file}
@@ -4813,7 +6744,7 @@ $assert and $assume cells are converted to AIGER bad state properties and
invariant constraints.
-ascii
- write ASCII version of AGIER format
+ write ASCII version of AIGER format
-zinit
convert FFs to zero-initialized FFs, adding additional inputs for
@@ -4830,6 +6761,11 @@ invariant constraints.
-vmap <filename>
like -map, but more verbose
+
+ -I, -O, -B, -L
+ If the design contains no input/output/assert/flip-flop then create one
+ dummy input/output/bad_state-pin or latch to make the tools reading the
+ AIGER file happy.
\end{lstlisting}
\section{write\_blif -- write design to BLIF file}
@@ -4913,6 +6849,58 @@ Write a BTOR description of the current design.
-s
Output only a single bad property for all asserts
+
+ -c
+ Output cover properties using 'bad' statements instead of asserts
+
+ -i <filename>
+ Create additional info file with auxiliary information
+\end{lstlisting}
+
+\section{write\_cxxrtl -- convert design to C++ RTL simulation}
+\label{cmd:write_cxxrtl}
+\begin{lstlisting}[numbers=left,frame=single]
+ write_cxxrtl [options] [filename]
+
+Write C++ code for simulating the design. The generated code requires a driver;
+the following simple driver is provided as an example:
+
+ #include "top.cc"
+
+ int main() {
+ cxxrtl_design::p_top top;
+ while (1) {
+ top.p_clk.next = value<1> {1u};
+ top.step();
+ top.p_clk.next = value<1> {0u};
+ top.step();
+ }
+ }
+
+The following options are supported by this backend:
+
+ -O <level>
+ set the optimization level. the default is -O5. higher optimization
+ levels dramatically decrease compile and run time, and highest level
+ possible for a design should be used.
+
+ -O0
+ no optimization.
+
+ -O1
+ elide internal wires if possible.
+
+ -O2
+ like -O1, and localize internal wires if possible.
+
+ -O3
+ like -O2, and elide public wires not marked (*keep*) if possible.
+
+ -O4
+ like -O3, and localize public wires not marked (*keep*) if possible.
+
+ -O5
+ like -O4, and run `splitnets -driver; opt_clean -purge` first.
\end{lstlisting}
\section{write\_edif -- write design to EDIF netlist file}
@@ -4930,6 +6918,13 @@ Write the current design to an EDIF netlist file.
if the design contains constant nets. use "hilomap" to map to custom
constant drivers first)
+ -gndvccy
+ create "GND" and "VCC" cells with "Y" outputs. (the default is "G"
+ for "GND" and "P" for "VCC".)
+
+ -attrprop
+ create EDIF properties for cell attributes
+
-pvector {par|bra|ang}
sets the delimiting character for module port rename clauses to
parentheses, square brackets, or angle brackets.
@@ -4964,6 +6959,8 @@ Inside a script the input file can also can a here-document:
write_firrtl [options] [filename]
Write a FIRRTL netlist of the current design.
+The following commands are executed by this command:
+ pmuxtree
\end{lstlisting}
\section{write\_ilang -- write design to ilang file}
@@ -5012,6 +7009,10 @@ Write a JSON netlist of the current design.
-aig
include AIG models for the different gate types
+ -compat-int
+ emit 32-bit or smaller fully-defined parameter values directly
+ as JSON numbers (for compatibility with old parsers)
+
The general syntax of the JSON output created by this command is as follows:
@@ -5083,12 +7084,10 @@ interface is known.
Module and cell ports and nets can be single bit wide or vectors of multiple
bits. Each individual signal bit is assigned a unique integer. The <bit_vector>
values referenced above are vectors of this integers. Signal bits that are
-connected to a constant driver are denoted as string "0" or "1" instead of
-a number.
+connected to a constant driver are denoted as string "0", "1", "x", or
+"z" instead of a number.
-Numeric parameter and attribute values up to 32 bits are written as decimal
-values. Numbers larger than that are written as string holding the binary
-representation of the value.
+Bit vectors (including integers) are written as string holding the binaryrepresentation of the value. Strings are written as strings, with an appendedblank in cases of strings of the form /[01xz]* */.
For example the following Verilog code:
@@ -5214,7 +7213,7 @@ format. A program processing this format must ignore all unknown fields.
\begin{lstlisting}[numbers=left,frame=single]
write_simplec [options] [filename]
-Write simple C code for simulating the design. The C code writen can be used to
+Write simple C code for simulating the design. The C code written can be used to
simulate the design in a C environment, but the purpose of this command is to
generate code that works well with C-based formal verification.
@@ -5471,6 +7470,10 @@ Write the current design to a Verilog file.
without this option all internal cells are converted to Verilog
expressions.
+ -siminit
+ add initial statements with hierarchical refs to initialize FFs when
+ in -noexpr mode.
+
-nodec
32-bit constant values are by default dumped as decimal numbers,
not bit pattern. This option deactivates this feature and instead
@@ -5490,8 +7493,16 @@ Write the current design to a Verilog file.
deactivates this feature and instead will write string constants
as binary numbers.
+ -extmem
+ instead of initializing memories using assignments to individual
+ elements, use the '$readmemh' function to read initialization data
+ from a file. This data is written to a file named by appending
+ a sequential index to the Verilog filename and replacing the extension
+ with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',
+ 'foo-2.mem' and so on.
+
-defparam
- Use 'defparam' statements instead of the Verilog-2001 syntax for
+ use 'defparam' statements instead of the Verilog-2001 syntax for
cell parameters.
-blackboxes
@@ -5513,6 +7524,97 @@ processes to logic networks and registers. A warning is generated when
this command is called on a design with RTLIL processes.
\end{lstlisting}
+\section{write\_xaiger -- write design to XAIGER file}
+\label{cmd:write_xaiger}
+\begin{lstlisting}[numbers=left,frame=single]
+ write_xaiger [options] [filename]
+
+Write the top module (according to the (* top *) attribute or if only one module
+is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_ABC9_FF_, ornon (* abc9_box_id *) cells will be converted into psuedo-inputs and
+pseudo-outputs. Whitebox contents will be taken from the '<module-name>$holes'
+module, if it exists.
+
+ -ascii
+ write ASCII version of AIGER format
+
+ -map <filename>
+ write an extra file with port and box symbols
+\end{lstlisting}
+
+\section{xilinx\_dffopt -- Xilinx: optimize FF control signal usage}
+\label{cmd:xilinx_dffopt}
+\begin{lstlisting}[numbers=left,frame=single]
+ xilinx_dffopt [options] [selection]
+
+Converts hardware clock enable and set/reset signals on FFs to emulation
+using LUTs, if doing so would improve area. Operates on post-techmap Xilinx
+cells (LUT*, FD*).
+
+ -lut4
+ Assume a LUT4-based device (instead of a LUT6-based device).
+\end{lstlisting}
+
+\section{xilinx\_dsp -- Xilinx: pack resources into DSPs}
+\label{cmd:xilinx_dsp}
+\begin{lstlisting}[numbers=left,frame=single]
+ xilinx_dsp [options] [selection]
+
+Pack input registers (A2, A1, B2, B1, C, D, AD; with optional enable/reset),
+pipeline registers (M; with optional enable/reset), output registers (P; with
+optional enable/reset), pre-adder and/or post-adder into Xilinx DSP resources.
+
+Multiply-accumulate operations using the post-adder with feedback on the 'C'
+input will be folded into the DSP. In this scenario only, the 'C' input can be
+used to override the current accumulation result with a new value, which will
+be added to the multiplier result to form the next accumulation result.
+
+Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'
+connections (optionally, where 'P' is right-shifted by 17-bits and used as an
+input to the post-adder -- a pattern common for summing partial products to
+implement wide multipliers). Limited support also exists for similar cascading
+for A and B using '[AB]COUT' -> '[AB]CIN'. Currently, cascade chains are limited
+to a maximum length of 20 cells, corresponding to the smallest Xilinx 7 Series
+device.
+
+This pass is a no-op if the scratchpad variable 'xilinx_dsp.multonly' is set
+to 1.
+
+
+Experimental feature: addition/subtractions less than 12 or 24 bits with the
+'(* use_dsp="simd" *)' attribute attached to the output wire or attached to
+the add/subtract operator will cause those operations to be implemented using
+the 'SIMD' feature of DSPs.
+
+Experimental feature: the presence of a `$ge' cell attached to the registered
+P output implementing the operation "(P >= <power-of-2>)" will be transformed
+into using the DSP48E1's pattern detector feature for overflow detection.
+
+ -family {xcup|xcu|xc7|xc6v|xc5v|xc4v|xc6s|xc3sda}
+ select the family to target
+ default: xc7
+\end{lstlisting}
+
+\section{xilinx\_srl -- Xilinx shift register extraction}
+\label{cmd:xilinx_srl}
+\begin{lstlisting}[numbers=left,frame=single]
+ xilinx_srl [options] [selection]
+
+This pass converts chains of built-in flops (bit-level: $_DFF_[NP]_, $_DFFE_*
+and word-level: $dff, $dffe) as well as Xilinx flops (FDRE, FDRE_1) into a
+$__XILINX_SHREG cell. Chains must be of the same cell type, clock, clock polarity,
+enable, and enable polarity (where relevant).
+Flops with resets cannot be mapped to Xilinx devices and will not be inferred.
+ -minlen N
+ min length of shift register (default = 3)
+
+ -fixed
+ infer fixed-length shift registers.
+
+ -variable
+ infer variable-length shift registers (i.e. fixed-length shifts where
+ each element also fans-out to a $shiftx cell).
+\end{lstlisting}
+
\section{zinit -- add inverters so all FF are zero-initialized}
\label{cmd:zinit}
\begin{lstlisting}[numbers=left,frame=single]
diff --git a/misc/yosys-config.in b/misc/yosys-config.in
index 1473948cf..370835f8f 100644
--- a/misc/yosys-config.in
+++ b/misc/yosys-config.in
@@ -18,21 +18,21 @@ help() {
echo ""
echo "Use --exec to call a command instead of generating output. Example usage:"
echo ""
- echo " yosys-config --exec --cxx --cxxflags --ldflags -o plugin.so -shared plugin.cc --ldlibs"
+ echo " $0 --exec --cxx --cxxflags --ldflags -o plugin.so -shared plugin.cc --ldlibs"
echo ""
echo "The above command can be abbreviated as:"
echo ""
- echo " yosys-config --build plugin.so plugin.cc"
+ echo " $0 --build plugin.so plugin.cc"
echo ""
echo "Use --prefix to change the prefix for the special args from '--' to"
echo "something else. Example:"
echo ""
- echo " yosys-config --prefix @ bindir: @bindir"
+ echo " $0 --prefix @ bindir: @bindir"
echo ""
echo "The args --bindir and --datdir can be directly followed by a slash and"
echo "additional text. Example:"
echo ""
- echo " yosys-config --datdir/simlib.v"
+ echo " $0 --datdir/simlib.v"
echo ""
} >&2
exit 1
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
index ed427693d..ad6a07fa0 100644
--- a/passes/cmds/bugpoint.cc
+++ b/passes/cmds/bugpoint.cc
@@ -114,8 +114,8 @@ struct BugpointPass : public Pass {
return design;
RTLIL::Design *design_copy = new RTLIL::Design;
- for (auto &it : design->modules_)
- design_copy->add(it.second->clone());
+ for (auto module : design->modules())
+ design_copy->add(module->clone());
Pass::call(design_copy, "proc_clean -quiet");
Pass::call(design_copy, "clean -purge");
@@ -127,21 +127,21 @@ struct BugpointPass : public Pass {
RTLIL::Design *simplify_something(RTLIL::Design *design, int &seed, bool stage2, bool modules, bool ports, bool cells, bool connections, bool assigns, bool updates)
{
RTLIL::Design *design_copy = new RTLIL::Design;
- for (auto &it : design->modules_)
- design_copy->add(it.second->clone());
+ for (auto module : design->modules())
+ design_copy->add(module->clone());
int index = 0;
if (modules)
{
- for (auto &it : design_copy->modules_)
+ for (auto module : design_copy->modules())
{
- if (it.second->get_blackbox_attribute())
+ if (module->get_blackbox_attribute())
continue;
if (index++ == seed)
{
- log("Trying to remove module %s.\n", it.first.c_str());
- design_copy->remove(it.second);
+ log("Trying to remove module %s.\n", module->name.c_str());
+ design_copy->remove(module);
return design_copy;
}
}
@@ -178,12 +178,12 @@ struct BugpointPass : public Pass {
if (mod->get_blackbox_attribute())
continue;
- for (auto &it : mod->cells_)
+ for (auto cell : mod->cells())
{
if (index++ == seed)
{
- log("Trying to remove cell %s.%s.\n", mod->name.c_str(), it.first.c_str());
- mod->remove(it.second);
+ log("Trying to remove cell %s.%s.\n", mod->name.c_str(), cell->name.c_str());
+ mod->remove(cell);
return design_copy;
}
}
@@ -285,7 +285,7 @@ struct BugpointPass : public Pass {
}
}
}
- return NULL;
+ return nullptr;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -433,8 +433,8 @@ struct BugpointPass : public Pass {
{
Pass::call(design, "design -reset");
crashing_design = clean_design(crashing_design, clean, /*do_delete=*/true);
- for (auto &it : crashing_design->modules_)
- design->add(it.second->clone());
+ for (auto module : crashing_design->modules())
+ design->add(module->clone());
delete crashing_design;
}
}
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
index 63703b848..ba29e6f4b 100644
--- a/passes/cmds/check.cc
+++ b/passes/cmds/check.cc
@@ -98,49 +98,6 @@ struct CheckPass : public Pass {
log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
- pool<IdString> fftypes;
- fftypes.insert(ID($sr));
- fftypes.insert(ID($ff));
- fftypes.insert(ID($dff));
- fftypes.insert(ID($dffe));
- fftypes.insert(ID($dffsr));
- fftypes.insert(ID($adff));
- fftypes.insert(ID($dlatch));
- fftypes.insert(ID($dlatchsr));
- fftypes.insert(ID($_DFFE_NN_));
- fftypes.insert(ID($_DFFE_NP_));
- fftypes.insert(ID($_DFFE_PN_));
- fftypes.insert(ID($_DFFE_PP_));
- fftypes.insert(ID($_DFFSR_NNN_));
- fftypes.insert(ID($_DFFSR_NNP_));
- fftypes.insert(ID($_DFFSR_NPN_));
- fftypes.insert(ID($_DFFSR_NPP_));
- fftypes.insert(ID($_DFFSR_PNN_));
- fftypes.insert(ID($_DFFSR_PNP_));
- fftypes.insert(ID($_DFFSR_PPN_));
- fftypes.insert(ID($_DFFSR_PPP_));
- fftypes.insert(ID($_DFF_NN0_));
- fftypes.insert(ID($_DFF_NN1_));
- fftypes.insert(ID($_DFF_NP0_));
- fftypes.insert(ID($_DFF_NP1_));
- fftypes.insert(ID($_DFF_N_));
- fftypes.insert(ID($_DFF_PN0_));
- fftypes.insert(ID($_DFF_PN1_));
- fftypes.insert(ID($_DFF_PP0_));
- fftypes.insert(ID($_DFF_PP1_));
- fftypes.insert(ID($_DFF_P_));
- fftypes.insert(ID($_DLATCHSR_NNN_));
- fftypes.insert(ID($_DLATCHSR_NNP_));
- fftypes.insert(ID($_DLATCHSR_NPN_));
- fftypes.insert(ID($_DLATCHSR_NPP_));
- fftypes.insert(ID($_DLATCHSR_PNN_));
- fftypes.insert(ID($_DLATCHSR_PNP_));
- fftypes.insert(ID($_DLATCHSR_PPN_));
- fftypes.insert(ID($_DLATCHSR_PPP_));
- fftypes.insert(ID($_DLATCH_N_));
- fftypes.insert(ID($_DLATCH_P_));
- fftypes.insert(ID($_FF_));
-
for (auto module : design->selected_whole_modules_warn())
{
if (module->has_processes_warn())
@@ -242,7 +199,7 @@ struct CheckPass : public Pass {
{
for (auto cell : module->cells())
{
- if (fftypes.count(cell->type) == 0)
+ if (RTLIL::builtin_ff_cell_types().count(cell->type) == 0)
continue;
for (auto bit : sigmap(cell->getPort(ID::Q)))
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc
index f93bada27..0b0868dfb 100644
--- a/passes/cmds/connect.cc
+++ b/passes/cmds/connect.cc
@@ -32,9 +32,9 @@ static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &
RTLIL::Wire *dummy_wire = module->addWire(NEW_ID, sig.size());
- for (auto &it : module->cells_)
- for (auto &port : it.second->connections_)
- if (ct.cell_output(it.second->type, port.first))
+ for (auto cell : module->cells())
+ for (auto &port : cell->connections_)
+ if (ct.cell_output(cell->type, port.first))
sigmap(port.second).replace(sig, dummy_wire, &port.second);
for (auto &conn : module->connections_)
@@ -77,15 +77,13 @@ struct ConnectPass : public Pass {
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- RTLIL::Module *module = NULL;
- for (auto &it : design->modules_) {
- if (!design->selected(it.second))
- continue;
- if (module != NULL)
- log_cmd_error("Multiple modules selected: %s, %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.first));
- module = it.second;
+ RTLIL::Module *module = nullptr;
+ for (auto mod : design->selected_modules()) {
+ if (module != nullptr)
+ log_cmd_error("Multiple modules selected: %s, %s\n", log_id(module->name), log_id(mod->name));
+ module = mod;
}
- if (module == NULL)
+ if (module == nullptr)
log_cmd_error("No modules selected.\n");
if (!module->processes.empty())
log_cmd_error("Found processes in selected module.\n");
@@ -130,7 +128,7 @@ struct ConnectPass : public Pass {
std::vector<RTLIL::SigBit> lhs = it.first.to_sigbit_vector();
std::vector<RTLIL::SigBit> rhs = it.first.to_sigbit_vector();
for (size_t i = 0; i < lhs.size(); i++)
- if (rhs[i].wire != NULL)
+ if (rhs[i].wire != nullptr)
sigmap.add(lhs[i], rhs[i]);
}
@@ -172,14 +170,14 @@ struct ConnectPass : public Pass {
if (flag_nounset)
log_cmd_error("Can't use -port together with -nounset.\n");
- if (module->cells_.count(RTLIL::escape_id(port_cell)) == 0)
+ if (module->cell(RTLIL::escape_id(port_cell)) == nullptr)
log_cmd_error("Can't find cell %s.\n", port_cell.c_str());
RTLIL::SigSpec sig;
if (!RTLIL::SigSpec::parse_sel(sig, design, module, port_expr))
log_cmd_error("Failed to parse port expression `%s'.\n", port_expr.c_str());
- module->cells_.at(RTLIL::escape_id(port_cell))->setPort(RTLIL::escape_id(port_port), sigmap(sig));
+ module->cell(RTLIL::escape_id(port_cell))->setPort(RTLIL::escape_id(port_port), sigmap(sig));
}
else
log_cmd_error("Expected -set, -unset, or -port.\n");
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
index 5a15cbbaf..6ae7c9304 100644
--- a/passes/cmds/connwrappers.cc
+++ b/passes/cmds/connwrappers.cc
@@ -65,15 +65,13 @@ struct ConnwrappersWorker
decls[key] = decl;
}
- void work(RTLIL::Design *design, RTLIL::Module *module)
+ void work(RTLIL::Module *module)
{
std::map<RTLIL::SigBit, std::pair<bool, RTLIL::SigSpec>> extend_map;
SigMap sigmap(module);
- for (auto &it : module->cells_)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = it.second;
-
if (!decl_celltypes.count(cell->type))
continue;
@@ -105,13 +103,8 @@ struct ConnwrappersWorker
}
}
- for (auto &it : module->cells_)
+ for (auto cell : module->selected_cells())
{
- RTLIL::Cell *cell = it.second;
-
- if (!design->selected(module, cell))
- continue;
-
for (auto &conn : cell->connections_)
{
std::vector<RTLIL::SigBit> sigbits = sigmap(conn.second).to_sigbit_vector();
@@ -141,8 +134,8 @@ struct ConnwrappersWorker
}
if (old_sig.size())
- log("Connected extended bits of %s.%s:%s: %s -> %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name),
- RTLIL::id2cstr(conn.first), log_signal(old_sig), log_signal(conn.second));
+ log("Connected extended bits of %s.%s:%s: %s -> %s\n", log_id(module->name), log_id(cell->name),
+ log_id(conn.first), log_signal(old_sig), log_signal(conn.second));
}
}
}
@@ -200,9 +193,8 @@ struct ConnwrappersPass : public Pass {
log_header(design, "Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
- for (auto &mod_it : design->modules_)
- if (design->selected(mod_it.second))
- worker.work(design, mod_it.second);
+ for (auto module : design->selected_modules())
+ worker.work(module);
}
} ConnwrappersPass;
diff --git a/passes/cmds/copy.cc b/passes/cmds/copy.cc
index acd2dba52..99f1f69cf 100644
--- a/passes/cmds/copy.cc
+++ b/passes/cmds/copy.cc
@@ -44,10 +44,10 @@ struct CopyPass : public Pass {
std::string src_name = RTLIL::escape_id(args[1]);
std::string trg_name = RTLIL::escape_id(args[2]);
- if (design->modules_.count(src_name) == 0)
+ if (design->module(src_name) == nullptr)
log_cmd_error("Can't find source module %s.\n", src_name.c_str());
- if (design->modules_.count(trg_name) != 0)
+ if (design->module(trg_name) != nullptr)
log_cmd_error("Target module name %s already exists.\n", trg_name.c_str());
RTLIL::Module *new_mod = design->module(src_name)->clone();
diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc
index 125bc96ca..b124e3b0f 100644
--- a/passes/cmds/delete.cc
+++ b/passes/cmds/delete.cc
@@ -65,27 +65,24 @@ struct DeletePass : public Pass {
}
extra_args(args, argidx, design);
- std::vector<RTLIL::IdString> delete_mods;
-
- for (auto &mod_it : design->modules_)
+ std::vector<RTLIL::Module *> delete_mods;
+ for (auto module : design->modules())
{
- if (design->selected_whole_module(mod_it.first) && !flag_input && !flag_output) {
- delete_mods.push_back(mod_it.first);
+ if (design->selected_whole_module(module->name) && !flag_input && !flag_output) {
+ delete_mods.push_back(module);
continue;
}
- if (!design->selected_module(mod_it.first))
+ if (!design->selected_module(module->name))
continue;
- RTLIL::Module *module = mod_it.second;
-
if (flag_input || flag_output) {
- for (auto &it : module->wires_)
- if (design->selected(module, it.second)) {
+ for (auto wire : module->wires())
+ if (design->selected(module, wire)) {
if (flag_input)
- it.second->port_input = false;
+ wire->port_input = false;
if (flag_output)
- it.second->port_output = false;
+ wire->port_output = false;
}
module->fixup_ports();
continue;
@@ -96,20 +93,19 @@ struct DeletePass : public Pass {
pool<RTLIL::IdString> delete_procs;
pool<RTLIL::IdString> delete_mems;
- for (auto &it : module->wires_)
- if (design->selected(module, it.second))
- delete_wires.insert(it.second);
+ for (auto wire : module->selected_wires())
+ delete_wires.insert(wire);
for (auto &it : module->memories)
if (design->selected(module, it.second))
delete_mems.insert(it.first);
- for (auto &it : module->cells_) {
- if (design->selected(module, it.second))
- delete_cells.insert(it.second);
- if (it.second->type.in(ID($memrd), ID($memwr)) &&
- delete_mems.count(it.second->parameters.at(ID::MEMID).decode_string()) != 0)
- delete_cells.insert(it.second);
+ for (auto cell : module->cells()) {
+ if (design->selected(module, cell))
+ delete_cells.insert(cell);
+ if (cell->type.in(ID($memrd), ID($memwr)) &&
+ delete_mems.count(cell->parameters.at(ID::MEMID).decode_string()) != 0)
+ delete_cells.insert(cell);
}
for (auto &it : module->processes)
@@ -134,9 +130,8 @@ struct DeletePass : public Pass {
module->fixup_ports();
}
- for (auto &it : delete_mods) {
- delete design->modules_.at(it);
- design->modules_.erase(it);
+ for (auto mod : delete_mods) {
+ design->remove(mod);
}
}
} DeletePass;
diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc
index 4fd43329f..cfe97067d 100644
--- a/passes/cmds/design.cc
+++ b/passes/cmds/design.cc
@@ -60,6 +60,11 @@ struct DesignPass : public Pass {
log("Push the current design to the stack and then clear the current design.\n");
log("\n");
log("\n");
+ log(" design -push-copy\n");
+ log("\n");
+ log("Push the current design to the stack without clearing the current design.\n");
+ log("\n");
+ log("\n");
log(" design -pop\n");
log("\n");
log("Reset the current design and pop the last design from the stack.\n");
@@ -94,6 +99,11 @@ struct DesignPass : public Pass {
log("The Verilog front-end remembers defined macros and top-level declarations\n");
log("between calls to 'read_verilog'. This command resets this memory.\n");
log("\n");
+ log(" design -delete <name>\n");
+ log("\n");
+ log("Delete the design previously saved under the given name.\n");
+ log("\n");
+
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -101,10 +111,11 @@ struct DesignPass : public Pass {
bool reset_mode = false;
bool reset_vlog_mode = false;
bool push_mode = false;
+ bool push_copy_mode = false;
bool pop_mode = false;
bool import_mode = false;
RTLIL::Design *copy_from_design = NULL, *copy_to_design = NULL;
- std::string save_name, load_name, as_name;
+ std::string save_name, load_name, as_name, delete_name;
std::vector<RTLIL::Module*> copy_src_modules;
size_t argidx;
@@ -126,6 +137,11 @@ struct DesignPass : public Pass {
push_mode = true;
continue;
}
+ if (!got_mode && args[argidx] == "-push-copy") {
+ got_mode = true;
+ push_copy_mode = true;
+ continue;
+ }
if (!got_mode && args[argidx] == "-pop") {
got_mode = true;
pop_mode = true;
@@ -179,6 +195,13 @@ struct DesignPass : public Pass {
as_name = args[++argidx];
continue;
}
+ if (!got_mode && args[argidx] == "-delete" && argidx+1 < args.size()) {
+ got_mode = true;
+ delete_name = args[++argidx];
+ if (saved_designs.count(delete_name) == 0)
+ log_cmd_error("No saved design '%s' found!\n", delete_name.c_str());
+ continue;
+ }
break;
}
@@ -307,7 +330,7 @@ struct DesignPass : public Pass {
}
}
- if (!save_name.empty() || push_mode)
+ if (!save_name.empty() || push_mode || push_copy_mode)
{
RTLIL::Design *design_copy = new RTLIL::Design;
@@ -321,7 +344,7 @@ struct DesignPass : public Pass {
if (saved_designs.count(save_name))
delete saved_designs.at(save_name);
- if (push_mode)
+ if (push_mode || push_copy_mode)
pushed_designs.push_back(design_copy);
else
saved_designs[save_name] = design_copy;
@@ -329,7 +352,7 @@ struct DesignPass : public Pass {
if (reset_mode || !load_name.empty() || push_mode || pop_mode)
{
- for (auto mod : design->modules())
+ for (auto mod : design->modules().to_vector())
design->remove(mod);
design->selection_stack.clear();
@@ -368,6 +391,14 @@ struct DesignPass : public Pass {
pushed_designs.pop_back();
}
}
+
+ if (!delete_name.empty())
+ {
+ auto it = saved_designs.find(delete_name);
+ log_assert(it != saved_designs.end());
+ delete it->second;
+ saved_designs.erase(it);
+ }
}
} DesignPass;
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 9b1830b7b..7d6d84d42 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -32,27 +32,27 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
if (module->count_id(to_name))
log_cmd_error("There is already an object `%s' in module `%s'.\n", to_name.c_str(), module->name.c_str());
- for (auto &it : module->wires_)
- if (it.first == from_name) {
- Wire *w = it.second;
- log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
- module->rename(w, to_name);
- if (w->port_id || flag_output) {
- if (flag_output)
- w->port_output = true;
- module->fixup_ports();
- }
- return;
- }
+ RTLIL::Wire *wire_to_rename = module->wire(from_name);
+ RTLIL::Cell *cell_to_rename = module->cell(from_name);
- for (auto &it : module->cells_)
- if (it.first == from_name) {
+ if (wire_to_rename != nullptr) {
+ log("Renaming wire %s to %s in module %s.\n", log_id(wire_to_rename), log_id(to_name), log_id(module));
+ module->rename(wire_to_rename, to_name);
+ if (wire_to_rename->port_id || flag_output) {
if (flag_output)
- log_cmd_error("Called with -output but the specified object is a cell.\n");
- log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
- module->rename(it.second, to_name);
- return;
+ wire_to_rename->port_output = true;
+ module->fixup_ports();
}
+ return;
+ }
+
+ if (cell_to_rename != nullptr) {
+ if (flag_output)
+ log_cmd_error("Called with -output but the specified object is a cell.\n");
+ log("Renaming cell %s to %s in module %s.\n", log_id(cell_to_rename), log_id(to_name), log_id(module));
+ module->rename(cell_to_rename, to_name);
+ return;
+ }
log_cmd_error("Object `%s' not found!\n", from_name.c_str());
}
@@ -66,26 +66,26 @@ static std::string derive_name_from_src(const std::string &src, int counter)
return stringf("\\%s$%d", src_base.c_str(), counter);
}
-static IdString derive_name_from_wire(const RTLIL::Cell &cell)
+static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell)
{
// Find output
const SigSpec *output = nullptr;
int num_outputs = 0;
- for (auto &connection : cell.connections()) {
- if (cell.output(connection.first)) {
+ for (auto &connection : cell->connections()) {
+ if (cell->output(connection.first)) {
output = &connection.second;
num_outputs++;
}
}
if (num_outputs != 1) // Skip cells thad drive multiple outputs
- return cell.name;
+ return cell->name;
std::string name = "";
for (auto &chunk : output->chunks()) {
// Skip cells that drive privately named wires
if (!chunk.wire || chunk.wire->name.str()[0] == '$')
- return cell.name;
+ return cell->name;
if (name != "")
name += "$";
@@ -99,7 +99,7 @@ static IdString derive_name_from_wire(const RTLIL::Cell &cell)
}
}
- return name + cell.type.str();
+ return name + cell->type.str();
}
struct RenamePass : public Pass {
@@ -210,30 +210,25 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
+ for (auto module : design->selected_modules())
{
int counter = 0;
+ dict<RTLIL::Wire *, IdString> new_wire_names;
+ dict<RTLIL::Cell *, IdString> new_cell_names;
+
+ for (auto wire : module->selected_wires())
+ if (wire->name[0] == '$')
+ new_wire_names.emplace(wire, derive_name_from_src(wire->get_src_attribute(), counter++));
+
+ for (auto cell : module->selected_cells())
+ if (cell->name[0] == '$')
+ new_cell_names.emplace(cell, derive_name_from_src(cell->get_src_attribute(), counter++));
- RTLIL::Module *module = mod.second;
- if (!design->selected(module))
- continue;
-
- dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++);
- new_wires[it.second->name] = it.second;
- }
- module->wires_.swap(new_wires);
- module->fixup_ports();
-
- dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++);
- new_cells[it.second->name] = it.second;
- }
- module->cells_.swap(new_cells);
+ for (auto &it : new_wire_names)
+ module->rename(it.first, it.second);
+
+ for (auto &it : new_cell_names)
+ module->rename(it.first, it.second);
}
}
else
@@ -241,19 +236,13 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
- {
- RTLIL::Module *module = mod.second;
- if (!design->selected(module))
- continue;
-
- dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- it.second->name = derive_name_from_wire(*it.second);
- new_cells[it.second->name] = it.second;
- }
- module->cells_.swap(new_cells);
+ for (auto module : design->selected_modules()) {
+ dict<RTLIL::Cell *, IdString> new_cell_names;
+ for (auto cell : module->selected_cells())
+ if (cell->name[0] == '$')
+ new_cell_names[cell] = derive_name_from_cell_output_wire(cell);
+ for (auto &it : new_cell_names)
+ module->rename(it.first, it.second);
}
}
else
@@ -261,32 +250,33 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
+ for (auto module : design->selected_modules())
{
int counter = 0;
+ dict<RTLIL::Wire *, IdString> new_wire_names;
+ dict<RTLIL::Cell *, IdString> new_cell_names;
+
+ for (auto wire : module->selected_wires())
+ if (wire->name[0] == '$') {
+ RTLIL::IdString buf;
+ do buf = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
+ while (module->wire(buf) != nullptr);
+ new_wire_names[wire] = buf;
+ }
+
+ for (auto cell : module->selected_cells())
+ if (cell->name[0] == '$') {
+ RTLIL::IdString buf;
+ do buf = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
+ while (module->cell(buf) != nullptr);
+ new_cell_names[cell] = buf;
+ }
- RTLIL::Module *module = mod.second;
- if (!design->selected(module))
- continue;
-
- dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
- while (module->count_id(it.second->name) > 0);
- new_wires[it.second->name] = it.second;
- }
- module->wires_.swap(new_wires);
- module->fixup_ports();
-
- dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
- while (module->count_id(it.second->name) > 0);
- new_cells[it.second->name] = it.second;
- }
- module->cells_.swap(new_cells);
+ for (auto &it : new_wire_names)
+ module->rename(it.first, it.second);
+
+ for (auto &it : new_cell_names)
+ module->rename(it.first, it.second);
}
}
else
@@ -294,30 +284,24 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
+ for (auto module : design->selected_modules())
{
- RTLIL::Module *module = mod.second;
- if (!design->selected(module))
- continue;
-
- dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires_) {
- if (design->selected(module, it.second))
- if (it.first[0] == '\\' && it.second->port_id == 0)
- it.second->name = NEW_ID;
- new_wires[it.second->name] = it.second;
- }
- module->wires_.swap(new_wires);
- module->fixup_ports();
-
- dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells_) {
- if (design->selected(module, it.second))
- if (it.first[0] == '\\')
- it.second->name = NEW_ID;
- new_cells[it.second->name] = it.second;
- }
- module->cells_.swap(new_cells);
+ dict<RTLIL::Wire *, IdString> new_wire_names;
+ dict<RTLIL::Cell *, IdString> new_cell_names;
+
+ for (auto wire : module->selected_wires())
+ if (wire->name[0] == '\\' && wire->port_id == 0)
+ new_wire_names[wire] = NEW_ID;
+
+ for (auto cell : module->selected_cells())
+ if (cell->name[0] == '\\')
+ new_cell_names[cell] = NEW_ID;
+
+ for (auto &it : new_wire_names)
+ module->rename(it.first, it.second);
+
+ for (auto &it : new_cell_names)
+ module->rename(it.first, it.second);
}
}
else
@@ -329,7 +313,7 @@ struct RenamePass : public Pass {
IdString new_name = RTLIL::escape_id(args[argidx]);
RTLIL::Module *module = design->top_module();
- if (module == NULL)
+ if (module == nullptr)
log_cmd_error("No top module found!\n");
log("Renaming module %s to %s.\n", log_id(module), log_id(new_name));
@@ -345,27 +329,27 @@ struct RenamePass : public Pass {
if (!design->selected_active_module.empty())
{
- if (design->modules_.count(design->selected_active_module) > 0)
- rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output);
+ if (design->module(design->selected_active_module) != nullptr)
+ rename_in_module(design->module(design->selected_active_module), from_name, to_name, flag_output);
}
else
{
if (flag_output)
log_cmd_error("Mode -output requires that there is an active module selected.\n");
- for (auto &mod : design->modules_) {
- if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
- to_name = RTLIL::escape_id(to_name);
- log("Renaming module %s to %s.\n", mod.first.c_str(), to_name.c_str());
- RTLIL::Module *module = mod.second;
- design->modules_.erase(module->name);
- module->name = to_name;
- design->modules_[module->name] = module;
- goto rename_ok;
+
+ RTLIL::Module *module_to_rename = nullptr;
+ for (auto module : design->modules())
+ if (module->name == from_name || RTLIL::unescape_id(module->name) == from_name) {
+ module_to_rename = module;
+ break;
}
- }
- log_cmd_error("Object `%s' not found!\n", from_name.c_str());
- rename_ok:;
+ if (module_to_rename != nullptr) {
+ to_name = RTLIL::escape_id(to_name);
+ log("Renaming module %s to %s.\n", module_to_rename->name.c_str(), to_name.c_str());
+ design->rename(module_to_rename, to_name);
+ } else
+ log_cmd_error("Object `%s' not found!\n", from_name.c_str());
}
}
}
diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc
index 7123ba9fb..a5ef95f02 100644
--- a/passes/cmds/scatter.cc
+++ b/passes/cmds/scatter.cc
@@ -46,25 +46,19 @@ struct ScatterPass : public Pass {
CellTypes ct(design);
extra_args(args, 1, design);
- for (auto &mod_it : design->modules_)
+ for (auto module : design->selected_modules())
{
- if (!design->selected(mod_it.second))
- continue;
-
- for (auto &c : mod_it.second->cells_)
- for (auto &p : c.second->connections_)
- {
- RTLIL::Wire *wire = mod_it.second->addWire(NEW_ID, p.second.size());
-
- if (ct.cell_output(c.second->type, p.first)) {
- RTLIL::SigSig sigsig(p.second, wire);
- mod_it.second->connect(sigsig);
- } else {
- RTLIL::SigSig sigsig(wire, p.second);
- mod_it.second->connect(sigsig);
+ for (auto cell : module->cells()) {
+ dict<RTLIL::IdString, RTLIL::SigSig> new_connections;
+ for (auto conn : cell->connections())
+ new_connections.emplace(conn.first, RTLIL::SigSig(conn.second, module->addWire(NEW_ID, GetSize(conn.second))));
+ for (auto &it : new_connections) {
+ if (ct.cell_output(cell->type, it.first))
+ module->connect(RTLIL::SigSig(it.second.first, it.second.second));
+ else
+ module->connect(RTLIL::SigSig(it.second.second, it.second.first));
+ cell->setPort(it.first, it.second.second);
}
-
- p.second = wire;
}
}
}
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index b64b077e4..c04ff438a 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -1007,6 +1007,7 @@ struct SelectPass : public Pass {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" select [ -add | -del | -set <name> ] {-read <filename> | <selection>}\n");
+ log(" select [ -unset <name> ]\n");
log(" select [ <assert_option> ] {-read <filename> | <selection>}\n");
log(" select [ -list | -write <filename> | -count | -clear ]\n");
log(" select -module <modname>\n");
@@ -1029,6 +1030,10 @@ struct SelectPass : public Pass {
log(" under the given name (see @<name> below). to save the current selection,\n");
log(" use \"select -set <name> %%\"\n");
log("\n");
+ log(" -unset <name>\n");
+ log(" do not modify the current selection. instead remove a previously saved\n");
+ log(" selection under the given name (see @<name> below).");
+ log("\n");
log(" -assert-none\n");
log(" do not modify the current selection. instead assert that the given\n");
log(" selection is empty. i.e. produce an error if any object matching the\n");
@@ -1238,7 +1243,7 @@ struct SelectPass : public Pass {
int assert_max = -1;
int assert_min = -1;
std::string write_file, read_file;
- std::string set_name, sel_str;
+ std::string set_name, unset_name, sel_str;
work_stack.clear();
@@ -1310,6 +1315,10 @@ struct SelectPass : public Pass {
set_name = RTLIL::escape_id(args[++argidx]);
continue;
}
+ if (arg == "-unset" && argidx+1 < args.size()) {
+ unset_name = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
if (arg.size() > 0 && arg[0] == '-')
log_cmd_error("Unknown option %s.\n", arg.c_str());
bool disable_empty_warning = count_mode || assert_none || assert_any || (assert_count != -1) || (assert_max != -1) || (assert_min != -1);
@@ -1358,8 +1367,11 @@ struct SelectPass : public Pass {
if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any, assert-count, -assert-max, or -assert-min.\n");
- if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
- log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any, -assert-count, -assert-max, or -assert-min.\n");
+ if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || !unset_name.empty() || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
+ log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -unset, -assert-none, -assert-any, -assert-count, -assert-max, or -assert-min.\n");
+
+ if (!unset_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || !set_name.empty() || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
+ log_cmd_error("Option -unset can not be combined with -list, -write, -count, -add, -del, -set, -assert-none, -assert-any, -assert-count, -assert-max, or -assert-min.\n");
if (work_stack.size() == 0 && got_module) {
RTLIL::Selection sel;
@@ -1527,6 +1539,13 @@ struct SelectPass : public Pass {
return;
}
+ if (!unset_name.empty())
+ {
+ if (!design->selection_vars.erase(unset_name))
+ log_error("Selection '%s' does not exist!\n", unset_name.c_str());
+ return;
+ }
+
if (work_stack.size() == 0) {
RTLIL::Selection &sel = design->selection_stack.back();
if (sel.full_selection)
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 08abb94cb..515f5a4ef 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -38,7 +38,7 @@ struct setunset_t
value = RTLIL::Const(set_value.substr(1, GetSize(set_value)-2));
} else {
RTLIL::SigSpec sig_value;
- if (!RTLIL::SigSpec::parse(sig_value, NULL, set_value))
+ if (!RTLIL::SigSpec::parse(sig_value, nullptr, set_value))
log_cmd_error("Can't decode value '%s'!\n", set_value.c_str());
value = sig_value.as_const();
}
@@ -96,10 +96,8 @@ struct SetattrPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
+ for (auto module : design->modules())
{
- RTLIL::Module *module = mod.second;
-
if (flag_mod) {
if (design->selected_whole_module(module->name))
do_setunset(module->attributes, setunset_list);
@@ -109,17 +107,17 @@ struct SetattrPass : public Pass {
if (!design->selected(module))
continue;
- for (auto &it : module->wires_)
- if (design->selected(module, it.second))
- do_setunset(it.second->attributes, setunset_list);
+ for (auto wire : module->wires())
+ if (design->selected(module, wire))
+ do_setunset(wire->attributes, setunset_list);
for (auto &it : module->memories)
if (design->selected(module, it.second))
do_setunset(it.second->attributes, setunset_list);
- for (auto &it : module->cells_)
- if (design->selected(module, it.second))
- do_setunset(it.second->attributes, setunset_list);
+ for (auto cell : module->cells())
+ if (design->selected(module, cell))
+ do_setunset(cell->attributes, setunset_list);
for (auto &it : module->processes)
if (design->selected(module, it.second))
@@ -208,19 +206,13 @@ struct SetparamPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
+ for (auto module : design->selected_modules())
{
- RTLIL::Module *module = mod.second;
-
- if (!design->selected(module))
- continue;
-
- for (auto &it : module->cells_)
- if (design->selected(module, it.second)) {
- if (!new_cell_type.empty())
- it.second->type = new_cell_type;
- do_setunset(it.second->parameters, setunset_list);
- }
+ for (auto cell : module->selected_cells()) {
+ if (!new_cell_type.empty())
+ cell->type = new_cell_type;
+ do_setunset(cell->parameters, setunset_list);
+ }
}
}
} SetparamPass;
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index 5afd40923..8d973869e 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -149,7 +149,7 @@ struct SetundefPass : public Pass {
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- bool got_value = false;
+ int got_value = 0;
bool undriven_mode = false;
bool expose_mode = false;
bool init_mode = false;
@@ -170,31 +170,31 @@ struct SetundefPass : public Pass {
continue;
}
if (args[argidx] == "-zero") {
- got_value = true;
+ got_value++;
worker.next_bit_mode = MODE_ZERO;
worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-one") {
- got_value = true;
+ got_value++;
worker.next_bit_mode = MODE_ONE;
worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-anyseq") {
- got_value = true;
+ got_value++;
worker.next_bit_mode = MODE_ANYSEQ;
worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-anyconst") {
- got_value = true;
+ got_value++;
worker.next_bit_mode = MODE_ANYCONST;
worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-undef") {
- got_value = true;
+ got_value++;
worker.next_bit_mode = MODE_UNDEF;
worker.next_bit_state = 0;
continue;
@@ -207,8 +207,8 @@ struct SetundefPass : public Pass {
params_mode = true;
continue;
}
- if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
- got_value = true;
+ if (args[argidx] == "-random" && argidx+1 < args.size()) {
+ got_value++;
worker.next_bit_mode = MODE_RANDOM;
worker.next_bit_state = atoi(args[++argidx].c_str()) + 1;
for (int i = 0; i < 10; i++)
@@ -221,7 +221,7 @@ struct SetundefPass : public Pass {
if (!got_value && expose_mode) {
log("Using default as -undef with -expose.\n");
- got_value = true;
+ got_value++;
worker.next_bit_mode = MODE_UNDEF;
worker.next_bit_state = 0;
}
@@ -229,7 +229,9 @@ struct SetundefPass : public Pass {
if (expose_mode && !undriven_mode)
log_cmd_error("Option -expose must be used with option -undriven.\n");
if (!got_value)
- log_cmd_error("One of the options -zero, -one, -anyseq, -anyconst, or -random <seed> must be specified.\n");
+ log_cmd_error("One of the options -zero, -one, -anyseq, -anyconst, -random <seed>, or -expose must be specified.\n");
+ else if (got_value > 1)
+ log_cmd_error("Only one of the options -zero, -one, -anyseq, -anyconst, or -random <seed> can be specified.\n");
if (init_mode && (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST))
log_cmd_error("The options -init and -anyseq / -anyconst are exclusive.\n");
@@ -359,34 +361,9 @@ struct SetundefPass : public Pass {
pool<SigBit> ffbits;
pool<Wire*> initwires;
- pool<IdString> fftypes;
- fftypes.insert(ID($dff));
- fftypes.insert(ID($dffe));
- fftypes.insert(ID($dffsr));
- fftypes.insert(ID($adff));
-
- std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};
-
- for (auto c1 : list_np)
- fftypes.insert(stringf("$_DFF_%c_", c1));
-
- for (auto c1 : list_np)
- for (auto c2 : list_np)
- fftypes.insert(stringf("$_DFFE_%c%c_", c1, c2));
-
- for (auto c1 : list_np)
- for (auto c2 : list_np)
- for (auto c3 : list_01)
- fftypes.insert(stringf("$_DFF_%c%c%c_", c1, c2, c3));
-
- for (auto c1 : list_np)
- for (auto c2 : list_np)
- for (auto c3 : list_np)
- fftypes.insert(stringf("$_DFFSR_%c%c%c_", c1, c2, c3));
-
for (auto cell : module->cells())
{
- if (!fftypes.count(cell->type))
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;
for (auto bit : sigmap(cell->getPort(ID::Q)))
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index c0e07b6e1..155ed0fcd 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -41,8 +41,6 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-using RTLIL::id2cstr;
-
#undef CLUSTER_CELLS_AND_PORTBOXES
struct ShowWorker
@@ -101,7 +99,7 @@ struct ShowWorker
{
sig.sort_and_unify();
for (auto &c : sig.chunks()) {
- if (c.wire != NULL)
+ if (c.wire != nullptr)
for (auto &s : color_selections)
if (s.second.selected_members.count(module->name) > 0 && s.second.selected_members.at(module->name).count(c.wire->name) > 0)
return stringf("color=\"%s\"", s.first.c_str());
@@ -218,7 +216,7 @@ struct ShowWorker
if (sig.is_chunk()) {
const RTLIL::SigChunk &c = sig.as_chunk();
- if (c.wire != NULL && design->selected_member(module->name, c.wire->name)) {
+ if (c.wire != nullptr && design->selected_member(module->name, c.wire->name)) {
if (!range_check || c.wire->width == c.width)
return stringf("n%d", id2num(c.wire->name));
} else {
@@ -230,7 +228,7 @@ struct ShowWorker
return std::string();
}
- std::string gen_portbox(std::string port, RTLIL::SigSpec sig, bool driver, std::string *node = NULL)
+ std::string gen_portbox(std::string port, RTLIL::SigSpec sig, bool driver, std::string *node = nullptr)
{
std::string code;
std::string net = gen_signode_simple(sig);
@@ -287,7 +285,7 @@ struct ShowWorker
else
code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", idx, port.c_str(), nextColor(sig).c_str(), widthLabel(sig.size()).c_str());
}
- if (node != NULL)
+ if (node != nullptr)
*node = stringf("x%d", idx);
}
else
@@ -300,7 +298,7 @@ struct ShowWorker
net_conn_map[net].bits = sig.size();
net_conn_map[net].color = nextColor(sig, net_conn_map[net].color);
}
- if (node != NULL)
+ if (node != nullptr)
*node = net;
}
return code;
@@ -366,22 +364,20 @@ struct ShowWorker
std::set<std::string> all_sources, all_sinks;
std::map<std::string, std::string> wires_on_demand;
- for (auto &it : module->wires_) {
- if (!design->selected_member(module->name, it.first))
- continue;
+ for (auto wire : module->selected_wires()) {
const char *shape = "diamond";
- if (it.second->port_input || it.second->port_output)
+ if (wire->port_input || wire->port_output)
shape = "octagon";
- if (it.first[0] == '\\') {
+ if (wire->name[0] == '\\') {
fprintf(f, "n%d [ shape=%s, label=\"%s\", %s, fontcolor=\"black\" ];\n",
- id2num(it.first), shape, findLabel(it.first.str()),
- nextColor(RTLIL::SigSpec(it.second), "color=\"black\"").c_str());
- if (it.second->port_input)
- all_sources.insert(stringf("n%d", id2num(it.first)));
- else if (it.second->port_output)
- all_sinks.insert(stringf("n%d", id2num(it.first)));
+ id2num(wire->name), shape, findLabel(wire->name.str()),
+ nextColor(RTLIL::SigSpec(wire), "color=\"black\"").c_str());
+ if (wire->port_input)
+ all_sources.insert(stringf("n%d", id2num(wire->name)));
+ else if (wire->port_output)
+ all_sinks.insert(stringf("n%d", id2num(wire->name)));
} else {
- wires_on_demand[stringf("n%d", id2num(it.first))] = it.first.str();
+ wires_on_demand[stringf("n%d", id2num(wire->name))] = wire->name.str();
}
}
@@ -398,15 +394,12 @@ struct ShowWorker
fprintf(f, "}\n");
}
- for (auto &it : module->cells_)
+ for (auto cell : module->selected_cells())
{
- if (!design->selected_member(module->name, it.first))
- continue;
-
std::vector<RTLIL::IdString> in_ports, out_ports;
- for (auto &conn : it.second->connections()) {
- if (!ct.cell_output(it.second->type, conn.first))
+ for (auto &conn : cell->connections()) {
+ if (!ct.cell_output(cell->type, conn.first))
in_ports.push_back(conn.first);
else
out_ports.push_back(conn.first);
@@ -419,12 +412,12 @@ struct ShowWorker
for (auto &p : in_ports)
label_string += stringf("<p%d> %s%s|", id2num(p), escape(p.str()),
- genSignedLabels && it.second->hasParam(p.str() + "_SIGNED") &&
- it.second->getParam(p.str() + "_SIGNED").as_bool() ? "*" : "");
+ genSignedLabels && cell->hasParam(p.str() + "_SIGNED") &&
+ cell->getParam(p.str() + "_SIGNED").as_bool() ? "*" : "");
if (label_string[label_string.size()-1] == '|')
label_string = label_string.substr(0, label_string.size()-1);
- label_string += stringf("}|%s\\n%s|{", findLabel(it.first.str()), escape(it.second->type.str()));
+ label_string += stringf("}|%s\\n%s|{", findLabel(cell->name.str()), escape(cell->type.str()));
for (auto &p : out_ports)
label_string += stringf("<p%d> %s|", id2num(p), escape(p.str()));
@@ -434,19 +427,19 @@ struct ShowWorker
label_string += "}}";
std::string code;
- for (auto &conn : it.second->connections()) {
- code += gen_portbox(stringf("c%d:p%d", id2num(it.first), id2num(conn.first)),
- conn.second, ct.cell_output(it.second->type, conn.first));
+ for (auto &conn : cell->connections()) {
+ code += gen_portbox(stringf("c%d:p%d", id2num(cell->name), id2num(conn.first)),
+ conn.second, ct.cell_output(cell->type, conn.first));
}
#ifdef CLUSTER_CELLS_AND_PORTBOXES
if (!code.empty())
fprintf(f, "subgraph cluster_c%d {\nc%d [ shape=record, label=\"%s\"%s ];\n%s}\n",
- id2num(it.first), id2num(it.first), label_string.c_str(), findColor(it.first), code.c_str());
+ id2num(cell->name), id2num(cell->name), label_string.c_str(), findColor(cell->name), code.c_str());
else
#endif
fprintf(f, "c%d [ shape=record, label=\"%s\"%s ];\n%s",
- id2num(it.first), label_string.c_str(), findColor(it.first.str()), code.c_str());
+ id2num(cell->name), label_string.c_str(), findColor(cell->name.str()), code.c_str());
}
for (auto &it : module->processes)
@@ -491,12 +484,12 @@ struct ShowWorker
{
bool found_lhs_wire = false;
for (auto &c : conn.first.chunks()) {
- if (c.wire == NULL || design->selected_member(module->name, c.wire->name))
+ if (c.wire == nullptr || design->selected_member(module->name, c.wire->name))
found_lhs_wire = true;
}
bool found_rhs_wire = false;
for (auto &c : conn.second.chunks()) {
- if (c.wire == NULL || design->selected_member(module->name, c.wire->name))
+ if (c.wire == nullptr || design->selected_member(module->name, c.wire->name))
found_rhs_wire = true;
}
if (!found_lhs_wire || !found_rhs_wire)
@@ -572,23 +565,21 @@ struct ShowWorker
design->optimize();
page_counter = 0;
- for (auto &mod_it : design->modules_)
+ for (auto mod : design->selected_modules())
{
- module = mod_it.second;
- if (!design->selected_module(module->name))
- continue;
+ module = mod;
if (design->selected_whole_module(module->name)) {
if (module->get_blackbox_attribute()) {
- // log("Skipping blackbox module %s.\n", id2cstr(module->name));
+ // log("Skipping blackbox module %s.\n", log_id(module->name));
continue;
} else
- if (module->cells_.empty() && module->connections().empty() && module->processes.empty()) {
- log("Skipping empty module %s.\n", id2cstr(module->name));
+ if (module->cells().size() == 0 && module->connections().empty() && module->processes.empty()) {
+ log("Skipping empty module %s.\n", log_id(module->name));
continue;
} else
- log("Dumping module %s to page %d.\n", id2cstr(module->name), ++page_counter);
+ log("Dumping module %s to page %d.\n", log_id(module->name), ++page_counter);
} else
- log("Dumping selected parts of module %s to page %d.\n", id2cstr(module->name), ++page_counter);
+ log("Dumping selected parts of module %s to page %d.\n", log_id(module->name), ++page_counter);
handle_module();
}
}
@@ -802,13 +793,12 @@ struct ShowPass : public Pass {
if (format != "ps" && format != "dot") {
int modcount = 0;
- for (auto &mod_it : design->modules_) {
- if (mod_it.second->get_blackbox_attribute())
+ for (auto module : design->selected_modules()) {
+ if (module->get_blackbox_attribute())
continue;
- if (mod_it.second->cells_.empty() && mod_it.second->connections().empty())
+ if (module->cells().size() == 0 && module->connections().empty())
continue;
- if (design->selected_module(mod_it.first))
- modcount++;
+ modcount++;
}
if (modcount > 1)
log_cmd_error("For formats different than 'ps' or 'dot' only one module must be selected.\n");
@@ -835,7 +825,7 @@ struct ShowPass : public Pass {
FILE *f = fopen(dot_file.c_str(), "w");
if (custom_prefix)
yosys_output_files.insert(dot_file);
- if (f == NULL) {
+ if (f == nullptr) {
for (auto lib : libs)
delete lib;
log_cmd_error("Can't open dot file `%s' for writing.\n", dot_file.c_str());
@@ -889,8 +879,8 @@ struct ShowPass : public Pass {
if (flag_pause) {
#ifdef YOSYS_ENABLE_READLINE
- char *input = NULL;
- while ((input = readline("Press ENTER to continue (or type 'shell' to open a shell)> ")) != NULL) {
+ char *input = nullptr;
+ while ((input = readline("Press ENTER to continue (or type 'shell' to open a shell)> ")) != nullptr) {
if (input[strspn(input, " \t\r\n")] == 0)
break;
char *p = input + strspn(input, " \t\r\n");
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index f99090279..ea9e06979 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -102,7 +102,7 @@ struct SpliceWorker
for (auto &bit : sig.to_sigbit_vector())
{
- if (bit.wire == NULL)
+ if (bit.wire == nullptr)
{
if (last_bit == 0)
chunks.back().append(bit);
@@ -149,23 +149,23 @@ struct SpliceWorker
void run()
{
- log("Splicing signals in module %s:\n", RTLIL::id2cstr(module->name));
+ log("Splicing signals in module %s:\n", log_id(module->name));
driven_bits.push_back(RTLIL::State::Sm);
driven_bits.push_back(RTLIL::State::Sm);
- for (auto &it : module->wires_)
- if (it.second->port_input) {
- RTLIL::SigSpec sig = sigmap(it.second);
+ for (auto wire : module->wires())
+ if (wire->port_input) {
+ RTLIL::SigSpec sig = sigmap(wire);
driven_chunks.insert(sig);
for (auto &bit : sig.to_sigbit_vector())
driven_bits.push_back(bit);
driven_bits.push_back(RTLIL::State::Sm);
}
- for (auto &it : module->cells_)
- for (auto &conn : it.second->connections())
- if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) {
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections())
+ if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first)) {
RTLIL::SigSpec sig = sigmap(conn.second);
driven_chunks.insert(sig);
for (auto &bit : sig.to_sigbit_vector())
@@ -180,9 +180,8 @@ struct SpliceWorker
SigPool selected_bits;
if (!sel_by_cell)
- for (auto &it : module->wires_)
- if (design->selected(module, it.second))
- selected_bits.add(sigmap(it.second));
+ for (auto wire : module->selected_wires())
+ selected_bits.add(sigmap(wire));
std::vector<Cell*> mod_cells = module->cells();
@@ -343,17 +342,14 @@ struct SplicePass : public Pass {
log_header(design, "Executing SPLICE pass (creating cells for signal splicing).\n");
- for (auto &mod_it : design->modules_)
+ for (auto module : design->selected_modules())
{
- if (!design->selected(mod_it.second))
- continue;
-
- if (mod_it.second->processes.size()) {
- log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
+ if (module->processes.size()) {
+ log("Skipping module %s as it contains processes.\n", module->name.c_str());
continue;
}
- SpliceWorker worker(design, mod_it.second);
+ SpliceWorker worker(design, module);
worker.sel_by_cell = sel_by_cell;
worker.sel_by_wire = sel_by_wire;
worker.sel_any_bit = sel_any_bit;
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index bf693e3d4..1e7dedd70 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -141,6 +141,9 @@ struct SplitnetsPass : public Pass {
for (auto module : design->selected_modules())
{
+ if (module->has_processes_warn())
+ continue;
+
SplitnetsWorker worker;
if (flag_ports)
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 758a59661..6c4bc0e5b 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -79,18 +79,15 @@ struct statdata_t
STAT_NUMERIC_MEMBERS
#undef X
- for (auto &it : mod->wires_)
+ for (auto wire : mod->selected_wires())
{
- if (!design->selected(mod, it.second))
- continue;
-
- if (it.first[0] == '\\') {
+ if (wire->name[0] == '\\') {
num_pub_wires++;
- num_pub_wire_bits += it.second->width;
+ num_pub_wire_bits += wire->width;
}
num_wires++;
- num_wire_bits += it.second->width;
+ num_wire_bits += wire->width;
}
for (auto &it : mod->memories) {
@@ -100,12 +97,9 @@ struct statdata_t
num_memory_bits += it.second->width * it.second->size;
}
- for (auto &it : mod->cells_)
+ for (auto cell : mod->selected_cells())
{
- if (!design->selected(mod, it.second))
- continue;
-
- RTLIL::IdString cell_type = it.second->type;
+ RTLIL::IdString cell_type = cell->type;
if (width_mode)
{
@@ -116,15 +110,15 @@ struct statdata_t
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow), ID($alu))) {
- int width_a = it.second->hasPort(ID::A) ? GetSize(it.second->getPort(ID::A)) : 0;
- int width_b = it.second->hasPort(ID::B) ? GetSize(it.second->getPort(ID::B)) : 0;
- int width_y = it.second->hasPort(ID::Y) ? GetSize(it.second->getPort(ID::Y)) : 0;
+ int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0;
+ int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0;
+ int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0;
cell_type = stringf("%s_%d", cell_type.c_str(), max<int>({width_a, width_b, width_y}));
}
else if (cell_type.in(ID($mux), ID($pmux)))
- cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort(ID::Y)));
+ cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)));
else if (cell_type.in(ID($sr), ID($dff), ID($dffsr), ID($adff), ID($dlatch), ID($dlatchsr)))
- cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort(ID::Q)));
+ cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Q)));
}
if (!cell_area.empty()) {
@@ -157,7 +151,7 @@ struct statdata_t
log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type)
if (it.second)
- log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
+ log(" %-26s %6d\n", log_id(it.first), it.second);
if (!unknown_cell_area.empty()) {
log("\n");
@@ -255,7 +249,7 @@ statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTL
for (auto &it : num_cells_by_type)
if (mod_stat.count(it.first) > 0) {
- log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, RTLIL::id2cstr(it.first), it.second);
+ log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, log_id(it.first), it.second);
mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second;
mod_data.num_cells -= it.second;
} else {
@@ -281,7 +275,7 @@ void read_liberty_cellarea(dict<IdString, double> &cell_area, string liberty_fil
continue;
LibertyAst *ar = cell->find("area");
- if (ar != NULL && !ar->value.empty())
+ if (ar != nullptr && !ar->value.empty())
cell_area["\\" + cell->args[0]] = atof(ar->value.c_str());
}
}
@@ -319,7 +313,7 @@ struct StatPass : public Pass {
log_header(design, "Printing statistics.\n");
bool width_mode = false;
- RTLIL::Module *top_mod = NULL;
+ RTLIL::Module *top_mod = nullptr;
std::map<RTLIL::IdString, statdata_t> mod_stat;
dict<IdString, double> cell_area;
string techname;
@@ -342,9 +336,9 @@ struct StatPass : public Pass {
continue;
}
if (args[argidx] == "-top" && argidx+1 < args.size()) {
- if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
+ if (design->module(RTLIL::escape_id(args[argidx+1])) == nullptr)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
- top_mod = design->modules_.at(RTLIL::escape_id(args[++argidx]));
+ top_mod = design->module(RTLIL::escape_id(args[++argidx]));
continue;
}
break;
@@ -364,18 +358,18 @@ struct StatPass : public Pass {
mod_stat[mod->name] = data;
log("\n");
- log("=== %s%s ===\n", RTLIL::id2cstr(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
+ log("=== %s%s ===\n", log_id(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
log("\n");
data.log_data(mod->name, false);
}
- if (top_mod != NULL && GetSize(mod_stat) > 1)
+ if (top_mod != nullptr && GetSize(mod_stat) > 1)
{
log("\n");
log("=== design hierarchy ===\n");
log("\n");
- log(" %-28s %6d\n", RTLIL::id2cstr(top_mod->name), 1);
+ log(" %-28s %6d\n", log_id(top_mod->name), 1);
statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0);
log("\n");
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index f5701acee..2db7cf26b 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -51,7 +51,7 @@ struct SubmodWorker
RTLIL::Wire *new_wire;
RTLIL::Const is_int_driven;
bool is_int_used, is_ext_driven, is_ext_used;
- wire_flags_t(RTLIL::Wire* wire) : new_wire(NULL), is_int_driven(State::S0, GetSize(wire)), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
+ wire_flags_t(RTLIL::Wire* wire) : new_wire(nullptr), is_int_driven(State::S0, GetSize(wire)), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
};
std::map<RTLIL::Wire*, wire_flags_t> wire_flags;
bool flag_found_something;
@@ -75,7 +75,7 @@ struct SubmodWorker
void flag_signal(const RTLIL::SigSpec &sig, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
{
for (auto &c : sig.chunks())
- if (c.wire != NULL) {
+ if (c.wire != nullptr) {
flag_wire(c.wire, create, set_int_used, set_ext_driven, set_ext_used);
if (set_int_driven)
for (int i = c.offset; i < c.offset+c.width; i++) {
@@ -100,8 +100,7 @@ struct SubmodWorker
flag_signal(conn.second, true, true, true, false, false);
}
}
- for (auto &it : module->cells_) {
- RTLIL::Cell *cell = it.second;
+ for (auto cell : module->cells()) {
if (submod.cells.count(cell) > 0)
continue;
if (ct.cell_known(cell->type)) {
@@ -211,7 +210,7 @@ struct SubmodWorker
RTLIL::Cell *new_cell = new_mod->addCell(cell->name, cell);
for (auto &conn : new_cell->connections_)
for (auto &bit : conn.second)
- if (bit.wire != NULL) {
+ if (bit.wire != nullptr) {
log_assert(wire_flags.count(bit.wire) > 0);
bit.wire = wire_flags.at(bit.wire).new_wire;
}
@@ -274,12 +273,11 @@ struct SubmodWorker
if (opt_name.empty())
{
- for (auto &it : module->wires_)
- it.second->attributes.erase(ID::submod);
+ for (auto wire : module->wires())
+ wire->attributes.erase(ID::submod);
- for (auto &it : module->cells_)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = it.second;
if (cell->attributes.count(ID::submod) == 0 || cell->attributes[ID::submod].bits.size() == 0) {
cell->attributes.erase(ID::submod);
continue;
@@ -291,7 +289,7 @@ struct SubmodWorker
if (submodules.count(submod_str) == 0) {
submodules[submod_str].name = submod_str;
submodules[submod_str].full_name = module->name.str() + "_" + submod_str;
- while (design->modules_.count(submodules[submod_str].full_name) != 0 ||
+ while (design->module(submodules[submod_str].full_name) != nullptr ||
module->count_id(submodules[submod_str].full_name) != 0)
submodules[submod_str].full_name += "_";
}
@@ -301,9 +299,8 @@ struct SubmodWorker
}
else
{
- for (auto &it : module->cells_)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = it.second;
if (!design->selected(module, cell))
continue;
submodules[opt_name].name = opt_name;
@@ -392,12 +389,12 @@ struct SubmodPass : public Pass {
while (did_something) {
did_something = false;
std::vector<RTLIL::IdString> queued_modules;
- for (auto &mod_it : design->modules_)
- if (handled_modules.count(mod_it.first) == 0 && design->selected_whole_module(mod_it.first))
- queued_modules.push_back(mod_it.first);
+ for (auto mod : design->modules())
+ if (handled_modules.count(mod->name) == 0 && design->selected_whole_module(mod->name))
+ queued_modules.push_back(mod->name);
for (auto &modname : queued_modules)
- if (design->modules_.count(modname) != 0) {
- SubmodWorker worker(design, design->modules_[modname], copy_mode, hidden_mode);
+ if (design->module(modname) != nullptr) {
+ SubmodWorker worker(design, design->module(modname), copy_mode, hidden_mode);
handled_modules.insert(modname);
did_something = true;
}
@@ -407,15 +404,13 @@ struct SubmodPass : public Pass {
}
else
{
- RTLIL::Module *module = NULL;
- for (auto &mod_it : design->modules_) {
- if (!design->selected_module(mod_it.first))
- continue;
- if (module != NULL)
- log_cmd_error("More than one module selected: %s %s\n", module->name.c_str(), mod_it.first.c_str());
- module = mod_it.second;
+ RTLIL::Module *module = nullptr;
+ for (auto mod : design->selected_modules()) {
+ if (module != nullptr)
+ log_cmd_error("More than one module selected: %s %s\n", module->name.c_str(), mod->name.c_str());
+ module = mod;
}
- if (module == NULL)
+ if (module == nullptr)
log("Nothing selected -> do nothing.\n");
else {
Pass::call_on_module(design, module, "opt_clean");
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index 52ee1e99d..0898ec288 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -137,9 +137,26 @@ struct rules_t
vector<vector<std::tuple<bool,IdString,Const>>> attributes;
};
+ bool attr_icase;
dict<IdString, vector<bram_t>> brams;
vector<match_t> matches;
+ std::string map_case(std::string value) const
+ {
+ if (attr_icase) {
+ for (char &c : value)
+ c = tolower(c);
+ }
+ return value;
+ }
+
+ RTLIL::Const map_case(RTLIL::Const value) const
+ {
+ if (value.flags & RTLIL::CONST_FLAG_STRING)
+ return map_case(value.decode_string());
+ return value;
+ }
+
std::ifstream infile;
vector<string> tokens;
vector<string> labels;
@@ -337,7 +354,7 @@ struct rules_t
IdString key = RTLIL::escape_id(tokens[idx].substr(c1, c2));
Const val = c2 != std::string::npos ? tokens[idx].substr(c2+1) : RTLIL::Const(1);
- data.attributes.back().emplace_back(exists, key, val);
+ data.attributes.back().emplace_back(exists, key, map_case(val));
}
continue;
}
@@ -351,6 +368,7 @@ struct rules_t
rewrite_filename(filename);
infile.open(filename);
linecount = 0;
+ attr_icase = false;
if (infile.fail())
log_error("Can't open rules file `%s'.\n", filename.c_str());
@@ -360,6 +378,11 @@ struct rules_t
if (!labels.empty())
syntax_error();
+ if (GetSize(tokens) == 2 && tokens[0] == "attr_icase") {
+ attr_icase = atoi(tokens[1].c_str());
+ continue;
+ }
+
if (tokens[0] == "bram") {
parse_bram();
continue;
@@ -843,7 +866,7 @@ grow_read_ports:;
}
else if (!exists)
continue;
- if (it->second != value)
+ if (rules.map_case(it->second) != value)
continue;
found = true;
break;
@@ -855,7 +878,7 @@ grow_read_ports:;
ss << "!";
IdString key = std::get<1>(sums.front());
ss << log_id(key);
- const Const &value = std::get<2>(sums.front());
+ const Const &value = rules.map_case(std::get<2>(sums.front()));
if (exists && value != Const(1))
ss << "=\"" << value.decode_string() << "\"";
@@ -1079,9 +1102,6 @@ void handle_cell(Cell *cell, const rules_t &rules)
auto &bram = rules.brams.at(match.name).at(vi);
bool or_next_if_better = match.or_next_if_better || vi+1 < GetSize(rules.brams.at(match.name));
- if (failed_brams.count(pair<IdString, int>(bram.name, bram.variant)))
- continue;
-
int avail_rd_ports = 0;
int avail_wr_ports = 0;
for (int j = 0; j < bram.groups; j++) {
@@ -1117,6 +1137,9 @@ void handle_cell(Cell *cell, const rules_t &rules)
int efficiency = (100 * match_properties["bits"]) / (dups * cells * bram.dbits * (1 << bram.abits));
match_properties["efficiency"] = efficiency;
+ if (failed_brams.count(pair<IdString, int>(bram.name, bram.variant)))
+ goto next_match_rule;
+
log(" Metrics for %s: awaste=%d dwaste=%d bwaste=%d waste=%d efficiency=%d\n",
log_id(match.name), awaste, dwaste, bwaste, waste, efficiency);
@@ -1167,7 +1190,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
}
else if (!exists)
continue;
- if (it->second != value)
+ if (rules.map_case(it->second) != value)
continue;
found = true;
break;
@@ -1179,7 +1202,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
ss << "!";
IdString key = std::get<1>(sums.front());
ss << log_id(key);
- const Const &value = std::get<2>(sums.front());
+ const Const &value = rules.map_case(std::get<2>(sums.front()));
if (exists && value != Const(1))
ss << "=\"" << value.decode_string() << "\"";
@@ -1252,8 +1275,13 @@ struct MemoryBramPass : public Pass {
log("The given rules file describes the available resources and how they should be\n");
log("used.\n");
log("\n");
- log("The rules file contains a set of block ram description and a sequence of match\n");
- log("rules. A block ram description looks like this:\n");
+ log("The rules file contains configuration options, a set of block ram description\n");
+ log("and a sequence of match rules.\n");
+ log("\n");
+ log("The option 'attr_icase' configures how attribute values are matched. The value 0\n");
+ log("means case-sensitive, 1 means case-insensitive.\n");
+ log("\n");
+ log("A block ram description looks like this:\n");
log("\n");
log(" bram RAMB1024X32 # name of BRAM cell\n");
log(" init 1 # set to '1' if BRAM can be initialized\n");
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index a62dcc2c4..ef8b07811 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -60,8 +60,7 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
int addr_bits = 0;
std::vector<Cell*> memcells;
- for (auto &cell_it : module->cells_) {
- Cell *cell = cell_it.second;
+ for (auto cell : module->cells())
if (cell->type.in(ID($memrd), ID($memwr), ID($meminit)) && memory->name == cell->parameters[ID::MEMID].decode_string()) {
SigSpec addr = sigmap(cell->getPort(ID::ADDR));
for (int i = 0; i < GetSize(addr); i++)
@@ -69,7 +68,6 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
addr_bits = std::max(addr_bits, i+1);
memcells.push_back(cell);
}
- }
if (memory->start_offset == 0 && addr_bits < 30 && (1 << addr_bits) < memory->size)
memory->size = 1 << addr_bits;
@@ -260,9 +258,8 @@ struct MemoryCollectPass : public Pass {
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_COLLECT pass (generating $mem cells).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules_)
- if (design->selected(mod_it.second))
- handle_module(design, mod_it.second);
+ for (auto module : design->selected_modules())
+ handle_module(design, module);
}
} MemoryCollectPass;
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index da0673c8f..9d455f55b 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -28,11 +28,32 @@ PRIVATE_NAMESPACE_BEGIN
struct MemoryMapWorker
{
+ bool attr_icase = false;
+ dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes;
+
RTLIL::Design *design;
RTLIL::Module *module;
std::map<std::pair<RTLIL::SigSpec, RTLIL::SigSpec>, RTLIL::SigBit> decoder_cache;
+ MemoryMapWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module) {}
+
+ std::string map_case(std::string value) const
+ {
+ if (attr_icase) {
+ for (char &c : value)
+ c = tolower(c);
+ }
+ return value;
+ }
+
+ RTLIL::Const map_case(RTLIL::Const value) const
+ {
+ if (value.flags & RTLIL::CONST_FLAG_STRING)
+ return map_case(value.decode_string());
+ return value;
+ }
+
std::string genid(RTLIL::IdString name, std::string token1 = "", int i = -1, std::string token2 = "", int j = -1, std::string token3 = "", int k = -1, std::string token4 = "")
{
std::stringstream sstr;
@@ -98,6 +119,36 @@ struct MemoryMapWorker
return;
}
+ // check if attributes allow us to infer FFRAM for this cell
+ for (const auto &attr : attributes) {
+ if (cell->attributes.count(attr.first)) {
+ const auto &cell_attr = cell->attributes[attr.first];
+ if (attr.second.empty()) {
+ log("Not mapping memory cell %s in module %s (attribute %s is set).\n",
+ cell->name.c_str(), module->name.c_str(), attr.first.c_str());
+ return;
+ }
+
+ bool found = false;
+ for (auto &value : attr.second) {
+ if (map_case(cell_attr) == map_case(value)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ if (cell_attr.flags & RTLIL::CONST_FLAG_STRING) {
+ log("Not mapping memory cell %s in module %s (attribute %s is set to \"%s\").\n",
+ cell->name.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.decode_string().c_str());
+ } else {
+ log("Not mapping memory cell %s in module %s (attribute %s is set to %d).\n",
+ cell->name.c_str(), module->name.c_str(), attr.first.c_str(), cell_attr.as_int());
+ }
+ return;
+ }
+ }
+ }
+
// all write ports must share the same clock
RTLIL::SigSpec clocks = cell->getPort(ID::WR_CLK);
RTLIL::Const clocks_pol = cell->parameters[ID::WR_CLK_POLARITY];
@@ -339,7 +390,7 @@ struct MemoryMapWorker
module->remove(cell);
}
- MemoryMapWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module)
+ void run()
{
std::vector<RTLIL::Cell*> cells;
for (auto cell : module->selected_cells())
@@ -356,17 +407,73 @@ struct MemoryMapPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" memory_map [selection]\n");
+ log(" memory_map [options] [selection]\n");
log("\n");
log("This pass converts multiport memory cells as generated by the memory_collect\n");
log("pass to word-wide DFFs and address decoders.\n");
log("\n");
+ log(" -attr !<name>\n");
+ log(" do not map memories that have attribute <name> set.\n");
+ log("\n");
+ log(" -attr <name>[=<value>]\n");
+ log(" for memories that have attribute <name> set, only map them if its value\n");
+ log(" is a string <value> (if specified), or an integer 1 (otherwise). if this\n");
+ log(" option is specified multiple times, map the memory if the attribute is\n");
+ log(" to any of the values.\n");
+ log("\n");
+ log(" -iattr\n");
+ log(" for -attr, ignore case of <value>.\n");
+ log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool attr_icase = false;
+ dict<RTLIL::IdString, std::vector<RTLIL::Const>> attributes;
+
log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
- extra_args(args, 1, design);
- for (auto mod : design->selected_modules())
- MemoryMapWorker(design, mod);
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-attr" && argidx + 1 < args.size())
+ {
+ std::string attr_arg = args[++argidx];
+ std::string name;
+ RTLIL::Const value;
+ size_t eq_at = attr_arg.find('=');
+ if (eq_at != std::string::npos) {
+ name = attr_arg.substr(0, eq_at);
+ value = attr_arg.substr(eq_at + 1);
+ } else {
+ name = attr_arg;
+ value = RTLIL::Const(1);
+ }
+ if (attr_arg.size() > 1 && attr_arg[0] == '!') {
+ if (value != RTLIL::Const(1)) {
+ --argidx;
+ break; // we don't support -attr !<name>=<value>
+ }
+ attributes[RTLIL::escape_id(name.substr(1))].clear();
+ } else {
+ attributes[RTLIL::escape_id(name)].push_back(value);
+ }
+ continue;
+ }
+ if (args[argidx] == "-iattr")
+ {
+ attr_icase = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules()) {
+ MemoryMapWorker worker(design, mod);
+ worker.attr_icase = attr_icase;
+ worker.attributes = attributes;
+ worker.run();
+ }
}
} MemoryMapPass;
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 9173c791b..8d284edcd 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -118,11 +118,11 @@ void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
void handle_module(RTLIL::Design *design, RTLIL::Module *module)
{
std::vector<RTLIL::IdString> memcells;
- for (auto &cell_it : module->cells_)
- if (cell_it.second->type == ID($mem) && design->selected(module, cell_it.second))
- memcells.push_back(cell_it.first);
+ for (auto cell : module->cells())
+ if (cell->type == ID($mem) && design->selected(module, cell))
+ memcells.push_back(cell->name);
for (auto &it : memcells)
- handle_memory(module, module->cells_.at(it));
+ handle_memory(module, module->cell(it));
}
struct MemoryUnpackPass : public Pass {
@@ -140,9 +140,8 @@ struct MemoryUnpackPass : public Pass {
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules_)
- if (design->selected(mod_it.second))
- handle_module(design, mod_it.second);
+ for (auto module : design->selected_modules())
+ handle_module(design, module);
}
} MemoryUnpackPass;
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index da3961218..6271376f1 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -406,6 +406,9 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (verbose && del_temp_wires_count)
log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
+ if (!del_wires_queue.empty())
+ module->design->scratchpad_set_bool("opt.did_something", true);
+
return !del_wires_queue.empty();
}
@@ -476,6 +479,9 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
next_wire:;
}
+ if (did_something)
+ module->design->scratchpad_set_bool("opt.did_something", true);
+
return did_something;
}
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 1a4dd9239..2b35ace5e 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -717,31 +717,27 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
RTLIL::SigSpec sig_co = cell->getPort(ID::CO);
- bool sub = (sig_ci == State::S1 && sig_bi == State::S1);
+ if (sig_bi != State::S0 && sig_bi != State::S1)
+ goto skip_fine_alu;
+ if (sig_ci != State::S0 && sig_ci != State::S1)
+ goto skip_fine_alu;
- // If not a subtraction, yet there is a carry or B is inverted
- // then no optimisation is possible as carry will not be constant
- if (!sub && (sig_ci != State::S0 || sig_bi != State::S0))
- goto next_cell;
+ bool bi = sig_bi == State::S1;
+ bool ci = sig_ci == State::S1;
int i;
for (i = 0; i < GetSize(sig_y); i++) {
RTLIL::SigBit b = sig_b.at(i, State::Sx);
RTLIL::SigBit a = sig_a.at(i, State::Sx);
- if (b == State::S0 && a != State::Sx) {
- module->connect(sig_y[i], sig_a[i]);
- module->connect(sig_x[i], sub ? module->Not(NEW_ID, a).as_bit() : a);
- module->connect(sig_co[i], sub ? State::S1 : State::S0);
- }
- else if (sub && b == State::S1 && a == State::S1) {
- module->connect(sig_y[i], State::S0);
- module->connect(sig_x[i], module->Not(NEW_ID, a));
- module->connect(sig_co[i], State::S0);
+ if (b == ((bi ^ ci) ? State::S1 : State::S0) && a != State::Sx) {
+ module->connect(sig_y[i], a);
+ module->connect(sig_x[i], ci ? module->Not(NEW_ID, a).as_bit() : a);
+ module->connect(sig_co[i], ci ? State::S1 : State::S0);
}
- else if (!sub && a == State::S0 && b != State::Sx) {
- module->connect(sig_y[i], b);
- module->connect(sig_x[i], b);
- module->connect(sig_co[i], State::S0);
+ else if (a == (ci ? State::S1 : State::S0) && b != State::Sx) {
+ module->connect(sig_y[i], bi ? module->Not(NEW_ID, b).as_bit() : b);
+ module->connect(sig_x[i], (bi ^ ci) ? module->Not(NEW_ID, b).as_bit() : b);
+ module->connect(sig_co[i], ci ? State::S1 : State::S0);
}
else
break;
@@ -758,6 +754,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
}
+skip_fine_alu:
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr),
ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow)))
@@ -1089,7 +1086,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
// If not a subtraction, yet there is a carry or B is inverted
// then no optimisation is possible as carry will not be constant
if (!sub && (sig_ci != State::S0 || sig_bi != State::S0))
- goto next_cell;
+ goto skip_identity;
}
if (!sub && a.is_fully_const() && a.as_bool() == false)
@@ -1138,9 +1135,24 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
if (cell->type == ID($alu)) {
+ bool a_signed = cell->parameters[ID::A_SIGNED].as_bool();
+ bool b_signed = cell->parameters[ID::B_SIGNED].as_bool();
+ bool is_signed = a_signed && b_signed;
+ RTLIL::SigBit sig_ci = assign_map(cell->getPort(ID::CI));
int y_width = GetSize(cell->getPort(ID::Y));
- module->connect(cell->getPort(ID::X), RTLIL::Const(State::S0, y_width));
- module->connect(cell->getPort(ID::CO), RTLIL::Const(State::S0, y_width));
+ if (sig_ci == State::S1) {
+ /* sub, b is 0 */
+ RTLIL::SigSpec a = cell->getPort(ID::A);
+ a.extend_u0(y_width, is_signed);
+ module->connect(cell->getPort(ID::X), module->Not(NEW_ID, a));
+ module->connect(cell->getPort(ID::CO), RTLIL::Const(State::S1, y_width));
+ } else {
+ /* add */
+ RTLIL::SigSpec ab = cell->getPort(identity_wrt_a ? ID::A : ID::B);
+ ab.extend_u0(y_width, is_signed);
+ module->connect(cell->getPort(ID::X), ab);
+ module->connect(cell->getPort(ID::CO), RTLIL::Const(State::S0, y_width));
+ }
cell->unsetPort(ID::BI);
cell->unsetPort(ID::CI);
cell->unsetPort(ID::X);
@@ -1163,6 +1175,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
goto next_cell;
}
}
+skip_identity:
if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) &&
cell->getPort(ID::A) == State::S0 && cell->getPort(ID::B) == State::S1) {
@@ -1426,6 +1439,39 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
goto next_cell;
}
}
+
+ sig_a = assign_map(cell->getPort(ID::A));
+ sig_b = assign_map(cell->getPort(ID::B));
+ int a_zeros, b_zeros;
+ for (a_zeros = 0; a_zeros < GetSize(sig_a); a_zeros++)
+ if (sig_a[a_zeros] != RTLIL::State::S0)
+ break;
+ for (b_zeros = 0; b_zeros < GetSize(sig_b); b_zeros++)
+ if (sig_b[b_zeros] != RTLIL::State::S0)
+ break;
+ if (a_zeros || b_zeros) {
+ int y_zeros = a_zeros + b_zeros;
+ cover("opt.opt_expr.mul_low_zeros");
+
+ log_debug("Removing low %d A and %d B bits from cell `%s' in module `%s'.\n",
+ a_zeros, b_zeros, cell->name.c_str(), module->name.c_str());
+
+ if (a_zeros) {
+ cell->setPort(ID::A, sig_a.extract_end(a_zeros));
+ cell->parameters[ID::A_WIDTH] = GetSize(sig_a) - a_zeros;
+ }
+ if (b_zeros) {
+ cell->setPort(ID::B, sig_b.extract_end(b_zeros));
+ cell->parameters[ID::B_WIDTH] = GetSize(sig_b) - b_zeros;
+ }
+ cell->setPort(ID::Y, sig_y.extract_end(y_zeros));
+ cell->parameters[ID::Y_WIDTH] = GetSize(sig_y) - y_zeros;
+ module->connect(RTLIL::SigSig(sig_y.extract(0, y_zeros), RTLIL::SigSpec(0, y_zeros)));
+ cell->check();
+
+ did_something = true;
+ goto next_cell;
+ }
}
if (!keepdc && cell->type.in(ID($div), ID($mod)))
@@ -1497,6 +1543,99 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
+ // Find places in $alu cell where the carry is constant, and split it at these points.
+ if (do_fine && !keepdc && cell->type == ID($alu))
+ {
+ bool a_signed = cell->parameters[ID::A_SIGNED].as_bool();
+ bool b_signed = cell->parameters[ID::B_SIGNED].as_bool();
+ bool is_signed = a_signed && b_signed;
+
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
+ RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID::Y));
+ RTLIL::SigSpec sig_bi = assign_map(cell->getPort(ID::BI));
+ if (GetSize(sig_a) == 0)
+ sig_a = State::S0;
+ if (GetSize(sig_b) == 0)
+ sig_b = State::S0;
+ sig_a.extend_u0(GetSize(sig_y), is_signed);
+ sig_b.extend_u0(GetSize(sig_y), is_signed);
+
+ if (sig_bi != State::S0 && sig_bi != State::S1)
+ goto skip_alu_split;
+
+ std::vector<std::pair<int, State>> split_points;
+
+ for (int i = 0; i < GetSize(sig_y); i++) {
+ SigBit bit_a = sig_a[i];
+ SigBit bit_b = sig_b[i];
+ if (bit_a != State::S0 && bit_a != State::S1)
+ continue;
+ if (bit_b != State::S0 && bit_b != State::S1)
+ continue;
+ if (sig_bi == State::S1) {
+ if (bit_b == State::S0)
+ bit_b = State::S1;
+ else
+ bit_b = State::S0;
+ }
+ if (bit_a != bit_b)
+ continue;
+ split_points.push_back(std::make_pair(i + 1, bit_a.data));
+ }
+
+ if (split_points.empty() || split_points[0].first == GetSize(sig_y))
+ goto skip_alu_split;
+
+ for (auto &p : split_points)
+ log_debug("Splitting $alu cell `%s' in module `%s' at const-carry point %d.\n",
+ cell->name.c_str(), module->name.c_str(), p.first);
+
+ if (split_points.back().first != GetSize(sig_y))
+ split_points.push_back(std::make_pair(GetSize(sig_y), State::Sx));
+
+ RTLIL::SigSpec sig_ci = assign_map(cell->getPort(ID::CI));
+ int prev = 0;
+ RTLIL::SigSpec sig_x = assign_map(cell->getPort(ID::X));
+ RTLIL::SigSpec sig_co = assign_map(cell->getPort(ID::CO));
+
+ for (auto &p : split_points) {
+ int cur = p.first;
+ int sz = cur - prev;
+ bool last = cur == GetSize(sig_y);
+
+ RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
+ c->setPort(ID::A, sig_a.extract(prev, sz));
+ c->setPort(ID::B, sig_b.extract(prev, sz));
+ c->setPort(ID::BI, sig_bi);
+ c->setPort(ID::CI, sig_ci);
+ c->setPort(ID::Y, sig_y.extract(prev, sz));
+ c->setPort(ID::X, sig_x.extract(prev, sz));
+ RTLIL::SigSpec new_co = sig_co.extract(prev, sz);
+ if (p.second != State::Sx) {
+ module->connect(new_co[sz-1], p.second);
+ RTLIL::Wire *dummy = module->addWire(NEW_ID);
+ new_co[sz-1] = dummy;
+ }
+ c->setPort(ID::CO, new_co);
+ c->parameters[ID::A_WIDTH] = sz;
+ c->parameters[ID::B_WIDTH] = sz;
+ c->parameters[ID::Y_WIDTH] = sz;
+ c->parameters[ID::A_SIGNED] = last ? a_signed : false;
+ c->parameters[ID::B_SIGNED] = last ? b_signed : false;
+
+ prev = p.first;
+ sig_ci = p.second;
+ }
+
+ cover("opt.opt_expr.alu_split");
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+skip_alu_split:
+
// remove redundant pairs of bits in ==, ===, !=, and !==
// replace cell with const driver if inputs can't be equal
if (do_fine && cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex)))
diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc
index a861bd7a4..d845926fc 100644
--- a/passes/opt/opt_merge.cc
+++ b/passes/opt/opt_merge.cc
@@ -118,9 +118,7 @@ struct OptMergeWorker
for (auto &it : *conn) {
RTLIL::SigSpec sig;
if (cell->output(it.first)) {
- if (it.first == ID::Q && (cell->type.begins_with("$dff") || cell->type.begins_with("$dlatch") ||
- cell->type.begins_with("$_DFF") || cell->type.begins_with("$_DLATCH") || cell->type.begins_with("$_SR_") ||
- cell->type.in(ID($adff), ID($sr), ID($ff), ID($_FF_)))) {
+ if (it.first == ID::Q && RTLIL::builtin_ff_cell_types().count(cell->type)) {
// For the 'Q' output of state elements,
// use its (* init *) attribute value
for (const auto &b : dff_init_map(it.second))
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index 4bb4b0edc..a928c57de 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -13,4 +13,5 @@ OBJS += passes/sat/fmcombine.o
OBJS += passes/sat/mutate.o
OBJS += passes/sat/cutpoint.o
OBJS += passes/sat/fminit.o
+OBJS += passes/sat/qbfsat.o
diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc
new file mode 100644
index 000000000..44691425f
--- /dev/null
+++ b/passes/sat/qbfsat.cc
@@ -0,0 +1,550 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2020 Alberto Gonzalez <boqwxp@airmail.cc>
+ *
+ * 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/celltypes.h"
+#include "kernel/log.h"
+#include "kernel/rtlil.h"
+#include "kernel/register.h"
+#include <cstdio>
+#include <algorithm>
+
+#if defined(_WIN32)
+# define WIFEXITED(x) 1
+# define WIFSIGNALED(x) 0
+# define WIFSTOPPED(x) 0
+# define WEXITSTATUS(x) ((x) & 0xff)
+# define WTERMSIG(x) SIGTERM
+#else
+# include <sys/wait.h>
+#endif
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct QbfSolutionType {
+ std::vector<std::string> stdout;
+ dict<std::string, std::string> hole_to_value;
+ bool sat;
+ bool unknown; //true if neither 'sat' nor 'unsat'
+ bool success; //true if exit code 0
+
+ QbfSolutionType() : sat(false), unknown(true), success(false) {}
+};
+
+struct QbfSolveOptions {
+ bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs;
+ bool sat, unsat, show_smtbmc;
+ std::string specialize_soln_file;
+ std::string write_soln_soln_file;
+ std::string dump_final_smt2_file;
+ size_t argidx;
+ QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false),
+ nocleanup(false), dump_final_smt2(false), assume_outputs(false), sat(false), unsat(false),
+ show_smtbmc(false), argidx(0) {};
+};
+
+void recover_solution(QbfSolutionType &sol) {
+ YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED");
+ YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available");
+ YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)");
+#ifndef NDEBUG
+ YS_REGEX_TYPE hole_loc_regex = YS_REGEX_COMPILE("[^:]*:[0-9]+.[0-9]+-[0-9]+.[0-9]+");
+ YS_REGEX_TYPE hole_val_regex = YS_REGEX_COMPILE("[0-9]+");
+#endif
+ YS_REGEX_MATCH_TYPE m;
+ bool sat_regex_found = false;
+ bool unsat_regex_found = false;
+ dict<std::string, bool> hole_value_recovered;
+ for (const std::string &x : sol.stdout) {
+ if(YS_REGEX_NS::regex_search(x, m, hole_value_regex)) {
+ std::string loc = m[1].str();
+ std::string val = m[2].str();
+#ifndef NDEBUG
+ log_assert(YS_REGEX_NS::regex_search(loc, hole_loc_regex));
+ log_assert(YS_REGEX_NS::regex_search(val, hole_val_regex));
+#endif
+ sol.hole_to_value[loc] = val;
+ }
+ else if (YS_REGEX_NS::regex_search(x, sat_regex))
+ sat_regex_found = true;
+ else if (YS_REGEX_NS::regex_search(x, unsat_regex))
+ unsat_regex_found = true;
+ }
+#ifndef NDEBUG
+ log_assert(!sol.unknown && sol.sat? sat_regex_found : true);
+ log_assert(!sol.unknown && !sol.sat? unsat_regex_found : true);
+#endif
+}
+
+dict<std::string, std::string> get_hole_loc_name_map(RTLIL::Module *module, const QbfSolutionType &sol) {
+ dict<std::string, std::string> hole_loc_to_name;
+ for (auto cell : module->cells()) {
+ std::string cell_src = cell->get_src_attribute();
+ auto pos = sol.hole_to_value.find(cell_src);
+ if (pos != sol.hole_to_value.end()) {
+#ifndef NDEBUG
+ log_assert(cell->type.in("$anyconst", "$anyseq"));
+ log_assert(cell->getPort(ID::Y).is_wire());
+#endif
+ hole_loc_to_name[pos->first] = cell->getPort(ID::Y).as_wire()->name.str();
+ }
+ }
+
+ return hole_loc_to_name;
+}
+
+void write_solution(RTLIL::Module *module, const QbfSolutionType &sol, const std::string &file) {
+ std::ofstream fout(file.c_str());
+ if (!fout)
+ log_cmd_error("could not open solution file for writing.\n");
+
+ dict<std::string, std::string> hole_loc_to_name = get_hole_loc_name_map(module, sol);
+ for(auto &x : sol.hole_to_value)
+ fout << hole_loc_to_name[x.first] << "=" << x.second << std::endl;
+}
+
+void specialize_from_file(RTLIL::Module *module, const std::string &file) {
+ YS_REGEX_TYPE hole_assn_regex = YS_REGEX_COMPILE_WITH_SUBS("^(.*)=([01]+)$");
+ YS_REGEX_MATCH_TYPE m;
+ pool<RTLIL::Cell *> anyconsts_to_remove;
+ dict<std::string, std::string> hole_name_to_value;
+ std::ifstream fin(file.c_str());
+ if (!fin)
+ log_cmd_error("could not read solution file.\n");
+
+ std::string buf;
+ while (std::getline(fin, buf)) {
+ log_assert(YS_REGEX_NS::regex_search(buf, m, hole_assn_regex));
+ std::string hole_name = m[1].str();
+ std::string hole_value = m[2].str();
+ hole_name_to_value[hole_name] = hole_value;
+ }
+
+ for (auto cell : module->cells())
+ if (cell->type == "$anyconst") {
+ auto anyconst_port_y = cell->getPort(ID::Y).as_wire();
+ if (anyconst_port_y == nullptr)
+ continue;
+ if (hole_name_to_value.find(anyconst_port_y->name.str()) != hole_name_to_value.end())
+ anyconsts_to_remove.insert(cell);
+ }
+ for (auto cell : anyconsts_to_remove)
+ module->remove(cell);
+
+ for (auto &it : hole_name_to_value) {
+ std::string hole_name = it.first;
+ std::string hole_value = it.second;
+ RTLIL::Wire *wire = module->wire(hole_name);
+#ifndef NDEBUG
+ log_assert(wire != nullptr);
+ log_assert(wire->width > 0 && GetSize(hole_value) == wire->width);
+#endif
+
+ log("Specializing %s from file with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str());
+ std::vector<RTLIL::SigBit> value_bv;
+ value_bv.reserve(wire->width);
+ for (char c : hole_value)
+ value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0);
+ std::reverse(value_bv.begin(), value_bv.end());
+ module->connect(wire, value_bv);
+ }
+}
+
+void specialize(RTLIL::Module *module, const QbfSolutionType &sol) {
+ dict<std::string, std::string> hole_loc_to_name = get_hole_loc_name_map(module, sol);
+ pool<RTLIL::Cell *> anyconsts_to_remove;
+ for (auto cell : module->cells())
+ if (cell->type == "$anyconst")
+ if (hole_loc_to_name.find(cell->get_src_attribute()) != hole_loc_to_name.end())
+ anyconsts_to_remove.insert(cell);
+ for (auto cell : anyconsts_to_remove)
+ module->remove(cell);
+ for (auto &it : sol.hole_to_value) {
+ std::string hole_loc = it.first;
+ std::string hole_value = it.second;
+
+#ifndef NDEBUG
+ auto pos = hole_loc_to_name.find(hole_loc);
+ log_assert(pos != hole_loc_to_name.end());
+#endif
+
+ std::string hole_name = hole_loc_to_name[hole_loc];
+ RTLIL::Wire *wire = module->wire(hole_name);
+#ifndef NDEBUG
+ log_assert(wire != nullptr);
+ log_assert(wire->width > 0 && GetSize(hole_value) == wire->width);
+#endif
+
+ log("Specializing %s with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str());
+ std::vector<RTLIL::SigBit> value_bv;
+ value_bv.reserve(wire->width);
+ for (char c : hole_value)
+ value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0);
+ std::reverse(value_bv.begin(), value_bv.end());
+ module->connect(wire, value_bv);
+ }
+}
+
+void dump_model(RTLIL::Module *module, const QbfSolutionType &sol) {
+ log("Satisfiable model:\n");
+ dict<std::string, std::string> hole_loc_to_name = get_hole_loc_name_map(module, sol);
+ for (auto &it : sol.hole_to_value) {
+ std::string hole_loc = it.first;
+ std::string hole_value = it.second;
+
+#ifndef NDEBUG
+ auto pos = hole_loc_to_name.find(hole_loc);
+ log_assert(pos != hole_loc_to_name.end());
+#endif
+
+ std::string hole_name = hole_loc_to_name[hole_loc];
+ log("\t%s = %lu'b%s\n", hole_name.c_str(), hole_value.size(), hole_value.c_str());
+ std::vector<RTLIL::SigBit> value_bv;
+ value_bv.reserve(hole_value.size());
+ for (char c : hole_value)
+ value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0);
+ std::reverse(value_bv.begin(), value_bv.end());
+ }
+
+}
+
+void allconstify_inputs(RTLIL::Module *module, const pool<std::string> &input_wires) {
+ for (auto &n : input_wires) {
+ RTLIL::Wire *input = module->wire(n);
+#ifndef NDEBUG
+ log_assert(input != nullptr);
+#endif
+
+ RTLIL::Cell *allconst = module->addCell("$allconst$" + n, "$allconst");
+ allconst->setParam(ID(WIDTH), input->width);
+ allconst->setPort(ID::Y, input);
+ allconst->set_src_attribute(input->get_src_attribute());
+ input->port_input = false;
+ log("Replaced input %s with $allconst cell.\n", n.c_str());
+ }
+ module->fixup_ports();
+}
+
+void assume_miter_outputs(RTLIL::Module *module) {
+ std::vector<RTLIL::Wire *> wires_to_assume;
+ for (auto w : module->wires())
+ if (w->port_output && w->width == 1)
+ wires_to_assume.push_back(w);
+
+ if (wires_to_assume.size() == 0)
+ return;
+ else {
+ log("Adding $assume cell for output(s): ");
+ for (auto w : wires_to_assume)
+ log("\"%s\" ", w->name.c_str());
+ log("\n");
+ }
+
+ for(auto i = 0; wires_to_assume.size() > 1; ++i) {
+ std::vector<RTLIL::Wire *> buf;
+ for (auto j = 0; j + 1 < GetSize(wires_to_assume); j += 2) {
+ std::stringstream strstr; strstr << i << "_" << j;
+ RTLIL::Wire *and_wire = module->addWire("\\_qbfsat_and_" + strstr.str(), 1);
+ module->addLogicAnd("$_qbfsat_and_" + strstr.str(), wires_to_assume[j], wires_to_assume[j+1], and_wire, false, wires_to_assume[j]->get_src_attribute());
+ buf.push_back(and_wire);
+ }
+ if (wires_to_assume.size() % 2 == 1)
+ buf.push_back(wires_to_assume[wires_to_assume.size() - 1]);
+ wires_to_assume.swap(buf);
+ }
+
+#ifndef NDEBUG
+ log_assert(wires_to_assume.size() == 1);
+#endif
+ module->addAssume("$assume_qbfsat_miter_outputs", wires_to_assume[0], RTLIL::S1);
+}
+
+QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
+ QbfSolutionType ret;
+ const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc";
+ const std::string smtbmc_warning = "z3: WARNING:";
+ const bool show_smtbmc = opt.show_smtbmc;
+
+ const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX");
+ const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem.smt2";
+#ifndef NDEBUG
+ log_assert(mod->design != nullptr);
+#endif
+ Pass::call(mod->design, smt2_command);
+ log_header(mod->design, "Solving QBF-SAT problem.\n");
+
+ //Execute and capture stdout from `yosys-smtbmc -s z3 -t 1 -g --binary [--dump-smt2 <file>]`
+ {
+ const std::string cmd = yosys_smtbmc_exe + " -s z3 -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem.smt2 2>&1";
+ auto process_line = [&ret, &smtbmc_warning, &show_smtbmc](const std::string &line) {
+ ret.stdout.push_back(line.substr(0, line.size()-1)); //don't include trailing newline
+ auto warning_pos = line.find(smtbmc_warning);
+ if (warning_pos != std::string::npos)
+ log_warning("%s", line.substr(warning_pos + smtbmc_warning.size() + 1).c_str());
+ else
+ if (show_smtbmc)
+ log("smtbmc output: %s", line.c_str());
+ };
+
+ log("Launching \"%s\".\n", cmd.c_str());
+ int retval = run_command(cmd, process_line);
+ if (retval == 0) {
+ ret.sat = true;
+ ret.unknown = false;
+ } else if (retval == 1) {
+ ret.sat = false;
+ ret.unknown = false;
+ }
+ }
+
+ if(!opt.nocleanup)
+ remove_directory(tempdir_name);
+
+ recover_solution(ret);
+
+ return ret;
+}
+
+pool<std::string> validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
+ bool found_input = false;
+ bool found_hole = false;
+ bool found_1bit_output = false;
+ bool found_assert_assume = false;
+ pool<std::string> input_wires;
+ for (auto wire : module->wires()) {
+ if (wire->port_input) {
+ found_input = true;
+ input_wires.insert(wire->name.str());
+ }
+ if (wire->port_output && wire->width == 1)
+ found_1bit_output = true;
+ }
+ for (auto cell : module->cells()) {
+ if (cell->type == "$allconst")
+ found_input = true;
+ if (cell->type == "$anyconst")
+ found_hole = true;
+ if (cell->type.in("$assert", "$assume"))
+ found_assert_assume = true;
+ }
+ if (!found_input)
+ log_cmd_error("Can't perform QBF-SAT on a miter with no inputs!\n");
+ if (!found_hole)
+ log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n");
+ if (!found_1bit_output && !found_assert_assume)
+ log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n");
+ if (!found_assert_assume && !opt.assume_outputs)
+ log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n");
+
+ return input_wires;
+}
+
+QbfSolveOptions parse_args(const std::vector<std::string> &args) {
+ QbfSolveOptions opt;
+ for (opt.argidx = 1; opt.argidx < args.size(); opt.argidx++) {
+ if (args[opt.argidx] == "-nocleanup") {
+ opt.nocleanup = true;
+ continue;
+ }
+ else if (args[opt.argidx] == "-specialize") {
+ opt.specialize = true;
+ continue;
+ }
+ else if (args[opt.argidx] == "-assume-outputs") {
+ opt.assume_outputs = true;
+ continue;
+ }
+ else if (args[opt.argidx] == "-sat") {
+ opt.sat = true;
+ continue;
+ }
+ else if (args[opt.argidx] == "-unsat") {
+ opt.unsat = true;
+ continue;
+ }
+ else if (args[opt.argidx] == "-show-smtbmc") {
+ opt.show_smtbmc = true;
+ continue;
+ }
+ else if (args[opt.argidx] == "-dump-final-smt2") {
+ opt.dump_final_smt2 = true;
+ if (args.size() <= opt.argidx + 1)
+ log_cmd_error("smt2 file not specified.\n");
+ else
+ opt.dump_final_smt2_file = args[++opt.argidx];
+ continue;
+ }
+ else if (args[opt.argidx] == "-specialize-from-file") {
+ opt.specialize_from_file = true;
+ if (args.size() <= opt.argidx + 1)
+ log_cmd_error("solution file not specified.\n");
+ else
+ opt.specialize_soln_file = args[++opt.argidx];
+ continue;
+ }
+ else if (args[opt.argidx] == "-write-solution") {
+ opt.write_solution = true;
+ if (args.size() <= opt.argidx + 1)
+ log_cmd_error("solution file not specified.\n");
+ else
+ opt.write_soln_soln_file = args[++opt.argidx];
+ continue;
+ }
+ break;
+ }
+
+ return opt;
+}
+
+void print_proof_failed()
+{
+ log("\n");
+ log(" ______ ___ ___ _ _ _ _ \n");
+ log(" (_____ \\ / __) / __) (_) | | | |\n");
+ log(" _____) )___ ___ ___ _| |__ _| |__ _____ _| | _____ __| | |\n");
+ log(" | ____/ ___) _ \\ / _ (_ __) (_ __|____ | | || ___ |/ _ |_|\n");
+ log(" | | | | | |_| | |_| || | | | / ___ | | || ____( (_| |_ \n");
+ log(" |_| |_| \\___/ \\___/ |_| |_| \\_____|_|\\_)_____)\\____|_|\n");
+ log("\n");
+}
+
+void print_qed()
+{
+ log("\n");
+ log(" /$$$$$$ /$$$$$$$$ /$$$$$$$ \n");
+ log(" /$$__ $$ | $$_____/ | $$__ $$ \n");
+ log(" | $$ \\ $$ | $$ | $$ \\ $$ \n");
+ log(" | $$ | $$ | $$$$$ | $$ | $$ \n");
+ log(" | $$ | $$ | $$__/ | $$ | $$ \n");
+ log(" | $$/$$ $$ | $$ | $$ | $$ \n");
+ log(" | $$$$$$/ /$$| $$$$$$$$ /$$| $$$$$$$//$$\n");
+ log(" \\____ $$$|__/|________/|__/|_______/|__/\n");
+ log(" \\__/ \n");
+ log("\n");
+}
+
+struct QbfSatPass : public Pass {
+ QbfSatPass() : Pass("qbfsat", "solve a 2QBF-SAT problem in the circuit") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" qbfsat [options] [selection]\n");
+ log("\n");
+ log("This command solves a 2QBF-SAT problem defined over the currently selected module.\n");
+ log("Existentially-quantified variables are declared by assigning a wire \"$anyconst\".\n");
+ log("Universally-quantified variables may be explicitly declared by assigning a wire\n");
+ log("\"$allconst\", but module inputs will be treated as universally-quantified variables\n");
+ log("by default.\n");
+ log("\n");
+ log(" -nocleanup\n");
+ log(" Do not delete temporary files and directories. Useful for\n");
+ log(" debugging.\n");
+ log("\n");
+ log(" -dump-final-smt2 <file>\n");
+ log(" Pass the --dump-smt2 option to yosys-smtbmc.\n");
+ log("\n");
+ log(" -assume-outputs\n");
+ log(" Add an $assume cell for the conjunction of all one-bit module output wires.\n");
+ log("\n");
+ log(" -sat\n");
+ log(" Generate an error if the solver does not return \"sat\".\n");
+ log("\n");
+ log(" -unsat\n");
+ log(" Generate an error if the solver does not return \"unsat\".\n");
+ log("\n");
+ log(" -show-smtbmc\n");
+ log(" Print the output from yosys-smtbmc.\n");
+ log("\n");
+ log(" -specialize\n");
+ log(" Replace all \"$anyconst\" cells with constant values determined by the solver.\n");
+ log("\n");
+ log(" -specialize-from-file <solution file>\n");
+ log(" Do not run the solver, but instead only attempt to replace all \"$anyconst\"\n");
+ log(" cells in the current module with values provided by the specified file.\n");
+ log("\n");
+ log(" -write-solution <solution file>\n");
+ log(" Write the assignments discovered by the solver for all \"$anyconst\" cells\n");
+ log(" to the specified file.");
+ log("\n");
+ log("\n");
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing QBFSAT pass (solving QBF-SAT problems in the circuit).\n");
+ QbfSolveOptions opt = parse_args(args);
+ extra_args(args, opt.argidx, design);
+
+ RTLIL::Module *module = nullptr;
+ for (auto mod : design->selected_modules()) {
+ if (module)
+ log_cmd_error("Only one module must be selected for the QBF-SAT pass! (selected: %s and %s)\n", log_id(module), log_id(mod));
+ module = mod;
+ }
+ if (module == nullptr)
+ log_cmd_error("Can't perform QBF-SAT on an empty selection!\n");
+
+ log_push();
+ if (!opt.specialize_from_file) {
+ //Save the design to restore after modiyfing the current module.
+ std::string module_name = module->name.str();
+ Pass::call(design, "design -push-copy");
+
+ //Replace input wires with wires assigned $allconst cells.
+ pool<std::string> input_wires = validate_design_and_get_inputs(module, opt);
+ allconstify_inputs(module, input_wires);
+ if (opt.assume_outputs)
+ assume_miter_outputs(module);
+
+ QbfSolutionType ret = qbf_solve(module, opt);
+ Pass::call(design, "design -pop");
+ module = design->module(module_name);
+
+ if (ret.unknown)
+ log_warning("solver did not give an answer\n");
+ else if (ret.sat)
+ print_qed();
+ else
+ print_proof_failed();
+
+ if(!ret.unknown && ret.sat) {
+ if (opt.write_solution) {
+ write_solution(module, ret, opt.write_soln_soln_file);
+ }
+ if (opt.specialize) {
+ specialize(module, ret);
+ } else {
+ dump_model(module, ret);
+ }
+ if (opt.unsat)
+ log_cmd_error("expected problem to be UNSAT\n");
+ }
+ else if (!ret.unknown && !ret.sat && opt.sat)
+ log_cmd_error("expected problem to be SAT\n");
+ else if (ret.unknown && (opt.sat || opt.unsat))
+ log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT");
+ } else
+ specialize_from_file(module, opt.specialize_soln_file);
+ log_pop();
+ }
+} QbfSatPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index c16db0d57..766b954df 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -34,7 +34,6 @@ OBJS += passes/techmap/aigmap.o
OBJS += passes/techmap/tribuf.o
OBJS += passes/techmap/lut2mux.o
OBJS += passes/techmap/nlutmap.o
-OBJS += passes/techmap/dffsr2dff.o
OBJS += passes/techmap/shregmap.o
OBJS += passes/techmap/deminout.o
OBJS += passes/techmap/insbuf.o
@@ -59,10 +58,10 @@ passes/techmap/techmap.inc: techlibs/common/techmap.v
passes/techmap/techmap.o: passes/techmap/techmap.inc
ifneq ($(CONFIG),emcc)
-TARGETS += yosys-filterlib$(EXE)
+TARGETS += $(PROGRAM_PREFIX)yosys-filterlib$(EXE)
EXTRA_OBJS += passes/techmap/filterlib.o
-yosys-filterlib$(EXE): passes/techmap/filterlib.o
+$(PROGRAM_PREFIX)yosys-filterlib$(EXE): passes/techmap/filterlib.o
$(Q) mkdir -p $(dir $@)
- $(P) $(LD) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS)
+ $(P) $(LD) -o $(PROGRAM_PREFIX)yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS)
endif
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 71ac7a110..aff0baa44 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -702,7 +702,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (dff_mode && clk_sig.empty())
log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
- std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
+ std::string tempdir_name = "/tmp/" + proc_program_prefix()+ "yosys-abc-XXXXXX";
if (!cleanup)
tempdir_name[0] = tempdir_name[4] = '_';
tempdir_name = make_temp_dir(tempdir_name);
@@ -1286,7 +1286,7 @@ struct AbcPass : public Pass {
#ifdef ABCEXTERNAL
log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
#else
- log(" use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n");
+ log(" use the specified command instead of \"<yosys-bindir>/%syosys-abc\" to execute ABC.\n", proc_program_prefix().c_str());
#endif
log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n");
log("\n");
@@ -1472,7 +1472,7 @@ struct AbcPass : public Pass {
#ifdef ABCEXTERNAL
std::string exe_file = ABCEXTERNAL;
#else
- std::string exe_file = proc_self_dirname() + "yosys-abc";
+ std::string exe_file = proc_self_dirname() + proc_program_prefix() + "yosys-abc";
#endif
std::string script_file, liberty_file, constr_file, clk_str;
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
@@ -1490,8 +1490,8 @@ struct AbcPass : public Pass {
#ifdef _WIN32
#ifndef ABCEXTERNAL
- if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
- exe_file = proc_self_dirname() + "..\\yosys-abc";
+ if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix()+ "yosys-abc.exe"))
+ exe_file = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc";
#endif
#endif
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 9757b1539..1b3d5ff06 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -100,7 +100,7 @@ struct Abc9Pass : public ScriptPass
#ifdef ABCEXTERNAL
log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
#else
- log(" use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n");
+ log(" use the specified command instead of \"<yosys-bindir>/%syosys-abc\" to execute ABC.\n", proc_program_prefix().c_str());
#endif
log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n");
log("\n");
@@ -326,7 +326,7 @@ struct Abc9Pass : public ScriptPass
if (!active_design->selected_whole_module(mod))
log_error("Can't handle partially selected module %s!\n", log_id(mod));
- std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
+ std::string tempdir_name = "/tmp/" + proc_program_prefix() + "yosys-abc-XXXXXX";
if (!cleanup)
tempdir_name[0] = tempdir_name[4] = '_';
tempdir_name = make_temp_dir(tempdir_name);
diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc
index 898285c69..18618ff91 100644
--- a/passes/techmap/abc9_exe.cc
+++ b/passes/techmap/abc9_exe.cc
@@ -222,9 +222,9 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name.c_str());
if (design->scratchpad_get_bool("abc9.verify")) {
if (dff_mode)
- abc9_script += "; verify -s";
+ abc9_script += "; &verify -s";
else
- abc9_script += "; verify";
+ abc9_script += "; &verify";
}
abc9_script += "; time";
abc9_script = add_echos_to_abc9_cmd(abc9_script);
@@ -293,7 +293,7 @@ struct Abc9ExePass : public Pass {
#ifdef ABCEXTERNAL
log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
#else
- log(" use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n");
+ log(" use the specified command instead of \"<yosys-bindir>/%syosys-abc\" to execute ABC.\n", proc_program_prefix().c_str());
#endif
log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n");
log("\n");
@@ -367,7 +367,7 @@ struct Abc9ExePass : public Pass {
#ifdef ABCEXTERNAL
std::string exe_file = ABCEXTERNAL;
#else
- std::string exe_file = proc_self_dirname() + "yosys-abc";
+ std::string exe_file = proc_self_dirname() + proc_program_prefix()+ "yosys-abc";
#endif
std::string script_file, clk_str, box_file, lut_file;
std::string delay_target, lutin_shared = "-S 1", wire_delay;
@@ -383,8 +383,8 @@ struct Abc9ExePass : public Pass {
#ifdef _WIN32
#ifndef ABCEXTERNAL
- if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
- exe_file = proc_self_dirname() + "..\\yosys-abc";
+ if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc.exe"))
+ exe_file = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc";
#endif
#endif
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 00af36615..8ae1b51ff 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -434,6 +434,9 @@ void prep_delays(RTLIL::Design *design, bool dff_mode)
auto &t = timing.at(derived_type).required;
for (auto &conn : cell->connections_) {
auto port_wire = inst_module->wire(conn.first);
+ if (!port_wire)
+ log_error("Port %s in cell %s (type %s) of module %s does not actually exist",
+ log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name));
if (!port_wire->port_input)
continue;
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index 0424ce434..35645582b 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -154,9 +154,11 @@ struct DffinitPass : public Pass {
value = Const(low_string);
}
- log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second),
- log_id(it.first), log_signal(sig), log_signal(value));
- cell->setParam(it.second, value);
+ if (value.size() != 0) {
+ log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second),
+ log_id(it.first), log_signal(sig), log_signal(value));
+ cell->setParam(it.second, value);
+ }
}
}
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index b15109cd3..aa344cf8a 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -78,7 +78,7 @@ static void logmap_all()
static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, bool &pin_pol)
{
- if (cell == NULL || attr == NULL || attr->value.empty())
+ if (cell == nullptr || attr == nullptr || attr->value.empty())
return false;
std::string value = attr->value;
@@ -117,7 +117,7 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name,
static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode)
{
- LibertyAst *best_cell = NULL;
+ LibertyAst *best_cell = nullptr;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
bool best_cell_noninv = false;
@@ -132,11 +132,11 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has
continue;
LibertyAst *dn = cell->find("dont_use");
- if (dn != NULL && dn->value == "true")
+ if (dn != nullptr && dn->value == "true")
continue;
LibertyAst *ff = cell->find("ff");
- if (ff == NULL)
+ if (ff == nullptr)
continue;
std::string cell_clk_pin, cell_rst_pin, cell_next_pin;
@@ -163,7 +163,7 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has
double area = 0;
LibertyAst *ar = cell->find("area");
- if (ar != NULL && !ar->value.empty())
+ if (ar != nullptr && !ar->value.empty())
area = atof(ar->value.c_str());
int num_pins = 0;
@@ -175,7 +175,7 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has
continue;
LibertyAst *dir = pin->find("direction");
- if (dir == NULL || dir->value == "internal")
+ if (dir == nullptr || dir->value == "internal")
continue;
num_pins++;
@@ -183,7 +183,7 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has
goto continue_cell_loop;
LibertyAst *func = pin->find("function");
- if (dir->value == "output" && func != NULL) {
+ if (dir->value == "output" && func != nullptr) {
std::string value = func->value;
for (size_t pos = value.find_first_of("\" \t"); pos != std::string::npos; pos = value.find_first_of("\" \t"))
value.erase(pos, 1);
@@ -205,10 +205,10 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has
this_cell_ports[pin->args[0]] = 0;
}
- if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
+ if (!found_output || (best_cell != nullptr && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
continue;
- if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area)
+ if (best_cell != nullptr && num_pins == best_cell_pins && area > best_cell_area)
continue;
best_cell = cell;
@@ -219,7 +219,7 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has
continue_cell_loop:;
}
- if (best_cell != NULL) {
+ if (best_cell != nullptr) {
log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
if (prepare_mode) {
@@ -238,7 +238,7 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has
static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode)
{
- LibertyAst *best_cell = NULL;
+ LibertyAst *best_cell = nullptr;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
bool best_cell_noninv = false;
@@ -253,11 +253,11 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool
continue;
LibertyAst *dn = cell->find("dont_use");
- if (dn != NULL && dn->value == "true")
+ if (dn != nullptr && dn->value == "true")
continue;
LibertyAst *ff = cell->find("ff");
- if (ff == NULL)
+ if (ff == nullptr)
continue;
std::string cell_clk_pin, cell_set_pin, cell_clr_pin, cell_next_pin;
@@ -280,7 +280,7 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool
double area = 0;
LibertyAst *ar = cell->find("area");
- if (ar != NULL && !ar->value.empty())
+ if (ar != nullptr && !ar->value.empty())
area = atof(ar->value.c_str());
int num_pins = 0;
@@ -292,7 +292,7 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool
continue;
LibertyAst *dir = pin->find("direction");
- if (dir == NULL || dir->value == "internal")
+ if (dir == nullptr || dir->value == "internal")
continue;
num_pins++;
@@ -300,7 +300,7 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool
goto continue_cell_loop;
LibertyAst *func = pin->find("function");
- if (dir->value == "output" && func != NULL) {
+ if (dir->value == "output" && func != nullptr) {
std::string value = func->value;
for (size_t pos = value.find_first_of("\" \t"); pos != std::string::npos; pos = value.find_first_of("\" \t"))
value.erase(pos, 1);
@@ -322,10 +322,10 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool
this_cell_ports[pin->args[0]] = 0;
}
- if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
+ if (!found_output || (best_cell != nullptr && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
continue;
- if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area)
+ if (best_cell != nullptr && num_pins == best_cell_pins && area > best_cell_area)
continue;
best_cell = cell;
@@ -336,7 +336,7 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool
continue_cell_loop:;
}
- if (best_cell != NULL) {
+ if (best_cell != nullptr) {
log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
if (prepare_mode) {
@@ -481,11 +481,11 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
SigMap sigmap(module);
std::vector<RTLIL::Cell*> cell_list;
- for (auto &it : module->cells_) {
- if (design->selected(module, it.second) && cell_mappings.count(it.second->type) > 0)
- cell_list.push_back(it.second);
- if (it.second->type == ID($_NOT_))
- notmap[sigmap(it.second->getPort(ID::A))].insert(it.second);
+ for (auto cell : module->cells()) {
+ if (design->selected(module, cell) && cell_mappings.count(cell->type) > 0)
+ cell_list.push_back(cell);
+ if (cell->type == ID($_NOT_))
+ notmap[sigmap(cell->getPort(ID::A))].insert(cell);
}
std::map<std::string, int> stats;
@@ -663,9 +663,9 @@ struct DfflibmapPass : public Pass {
log(" final dff cell mappings:\n");
logmap_all();
- for (auto &it : design->modules_)
- if (design->selected(it.second) && !it.second->get_blackbox_attribute())
- dfflibmap(design, it.second, prepare_mode);
+ for (auto module : design->selected_modules())
+ if (!module->get_blackbox_attribute())
+ dfflibmap(design, module, prepare_mode);
cell_mappings.clear();
}
diff --git a/passes/techmap/dffsr2dff.cc b/passes/techmap/dffsr2dff.cc
deleted file mode 100644
index 4a3ddaf73..000000000
--- a/passes/techmap/dffsr2dff.cc
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * 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
-
-void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell)
-{
- if (cell->type == ID($dffsr))
- {
- int width = cell->getParam(ID::WIDTH).as_int();
- bool setpol = cell->getParam(ID::SET_POLARITY).as_bool();
- bool clrpol = cell->getParam(ID::CLR_POLARITY).as_bool();
-
- SigBit setunused = setpol ? State::S0 : State::S1;
- SigBit clrunused = clrpol ? State::S0 : State::S1;
-
- SigSpec setsig = sigmap(cell->getPort(ID::SET));
- SigSpec clrsig = sigmap(cell->getPort(ID::CLR));
-
- Const reset_val;
- SigSpec setctrl, clrctrl;
-
- for (int i = 0; i < width; i++)
- {
- SigBit setbit = setsig[i], clrbit = clrsig[i];
-
- if (setbit == setunused) {
- clrctrl.append(clrbit);
- reset_val.bits.push_back(State::S0);
- continue;
- }
-
- if (clrbit == clrunused) {
- setctrl.append(setbit);
- reset_val.bits.push_back(State::S1);
- continue;
- }
-
- return;
- }
-
- setctrl.sort_and_unify();
- clrctrl.sort_and_unify();
-
- if (GetSize(setctrl) > 1 || GetSize(clrctrl) > 1)
- return;
-
- if (GetSize(setctrl) == 0 && GetSize(clrctrl) == 0)
- return;
-
- if (GetSize(setctrl) == 1 && GetSize(clrctrl) == 1) {
- if (setpol != clrpol)
- return;
- if (setctrl != clrctrl)
- return;
- }
-
- log("Converting %s cell %s.%s to $adff.\n", log_id(cell->type), log_id(module), log_id(cell));
-
- if (GetSize(setctrl) == 1) {
- cell->setPort(ID::ARST, setctrl);
- cell->setParam(ID::ARST_POLARITY, setpol);
- } else {
- cell->setPort(ID::ARST, clrctrl);
- cell->setParam(ID::ARST_POLARITY, clrpol);
- }
-
- cell->type = ID($adff);
- cell->unsetPort(ID::SET);
- cell->unsetPort(ID::CLR);
- cell->setParam(ID::ARST_VALUE, reset_val);
- cell->unsetParam(ID::SET_POLARITY);
- cell->unsetParam(ID::CLR_POLARITY);
-
- return;
- }
-
- if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
- ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
- {
- char clkpol = cell->type.c_str()[8];
- char setpol = cell->type.c_str()[9];
- char clrpol = cell->type.c_str()[10];
-
- SigBit setbit = sigmap(cell->getPort(ID::S));
- SigBit clrbit = sigmap(cell->getPort(ID::R));
-
- SigBit setunused = setpol == 'P' ? State::S0 : State::S1;
- SigBit clrunused = clrpol == 'P' ? State::S0 : State::S1;
-
- IdString oldtype = cell->type;
-
- if (setbit == setunused) {
- cell->type = stringf("$_DFF_%c%c0_", clkpol, clrpol);
- cell->unsetPort(ID::S);
- goto converted_gate;
- }
-
- if (clrbit == clrunused) {
- cell->type = stringf("$_DFF_%c%c1_", clkpol, setpol);
- cell->setPort(ID::R, cell->getPort(ID::S));
- cell->unsetPort(ID::S);
- goto converted_gate;
- }
-
- return;
-
- converted_gate:
- log("Converting %s cell %s.%s to %s.\n", log_id(oldtype), log_id(module), log_id(cell), log_id(cell->type));
- return;
- }
-}
-
-void adff_worker(SigMap &sigmap, Module *module, Cell *cell)
-{
- if (cell->type == ID($adff))
- {
- bool rstpol = cell->getParam(ID::ARST_POLARITY).as_bool();
- SigBit rstunused = rstpol ? State::S0 : State::S1;
- SigSpec rstsig = sigmap(cell->getPort(ID::ARST));
-
- if (rstsig != rstunused)
- return;
-
- log("Converting %s cell %s.%s to $dff.\n", log_id(cell->type), log_id(module), log_id(cell));
-
- cell->type = ID($dff);
- cell->unsetPort(ID::ARST);
- cell->unsetParam(ID::ARST_VALUE);
- cell->unsetParam(ID::ARST_POLARITY);
-
- return;
- }
-
- if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
- ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)))
- {
- char clkpol = cell->type.c_str()[6];
- char rstpol = cell->type.c_str()[7];
-
- SigBit rstbit = sigmap(cell->getPort(ID::R));
- SigBit rstunused = rstpol == 'P' ? State::S0 : State::S1;
-
- if (rstbit != rstunused)
- return;
-
- IdString newtype = stringf("$_DFF_%c_", clkpol);
- log("Converting %s cell %s.%s to %s.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(newtype));
-
- cell->type = newtype;
- cell->unsetPort(ID::R);
-
- return;
- }
-}
-
-struct Dffsr2dffPass : public Pass {
- Dffsr2dffPass() : Pass("dffsr2dff", "convert DFFSR cells to simpler FF cell types") { }
- void help() YS_OVERRIDE
- {
- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
- log("\n");
- log(" dffsr2dff [options] [selection]\n");
- log("\n");
- log("This pass converts DFFSR cells ($dffsr, $_DFFSR_???_) and ADFF cells ($adff,\n");
- log("$_DFF_???_) to simpler FF cell types when any of the set/reset inputs is unused.\n");
- log("\n");
- }
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
- {
- log_header(design, "Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n");
-
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++)
- {
- // if (args[argidx] == "-v") {
- // continue;
- // }
- break;
- }
- extra_args(args, argidx, design);
-
- for (auto module : design->selected_modules()) {
- SigMap sigmap(module);
- for (auto cell : module->selected_cells()) {
- dffsr_worker(sigmap, module, cell);
- adff_worker(sigmap, module, cell);
- }
- }
- }
-} Dffsr2dffPass;
-
-PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index aea958f0f..f29044790 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -29,8 +29,6 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-using RTLIL::id2cstr;
-
class SubCircuitSolver : public SubCircuit::Solver
{
public:
@@ -121,8 +119,8 @@ public:
if (wire_attr.size() > 0)
{
- RTLIL::Wire *lastNeedleWire = NULL;
- RTLIL::Wire *lastHaystackWire = NULL;
+ RTLIL::Wire *lastNeedleWire = nullptr;
+ RTLIL::Wire *lastHaystackWire = nullptr;
dict<RTLIL::IdString, RTLIL::Const> emptyAttr;
for (auto &conn : needleCell->connections())
@@ -149,27 +147,27 @@ struct bit_ref_t {
int bit;
};
-bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL,
- int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
+bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = nullptr,
+ int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = nullptr)
{
SigMap sigmap(mod);
std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref;
if (sel && !sel->selected(mod)) {
- log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name));
+ log(" Skipping module %s as it is not selected.\n", log_id(mod->name));
return false;
}
if (mod->processes.size() > 0) {
- log(" Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name));
+ log(" Skipping module %s as it contains unprocessed processes.\n", log_id(mod->name));
return false;
}
if (constports) {
- graph.createNode("$const$0", "$const$0", NULL, true);
- graph.createNode("$const$1", "$const$1", NULL, true);
- graph.createNode("$const$x", "$const$x", NULL, true);
- graph.createNode("$const$z", "$const$z", NULL, true);
+ graph.createNode("$const$0", "$const$0", nullptr, true);
+ graph.createNode("$const$1", "$const$1", nullptr, true);
+ graph.createNode("$const$x", "$const$x", nullptr, true);
+ graph.createNode("$const$z", "$const$z", nullptr, true);
graph.createPort("$const$0", "\\Y", 1);
graph.createPort("$const$1", "\\Y", 1);
graph.createPort("$const$x", "\\Y", 1);
@@ -182,28 +180,26 @@ bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports,
std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
if (max_fanout > 0)
- for (auto &cell_it : mod->cells_)
+ for (auto cell : mod->cells())
{
- RTLIL::Cell *cell = cell_it.second;
if (!sel || sel->selected(mod, cell))
for (auto &conn : cell->connections()) {
RTLIL::SigSpec conn_sig = conn.second;
sigmap.apply(conn_sig);
for (auto &bit : conn_sig)
- if (bit.wire != NULL)
+ if (bit.wire != nullptr)
sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++;
}
}
// create graph nodes from cells
- for (auto &cell_it : mod->cells_)
+ for (auto cell : mod->cells())
{
- RTLIL::Cell *cell = cell_it.second;
if (sel && !sel->selected(mod, cell))
continue;
std::string type = cell->type.str();
- if (sel == NULL && type.compare(0, 2, "\\$") == 0)
+ if (sel == nullptr && type.compare(0, 2, "\\$") == 0)
type = type.substr(1);
graph.createNode(cell->name.str(), type, (void*)cell);
@@ -221,7 +217,7 @@ bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports,
{
auto &bit = conn_sig[i];
- if (bit.wire == NULL) {
+ if (bit.wire == nullptr) {
if (constports) {
std::string node = "$const$x";
if (bit == RTLIL::State::S0) node = "$const$0";
@@ -253,9 +249,8 @@ bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports,
}
// mark external signals (used in non-selected cells)
- for (auto &cell_it : mod->cells_)
+ for (auto cell : mod->cells())
{
- RTLIL::Cell *cell = cell_it.second;
if (sel && !sel->selected(mod, cell))
for (auto &conn : cell->connections())
{
@@ -271,9 +266,8 @@ bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports,
}
// mark external signals (used in module ports)
- for (auto &wire_it : mod->wires_)
+ for (auto wire : mod->wires())
{
- RTLIL::Wire *wire = wire_it.second;
if (wire->port_id > 0)
{
RTLIL::SigSpec conn_sig(wire);
@@ -300,8 +294,7 @@ RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit:
RTLIL::Cell *cell = haystack->addCell(stringf("$extract$%s$%d", needle->name.c_str(), autoidx++), needle->name);
// create cell ports
- for (auto &it : needle->wires_) {
- RTLIL::Wire *wire = it.second;
+ for (auto wire : needle->wires()) {
if (wire->port_id > 0) {
for (int i = 0; i < wire->width; i++)
sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<RTLIL::IdString, int>(wire->name, i));
@@ -316,7 +309,7 @@ RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit:
RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData;
RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData;
- if (needle_cell == NULL)
+ if (needle_cell == nullptr)
continue;
for (auto &conn : needle_cell->connections()) {
@@ -587,7 +580,7 @@ struct ExtractPass : public Pass {
if (map_filenames.empty() && mine_outfile.empty())
log_cmd_error("Missing option -map <verilog_or_ilang_file> or -mine <output_ilang_file>.\n");
- RTLIL::Design *map = NULL;
+ RTLIL::Design *map = nullptr;
if (!mine_mode)
{
@@ -630,24 +623,24 @@ struct ExtractPass : public Pass {
log_header(design, "Creating graphs for SubCircuit library.\n");
if (!mine_mode)
- for (auto &mod_it : map->modules_) {
+ for (auto module : map->modules()) {
SubCircuit::Graph mod_graph;
- std::string graph_name = "needle_" + RTLIL::unescape_id(mod_it.first);
+ std::string graph_name = "needle_" + RTLIL::unescape_id(module->name);
log("Creating needle graph %s.\n", graph_name.c_str());
- if (module2graph(mod_graph, mod_it.second, constports)) {
+ if (module2graph(mod_graph, module, constports)) {
solver.addGraph(graph_name, mod_graph);
- needle_map[graph_name] = mod_it.second;
- needle_list.push_back(mod_it.second);
+ needle_map[graph_name] = module;
+ needle_list.push_back(module);
}
}
- for (auto &mod_it : design->modules_) {
+ for (auto module : design->modules()) {
SubCircuit::Graph mod_graph;
- std::string graph_name = "haystack_" + RTLIL::unescape_id(mod_it.first);
+ std::string graph_name = "haystack_" + RTLIL::unescape_id(module->name);
log("Creating haystack graph %s.\n", graph_name.c_str());
- if (module2graph(mod_graph, mod_it.second, constports, design, mine_mode ? mine_max_fanout : -1, mine_mode ? &mine_split : NULL)) {
+ if (module2graph(mod_graph, module, constports, design, mine_mode ? mine_max_fanout : -1, mine_mode ? &mine_split : nullptr)) {
solver.addGraph(graph_name, mod_graph);
- haystack_map[graph_name] = mod_it.second;
+ haystack_map[graph_name] = module;
}
}
@@ -680,7 +673,7 @@ struct ExtractPass : public Pass {
}
RTLIL::Cell *new_cell = replace(needle_map.at(result.needleGraphId), haystack_map.at(result.haystackGraphId), result);
design->select(haystack_map.at(result.haystackGraphId), new_cell);
- log(" new cell: %s\n", id2cstr(new_cell->name));
+ log(" new cell: %s\n", log_id(new_cell->name));
}
}
}
@@ -697,12 +690,12 @@ struct ExtractPass : public Pass {
for (auto &result: results)
{
log("\nFrequent SubCircuit with %d nodes and %d matches:\n", int(result.nodes.size()), result.totalMatchesAfterLimits);
- log(" primary match in %s:", id2cstr(haystack_map.at(result.graphId)->name));
+ log(" primary match in %s:", log_id(haystack_map.at(result.graphId)->name));
for (auto &node : result.nodes)
log(" %s", RTLIL::unescape_id(node.nodeId).c_str());
log("\n");
for (auto &it : result.matchesPerGraph)
- log(" matches in %s: %d\n", id2cstr(haystack_map.at(it.first)->name), it.second);
+ log(" matches in %s: %d\n", log_id(haystack_map.at(it.first)->name), it.second);
RTLIL::Module *mod = haystack_map.at(result.graphId);
std::set<RTLIL::Cell*> cells;
@@ -717,12 +710,12 @@ struct ExtractPass : public Pass {
for (auto &conn : cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
for (auto &chunk : sig.chunks())
- if (chunk.wire != NULL)
+ if (chunk.wire != nullptr)
wires.insert(chunk.wire);
}
RTLIL::Module *newMod = new RTLIL::Module;
- newMod->name = stringf("\\needle%05d_%s_%dx", needleCounter++, id2cstr(haystack_map.at(result.graphId)->name), result.totalMatchesAfterLimits);
+ newMod->name = stringf("\\needle%05d_%s_%dx", needleCounter++, log_id(haystack_map.at(result.graphId)->name), result.totalMatchesAfterLimits);
map->add(newMod);
for (auto wire : wires) {
@@ -739,8 +732,8 @@ struct ExtractPass : public Pass {
for (auto &conn : cell->connections()) {
std::vector<SigChunk> chunks = sigmap(conn.second);
for (auto &chunk : chunks)
- if (chunk.wire != NULL)
- chunk.wire = newMod->wires_.at(chunk.wire->name);
+ if (chunk.wire != nullptr)
+ chunk.wire = newMod->wire(chunk.wire->name);
newCell->setPort(conn.first, chunks);
}
}
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index 9ec651aef..5aeb5ea79 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -105,13 +105,9 @@ struct HilomapPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &it : design->modules_)
+ for (auto mod : design->selected_modules())
{
- module = it.second;
-
- if (!design->selected(module))
- continue;
-
+ module = mod;
last_hi = RTLIL::State::Sm;
last_lo = RTLIL::State::Sm;
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 518afa1a7..a554be257 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -1282,7 +1282,7 @@ struct TechmapPass : public Pass {
if (fn.compare(0, 1, "%") == 0) {
if (!saved_designs.count(fn.substr(1))) {
delete map;
- log_cmd_error("Can't saved design `%s'.\n", fn.c_str()+1);
+ log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1);
}
for (auto mod : saved_designs.at(fn.substr(1))->modules())
if (!map->has(mod->name))
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
index a427c4987..74604ba3b 100644
--- a/passes/techmap/zinit.cc
+++ b/passes/techmap/zinit.cc
@@ -57,8 +57,7 @@ struct ZinitPass : public Pass {
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
- dict<SigBit, State> initbits;
- pool<SigBit> donebits;
+ dict<SigBit, std::pair<State,SigBit>> initbits;
for (auto wire : module->selected_wires())
{
@@ -67,7 +66,6 @@ struct ZinitPass : public Pass {
SigSpec wirebits = sigmap(wire);
Const initval = wire->attributes.at(ID::init);
- wire->attributes.erase(ID::init);
for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
{
@@ -78,24 +76,35 @@ struct ZinitPass : public Pass {
continue;
if (initbits.count(bit)) {
- if (initbits.at(bit) != val)
+ if (initbits.at(bit).first != val)
log_error("Conflicting init values for signal %s (%s = %s != %s).\n",
log_signal(bit), log_signal(SigBit(wire, i)),
- log_signal(val), log_signal(initbits.at(bit)));
+ log_signal(val), log_signal(initbits.at(bit).first));
continue;
}
- initbits[bit] = val;
+ initbits[bit] = std::make_pair(val,SigBit(wire,i));
}
}
pool<IdString> dff_types = {
- ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($adff),
+ // FIXME: It would appear that supporting
+ // $dffsr/$_DFFSR_* would require a new
+ // cell type where S has priority over R
+ ID($ff), ID($dff), ID($dffe), /*ID($dffsr),*/ ID($adff),
ID($_FF_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_),
- ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
- ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_),
+ /*ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
+ ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_),*/
ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
- ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)
+ ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
+ // Async set/reset
+ ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1),
+ ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1),
+ // Sync set/reset
+ ID($__DFFS_NN0_), ID($__DFFS_NN1_), ID($__DFFS_NP0_), ID($__DFFS_NP1_),
+ ID($__DFFS_PN0_), ID($__DFFS_PN1_), ID($__DFFS_PP0_), ID($__DFFS_PP1_),
+ ID($__DFFSE_NN0), ID($__DFFSE_NN1), ID($__DFFSE_NP0), ID($__DFFSE_NP1),
+ ID($__DFFSE_PN0), ID($__DFFSE_PN1), ID($__DFFSE_PP0), ID($__DFFSE_PP1)
};
for (auto cell : module->selected_cells())
@@ -113,8 +122,10 @@ struct ZinitPass : public Pass {
for (int i = 0; i < GetSize(sig_q); i++) {
if (initbits.count(sig_q[i])) {
- initval.bits.push_back(initbits.at(sig_q[i]));
- donebits.insert(sig_q[i]);
+ const auto &d = initbits.at(sig_q[i]);
+ initval.bits.push_back(d.first);
+ const auto &b = d.second;
+ b.wire->attributes.at(ID::init)[b.offset] = State::Sx;
} else
initval.bits.push_back(all_mode ? State::S0 : State::Sx);
}
@@ -123,11 +134,11 @@ struct ZinitPass : public Pass {
initwire->attributes[ID::init] = initval;
for (int i = 0; i < GetSize(initwire); i++)
- if (initval.bits.at(i) == State::S1)
+ if (initval[i] == State::S1)
{
sig_d[i] = module->NotGate(NEW_ID, sig_d[i]);
module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]);
- initwire->attributes[ID::init].bits.at(i) = State::S0;
+ initwire->attributes[ID::init][i] = State::S0;
}
else
{
@@ -139,11 +150,36 @@ struct ZinitPass : public Pass {
cell->setPort(ID::D, sig_d);
cell->setPort(ID::Q, initwire);
- }
- for (auto &it : initbits)
- if (donebits.count(it.first) == 0)
- log_error("Failed to handle init bit %s = %s.\n", log_signal(it.first), log_signal(it.second));
+ if (cell->type == ID($adff)) {
+ auto val = cell->getParam(ID::ARST_VALUE);
+ for (int i = 0; i < GetSize(initwire); i++)
+ if (initval[i] == State::S1)
+ val[i] = (val[i] == State::S1 ? State::S0 : State::S1);
+ cell->setParam(ID::ARST_VALUE, std::move(val));
+ }
+ else if (initval == State::S1) {
+ std::string t = cell->type.str();
+ if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
+ ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)))
+ {
+ t[8] = (t[8] == '0' ? '1' : '0');
+ }
+ else if (cell->type.in(ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1),
+ ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1),
+ ID($__DFFS_NN0_), ID($__DFFS_NN1_), ID($__DFFS_NP0_), ID($__DFFS_NP1_),
+ ID($__DFFS_PN0_), ID($__DFFS_PN1_), ID($__DFFS_PP0_), ID($__DFFS_PP1_)))
+ {
+ t[10] = (t[10] == '0' ? '1' : '0');
+ }
+ else if (cell->type.in(ID($__DFFSE_NN0), ID($__DFFSE_NN1), ID($__DFFSE_NP0), ID($__DFFSE_NP1),
+ ID($__DFFSE_PN0), ID($__DFFSE_PN1), ID($__DFFSE_PP0), ID($__DFFSE_PP1)))
+ {
+ t[11] = (t[11] == '0' ? '1' : '0');
+ }
+ cell->type = t;
+ }
+ }
}
}
} ZinitPass;
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
index 1f071bd69..42e8a61ea 100644
--- a/passes/tests/test_autotb.cc
+++ b/passes/tests/test_autotb.cc
@@ -85,7 +85,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s
f << stringf("reg [31:0] xorshift128_x = 123456789;\n");
f << stringf("reg [31:0] xorshift128_y = 362436069;\n");
f << stringf("reg [31:0] xorshift128_z = 521288629;\n");
- f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", seed ? seed : int(time(NULL)));
+ f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", seed ? seed : int(time(nullptr)));
f << stringf("reg [31:0] xorshift128_t;\n\n");
f << stringf("task xorshift128;\n");
f << stringf("begin\n");
@@ -97,22 +97,19 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s
f << stringf("end\n");
f << stringf("endtask\n\n");
- for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it)
+ for (auto mod : design->modules())
{
std::map<std::string, int> signal_in;
std::map<std::string, std::string> signal_const;
std::map<std::string, int> signal_clk;
std::map<std::string, int> signal_out;
- RTLIL::Module *mod = it->second;
-
if (mod->get_bool_attribute(ID::gentb_skip))
continue;
int count_ports = 0;
- log("Generating test bench for module `%s'.\n", it->first.c_str());
- for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); ++it2) {
- RTLIL::Wire *wire = it2->second;
+ log("Generating test bench for module `%s'.\n", mod->name.c_str());
+ for (auto wire : mod->wires()) {
if (wire->port_output) {
count_ports++;
signal_out[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
@@ -140,8 +137,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s
}
}
f << stringf("%s %s(\n", id(mod->name.str()).c_str(), idy("uut", mod->name.str()).c_str());
- for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); ++it2) {
- RTLIL::Wire *wire = it2->second;
+ for (auto wire : mod->wires()) {
if (wire->port_output || wire->port_input)
f << stringf("\t.%s(%s)%s\n", id(wire->name.str()).c_str(),
idy("sig", mod->name.str(), wire->name.str()).c_str(), --count_ports ? "," : "");
@@ -312,9 +308,9 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s
f << stringf("\t// $dumpfile(\"testbench.vcd\");\n");
f << stringf("\t// $dumpvars(0, testbench);\n");
f << stringf("\tfile = $fopen(`outfile);\n");
- for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it)
- if (!it->second->get_bool_attribute(ID::gentb_skip))
- f << stringf("\t%s;\n", idy(it->first.str(), "test").c_str());
+ for (auto module : design->modules())
+ if (!module->get_bool_attribute(ID::gentb_skip))
+ f << stringf("\t%s;\n", idy(module->name.str(), "test").c_str());
f << stringf("\t$fclose(file);\n");
f << stringf("\t$finish;\n");
f << stringf("end\n\n");
diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc
index 1dc6bdb2f..262a5e700 100644
--- a/techlibs/achronix/synth_achronix.cc
+++ b/techlibs/achronix/synth_achronix.cc
@@ -144,7 +144,6 @@ struct SynthAchronixPass : public ScriptPass {
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");
diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc
index 96a231286..791dc922f 100644
--- a/techlibs/anlogic/synth_anlogic.cc
+++ b/techlibs/anlogic/synth_anlogic.cc
@@ -182,7 +182,6 @@ struct SynthAnlogicPass : public ScriptPass
if (check_label("map_ffs"))
{
- run("dffsr2dff");
run("techmap -D NO_LUT -map +/anlogic/cells_map.v");
run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit");
run("opt_expr -mux_undef");
diff --git a/techlibs/common/gen_fine_ffs.py b/techlibs/common/gen_fine_ffs.py
index 3a9aa6c59..0abe48f61 100644
--- a/techlibs/common/gen_fine_ffs.py
+++ b/techlibs/common/gen_fine_ffs.py
@@ -8,15 +8,14 @@ TEMPLATES = [
//-
//- Truth table: S R | Q
//- -----+---
-//- {S:0|1} {R:0|1} | x
-//- {S:0|1} {R:1|0} | 1
-//- {S:1|0} {R:0|1} | 0
-//- {S:1|0} {R:1|0} | y
+//- - {R:0|1} | 0
+//- {S:0|1} - | 1
+//- - - | q
//-
module \$_SR_{S:N|P}{R:N|P}_ (S, R, Q);
input S, R;
output reg Q;
-always @({S:neg|pos}edge S, {R:neg|pos}edge R) begin
+always @* begin
if (R == {R:0|1})
Q <= 0;
else if (S == {S:0|1})
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index 2bac78d38..157e8d23b 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -469,15 +469,14 @@ endmodule
//-
//- Truth table: S R | Q
//- -----+---
-//- 0 0 | x
-//- 0 1 | 1
-//- 1 0 | 0
-//- 1 1 | y
+//- - 0 | 0
+//- 0 - | 1
+//- - - | q
//-
module \$_SR_NN_ (S, R, Q);
input S, R;
output reg Q;
-always @(negedge S, negedge R) begin
+always @* begin
if (R == 0)
Q <= 0;
else if (S == 0)
@@ -493,15 +492,14 @@ endmodule
//-
//- Truth table: S R | Q
//- -----+---
-//- 0 1 | x
-//- 0 0 | 1
-//- 1 1 | 0
-//- 1 0 | y
+//- - 1 | 0
+//- 0 - | 1
+//- - - | q
//-
module \$_SR_NP_ (S, R, Q);
input S, R;
output reg Q;
-always @(negedge S, posedge R) begin
+always @* begin
if (R == 1)
Q <= 0;
else if (S == 0)
@@ -517,15 +515,14 @@ endmodule
//-
//- Truth table: S R | Q
//- -----+---
-//- 1 0 | x
-//- 1 1 | 1
-//- 0 0 | 0
-//- 0 1 | y
+//- - 0 | 0
+//- 1 - | 1
+//- - - | q
//-
module \$_SR_PN_ (S, R, Q);
input S, R;
output reg Q;
-always @(posedge S, negedge R) begin
+always @* begin
if (R == 0)
Q <= 0;
else if (S == 1)
@@ -541,15 +538,14 @@ endmodule
//-
//- Truth table: S R | Q
//- -----+---
-//- 1 1 | x
-//- 1 0 | 1
-//- 0 1 | 0
-//- 0 0 | y
+//- - 1 | 0
+//- 1 - | 1
+//- - - | q
//-
module \$_SR_PP_ (S, R, Q);
input S, R;
output reg Q;
-always @(posedge S, posedge R) begin
+always @* begin
if (R == 1)
Q <= 0;
else if (S == 1)
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 7845a3fed..2cdddeabb 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -1633,7 +1633,7 @@ wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR;
genvar i;
generate
for (i = 0; i < WIDTH; i = i+1) begin:bitslices
- always @(posedge pos_set[i], posedge pos_clr[i])
+ always @*
if (pos_clr[i])
Q[i] <= 0;
else if (pos_set[i])
diff --git a/techlibs/ecp5/brams.txt b/techlibs/ecp5/brams.txt
index 777ccaa2e..d34d9ec07 100644
--- a/techlibs/ecp5/brams.txt
+++ b/techlibs/ecp5/brams.txt
@@ -37,7 +37,17 @@ bram $__ECP5_DP16KD
clkpol 2 3
endbram
+# The syn_* attributes are described in:
+# https://www.latticesemi.com/-/media/LatticeSemi/Documents/Tutorials/AK/LatticeDiamondTutorial311.ashx
+attr_icase 1
+
match $__ECP5_PDPW16KD
+ # implicitly requested RAM or ROM
+ attribute !syn_ramstyle syn_ramstyle=auto
+ attribute !syn_romstyle syn_romstyle=auto
+ attribute !ram_block
+ attribute !rom_block
+ attribute !logic_block
min bits 2048
min efficiency 5
shuffle_enable A
@@ -45,8 +55,60 @@ match $__ECP5_PDPW16KD
or_next_if_better
endmatch
+match $__ECP5_PDPW16KD
+ # explicitly requested RAM
+ attribute syn_ramstyle=block_ram ram_block
+ attribute !syn_romstyle
+ attribute !rom_block
+ attribute !logic_block
+ min wports 1
+ shuffle_enable A
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__ECP5_PDPW16KD
+ # explicitly requested ROM
+ attribute syn_romstyle=ebr rom_block
+ attribute !syn_ramstyle
+ attribute !ram_block
+ attribute !logic_block
+ max wports 0
+ shuffle_enable A
+ make_transp
+ or_next_if_better
+endmatch
+
match $__ECP5_DP16KD
+ # implicitly requested RAM or ROM
+ attribute !syn_ramstyle syn_ramstyle=auto
+ attribute !syn_romstyle syn_romstyle=auto
+ attribute !ram_block
+ attribute !rom_block
+ attribute !logic_block
min bits 2048
min efficiency 5
shuffle_enable A
+ or_next_if_better
+endmatch
+
+match $__ECP5_DP16KD
+ # explicitly requested RAM
+ attribute syn_ramstyle=block_ram ram_block
+ attribute !syn_romstyle
+ attribute !rom_block
+ attribute !logic_block
+ min wports 1
+ shuffle_enable A
+ or_next_if_better
+endmatch
+
+match $__ECP5_DP16KD
+ # explicitly requested ROM
+ attribute syn_romstyle=ebr rom_block
+ attribute !syn_ramstyle
+ attribute !ram_block
+ attribute !logic_block
+ max wports 0
+ shuffle_enable A
endmatch
diff --git a/techlibs/ecp5/dsp_map.v b/techlibs/ecp5/dsp_map.v
index cb95ddb1c..df54d1d9f 100644
--- a/techlibs/ecp5/dsp_map.v
+++ b/techlibs/ecp5/dsp_map.v
@@ -10,7 +10,7 @@ module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
.A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .A4(A[4]), .A5(A[5]), .A6(A[6]), .A7(A[7]), .A8(A[8]), .A9(A[9]), .A10(A[10]), .A11(A[11]), .A12(A[12]), .A13(A[13]), .A14(A[14]), .A15(A[15]), .A16(A[16]), .A17(A[17]),
.B0(B[0]), .B1(B[1]), .B2(B[2]), .B3(B[3]), .B4(B[4]), .B5(B[5]), .B6(B[6]), .B7(B[7]), .B8(B[8]), .B9(B[9]), .B10(B[10]), .B11(B[11]), .B12(B[12]), .B13(B[13]), .B14(B[14]), .B15(B[15]), .B16(B[16]), .B17(B[17]),
.C17(1'b0), .C16(1'b0), .C15(1'b0), .C14(1'b0), .C13(1'b0), .C12(1'b0), .C11(1'b0), .C10(1'b0), .C9(1'b0), .C8(1'b0), .C7(1'b0), .C6(1'b0), .C5(1'b0), .C4(1'b0), .C3(1'b0), .C2(1'b0), .C1(1'b0), .C0(1'b0),
- .SIGNEDA(A_SIGNED), .SIGNEDB(B_SIGNED), .SOURCEA(1'b0), .SOURCEB(1'b0),
+ .SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), .SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), .SOURCEA(1'b0), .SOURCEB(1'b0),
.P0(Y[0]), .P1(Y[1]), .P2(Y[2]), .P3(Y[3]), .P4(Y[4]), .P5(Y[5]), .P6(Y[6]), .P7(Y[7]), .P8(Y[8]), .P9(Y[9]), .P10(Y[10]), .P11(Y[11]), .P12(Y[12]), .P13(Y[13]), .P14(Y[14]), .P15(Y[15]), .P16(Y[16]), .P17(Y[17]), .P18(Y[18]), .P19(Y[19]), .P20(Y[20]), .P21(Y[21]), .P22(Y[22]), .P23(Y[23]), .P24(Y[24]), .P25(Y[25]), .P26(Y[26]), .P27(Y[27]), .P28(Y[28]), .P29(Y[29]), .P30(Y[30]), .P31(Y[31]), .P32(Y[32]), .P33(Y[33]), .P34(Y[34]), .P35(Y[35])
);
diff --git a/techlibs/ecp5/lutrams.txt b/techlibs/ecp5/lutrams.txt
index b94357429..9e6a23eba 100644
--- a/techlibs/ecp5/lutrams.txt
+++ b/techlibs/ecp5/lutrams.txt
@@ -11,7 +11,16 @@ bram $__TRELLIS_DPR16X4
clkpol 0 2
endbram
+# The syn_* attributes are described in:
+# https://www.latticesemi.com/-/media/LatticeSemi/Documents/Tutorials/AK/LatticeDiamondTutorial311.ashx
+attr_icase 1
+
match $__TRELLIS_DPR16X4
+ attribute !syn_ramstyle syn_ramstyle=auto syn_ramstyle=distributed
+ attribute !syn_romstyle syn_romstyle=auto
+ attribute !ram_block
+ attribute !rom_block
+ attribute !logic_block
make_outreg
min wports 1
endmatch
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc
index 9916fdafb..ab740ea0d 100644
--- a/techlibs/ecp5/synth_ecp5.cc
+++ b/techlibs/ecp5/synth_ecp5.cc
@@ -279,7 +279,9 @@ struct SynthEcp5Pass : public ScriptPass
if (check_label("map_ffram"))
{
run("opt -fast -mux_undef -undriven -fine");
- run("memory_map");
+ run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block "
+ "-attr syn_ramstyle=auto -attr syn_ramstyle=registers "
+ "-attr syn_romstyle=auto -attr syn_romstyle=logic");
run("opt -undriven -fine");
}
@@ -296,7 +298,6 @@ struct SynthEcp5Pass : public ScriptPass
if (check_label("map_ffs"))
{
- run("dffsr2dff");
run("dff2dffs");
run("opt_clean");
if (!nodffe)
diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc
index 637d7c00d..f9a7ef865 100644
--- a/techlibs/efinix/synth_efinix.cc
+++ b/techlibs/efinix/synth_efinix.cc
@@ -182,7 +182,6 @@ struct SynthEfinixPass : public ScriptPass
if (check_label("map_ffs"))
{
- run("dffsr2dff");
run("techmap -D NO_LUT -map +/efinix/cells_map.v");
run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit");
run("opt_expr -mux_undef");
diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc
index 86ec9cdc2..dd965c0b8 100644
--- a/techlibs/gowin/synth_gowin.cc
+++ b/techlibs/gowin/synth_gowin.cc
@@ -219,7 +219,6 @@ struct SynthGowinPass : public ScriptPass
if (check_label("map_ffs"))
{
- run("dffsr2dff");
run("dff2dffs -match-init");
run("opt_clean");
if (!nodffe)
diff --git a/techlibs/ice40/brams.txt b/techlibs/ice40/brams.txt
index 03d596111..36dfddab2 100644
--- a/techlibs/ice40/brams.txt
+++ b/techlibs/ice40/brams.txt
@@ -28,13 +28,73 @@ bram $__ICE40_RAM4K_M123
clkpol 2 3
endbram
+# The syn_* attributes are described in:
+# https://www.latticesemi.com/-/media/LatticeSemi/Documents/Tutorials/AK/LatticeDiamondTutorial311.ashx
+attr_icase 1
+
match $__ICE40_RAM4K_M0
+ # implicitly requested RAM or ROM
+ attribute !syn_ramstyle syn_ramstyle=auto
+ attribute !syn_romstyle syn_romstyle=auto
+ attribute !ram_block
+ attribute !rom_block
+ attribute !logic_block
min efficiency 2
make_transp
or_next_if_better
endmatch
+match $__ICE40_RAM4K_M0
+ # explicitly requested RAM
+ attribute syn_ramstyle=block_ram ram_block
+ attribute !syn_romstyle
+ attribute !rom_block
+ attribute !logic_block
+ min wports 1
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__ICE40_RAM4K_M0
+ # explicitly requested ROM
+ attribute syn_romstyle=ebr rom_block
+ attribute !syn_ramstyle
+ attribute !ram_block
+ attribute !logic_block
+ max wports 0
+ make_transp
+ or_next_if_better
+endmatch
+
match $__ICE40_RAM4K_M123
+ # implicitly requested RAM or ROM
+ attribute !syn_ramstyle syn_ramstyle=auto
+ attribute !syn_romstyle syn_romstyle=auto
+ attribute !ram_block
+ attribute !rom_block
+ attribute !logic_block
min efficiency 2
make_transp
+ or_next_if_better
+endmatch
+
+match $__ICE40_RAM4K_M123
+ # explicitly requested RAM
+ attribute syn_ramstyle=block_ram ram_block
+ attribute !syn_romstyle
+ attribute !rom_block
+ attribute !logic_block
+ min wports 1
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__ICE40_RAM4K_M123
+ # explicitly requested ROM
+ attribute syn_romstyle=ebr rom_block
+ attribute !syn_ramstyle
+ attribute !ram_block
+ attribute !logic_block
+ max wports 0
+ make_transp
endmatch
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index 59ada8bae..9724b7dd5 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -319,7 +319,9 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("map_ffram"))
{
run("opt -fast -mux_undef -undriven -fine");
- run("memory_map");
+ run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block "
+ "-attr syn_ramstyle=auto -attr syn_ramstyle=registers "
+ "-attr syn_romstyle=auto -attr syn_romstyle=logic");
run("opt -undriven -fine");
}
@@ -339,7 +341,6 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("map_ffs"))
{
- run("dffsr2dff");
if (!nodffe)
run("dff2dffe -direct-match $_DFF_*");
if (min_ce_use >= 0) {
diff --git a/techlibs/intel/Makefile.inc b/techlibs/intel/Makefile.inc
index d97a9b58f..f751e341f 100644
--- a/techlibs/intel/Makefile.inc
+++ b/techlibs/intel/Makefile.inc
@@ -11,4 +11,3 @@ families := max10 arria10gx cyclonev cyclone10lp cycloneiv cycloneive
$(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_sim.v)))
$(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_map.v)))
#$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/arith_map.v))
-
diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc
index 3689df70e..8601ebb37 100644
--- a/techlibs/intel/synth_intel.cc
+++ b/techlibs/intel/synth_intel.cc
@@ -202,7 +202,6 @@ struct SynthIntelPass : public ScriptPass {
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");
diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc
new file mode 100644
index 000000000..66204c8fc
--- /dev/null
+++ b/techlibs/intel_alm/Makefile.inc
@@ -0,0 +1,23 @@
+
+OBJS += techlibs/intel_alm/synth_intel_alm.o
+
+# Techmap
+$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_map.v))
+$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_sim.v))
+$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/arith_alm_map.v))
+$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_map.v))
+$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_sim.v))
+
+# RAM
+bramtypes := m10k m20k
+$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype).txt)))
+$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype)_map.v)))
+$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt))
+$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab_map.v))
+
+families := cyclonev cyclone10gx
+
+# Miscellaneous
+$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/megafunction_bb.v))
+$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/quartus_rename.v))
+$(foreach family, $(families), $(eval $(call add_share_file,share/intel_alm/$(family),techlibs/intel_alm/$(family)/quartus_rename.v)))
diff --git a/techlibs/intel_alm/common/alm_map.v b/techlibs/intel_alm/common/alm_map.v
new file mode 100644
index 000000000..fe646c5d6
--- /dev/null
+++ b/techlibs/intel_alm/common/alm_map.v
@@ -0,0 +1,56 @@
+module \$lut (A, Y);
+
+parameter WIDTH = 1;
+parameter LUT = 0;
+
+input [WIDTH-1:0] A;
+output Y;
+
+generate
+ if (WIDTH == 1) begin
+ generate
+ if (LUT == 2'b00) begin
+ assign Y = 1'b0;
+ end
+ else if (LUT == 2'b01) begin
+ MISTRAL_NOT _TECHMAP_REPLACE_(
+ .A(A[0]), .Q(Y)
+ );
+ end
+ else if (LUT == 2'b10) begin
+ assign Y = A;
+ end
+ else if (LUT == 2'b11) begin
+ assign Y = 1'b1;
+ end
+ endgenerate
+ end else
+ if (WIDTH == 2) begin
+ MISTRAL_ALUT2 #(.LUT(LUT)) _TECHMAP_REPLACE_(
+ .A(A[0]), .B(A[1]), .Q(Y)
+ );
+ end else
+ if (WIDTH == 3) begin
+ MISTRAL_ALUT3 #(.LUT(LUT)) _TECHMAP_REPLACE_(
+ .A(A[0]), .B(A[1]), .C(A[2]), .Q(Y)
+ );
+ end else
+ if (WIDTH == 4) begin
+ MISTRAL_ALUT4 #(.LUT(LUT)) _TECHMAP_REPLACE_(
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .Q(Y)
+ );
+ end else
+ if (WIDTH == 5) begin
+ MISTRAL_ALUT5 #(.LUT(LUT)) _TECHMAP_REPLACE_ (
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .Q(Y)
+ );
+ end else
+ if (WIDTH == 6) begin
+ MISTRAL_ALUT6 #(.LUT(LUT)) _TECHMAP_REPLACE_ (
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .F(A[5]), .Q(Y)
+ );
+ end else begin
+ wire _TECHMAP_FAIL_ = 1'b1;
+ end
+endgenerate
+endmodule
diff --git a/techlibs/intel_alm/common/alm_sim.v b/techlibs/intel_alm/common/alm_sim.v
new file mode 100644
index 000000000..69768d9f7
--- /dev/null
+++ b/techlibs/intel_alm/common/alm_sim.v
@@ -0,0 +1,482 @@
+`default_nettype none
+
+(* abc9_lut=2, lib_whitebox *)
+module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q);
+
+parameter [63:0] LUT = 64'h0000_0000_0000_0000;
+
+`ifdef cyclonev
+specify
+ (A => Q) = 602;
+ (B => Q) = 584;
+ (C => Q) = 510;
+ (D => Q) = 510;
+ (E => Q) = 339;
+ (F => Q) = 94;
+endspecify
+`endif
+`ifdef cyclone10gx
+specify
+ (A => Q) = 275;
+ (B => Q) = 272;
+ (C => Q) = 175;
+ (D => Q) = 165;
+ (E => Q) = 162;
+ (F => Q) = 53;
+endspecify
+`endif
+
+assign Q = LUT >> {F, E, D, C, B, A};
+
+endmodule
+
+
+(* abc9_lut=1, lib_whitebox *)
+module MISTRAL_ALUT5(input A, B, C, D, E, output Q);
+
+parameter [31:0] LUT = 32'h0000_0000;
+
+`ifdef cyclonev
+specify
+ (A => Q) = 584;
+ (B => Q) = 510;
+ (C => Q) = 510;
+ (D => Q) = 339;
+ (E => Q) = 94;
+endspecify
+`endif
+`ifdef cyclone10gx
+specify
+ (A => Q) = 272;
+ (B => Q) = 175;
+ (C => Q) = 165;
+ (D => Q) = 162;
+ (E => Q) = 53;
+endspecify
+`endif
+
+assign Q = LUT >> {E, D, C, B, A};
+
+endmodule
+
+
+(* abc9_lut=1, lib_whitebox *)
+module MISTRAL_ALUT4(input A, B, C, D, output Q);
+
+parameter [15:0] LUT = 16'h0000;
+
+`ifdef cyclonev
+specify
+ (A => Q) = 510;
+ (B => Q) = 510;
+ (C => Q) = 339;
+ (D => Q) = 94;
+endspecify
+`endif
+`ifdef cyclone10gx
+specify
+ (A => Q) = 175;
+ (B => Q) = 165;
+ (C => Q) = 162;
+ (D => Q) = 53;
+endspecify
+`endif
+
+assign Q = LUT >> {D, C, B, A};
+
+endmodule
+
+
+(* abc9_lut=1, lib_whitebox *)
+module MISTRAL_ALUT3(input A, B, C, output Q);
+
+parameter [7:0] LUT = 8'h00;
+
+`ifdef cyclonev
+specify
+ (A => Q) = 510;
+ (B => Q) = 339;
+ (C => Q) = 94;
+endspecify
+`endif
+`ifdef cyclone10gx
+specify
+ (A => Q) = 165;
+ (B => Q) = 162;
+ (C => Q) = 53;
+endspecify
+`endif
+
+assign Q = LUT >> {C, B, A};
+
+endmodule
+
+
+(* abc9_lut=1, lib_whitebox *)
+module MISTRAL_ALUT2(input A, B, output Q);
+
+parameter [3:0] LUT = 4'h0;
+
+`ifdef cyclonev
+specify
+ (A => Q) = 339;
+ (B => Q) = 94;
+endspecify
+`endif
+`ifdef cyclone10gx
+specify
+ (A => Q) = 162;
+ (B => Q) = 53;
+endspecify
+`endif
+
+assign Q = LUT >> {B, A};
+
+endmodule
+
+
+(* abc9_lut=1, lib_whitebox *)
+module MISTRAL_NOT(input A, output Q);
+
+`ifdef cyclonev
+specify
+ (A => Q) = 94;
+endspecify
+`endif
+`ifdef cyclone10gx
+specify
+ (A => Q) = 53;
+endspecify
+`endif
+
+assign Q = ~A;
+
+endmodule
+
+(* abc9_box, lib_whitebox *)
+module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, (* abc9_carry *) input CI, output SO, (* abc9_carry *) output CO);
+
+parameter LUT0 = 16'h0000;
+parameter LUT1 = 16'h0000;
+
+`ifdef cyclonev
+specify
+ (A => SO) = 1283;
+ (B => SO) = 1167;
+ (C => SO) = 866;
+ (D0 => SO) = 756;
+ (D1 => SO) = 756;
+ (CI => SO) = 355;
+ (A => CO) = 950;
+ (B => CO) = 1039;
+ (C => CO) = 820;
+ (D0 => CO) = 1006;
+ (D1 => CO) = 1006;
+ (CI => CO) = 23;
+endspecify
+`endif
+`ifdef cyclone10gx
+specify
+ (A => SO) = 644;
+ (B => SO) = 477;
+ (C => SO) = 416;
+ (D0 => SO) = 380;
+ (D1 => SO) = 431;
+ (CI => SO) = 276;
+ (A => CO) = 525;
+ (B => CO) = 433;
+ (C => CO) = 712;
+ (D0 => CO) = 653;
+ (D1 => CO) = 593;
+ (CI => CO) = 16;
+endspecify
+`endif
+
+wire q0, q1;
+
+assign q0 = LUT0 >> {D0, C, B, A};
+assign q1 = LUT1 >> {D1, C, B, A};
+
+assign {CO, SO} = q0 + !q1 + CI;
+
+endmodule
+
+
+/*
+// A, B, C0, C1, E0, E1, F0, F1: data inputs
+// CARRYIN: carry input
+// SHAREIN: shared-arithmetic input
+// CLK0, CLK1, CLK2: clock inputs
+//
+// COMB0, COMB1: combinational outputs
+// FF0, FF1, FF2, FF3: DFF outputs
+// SUM0, SUM1: adder outputs
+// CARRYOUT: carry output
+// SHAREOUT: shared-arithmetic output
+module MISTRAL_ALM(
+ input A, B, C0, C1, E0, E1, F0, F1, CARRYIN, SHAREIN, // LUT path
+ input CLK0, CLK1, CLK2, AC0, AC1, // FF path
+ output COMB0, COMB1, SUM0, SUM1, CARRYOUT, SHAREOUT,
+ output FF0, FF1, FF2, FF3
+);
+
+parameter LUT0 = 16'b0000;
+parameter LUT1 = 16'b0000;
+parameter LUT2 = 16'b0000;
+parameter LUT3 = 16'b0000;
+
+parameter INIT0 = 1'b0;
+parameter INIT1 = 1'b0;
+parameter INIT2 = 1'b0;
+parameter INIT3 = 1'b0;
+
+parameter C0_MUX = "C0";
+parameter C1_MUX = "C1";
+
+parameter F0_MUX = "VCC";
+parameter F1_MUX = "GND";
+
+parameter FEEDBACK0 = "FF0";
+parameter FEEDBACK1 = "FF2";
+
+parameter ADD_MUX = "LUT";
+
+parameter DFF01_DATA_MUX = "COMB";
+parameter DFF23_DATA_MUX = "COMB";
+
+parameter DFF0_CLK = "CLK0";
+parameter DFF1_CLK = "CLK0";
+parameter DFF2_CLK = "CLK0";
+parameter DFF3_CLK = "CLK0";
+
+parameter DFF0_AC = "AC0";
+parameter DFF1_AC = "AC0";
+parameter DFF2_AC = "AC0";
+parameter DFF3_AC = "AC0";
+
+// Feedback muxes from the flip-flop outputs.
+wire ff_feedback_mux0, ff_feedback_mux1;
+
+// C-input muxes which can be set to also use the F-input.
+wire c0_input_mux, c1_input_mux;
+
+// F-input muxes which can be set to a constant to allow LUT5 use.
+wire f0_input_mux, f1_input_mux;
+
+// Adder input muxes to select between shared-arithmetic mode and arithmetic mode.
+wire add0_input_mux, add1_input_mux;
+
+// Combinational-output muxes for LUT #1 and LUT #3
+wire lut1_comb_mux, lut3_comb_mux;
+
+// Sum-output muxes for LUT #1 and LUT #3
+wire lut1_sum_mux, lut3_sum_mux;
+
+// DFF data-input muxes
+wire dff01_data_mux, dff23_data_mux;
+
+// DFF clock selectors
+wire dff0_clk, dff1_clk, dff2_clk, dff3_clk;
+
+// DFF asynchronous-clear selectors
+wire dff0_ac, dff1_ac, dff2_ac, dff3_ac;
+
+// LUT, DFF and adder output wires for routing.
+wire lut0_out, lut1a_out, lut1b_out, lut2_out, lut3a_out, lut3b_out;
+wire dff0_out, dff1_out, dff2_out, dff3_out;
+wire add0_sum, add1_sum, add0_carry, add1_carry;
+
+generate
+ if (FEEDBACK0 === "FF0")
+ assign ff_feedback_mux0 = dff0_out;
+ else if (FEEDBACK0 === "FF1")
+ assign ff_feedback_mux0 = dff1_out;
+ else
+ $error("Invalid FEEDBACK0 setting!");
+
+ if (FEEDBACK1 == "FF2")
+ assign ff_feedback_mux1 = dff2_out;
+ else if (FEEDBACK1 == "FF3")
+ assign ff_feedback_mux1 = dff3_out;
+ else
+ $error("Invalid FEEDBACK1 setting!");
+
+ if (C0_MUX === "C0")
+ assign c0_input_mux = C0;
+ else if (C0_MUX === "F1")
+ assign c0_input_mux = F1;
+ else if (C0_MUX === "FEEDBACK1")
+ assign c0_input_mux = ff_feedback_mux1;
+ else
+ $error("Invalid C0_MUX setting!");
+
+ if (C1_MUX === "C1")
+ assign c1_input_mux = C1;
+ else if (C1_MUX === "F0")
+ assign c1_input_mux = F0;
+ else if (C1_MUX === "FEEDBACK0")
+ assign c1_input_mux = ff_feedback_mux0;
+ else
+ $error("Invalid C1_MUX setting!");
+
+ // F0 == VCC is LUT5
+ // F0 == F0 is LUT6
+ // F0 == FEEDBACK is unknown
+ if (F0_MUX === "VCC")
+ assign f0_input_mux = 1'b1;
+ else if (F0_MUX === "F0")
+ assign f0_input_mux = F0;
+ else if (F0_MUX === "FEEDBACK0")
+ assign f0_input_mux = ff_feedback_mux0;
+ else
+ $error("Invalid F0_MUX setting!");
+
+ // F1 == GND is LUT5
+ // F1 == F1 is LUT6
+ // F1 == FEEDBACK is unknown
+ if (F1_MUX === "GND")
+ assign f1_input_mux = 1'b0;
+ else if (F1_MUX === "F1")
+ assign f1_input_mux = F1;
+ else if (F1_MUX === "FEEDBACK1")
+ assign f1_input_mux = ff_feedback_mux1;
+ else
+ $error("Invalid F1_MUX setting!");
+
+ if (ADD_MUX === "LUT") begin
+ assign add0_input_mux = ~lut1_sum_mux;
+ assign add1_input_mux = ~lut3_sum_mux;
+ end else if (ADD_MUX === "SHARE") begin
+ assign add0_input_mux = SHAREIN;
+ assign add1_input_mux = lut1_comb_mux;
+ end else
+ $error("Invalid ADD_MUX setting!");
+
+ if (DFF01_DATA_MUX === "COMB")
+ assign dff01_data_mux = COMB0;
+ else if (DFF01_DATA_MUX === "SUM")
+ assign dff01_data_mux = SUM0;
+ else
+ $error("Invalid DFF01_DATA_MUX setting!");
+
+ if (DFF23_DATA_MUX === "COMB")
+ assign dff23_data_mux = COMB0;
+ else if (DFF23_DATA_MUX === "SUM")
+ assign dff23_data_mux = SUM0;
+ else
+ $error("Invalid DFF23_DATA_MUX setting!");
+
+ if (DFF0_CLK === "CLK0")
+ assign dff0_clk = CLK0;
+ else if (DFF0_CLK === "CLK1")
+ assign dff0_clk = CLK1;
+ else if (DFF0_CLK === "CLK2")
+ assign dff0_clk = CLK2;
+ else
+ $error("Invalid DFF0_CLK setting!");
+
+ if (DFF1_CLK === "CLK0")
+ assign dff1_clk = CLK0;
+ else if (DFF1_CLK === "CLK1")
+ assign dff1_clk = CLK1;
+ else if (DFF1_CLK === "CLK2")
+ assign dff1_clk = CLK2;
+ else
+ $error("Invalid DFF1_CLK setting!");
+
+ if (DFF2_CLK === "CLK0")
+ assign dff2_clk = CLK0;
+ else if (DFF2_CLK === "CLK1")
+ assign dff2_clk = CLK1;
+ else if (DFF2_CLK === "CLK2")
+ assign dff2_clk = CLK2;
+ else
+ $error("Invalid DFF2_CLK setting!");
+
+ if (DFF3_CLK === "CLK0")
+ assign dff3_clk = CLK0;
+ else if (DFF3_CLK === "CLK1")
+ assign dff3_clk = CLK1;
+ else if (DFF3_CLK === "CLK2")
+ assign dff3_clk = CLK2;
+ else
+ $error("Invalid DFF3_CLK setting!");
+
+ if (DFF0_AC === "AC0")
+ assign dff0_ac = AC0;
+ else if (DFF0_AC === "AC1")
+ assign dff0_ac = AC1;
+ else
+ $error("Invalid DFF0_AC setting!");
+
+ if (DFF1_AC === "AC0")
+ assign dff1_ac = AC0;
+ else if (DFF1_AC === "AC1")
+ assign dff1_ac = AC1;
+ else
+ $error("Invalid DFF1_AC setting!");
+
+ if (DFF2_AC === "AC0")
+ assign dff2_ac = AC0;
+ else if (DFF2_AC === "AC1")
+ assign dff2_ac = AC1;
+ else
+ $error("Invalid DFF2_AC setting!");
+
+ if (DFF3_AC === "AC0")
+ assign dff3_ac = AC0;
+ else if (DFF3_AC === "AC1")
+ assign dff3_ac = AC1;
+ else
+ $error("Invalid DFF3_AC setting!");
+
+endgenerate
+
+// F0 on the Quartus diagram
+MISTRAL_ALUT4 #(.LUT(LUT0)) lut0 (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut0_out));
+
+// F2 on the Quartus diagram
+MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_comb (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut1_comb_mux));
+MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_sum (.A(A), .B(B), .C(C0), .D(E0), .Q(lut1_sum_mux));
+
+// F1 on the Quartus diagram
+MISTRAL_ALUT4 #(.LUT(LUT2)) lut2 (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut2_out));
+
+// F3 on the Quartus diagram
+MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_comb (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut3_comb_mux));
+MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_sum (.A(A), .B(B), .C(C1), .D(E1), .Q(lut3_sum_mux));
+
+MISTRAL_FF #(.INIT(INIT0)) dff0 (.D(dff01_data_mux), .CLK(dff0_clk), .ACn(dff0_ac), .Q(dff0_out));
+MISTRAL_FF #(.INIT(INIT1)) dff1 (.D(dff01_data_mux), .CLK(dff1_clk), .ACn(dff1_ac), .Q(dff1_out));
+MISTRAL_FF #(.INIT(INIT2)) dff2 (.D(dff23_data_mux), .CLK(dff2_clk), .ACn(dff2_ac), .Q(dff2_out));
+MISTRAL_FF #(.INIT(INIT3)) dff3 (.D(dff23_data_mux), .CLK(dff3_clk), .ACn(dff3_ac), .Q(dff3_out));
+
+// Adders
+assign {add0_carry, add0_sum} = CARRYIN + lut0_out + lut1_sum_mux;
+assign {add1_carry, add1_sum} = add0_carry + lut2_out + lut3_sum_mux;
+
+// COMBOUT outputs on the Quartus diagram
+assign COMB0 = E0 ? (f0_input_mux ? lut3_comb_mux : lut1_comb_mux)
+ : (f0_input_mux ? lut2_out : lut0_out);
+
+assign COMB1 = E1 ? (f1_input_mux ? lut3_comb_mux : lut1_comb_mux)
+ : (f1_input_mux ? lut2_out : lut0_out);
+
+// SUMOUT output on the Quartus diagram
+assign SUM0 = add0_sum;
+assign SUM1 = add1_sum;
+
+// COUT output on the Quartus diagram
+assign CARRYOUT = add1_carry;
+
+// SHAREOUT output on the Quartus diagram
+assign SHAREOUT = lut3_comb_mux;
+
+// REGOUT outputs on the Quartus diagram
+assign FF0 = dff0_out;
+assign FF1 = dff1_out;
+assign FF2 = dff2_out;
+assign FF3 = dff3_out;
+
+endmodule
+*/
diff --git a/techlibs/intel_alm/common/arith_alm_map.v b/techlibs/intel_alm/common/arith_alm_map.v
new file mode 100644
index 000000000..ddf81d9d0
--- /dev/null
+++ b/techlibs/intel_alm/common/arith_alm_map.v
@@ -0,0 +1,64 @@
+`default_nettype none
+
+module \$alu (A, B, CI, BI, X, Y, CO);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 1;
+parameter B_WIDTH = 1;
+parameter Y_WIDTH = 1;
+
+parameter _TECHMAP_CONSTMSK_CI_ = 0;
+parameter _TECHMAP_CONSTVAL_CI_ = 0;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+input CI, BI;
+output [Y_WIDTH-1:0] X, Y, CO;
+
+wire [Y_WIDTH-1:0] A_buf, B_buf;
+\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+wire [Y_WIDTH-1:0] AA = A_buf;
+wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
+wire [Y_WIDTH-1:0] BX = B_buf;
+wire [Y_WIDTH:0] ALM_CARRY;
+
+// Start of carry chain
+generate
+ if (_TECHMAP_CONSTMSK_CI_ == 1) begin
+ assign ALM_CARRY[0] = _TECHMAP_CONSTVAL_CI_;
+ end else begin
+ MISTRAL_ALUT_ARITH #(
+ .LUT0(16'b1010_1010_1010_1010), // Q = A
+ .LUT1(16'b0000_0000_0000_0000), // Q = 0 (LUT1's input to the adder is inverted)
+ ) alm_start (
+ .A(CI), .B(1'b1), .C(1'b1), .D0(1'b1), .D1(1'b1),
+ .CI(1'b0),
+ .CO(ALM_CARRY[0])
+ );
+ end
+endgenerate
+
+// Carry chain
+genvar i;
+generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
+ // TODO: mwk suggests that a pass could merge pre-adder logic into this.
+ MISTRAL_ALUT_ARITH #(
+ .LUT0(16'b1010_1010_1010_1010), // Q = A
+ .LUT1(16'b1100_0011_1100_0011), // Q = C ? B : ~B (LUT1's input to the adder is inverted)
+ ) alm_i (
+ .A(AA[i]), .B(BX[i]), .C(BI), .D0(1'b1), .D1(1'b1),
+ .CI(ALM_CARRY[i]),
+ .SO(Y[i]),
+ .CO(ALM_CARRY[i+1])
+ );
+
+ // ALM carry chain is not directly accessible, so calculate the carry through soft logic if really needed.
+ assign CO[i] = (AA[i] && BB[i]) || ((Y[i] ^ AA[i] ^ BB[i]) && (AA[i] || BB[i]));
+end endgenerate
+
+assign X = AA ^ BB;
+
+endmodule
diff --git a/techlibs/intel_alm/common/bram_m10k.txt b/techlibs/intel_alm/common/bram_m10k.txt
new file mode 100644
index 000000000..837e3a330
--- /dev/null
+++ b/techlibs/intel_alm/common/bram_m10k.txt
@@ -0,0 +1,33 @@
+bram __MISTRAL_M10K_SDP
+ init 0 # TODO: Re-enable when I figure out how BRAM init works
+ abits 13 @D8192x1
+ dbits 1 @D8192x1
+ abits 12 @D4096x2
+ dbits 2 @D4096x2
+ abits 11 @D2048x4 @D2048x5
+ dbits 4 @D2048x4
+ dbits 5 @D2048x5
+ abits 10 @D1024x8 @D1024x10
+ dbits 8 @D1024x8
+ dbits 10 @D1024x10
+ abits 9 @D512x16 @D512x20
+ dbits 16 @D512x16
+ dbits 20 @D512x20
+ abits 8 @D256x32 @D256x40
+ dbits 32 @D256x32
+ dbits 40 @D256x40
+ groups 2
+ ports 1 1
+ wrmode 1 0
+ # read enable; write enable + byte enables (only for multiples of 8)
+ enable 1 1
+ transp 0 0
+ clocks 1 1
+ clkpol 1 1
+endbram
+
+
+match __MISTRAL_M10K_SDP
+ min efficiency 5
+ make_transp
+endmatch
diff --git a/techlibs/intel_alm/common/bram_m10k_map.v b/techlibs/intel_alm/common/bram_m10k_map.v
new file mode 100644
index 000000000..e5566010d
--- /dev/null
+++ b/techlibs/intel_alm/common/bram_m10k_map.v
@@ -0,0 +1,31 @@
+module __MISTRAL_M10K_SDP(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+
+parameter CFG_ABITS = 10;
+parameter CFG_DBITS = 10;
+parameter CFG_ENABLE_A = 1;
+parameter CFG_ENABLE_B = 1;
+
+input CLK1;
+input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
+input [CFG_DBITS-1:0] A1DATA;
+output [CFG_DBITS-1:0] B1DATA;
+input [CFG_ENABLE_A-1:0] A1EN, B1EN;
+
+altsyncram #(
+ .operation_mode("dual_port"),
+ .ram_block_type("m10k"),
+ .widthad_a(CFG_ABITS),
+ .width_a(CFG_DBITS),
+ .widthad_b(CFG_ABITS),
+ .width_b(CFG_DBITS),
+) _TECHMAP_REPLACE_ (
+ .address_a(A1ADDR),
+ .data_a(A1DATA),
+ .wren_a(A1EN),
+ .address_b(B1ADDR),
+ .q_b(B1DATA),
+ .clock0(CLK1),
+ .clock1(CLK1)
+);
+
+endmodule
diff --git a/techlibs/intel_alm/common/bram_m20k.txt b/techlibs/intel_alm/common/bram_m20k.txt
new file mode 100644
index 000000000..b4c5a5372
--- /dev/null
+++ b/techlibs/intel_alm/common/bram_m20k.txt
@@ -0,0 +1,33 @@
+bram __MISTRAL_M20K_SDP
+ init 1 # TODO: Re-enable when I figure out how BRAM init works
+ abits 14 @D16384x1
+ dbits 1 @D16384x1
+ abits 13 @D8192x2
+ dbits 2 @D8192x2
+ abits 12 @D4096x4 @D4096x5
+ dbits 4 @D4096x4
+ dbits 5 @D4096x5
+ abits 11 @D2048x8 @D2048x10
+ dbits 8 @D2048x8
+ dbits 10 @D2048x10
+ abits 10 @D1024x16 @D1024x20
+ dbits 16 @D1024x16
+ dbits 20 @D1024x20
+ abits 9 @D512x32 @D512x40
+ dbits 32 @D512x32
+ dbits 40 @D512x40
+ groups 2
+ ports 1 1
+ wrmode 1 0
+ # read enable; write enable + byte enables (only for multiples of 8)
+ enable 1 1
+ transp 0 0
+ clocks 1 1
+ clkpol 1 1
+endbram
+
+
+match __MISTRAL_M20K_SDP
+ min efficiency 5
+ make_transp
+endmatch
diff --git a/techlibs/intel_alm/common/bram_m20k_map.v b/techlibs/intel_alm/common/bram_m20k_map.v
new file mode 100644
index 000000000..92f41310f
--- /dev/null
+++ b/techlibs/intel_alm/common/bram_m20k_map.v
@@ -0,0 +1,31 @@
+module __MISTRAL_M20K_SDP(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+
+parameter CFG_ABITS = 10;
+parameter CFG_DBITS = 20;
+parameter CFG_ENABLE_A = 1;
+parameter CFG_ENABLE_B = 1;
+
+input CLK1;
+input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
+input [CFG_DBITS-1:0] A1DATA;
+output [CFG_DBITS-1:0] B1DATA;
+input [CFG_ENABLE_A-1:0] A1EN, B1EN;
+
+altsyncram #(
+ .operation_mode("dual_port"),
+ .ram_block_type("m20k"),
+ .widthad_a(CFG_ABITS),
+ .width_a(CFG_DBITS),
+ .widthad_b(CFG_ABITS),
+ .width_b(CFG_DBITS),
+) _TECHMAP_REPLACE_ (
+ .address_a(A1ADDR),
+ .data_a(A1DATA),
+ .wren_a(A1EN),
+ .address_b(B1ADDR),
+ .q_b(B1DATA),
+ .clock0(CLK1),
+ .clock1(CLK1)
+);
+
+endmodule
diff --git a/techlibs/intel_alm/common/dff_map.v b/techlibs/intel_alm/common/dff_map.v
new file mode 100644
index 000000000..f7f2fe3c3
--- /dev/null
+++ b/techlibs/intel_alm/common/dff_map.v
@@ -0,0 +1,124 @@
+`default_nettype none
+
+// D flip-flops
+module \$_DFF_P_ (input D, C, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFF_P_ with INIT=1");
+endmodule
+
+module \$_DFF_N_ (input D, C, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFF_N_ with INIT=1");
+endmodule
+
+// D flip-flops with reset
+module \$_DFF_PP0_ (input D, C, R, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFF_PP0_ with INIT=1");
+endmodule
+
+module \$_DFF_PN0_ (input D, C, R, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFF_PN0_ with INIT=1");
+endmodule
+
+module \$_DFF_NP0_ (input D, C, R, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFF_NP0_ with INIT=1");
+endmodule
+
+module \$_DFF_NN0_ (input D, C, R, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFF_NN0_ with INIT=1");
+endmodule
+
+// D flip-flops with set
+module \$_DFF_PP1_ (input D, C, R, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b1;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ wire Q_tmp;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp));
+ assign Q = ~Q_tmp;
+end else $error("Unsupported flop: $_DFF_PP1_ with INIT=0");
+endmodule
+
+module \$_DFF_PN1_ (input D, C, R, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b1;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ wire Q_tmp;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp));
+end else $error("Unsupported flop: $_DFF_PN1_ with INIT=0");
+endmodule
+
+module \$_DFF_NP1_ (input D, C, R, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b1;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ wire Q_tmp;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp));
+ assign Q = ~Q_tmp;
+end else $error("Unsupported flop: $_DFF_NP1_ with INIT=0");
+endmodule
+
+module \$_DFF_NN1_ (input D, C, R, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b1;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ wire Q_tmp;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp));
+ assign Q = ~Q_tmp;
+end else $error("Unsupported flop: $_DFF_NN1_ with INIT=0");
+endmodule
+
+// D flip-flops with clock enable
+module \$_DFFE_PP_ (input D, C, E, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFFE_PP_ with INIT=1");
+endmodule
+
+module \$_DFFE_PN_ (input D, C, E, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFFE_PN_ with INIT=1");
+endmodule
+
+module \$_DFFE_NP_ (input D, C, E, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFFE_NP_ with INIT=1");
+endmodule
+
+module \$_DFFE_NN_ (input D, C, E, output Q);
+parameter _TECHMAP_WIREINIT_Q_ = 1'b0;
+if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin
+ wire _TECHMAP_REMOVEINIT_Q_ = 1'b1;
+ MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q));
+end else $error("Unsupported flop: $_DFFE_NN_ with INIT=1");
+endmodule
diff --git a/techlibs/intel_alm/common/dff_sim.v b/techlibs/intel_alm/common/dff_sim.v
new file mode 100644
index 000000000..07865905f
--- /dev/null
+++ b/techlibs/intel_alm/common/dff_sim.v
@@ -0,0 +1,48 @@
+// DATAIN: synchronous data input
+// CLK: clock input (positive edge)
+// ACLR: asynchronous clear (negative-true)
+// ENA: clock-enable
+// SCLR: synchronous clear
+// SLOAD: synchronous load
+// SDATA: synchronous load data
+//
+// Q: data output
+//
+// Note: the DFFEAS primitive is mostly emulated; it does not reflect what the hardware implements.
+module MISTRAL_FF(
+ input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA,
+ output reg Q
+);
+
+`ifdef cyclonev
+specify
+ (posedge CLK => (Q : DATAIN)) = 262;
+ $setup(DATAIN, posedge CLK, 522);
+endspecify
+`endif
+`ifdef cyclone10gx
+specify
+ (posedge CLK => (Q : DATAIN)) = 219;
+ $setup(DATAIN, posedge CLK, 268);
+endspecify
+`endif
+
+initial begin
+ // Altera flops initialise to zero.
+ Q = 0;
+end
+
+always @(posedge CLK, negedge ACLR) begin
+ // Asynchronous clear
+ if (!ACLR) Q <= 0;
+ // Clock-enable
+ else if (ENA) begin
+ // Synchronous clear
+ if (SCLR) Q <= 0;
+ // Synchronous load
+ else if (SLOAD) Q <= SDATA;
+ else Q <= DATAIN;
+ end
+end
+
+endmodule
diff --git a/techlibs/intel_alm/common/lutram_mlab.txt b/techlibs/intel_alm/common/lutram_mlab.txt
new file mode 100644
index 000000000..1d6174d85
--- /dev/null
+++ b/techlibs/intel_alm/common/lutram_mlab.txt
@@ -0,0 +1,20 @@
+bram __MISTRAL_MLAB
+ init 0 # TODO: Re-enable when I figure out how LUTRAM init works
+ abits 5
+ dbits 16 @D32x16
+ dbits 18 @D32x18
+ dbits 20 @D32x20
+ groups 2
+ ports 1 1
+ wrmode 1 0
+ # read enable
+ enable 1 0
+ transp 1 0
+ clocks 1 2
+ clkpol 1 1
+endbram
+
+match __MISTRAL_MLAB
+ min efficiency 5
+ make_outreg
+endmatch
diff --git a/techlibs/intel_alm/common/lutram_mlab_map.v b/techlibs/intel_alm/common/lutram_mlab_map.v
new file mode 100644
index 000000000..3a9c8590e
--- /dev/null
+++ b/techlibs/intel_alm/common/lutram_mlab_map.v
@@ -0,0 +1,29 @@
+module __MISTRAL_MLAB(CLK1, CLK2, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA);
+
+parameter CFG_ABITS = 5;
+parameter CFG_DBITS = 20;
+
+input CLK1, CLK2;
+input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
+input [CFG_DBITS-1:0] A1DATA;
+input A1EN;
+output [CFG_DBITS-1:0] B1DATA;
+
+altsyncram #(
+ .operation_mode("dual_port"),
+ .ram_block_type("mlab"),
+ .widthad_a(CFG_ABITS),
+ .width_a(CFG_DBITS),
+ .widthad_b(CFG_ABITS),
+ .width_b(CFG_DBITS),
+) _TECHMAP_REPLACE_ (
+ .address_a(A1ADDR),
+ .data_a(A1DATA),
+ .wren_a(A1EN),
+ .address_b(B1ADDR),
+ .q_b(B1DATA),
+ .clock0(CLK1),
+ .clock1(CLK1),
+);
+
+endmodule
diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v
new file mode 100644
index 000000000..21ba73a09
--- /dev/null
+++ b/techlibs/intel_alm/common/megafunction_bb.v
@@ -0,0 +1,108 @@
+// Intel megafunction declarations, to avoid Yosys complaining.
+`default_nettype none
+
+(* blackbox *)
+module altera_std_synchronizer(clk, din, dout, reset_n);
+
+parameter depth = 2;
+
+input clk;
+input reset_n;
+input din;
+output dout;
+
+endmodule
+
+(* blackbox *)
+module altiobuf_in(datain, dataout);
+
+parameter enable_bus_hold = "FALSE";
+parameter use_differential_mode = "FALSE";
+parameter number_of_channels = 1;
+
+input [number_of_channels-1:0] datain;
+output [number_of_channels-1:0] dataout;
+
+endmodule
+
+(* blackbox *)
+module altiobuf_out(datain, dataout);
+
+parameter enable_bus_hold = "FALSE";
+parameter use_differential_mode = "FALSE";
+parameter use_oe = "FALSE";
+parameter number_of_channels = 1;
+
+input [number_of_channels-1:0] datain;
+output [number_of_channels-1:0] dataout;
+
+endmodule
+
+(* blackbox *)
+module altiobuf_bidir(dataio, oe, datain, dataout);
+
+parameter number_of_channels = 1;
+parameter enable_bus_hold = "OFF";
+
+inout [number_of_channels-1:0] dataio;
+input [number_of_channels-1:0] datain;
+output [number_of_channels-1:0] dataout;
+input [number_of_channels-1:0] oe;
+
+endmodule
+
+(* blackbox *)
+module altsyncram(clock0, clock1, address_a, data_a, rden_a, wren_a, byteena_a, q_a, addressstall_a, address_b, data_b, rden_b, wren_b, byteena_b, q_b, addressstall_b, clocken0, clocken1, clocken2, clocken3, aclr0, aclr1, eccstatus);
+
+parameter lpm_type = "altsyncram";
+parameter operation_mode = "dual_port";
+parameter ram_block_type = "auto";
+parameter intended_device_family = "auto";
+parameter power_up_uninitialized = "false";
+parameter read_during_write_mode_mixed_ports = "dontcare";
+parameter byte_size = 8;
+parameter widthad_a = 1;
+parameter width_a = 1;
+parameter width_byteena_a = 1;
+parameter numwords_a = 1;
+parameter clock_enable_input_a = "clocken0";
+parameter widthad_b = 1;
+parameter width_b = 1;
+parameter numwords_b = 1;
+parameter address_aclr_b = "aclr0";
+parameter address_reg_b = "";
+parameter outdata_aclr_b = "aclr0";
+parameter outdata_reg_b = "";
+parameter clock_enable_input_b = "clocken0";
+parameter clock_enable_output_b = "clocken0";
+
+input clock0, clock1;
+input [widthad_a-1:0] address_a;
+input [width_a-1:0] data_a;
+input rden_a;
+input wren_a;
+input [(width_a/8)-1:0] byteena_a;
+input addressstall_a;
+
+output [width_a-1:0] q_a;
+
+input wren_b;
+input rden_b;
+input [widthad_b-1:0] address_b;
+input [width_b-1:0] data_b;
+input [(width_b/8)-1:0] byteena_b;
+input addressstall_b;
+
+output [width_b-1:0] q_b;
+
+input clocken0;
+input clocken1;
+input clocken2;
+input clocken3;
+
+input aclr0;
+input aclr1;
+
+output eccstatus;
+
+endmodule
diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v
new file mode 100644
index 000000000..d9961c174
--- /dev/null
+++ b/techlibs/intel_alm/common/quartus_rename.v
@@ -0,0 +1,19 @@
+module __MISTRAL_VCC(output Q);
+
+MISTRAL_ALUT2 #(.LUT(4'b1111)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q));
+
+endmodule
+
+
+module __MISTRAL_GND(output Q);
+
+MISTRAL_ALUT2 #(.LUT(4'b0000)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q));
+
+endmodule
+
+
+module MISTRAL_FF(input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, output reg Q);
+
+dffeas #(.power_up("low"), .is_wysiwyg("true")) _TECHMAP_REPLACE_ (.d(DATAIN), .clk(CLK), .clrn(ACLR), .ena(ENA), .sclr(SCLR), .sload(SLOAD), .asdata(SDATA), .q(Q));
+
+endmodule
diff --git a/techlibs/intel_alm/cyclone10gx/quartus_rename.v b/techlibs/intel_alm/cyclone10gx/quartus_rename.v
new file mode 100644
index 000000000..3fbc508ed
--- /dev/null
+++ b/techlibs/intel_alm/cyclone10gx/quartus_rename.v
@@ -0,0 +1,54 @@
+module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q);
+parameter LUT = 64'h0000_0000_0000_0000;
+
+cyclone10gx_lcell_comb #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT5(input A, B, C, D, E, output Q);
+parameter LUT = 32'h0000_0000;
+
+cyclone10gx_lcell_comb #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT4(input A, B, C, D, output Q);
+parameter LUT = 16'h0000;
+
+cyclone10gx_lcell_comb #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT3(input A, B, C, output Q);
+parameter LUT = 8'h00;
+
+cyclone10gx_lcell_comb #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT2(input A, B, output Q);
+parameter LUT = 4'h0;
+
+cyclone10gx_lcell_comb #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_NOT(input A, output Q);
+
+NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO);
+parameter LUT0 = 16'h0000;
+parameter LUT1 = 16'h0000;
+
+cyclone10gx_lcell_comb #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO));
+
+endmodule
diff --git a/techlibs/intel_alm/cyclonev/quartus_rename.v b/techlibs/intel_alm/cyclonev/quartus_rename.v
new file mode 100644
index 000000000..6eff375e1
--- /dev/null
+++ b/techlibs/intel_alm/cyclonev/quartus_rename.v
@@ -0,0 +1,54 @@
+module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q);
+parameter LUT = 64'h0000_0000_0000_0000;
+
+cyclonev_lcell_comb #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT5(input A, B, C, D, E, output Q);
+parameter LUT = 32'h0000_0000;
+
+cyclonev_lcell_comb #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT4(input A, B, C, D, output Q);
+parameter LUT = 16'h0000;
+
+cyclonev_lcell_comb #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT3(input A, B, C, output Q);
+parameter LUT = 8'h00;
+
+cyclonev_lcell_comb #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT2(input A, B, output Q);
+parameter LUT = 4'h0;
+
+cyclonev_lcell_comb #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q));
+
+endmodule
+
+
+module MISTRAL_NOT(input A, output Q);
+
+NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q));
+
+endmodule
+
+
+module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO);
+parameter LUT0 = 16'h0000;
+parameter LUT1 = 16'h0000;
+
+cyclonev_lcell_comb #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO));
+
+endmodule
diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc
new file mode 100644
index 000000000..47aa11500
--- /dev/null
+++ b/techlibs/intel_alm/synth_intel_alm.cc
@@ -0,0 +1,241 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Claire Wolf <claire@symbioticeda.com>
+ * Copyright (C) 2019 Dan Ravensloft <dan.ravensloft@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/celltypes.h"
+#include "kernel/log.h"
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SynthIntelALMPass : public ScriptPass {
+ SynthIntelALMPass() : ScriptPass("synth_intel_alm", "synthesis for ALM-based Intel (Altera) FPGAs.") {}
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_intel_alm [options]\n");
+ log("\n");
+ log("This command runs synthesis for ALM-based Intel FPGAs.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module (default='top')\n");
+ log("\n");
+ log(" -family <family>\n");
+ log(" target one of:\n");
+ log(" \"cyclonev\" - Cyclone V (default)\n");
+ log(" \"cyclone10gx\" - Cyclone 10GX\n");
+ log("\n");
+ log(" -quartus\n");
+ log(" output a netlist using Quartus cells instead of MISTRAL_* cells\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. Implies -quartus.\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(" -nolutram\n");
+ log(" do not use LUT RAM cells in output netlist\n");
+ log("\n");
+ log(" -nobram\n");
+ log(" do not use block RAM cells in output netlist\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
+
+ string top_opt, family_opt, bram_type, vout_file;
+ bool flatten, quartus, nolutram, nobram;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ family_opt = "cyclonev";
+ bram_type = "m10k";
+ vout_file = "";
+ flatten = true;
+ quartus = false;
+ nolutram = false;
+ nobram = false;
+ }
+
+ 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()) {
+ quartus = true;
+ vout_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] == "-quartus") {
+ quartus = true;
+ continue;
+ }
+ if (args[argidx] == "-nolutram") {
+ nolutram = true;
+ continue;
+ }
+ if (args[argidx] == "-nobram") {
+ nobram = true;
+ continue;
+ }
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
+ 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 == "cyclonev") {
+ bram_type = "m10k";
+ } else if (family_opt == "cyclone10gx") {
+ bram_type = "m20k";
+ } else {
+ log_cmd_error("Invalid family specified: '%s'\n", family_opt.c_str());
+ }
+
+ log_header(design, "Executing SYNTH_INTEL_ALM pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ void script() YS_OVERRIDE
+ {
+ if (help_mode) {
+ family_opt = "<family>";
+ bram_type = "<bram_type>";
+ }
+
+ if (check_label("begin")) {
+ run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str()));
+ run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str()));
+ run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str()));
+
+ // Misc and common cells
+ run("read_verilog -lib +/intel/common/altpll_bb.v");
+ run("read_verilog -lib +/intel_alm/common/megafunction_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 (check_label("coarse")) {
+ run("synth -run coarse -lut 6");
+ run("techmap -map +/intel_alm/common/arith_alm_map.v");
+ }
+
+ if (!nobram && check_label("map_bram", "(skip if -nobram)")) {
+ run(stringf("memory_bram -rules +/intel_alm/common/bram_%s.txt", bram_type.c_str()));
+ run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str()));
+ }
+
+ if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) {
+ run("memory_bram -rules +/intel_alm/common/lutram_mlab.txt", "(for Cyclone V / Cyclone 10GX)");
+ run("techmap -map +/intel_alm/common/lutram_mlab_map.v", "(for Cyclone V / Cyclone 10GX)");
+ }
+
+ if (check_label("map_ffram")) {
+ run("memory_map");
+ run("opt -full");
+ }
+
+ if (check_label("map_ffs")) {
+ run("dff2dffe -direct-match $_DFF_*");
+ run("zinit");
+ run("techmap -map +/techmap.v -map +/intel_alm/common/dff_map.v");
+ run("opt -full -undriven -mux_undef");
+ run("clean -purge");
+ }
+
+ if (check_label("map_luts")) {
+ run("read_verilog -icells -specify -lib +/abc9_model.v");
+ run("abc9 -maxlut 6 -W 200");
+ run("techmap -map +/intel_alm/common/alm_map.v");
+ run("opt -fast");
+ run("autoname");
+ run("clean");
+ }
+
+ if (check_label("check")) {
+ run("hierarchy -check");
+ run("stat");
+ run("check");
+ }
+
+ if (check_label("quartus")) {
+ if (quartus || help_mode) {
+ run("setundef -zero");
+ run("hilomap -singleton -hicell __MISTRAL_VCC Q -locell __MISTRAL_GND Q");
+ run("techmap -map +/intel_alm/common/quartus_rename.v");
+ run(stringf("techmap -map +/intel_alm/%s/quartus_rename.v", family_opt.c_str()));
+ }
+ }
+
+ if (check_label("vqm")) {
+ if (!vout_file.empty() || help_mode) {
+ run(stringf("write_verilog -attr2comment -defparam -nohex -decimal %s", help_mode ? "<file-name>" : vout_file.c_str()));
+ }
+ }
+ }
+} SynthIntelALMPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc
index 5efa005c8..34a7e68be 100644
--- a/techlibs/sf2/synth_sf2.cc
+++ b/techlibs/sf2/synth_sf2.cc
@@ -187,7 +187,6 @@ struct SynthSf2Pass : public ScriptPass
if (check_label("map_ffs"))
{
- run("dffsr2dff");
run("techmap -D NO_LUT -map +/sf2/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index ac4f5bcf4..1c190d37e 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -522,10 +522,9 @@ struct SynthXilinxPass : public ScriptPass
}
if (check_label("map_ffram")) {
- // Required for dffsr2dff to work.
+ // Required for dff2dffs to work.
run("simplemap t:$dff t:$adff t:$mux");
// Needs to be done before opt -mux_bool happens.
- run("dffsr2dff");
if (help_mode)
run("dff2dffs [-match-init]", "(-match-init for xc6s only)");
else if (family == "xc6s")
diff --git a/tests/arch/common/blockram.v b/tests/arch/common/blockram.v
index dbc6ca65c..5ed0736d0 100644
--- a/tests/arch/common/blockram.v
+++ b/tests/arch/common/blockram.v
@@ -5,19 +5,20 @@ module sync_ram_sp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
input wire [ADDRESS_WIDTH-1:0] address_in,
output wire [DATA_WIDTH-1:0] data_out);
- localparam WORD = (DATA_WIDTH-1);
- localparam DEPTH = (2**ADDRESS_WIDTH-1);
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
- reg [WORD:0] data_out_r;
- reg [WORD:0] memory [0:DEPTH];
+ reg [WORD:0] data_out_r;
+ reg [WORD:0] memory [0:DEPTH];
- always @(posedge clk) begin
- if (write_enable)
- memory[address_in] <= data_in;
- data_out_r <= memory[address_in];
- end
+ always @(posedge clk) begin
+ if (write_enable)
+ memory[address_in] <= data_in;
+ data_out_r <= memory[address_in];
+ end
+
+ assign data_out = data_out_r;
- assign data_out = data_out_r;
endmodule // sync_ram_sp
@@ -28,18 +29,19 @@ module sync_ram_sdp #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
input wire [ADDRESS_WIDTH-1:0] address_in_r, address_in_w,
output wire [DATA_WIDTH-1:0] data_out);
- localparam WORD = (DATA_WIDTH-1);
- localparam DEPTH = (2**ADDRESS_WIDTH-1);
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
+
+ reg [WORD:0] data_out_r;
+ reg [WORD:0] memory [0:DEPTH];
- reg [WORD:0] data_out_r;
- reg [WORD:0] memory [0:DEPTH];
+ always @(posedge clk) begin
+ if (write_enable)
+ memory[address_in_w] <= data_in;
+ data_out_r <= memory[address_in_r];
+ end
- always @(posedge clk) begin
- if (write_enable)
- memory[address_in_w] <= data_in;
- data_out_r <= memory[address_in_r];
- end
+ assign data_out = data_out_r;
- assign data_out = data_out_r;
endmodule // sync_ram_sdp
diff --git a/tests/arch/common/blockrom.v b/tests/arch/common/blockrom.v
new file mode 100644
index 000000000..93f5c9ddf
--- /dev/null
+++ b/tests/arch/common/blockrom.v
@@ -0,0 +1,31 @@
+`default_nettype none
+module sync_rom #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
+ (input wire clk,
+ input wire [ADDRESS_WIDTH-1:0] address_in,
+ output wire [DATA_WIDTH-1:0] data_out);
+
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
+
+ reg [WORD:0] data_out_r;
+ reg [WORD:0] memory [0:DEPTH];
+
+ integer i,j = 64'hF4B1CA8127865242;
+ initial
+ for (i = 0; i <= DEPTH; i++) begin
+ // In case this ROM will be implemented in fabric: fill the memory with some data
+ // uncorrelated with the address, or Yosys might see through the ruse and e.g. not
+ // emit any LUTs at all for `memory[i] = i;`, just a latch.
+ memory[i] = j * 64'h2545F4914F6CDD1D;
+ j = j ^ (j >> 12);
+ j = j ^ (j << 25);
+ j = j ^ (j >> 27);
+ end
+
+ always @(posedge clk) begin
+ data_out_r <= memory[address_in];
+ end
+
+ assign data_out = data_out_r;
+
+endmodule // sync_rom
diff --git a/tests/arch/ecp5/memories.ys b/tests/arch/ecp5/memories.ys
new file mode 100644
index 000000000..e1f748e26
--- /dev/null
+++ b/tests/arch/ecp5/memories.ys
@@ -0,0 +1,330 @@
+# ================================ RAM ================================
+# RAM bits <= 18K; Data width <= 36; Address width <= 9: -> PDPW16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 36 sync_ram_sdp
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:PDPW16KD
+
+## With parameters
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:PDPW16KD # too inefficient
+select -assert-count 9 t:TRELLIS_DPR16X4
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+setattr -set syn_ramstyle "block_ram" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:PDPW16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+setattr -set syn_ramstyle "Block_RAM" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:PDPW16KD # any case works
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+setattr -set ram_block 1 m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:PDPW16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+setattr -set syn_ramstyle "registers" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:PDPW16KD # requested FFRAM explicitly
+select -assert-count 180 t:TRELLIS_FF
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+setattr -set logic_block 1 m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:PDPW16KD # requested FFRAM explicitly
+select -assert-count 180 t:TRELLIS_FF
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+setattr -set syn_romstyle "ebr" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BROM but this is a RAM
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+setattr -set rom_block 1 m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BROM but this is a RAM
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+setattr -set syn_ramstyle "block_ram" m:memory
+synth_ecp5 -top sync_ram_sdp -nobram; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BRAM but BRAM is disabled
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
+setattr -set ram_block 1 m:memory
+synth_ecp5 -top sync_ram_sdp -nobram; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BRAM but BRAM is disabled
+
+# RAM bits <= 18K; Data width <= 18; Address width <= 10: -> DP16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 18 sync_ram_sdp
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:DP16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 11 -set DATA_WIDTH 9 sync_ram_sdp
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:DP16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 12 -set DATA_WIDTH 4 sync_ram_sdp
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:DP16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 13 -set DATA_WIDTH 2 sync_ram_sdp
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:DP16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 14 -set DATA_WIDTH 1 sync_ram_sdp
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:DP16KD
+
+## With parameters
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:DP16KD # too inefficient
+select -assert-count 5 t:TRELLIS_DPR16X4
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+setattr -set syn_ramstyle "block_ram" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:DP16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+setattr -set syn_ramstyle "Block_RAM" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:DP16KD # any case works
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+setattr -set ram_block 1 m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:DP16KD
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+setattr -set syn_ramstyle "registers" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:DP16KD # requested FFRAM explicitly
+select -assert-count 90 t:TRELLIS_FF
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+setattr -set logic_block 1 m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:DP16KD # requested FFRAM explicitly
+select -assert-count 90 t:TRELLIS_FF
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+setattr -set syn_romstyle "ebr" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BROM but this is a RAM
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+setattr -set rom_block 1 m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BROM but this is a RAM
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+setattr -set syn_ramstyle "block_ram" m:memory
+synth_ecp5 -top sync_ram_sdp -nobram; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BRAM but BRAM is disabled
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
+setattr -set ram_block 1 m:memory
+synth_ecp5 -top sync_ram_sdp -nobram; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BRAM but BRAM is disabled
+
+# RAM bits <= 64; Data width <= 4; Address width <= 4: -> DPR16X4
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 4 -set DATA_WIDTH 4 sync_ram_sdp
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:TRELLIS_DPR16X4
+
+## With parameters
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 4 -set DATA_WIDTH 4 sync_ram_sdp
+setattr -set syn_ramstyle "distributed" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:TRELLIS_DPR16X4
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 4 -set DATA_WIDTH 4 sync_ram_sdp
+setattr -set syn_ramstyle "registers" m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:TRELLIS_DPR16X4 # requested FFRAM explicitly
+select -assert-count 68 t:TRELLIS_FF
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 4 -set DATA_WIDTH 4 sync_ram_sdp
+setattr -set logic_block 1 m:memory
+synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:TRELLIS_DPR16X4 # requested FFRAM explicitly
+select -assert-count 68 t:TRELLIS_FF
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 4 -set DATA_WIDTH 4 sync_ram_sdp
+setattr -set syn_ramstyle "distributed" m:memory
+synth_ecp5 -top sync_ram_sdp -nolutram; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested LUTRAM but LUTRAM is disabled
+
+# ================================ ROM ================================
+# ROM bits <= 18K; Data width <= 36; Address width <= 9: -> PDPW16KD
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 36 sync_rom
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:PDPW16KD
+
+## With parameters
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 36 sync_rom
+write_ilang
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 0 t:PDPW16KD # too inefficient
+select -assert-min 18 t:LUT4
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
+setattr -set syn_romstyle "ebr" m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:PDPW16KD
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
+setattr -set rom_block 1 m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:PDPW16KD
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 36 sync_rom
+setattr -set syn_romstyle "logic" m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 0 t:PDPW16KD # requested LUTROM explicitly
+select -assert-min 18 t:LUT4
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 36 sync_rom
+setattr -set logic_block 1 m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 0 t:PDPW16KD # requested LUTROM explicitly
+select -assert-min 18 t:LUT4
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
+setattr -set syn_ramstyle "block_ram" m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:$mem # requested BRAM but this is a ROM
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
+setattr -set ram_block 1 m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:$mem # requested BRAM but this is a ROM
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
+setattr -set syn_ramstyle "block_rom" m:memory
+synth_ecp5 -top sync_rom -nobram; cd sync_rom
+select -assert-count 1 t:$mem # requested BROM but BRAM is disabled
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
+setattr -set rom_block 1 m:memory
+synth_ecp5 -top sync_rom -nobram; cd sync_rom
+select -assert-count 1 t:$mem # requested BROM but BRAM is disabled
+
+# ROM bits <= 18K; Data width <= 18; Address width <= 10: -> DP16KD
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 18 sync_rom
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:DP16KD
+
+## With parameters
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 18 sync_rom
+write_ilang
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 0 t:DP16KD # too inefficient
+select -assert-min 9 t:LUT4
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
+setattr -set syn_romstyle "ebr" m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:DP16KD
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
+setattr -set rom_block 1 m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:DP16KD
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 18 sync_rom
+setattr -set syn_romstyle "logic" m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 0 t:DP16KD # requested LUTROM explicitly
+select -assert-min 9 t:LUT4
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 18 sync_rom
+setattr -set logic_block 1 m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 0 t:DP16KD # requested LUTROM explicitly
+select -assert-min 9 t:LUT4
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
+setattr -set syn_ramstyle "block_ram" m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:$mem # requested BRAM but this is a ROM
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
+setattr -set ram_block 1 m:memory
+synth_ecp5 -top sync_rom; cd sync_rom
+select -assert-count 1 t:$mem # requested BRAM but this is a ROM
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
+setattr -set syn_ramstyle "block_rom" m:memory
+synth_ecp5 -top sync_rom -nobram; cd sync_rom
+select -assert-count 1 t:$mem # requested BROM but BRAM is disabled
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
+setattr -set rom_block 1 m:memory
+synth_ecp5 -top sync_rom -nobram; cd sync_rom
+select -assert-count 1 t:$mem # requested BROM but BRAM is disabled
diff --git a/tests/arch/ice40/lutram.ys b/tests/arch/ice40/lutram.ys
deleted file mode 100644
index 1ba40f8ec..000000000
--- a/tests/arch/ice40/lutram.ys
+++ /dev/null
@@ -1,15 +0,0 @@
-read_verilog ../common/lutram.v
-hierarchy -top lutram_1w1r
-proc
-memory -nomap
-equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40
-memory
-opt -full
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
-
-design -load postopt
-cd lutram_1w1r
-select -assert-count 1 t:SB_RAM40_4K
-select -assert-none t:SB_RAM40_4K %% t:* %D
diff --git a/tests/arch/ice40/memories.ys b/tests/arch/ice40/memories.ys
new file mode 100644
index 000000000..571edec1d
--- /dev/null
+++ b/tests/arch/ice40/memories.ys
@@ -0,0 +1,168 @@
+# ================================ RAM ================================
+# RAM bits <= 4K; Data width <= 16; Address width <= 11: -> SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 11 -set DATA_WIDTH 2 sync_ram_sdp
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 4 sync_ram_sdp
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 8 sync_ram_sdp
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 8 -set DATA_WIDTH 16 sync_ram_sdp
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:SB_RAM40_4K
+
+## With parameters
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:SB_RAM40_4K # too inefficient
+select -assert-min 1 t:SB_DFFE
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+setattr -set syn_ramstyle "block_ram" m:memory
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+setattr -set syn_ramstyle "Block_RAM" m:memory
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:SB_RAM40_4K # any case works
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+setattr -set ram_block 1 m:memory
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+setattr -set syn_ramstyle "registers" m:memory
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:SB_RAM40_4K # requested FFRAM explicitly
+select -assert-min 1 t:SB_DFFE
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+setattr -set logic_block 1 m:memory
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 0 t:SB_RAM40_4K # requested FFRAM explicitly
+select -assert-min 1 t:SB_DFFE
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+setattr -set syn_romstyle "ebr" m:memory
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BROM but this is a RAM
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+setattr -set rom_block 1 m:memory
+synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BROM but this is a RAM
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+setattr -set syn_ramstyle "block_ram" m:memory
+synth_ice40 -top sync_ram_sdp -nobram; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BRAM but BRAM is disabled
+
+design -reset; read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
+setattr -set ram_block 1 m:memory
+synth_ice40 -top sync_ram_sdp -nobram; cd sync_ram_sdp
+select -assert-count 1 t:$mem # requested BRAM but BRAM is disabled
+
+# ================================ ROM ================================
+# ROM bits <= 4K; Data width <= 16; Address width <= 11: -> SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 11 -set DATA_WIDTH 2 sync_rom
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 4 sync_rom
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 8 sync_rom
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 8 -set DATA_WIDTH 16 sync_rom
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 1 t:SB_RAM40_4K
+
+## With parameters
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
+write_ilang
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 0 t:SB_RAM40_4K # too inefficient
+select -assert-min 1 t:SB_LUT4
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
+setattr -set syn_romstyle "ebr" m:memory
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
+setattr -set rom_block 1 m:memory
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 1 t:SB_RAM40_4K
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
+setattr -set syn_romstyle "logic" m:memory
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 0 t:SB_RAM40_4K # requested LUTROM explicitly
+select -assert-min 1 t:SB_LUT4
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
+setattr -set logic_block 1 m:memory
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 0 t:SB_RAM40_4K # requested LUTROM explicitly
+select -assert-min 1 t:SB_LUT4
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
+setattr -set syn_ramstyle "block_ram" m:memory
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 1 t:$mem # requested BRAM but this is a ROM
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
+setattr -set ram_block 1 m:memory
+synth_ice40 -top sync_rom; cd sync_rom
+select -assert-count 1 t:$mem # requested BRAM but this is a ROM
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
+setattr -set syn_romstyle "ebr" m:memory
+synth_ice40 -top sync_rom -nobram; cd sync_rom
+select -assert-count 1 t:$mem # requested BROM but BRAM is disabled
+
+design -reset; read_verilog ../common/blockrom.v
+chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
+setattr -set rom_block 1 m:memory
+synth_ice40 -top sync_rom -nobram; cd sync_rom
+select -assert-count 1 t:$mem # requested BROM but BRAM is disabled
diff --git a/tests/arch/intel_alm/add_sub.ys b/tests/arch/intel_alm/add_sub.ys
new file mode 100644
index 000000000..4cb2c2e0d
--- /dev/null
+++ b/tests/arch/intel_alm/add_sub.ys
@@ -0,0 +1,8 @@
+read_verilog ../common/add_sub.v
+hierarchy -top top
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+stat
+select -assert-count 8 t:MISTRAL_ALUT_ARITH
+select -assert-none t:MISTRAL_ALUT_ARITH %% t:* %D
diff --git a/tests/arch/intel_alm/adffs.ys b/tests/arch/intel_alm/adffs.ys
new file mode 100644
index 000000000..5d8d3a220
--- /dev/null
+++ b/tests/arch/intel_alm/adffs.ys
@@ -0,0 +1,48 @@
+read_verilog ../common/adffs.v
+design -save read
+
+hierarchy -top adff
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd adff # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+select -assert-count 1 t:MISTRAL_NOT
+
+select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D
+
+
+design -load read
+hierarchy -top adffn
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd adffn # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+
+select -assert-none t:MISTRAL_FF %% t:* %D
+
+
+design -load read
+hierarchy -top dffs
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dffs # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+select -assert-count 1 t:MISTRAL_ALUT2
+
+select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 %% t:* %D
+
+
+design -load read
+hierarchy -top ndffnr
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd ndffnr # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+select -assert-count 1 t:MISTRAL_NOT
+select -assert-count 1 t:MISTRAL_ALUT2
+
+select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 %% t:* %D
diff --git a/tests/arch/intel_alm/counter.ys b/tests/arch/intel_alm/counter.ys
new file mode 100644
index 000000000..945c318d8
--- /dev/null
+++ b/tests/arch/intel_alm/counter.ys
@@ -0,0 +1,13 @@
+read_verilog ../common/counter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -async2sync -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 2 t:MISTRAL_NOT
+select -assert-count 8 t:MISTRAL_ALUT_ARITH
+select -assert-count 8 t:MISTRAL_FF
+
+select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT_ARITH t:MISTRAL_FF %% t:* %D
diff --git a/tests/arch/intel_alm/dffs.ys b/tests/arch/intel_alm/dffs.ys
new file mode 100644
index 000000000..cf29ad8e0
--- /dev/null
+++ b/tests/arch/intel_alm/dffs.ys
@@ -0,0 +1,22 @@
+read_verilog ../common/dffs.v
+design -save read
+
+hierarchy -top dff
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dff # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+
+select -assert-none t:MISTRAL_FF %% t:* %D
+
+design -load read
+hierarchy -top dffe
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dffe # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+select -assert-count 1 t:MISTRAL_ALUT3
+
+select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT3 %% t:* %D
diff --git a/tests/arch/intel_alm/fsm.ys b/tests/arch/intel_alm/fsm.ys
new file mode 100644
index 000000000..8bb0ebab2
--- /dev/null
+++ b/tests/arch/intel_alm/fsm.ys
@@ -0,0 +1,18 @@
+read_verilog ../common/fsm.v
+hierarchy -top fsm
+proc
+flatten
+
+equiv_opt -run :prove -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev
+async2sync
+miter -equiv -make_assert -flatten gold gate miter
+sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter
+
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd fsm # Constrain all select calls below inside the top module
+
+select -assert-count 6 t:MISTRAL_FF
+select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1
+select -assert-count 5 t:MISTRAL_ALUT5
+select -assert-count 1 t:MISTRAL_ALUT6
+select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D
diff --git a/tests/arch/intel_alm/logic.ys b/tests/arch/intel_alm/logic.ys
new file mode 100644
index 000000000..fad45db74
--- /dev/null
+++ b/tests/arch/intel_alm/logic.ys
@@ -0,0 +1,11 @@
+read_verilog ../common/logic.v
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_NOT
+select -assert-count 6 t:MISTRAL_ALUT2
+select -assert-count 2 t:MISTRAL_ALUT4
+select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 %% t:* %D
diff --git a/tests/arch/intel_alm/mux.ys b/tests/arch/intel_alm/mux.ys
new file mode 100644
index 000000000..308e45268
--- /dev/null
+++ b/tests/arch/intel_alm/mux.ys
@@ -0,0 +1,45 @@
+read_verilog ../common/mux.v
+design -save read
+
+hierarchy -top mux2
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux2 # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_ALUT3
+
+select -assert-none t:MISTRAL_ALUT3 %% t:* %D
+
+design -load read
+hierarchy -top mux4
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux4 # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_ALUT6
+
+select -assert-none t:MISTRAL_ALUT6 %% t:* %D
+
+design -load read
+hierarchy -top mux8
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux8 # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_ALUT3
+select -assert-count 1 t:MISTRAL_ALUT5
+select -assert-count 2 t:MISTRAL_ALUT6
+
+select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D
+
+design -load read
+hierarchy -top mux16
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux16 # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_ALUT3
+select -assert-count 2 t:MISTRAL_ALUT5
+select -assert-count 4 t:MISTRAL_ALUT6
+
+select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D
diff --git a/tests/arch/intel_alm/run-test.sh b/tests/arch/intel_alm/run-test.sh
new file mode 100755
index 000000000..bf19b887d
--- /dev/null
+++ b/tests/arch/intel_alm/run-test.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+set -e
+{
+echo "all::"
+for x in *.ys; do
+ echo "all:: run-$x"
+ echo "run-$x:"
+ echo " @echo 'Running $x..'"
+ echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
+done
+for s in *.sh; do
+ if [ "$s" != "run-test.sh" ]; then
+ echo "all:: run-$s"
+ echo "run-$s:"
+ echo " @echo 'Running $s..'"
+ echo " @bash $s"
+ fi
+done
+} > run-test.mk
+exec ${MAKE:-make} -f run-test.mk
diff --git a/tests/arch/intel_alm/shifter.ys b/tests/arch/intel_alm/shifter.ys
new file mode 100644
index 000000000..014dbd1a8
--- /dev/null
+++ b/tests/arch/intel_alm/shifter.ys
@@ -0,0 +1,10 @@
+read_verilog ../common/shifter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 8 t:MISTRAL_FF
+
+select -assert-none t:MISTRAL_FF %% t:* %D
diff --git a/tests/arch/intel_alm/tribuf.ys b/tests/arch/intel_alm/tribuf.ys
new file mode 100644
index 000000000..71b05a747
--- /dev/null
+++ b/tests/arch/intel_alm/tribuf.ys
@@ -0,0 +1,13 @@
+read_verilog ../common/tribuf.v
+hierarchy -top tristate
+proc
+tribuf
+flatten
+synth
+equiv_opt -assert -map +/simcells.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd tristate # Constrain all select calls below inside the top module
+#Internal cell type used. Need support it.
+select -assert-count 1 t:$_TBUF_
+
+select -assert-none t:$_TBUF_ %% t:* %D
diff --git a/tests/opt/opt_expr.ys b/tests/opt/opt_expr.ys
index e0acead82..7c446afd1 100644
--- a/tests/opt/opt_expr.ys
+++ b/tests/opt/opt_expr.ys
@@ -291,3 +291,31 @@ check
equiv_opt -assert opt_expr -keepdc
design -load postopt
select -assert-count 1 t:$shift r:A_WIDTH=13 %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_mul_low_bits(input [2:0] a, input [2:0] b, output [7:0] y);
+ \$mul #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(4), .Y_WIDTH(8)) mul (.A({a, 1'b0}), .B({b, 1'b0}), .Y(y));
+endmodule
+EOT
+check
+
+equiv_opt -assert opt_expr
+design -load postopt
+select -assert-count 1 t:$mul r:A_WIDTH=3 %i r:B_WIDTH=3 %i r:Y_WIDTH=6 %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_mul_low_bits(input [2:0] a, input [2:0] b, output [7:0] y);
+ \$mul #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(4), .Y_WIDTH(8)) mul (.A({a, 1'b0}), .B({b, 1'b0}), .Y(y));
+endmodule
+EOT
+check
+
+equiv_opt -assert opt_expr -keepdc
+design -load postopt
+select -assert-count 1 t:$mul r:A_WIDTH=4 %i r:B_WIDTH=4 %i r:Y_WIDTH=8 %i
diff --git a/tests/opt/opt_expr_alu.ys b/tests/opt/opt_expr_alu.ys
index a3361ca43..9121c0096 100644
--- a/tests/opt/opt_expr_alu.ys
+++ b/tests/opt/opt_expr_alu.ys
@@ -5,10 +5,10 @@ endmodule
EOT
alumacc
-equiv_opt opt_expr -fine
+equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
-select -assert-count none t:$pos t:* %D
+select -assert-none t:$pos t:* %D
design -reset
@@ -20,7 +20,7 @@ EOT
alumacc
select -assert-count 1 t:$alu
-select -assert-count none t:$alu t:* %D
+select -assert-none t:$alu t:* %D
design -reset
@@ -30,10 +30,10 @@ assign y = {a,1'b1} - 1'b1;
endmodule
EOT
-equiv_opt opt_expr -fine
+equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
-select -assert-count none t:$pos t:* %D
+select -assert-none t:$pos t:* %D
design -reset
@@ -43,10 +43,10 @@ assign y = {a,3'b101} - 1'b1;
endmodule
EOT
-equiv_opt opt_expr -fine
+equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
-select -assert-count none t:$pos t:* %D
+select -assert-none t:$pos t:* %D
design -reset
@@ -57,7 +57,113 @@ endmodule
EOT
alumacc
-equiv_opt opt_expr -fine
+equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
-select -assert-count none t:$pos t:* %D
+select -assert-count 1 t:$not
+select -assert-none t:$pos t:$not %% t:* %D
+
+
+design -reset
+read_verilog <<EOT
+module test(input [1:0] a, output [3:0] y);
+assign y = -{a[1], 2'b10, a[0]};
+endmodule
+EOT
+
+alumacc
+equiv_opt -assert opt -fine
+design -load postopt
+select -assert-count 1 t:$alu
+select -assert-count 1 t:$alu r:Y_WIDTH=3 %i
+select -assert-count 1 t:$not
+select -assert-none t:$alu t:$not t:* %D %D
+
+
+design -reset
+read_verilog <<EOT
+module test(input [3:0] a, input [2:0] b, output [5:0] y);
+assign y = {a[3:2], 1'b1, a[1:0]} + {b[2], 2'b11, b[1:0]};
+endmodule
+EOT
+
+alumacc
+equiv_opt -assert opt -fine
+design -load postopt
+dump
+select -assert-count 2 t:$alu
+select -assert-count 1 t:$alu r:Y_WIDTH=2 %i
+select -assert-count 1 t:$alu r:Y_WIDTH=3 %i
+select -assert-none t:$alu t:* %D
+
+
+design -reset
+read_verilog <<EOT
+module test(input [3:0] a, input [3:0] b, output [5:0] y);
+assign y = {a[3:2], 1'b0, a[1:0]} + {b[3:2], 1'b0, b[1:0]};
+endmodule
+EOT
+
+alumacc
+equiv_opt -assert opt -fine
+design -load postopt
+select -assert-count 2 t:$alu
+select -assert-count 2 t:$alu r:Y_WIDTH=3 %i
+select -assert-none t:$alu t:* %D
+
+
+design -reset
+read_verilog -icells <<EOT
+module test(input [3:0] a, output [3:0] y, output [3:0] x, output [3:0] co);
+$alu #(
+ .A_WIDTH(4), .B_WIDTH(4), .Y_WIDTH(4),
+ .A_SIGNED(0), .B_SIGNED(0),
+) alu (
+ .A(a), .B(4'h0),
+ .BI(1'b0), .CI(1'b0),
+ .Y(y), .X(x), .CO(co),
+);
+endmodule
+EOT
+
+equiv_opt -assert opt
+design -load postopt
+select -assert-none t:$alu
+
+
+design -reset
+read_verilog -icells <<EOT
+module test(input [3:0] a, output [3:0] y, output [3:0] x, output [3:0] co);
+$alu #(
+ .A_WIDTH(4), .B_WIDTH(4), .Y_WIDTH(4),
+ .A_SIGNED(0), .B_SIGNED(0),
+) alu (
+ .A(a), .B(4'h0),
+ .BI(1'b1), .CI(1'b1),
+ .Y(y), .X(x), .CO(co),
+);
+endmodule
+EOT
+
+equiv_opt -assert opt
+design -load postopt
+select -assert-none t:$alu
+
+
+design -reset
+read_verilog -icells <<EOT
+module test(input [3:0] a, output [3:0] y, output [3:0] x, output [3:0] co);
+$alu #(
+ .A_WIDTH(4), .B_WIDTH(4), .Y_WIDTH(4),
+ .A_SIGNED(0), .B_SIGNED(0),
+) alu (
+ .A(4'h0), .B(a),
+ .BI(1'b0), .CI(1'b0),
+ .Y(y), .X(x), .CO(co),
+);
+endmodule
+EOT
+
+equiv_opt -assert opt
+design -load postopt
+select -assert-none t:$alu
diff --git a/tests/select/.gitignore b/tests/select/.gitignore
new file mode 100644
index 000000000..50e13221d
--- /dev/null
+++ b/tests/select/.gitignore
@@ -0,0 +1 @@
+/*.log
diff --git a/tests/select/unset.ys b/tests/select/unset.ys
new file mode 100644
index 000000000..4f60781c2
--- /dev/null
+++ b/tests/select/unset.ys
@@ -0,0 +1,10 @@
+read_verilog <<EOT
+module top(input i, output o);
+assign o = i;
+endmodule
+EOT
+select -set foo w:*
+select -assert-any @foo
+select -unset foo
+logger -expect error "Selection '\\foo' does not exist!" 1
+select -unset foo
diff --git a/tests/select/unset2.ys b/tests/select/unset2.ys
new file mode 100644
index 000000000..456b84c22
--- /dev/null
+++ b/tests/select/unset2.ys
@@ -0,0 +1,10 @@
+read_verilog <<EOT
+module top(input i, output o);
+assign o = i;
+endmodule
+EOT
+select -set foo w:*
+select -assert-any @foo
+select -unset foo
+logger -expect error "Selection @foo is not defined!" 1
+select -list @foo
diff --git a/tests/svtypes/typedef_package.sv b/tests/svtypes/typedef_package.sv
index 57a78c53a..2d83742c5 100644
--- a/tests/svtypes/typedef_package.sv
+++ b/tests/svtypes/typedef_package.sv
@@ -1,6 +1,9 @@
package pkg;
typedef logic [7:0] uint8_t;
- typedef enum logic [7:0] {bb=8'hBB} enum8_t;
+ typedef enum logic [7:0] {bb=8'hBB, cc=8'hCC} enum8_t;
+
+ localparam uint8_t PCONST = cc;
+ parameter uint8_t PCONST_COPY = PCONST;
endpackage
module top;
@@ -8,7 +11,9 @@ module top;
(* keep *) pkg::uint8_t a = 8'hAA;
(* keep *) pkg::enum8_t b_enum = pkg::bb;
- always @* assert(a == 8'hAA);
- always @* assert(b_enum == 8'hBB);
+ always_comb assert(a == 8'hAA);
+ always_comb assert(b_enum == 8'hBB);
+ always_comb assert(pkg::PCONST == pkg::cc);
+ always_comb assert(pkg::PCONST_COPY == pkg::cc);
endmodule
diff --git a/tests/techmap/dffinit.ys b/tests/techmap/dffinit.ys
new file mode 100644
index 000000000..218d411f8
--- /dev/null
+++ b/tests/techmap/dffinit.ys
@@ -0,0 +1,25 @@
+read_verilog <<EOT
+
+module ff(...);
+input d;
+output q;
+
+endmodule
+
+module top(...);
+input d;
+output q1;
+(* init = 1'b1 *)
+output q2;
+
+ff my_ff1(.d(d), .q(q1));
+ff my_ff2(.d(d), .q(q2));
+
+endmodule
+
+EOT
+
+dffinit -ff ff q init
+select -assert-count 2 t:ff
+select -assert-count 1 t:ff r:init %i
+select -assert-count 1 t:ff r:init=1'b1 %i
diff --git a/tests/techmap/zinit.ys b/tests/techmap/zinit.ys
new file mode 100644
index 000000000..d0e41b4d2
--- /dev/null
+++ b/tests/techmap/zinit.ys
@@ -0,0 +1,151 @@
+read_verilog -icells <<EOT
+module top(input C, R, input [1:0] D, (* init = {2'b10, 2'b01, 1'b1, {8{1'b1}}} *) output [12:0] Q);
+
+(* init = 1'b1 *)
+wire unused;
+
+$_DFF_NN0_ dff0 (.C(C), .D(D[0]), .R(R), .Q(Q[0]));
+$_DFF_NN1_ dff1 (.C(C), .D(D[0]), .R(R), .Q(Q[1]));
+$_DFF_NP0_ dff2 (.C(C), .D(D[0]), .R(R), .Q(Q[2]));
+$_DFF_NP1_ dff3 (.C(C), .D(D[0]), .R(R), .Q(Q[3]));
+$_DFF_PN0_ dff4 (.C(C), .D(D[0]), .R(R), .Q(Q[4]));
+$_DFF_PN1_ dff5 (.C(C), .D(D[0]), .R(R), .Q(Q[5]));
+$_DFF_PP0_ dff6 (.C(C), .D(D[0]), .R(R), .Q(Q[6]));
+$_DFF_PP1_ dff7 (.C(C), .D(D[0]), .R(R), .Q(Q[7]));
+
+$adff #(.WIDTH(2), .CLK_POLARITY(1), .ARST_POLARITY(1'b0), .ARST_VALUE(2'b10)) dff8 (.CLK(C), .ARST(R), .D(D), .Q(Q[10:9]));
+$adff #(.WIDTH(2), .CLK_POLARITY(0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'b01)) dff9 (.CLK(C), .ARST(R), .D(D), .Q(Q[12:11]));
+endmodule
+EOT
+equiv_opt -assert -multiclock zinit
+design -load postopt
+
+select -assert-count 20 t:$_NOT_
+select -assert-count 1 w:unused a:init %i
+select -assert-count 1 w:Q a:init=13'bxxxx1xxxxxxxx %i
+select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFF_??1_ %i
+select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$_DFF_??0_ %i
+
+
+design -reset
+read_verilog -icells <<EOT
+module top(input C, R, input [1:0] D, (* init = {2'bx0, 2'b0x, 1'b1, {8{1'b0}}} *) output [12:0] Q);
+
+(* init = 1'b1 *)
+wire unused;
+
+$_DFF_NN0_ dff0 (.C(C), .D(D[0]), .R(R), .Q(Q[0]));
+$_DFF_NN1_ dff1 (.C(C), .D(D[0]), .R(R), .Q(Q[1]));
+$_DFF_NP0_ dff2 (.C(C), .D(D[0]), .R(R), .Q(Q[2]));
+$_DFF_NP1_ dff3 (.C(C), .D(D[0]), .R(R), .Q(Q[3]));
+$_DFF_PN0_ dff4 (.C(C), .D(D[0]), .R(R), .Q(Q[4]));
+$_DFF_PN1_ dff5 (.C(C), .D(D[0]), .R(R), .Q(Q[5]));
+$_DFF_PP0_ dff6 (.C(C), .D(D[0]), .R(R), .Q(Q[6]));
+$_DFF_PP1_ dff7 (.C(C), .D(D[0]), .R(R), .Q(Q[7]));
+
+$adff #(.WIDTH(2), .CLK_POLARITY(1), .ARST_POLARITY(1'b0), .ARST_VALUE(2'b10)) dff8 (.CLK(C), .ARST(R), .D(D), .Q(Q[10:9]));
+$adff #(.WIDTH(2), .CLK_POLARITY(0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'b01)) dff9 (.CLK(C), .ARST(R), .D(D), .Q(Q[12:11]));
+endmodule
+EOT
+equiv_opt -assert -multiclock zinit
+design -load postopt
+
+select -assert-count 0 t:$_NOT_
+select -assert-count 1 w:unused a:init %i
+select -assert-count 1 w:Q a:init=13'bxxxx1xxxxxxxx %i
+select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFF_??0_ %i
+select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$_DFF_??1_ %i
+
+
+design -reset
+read_verilog -icells <<EOT
+module top(input C, R, D, E, (* init = {24{1'b1}} *) output [23:0] Q);
+
+$__DFFE_NN0 dff0 (.C(C), .D(D), .E(E), .R(R), .Q(Q[0]));
+$__DFFE_NN1 dff1 (.C(C), .D(D), .E(E), .R(R), .Q(Q[1]));
+$__DFFE_NP0 dff2 (.C(C), .D(D), .E(E), .R(R), .Q(Q[2]));
+$__DFFE_NP1 dff3 (.C(C), .D(D), .E(E), .R(R), .Q(Q[3]));
+$__DFFE_PN0 dff4 (.C(C), .D(D), .E(E), .R(R), .Q(Q[4]));
+$__DFFE_PN1 dff5 (.C(C), .D(D), .E(E), .R(R), .Q(Q[5]));
+$__DFFE_PP0 dff6 (.C(C), .D(D), .E(E), .R(R), .Q(Q[6]));
+$__DFFE_PP1 dff7 (.C(C), .D(D), .E(E), .R(R), .Q(Q[7]));
+
+$__DFFS_NN0_ dff8 (.C(C), .D(D[0]), .R(R), .Q(Q[8]));
+$__DFFS_NN1_ dff9 (.C(C), .D(D[0]), .R(R), .Q(Q[9]));
+$__DFFS_NP0_ dff10(.C(C), .D(D[0]), .R(R), .Q(Q[10]));
+$__DFFS_NP1_ dff11(.C(C), .D(D[0]), .R(R), .Q(Q[11]));
+$__DFFS_PN0_ dff12(.C(C), .D(D[0]), .R(R), .Q(Q[12]));
+$__DFFS_PN1_ dff13(.C(C), .D(D[0]), .R(R), .Q(Q[13]));
+$__DFFS_PP0_ dff14(.C(C), .D(D[0]), .R(R), .Q(Q[14]));
+$__DFFS_PP1_ dff15(.C(C), .D(D[0]), .R(R), .Q(Q[15]));
+
+$__DFFSE_NN0 dff16(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[16]));
+$__DFFSE_NN1 dff17(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[17]));
+$__DFFSE_NP0 dff18(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[18]));
+$__DFFSE_NP1 dff19(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[19]));
+$__DFFSE_PN0 dff20(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[20]));
+$__DFFSE_PN1 dff21(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[21]));
+$__DFFSE_PP0 dff22(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[22]));
+$__DFFSE_PP1 dff23(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[23]));
+
+endmodule
+EOT
+#equiv_opt -assert -multiclock zinit
+#design -load postopt
+zinit
+
+select -assert-count 48 t:$_NOT_
+select -assert-count 1 w:Q a:init=24'bx %i
+select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$__DFFE_??1 %i
+select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$__DFFE_??0 %i
+select -assert-count 4 c:dff8 c:dff10 c:dff12 c:dff14 %% t:$__DFFS_??1_ %i
+select -assert-count 4 c:dff9 c:dff11 c:dff13 c:dff15 %% t:$__DFFS_??0_ %i
+select -assert-count 4 c:dff16 c:dff18 c:dff20 c:dff22 %% t:$__DFFSE_??1 %i
+select -assert-count 4 c:dff17 c:dff19 c:dff21 c:dff23 %% t:$__DFFSE_??0 %i
+
+
+design -reset
+read_verilog -icells <<EOT
+module top(input C, R, D, E, (* init = {24{1'b0}} *) output [23:0] Q);
+
+$__DFFE_NN0 dff0 (.C(C), .D(D), .E(E), .R(R), .Q(Q[0]));
+$__DFFE_NN1 dff1 (.C(C), .D(D), .E(E), .R(R), .Q(Q[1]));
+$__DFFE_NP0 dff2 (.C(C), .D(D), .E(E), .R(R), .Q(Q[2]));
+$__DFFE_NP1 dff3 (.C(C), .D(D), .E(E), .R(R), .Q(Q[3]));
+$__DFFE_PN0 dff4 (.C(C), .D(D), .E(E), .R(R), .Q(Q[4]));
+$__DFFE_PN1 dff5 (.C(C), .D(D), .E(E), .R(R), .Q(Q[5]));
+$__DFFE_PP0 dff6 (.C(C), .D(D), .E(E), .R(R), .Q(Q[6]));
+$__DFFE_PP1 dff7 (.C(C), .D(D), .E(E), .R(R), .Q(Q[7]));
+
+$__DFFS_NN0_ dff8 (.C(C), .D(D[0]), .R(R), .Q(Q[8]));
+$__DFFS_NN1_ dff9 (.C(C), .D(D[0]), .R(R), .Q(Q[9]));
+$__DFFS_NP0_ dff10(.C(C), .D(D[0]), .R(R), .Q(Q[10]));
+$__DFFS_NP1_ dff11(.C(C), .D(D[0]), .R(R), .Q(Q[11]));
+$__DFFS_PN0_ dff12(.C(C), .D(D[0]), .R(R), .Q(Q[12]));
+$__DFFS_PN1_ dff13(.C(C), .D(D[0]), .R(R), .Q(Q[13]));
+$__DFFS_PP0_ dff14(.C(C), .D(D[0]), .R(R), .Q(Q[14]));
+$__DFFS_PP1_ dff15(.C(C), .D(D[0]), .R(R), .Q(Q[15]));
+
+$__DFFSE_NN0 dff16(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[16]));
+$__DFFSE_NN1 dff17(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[17]));
+$__DFFSE_NP0 dff18(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[18]));
+$__DFFSE_NP1 dff19(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[19]));
+$__DFFSE_PN0 dff20(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[20]));
+$__DFFSE_PN1 dff21(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[21]));
+$__DFFSE_PP0 dff22(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[22]));
+$__DFFSE_PP1 dff23(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[23]));
+
+endmodule
+EOT
+#equiv_opt -assert -multiclock zinit
+#design -load postopt
+zinit
+
+select -assert-count 0 t:$_NOT_
+select -assert-count 1 w:Q a:init=24'bx %i
+select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$__DFFE_??0 %i
+select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$__DFFE_??1 %i
+select -assert-count 4 c:dff8 c:dff10 c:dff12 c:dff14 %% t:$__DFFS_??0_ %i
+select -assert-count 4 c:dff9 c:dff11 c:dff13 c:dff15 %% t:$__DFFS_??1_ %i
+select -assert-count 4 c:dff16 c:dff18 c:dff20 c:dff22 %% t:$__DFFSE_??0 %i
+select -assert-count 4 c:dff17 c:dff19 c:dff21 c:dff23 %% t:$__DFFSE_??1 %i
diff --git a/tests/various/.gitignore b/tests/various/.gitignore
index 4b286fd61..12d4e5048 100644
--- a/tests/various/.gitignore
+++ b/tests/various/.gitignore
@@ -3,3 +3,4 @@
/write_gzip.v
/write_gzip.v.gz
/run-test.mk
+/plugin.so
diff --git a/tests/various/bug1876.ys b/tests/various/bug1876.ys
new file mode 100644
index 000000000..7995eedcf
--- /dev/null
+++ b/tests/various/bug1876.ys
@@ -0,0 +1,60 @@
+read_verilog <<EOT
+module expression_00032(b5, y15);
+ input signed [5:0] b5;
+ output [3:0] y15;
+ assign y15 = (0 ? b5 : b5) > 0;
+endmodule
+EOT
+
+
+design -reset
+read_verilog <<EOT
+module expression_00057(a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5, y8);
+ input [3:0] a0;
+ input [4:0] a1;
+ input [5:0] a2;
+ input signed [3:0] a3;
+ input signed [4:0] a4;
+ input signed [5:0] a5;
+
+ input [3:0] b0;
+ input [4:0] b1;
+ input [5:0] b2;
+ input signed [3:0] b3;
+ input signed [4:0] b4;
+ input signed [5:0] b5;
+
+ output [5:0] y8;
+
+ localparam signed [4:0] p4 = ((2'd3)||(-4'sd1));
+ localparam signed [3:0] p9 = {3{(((2'sd0)^~(5'd20))>((-3'sd0)>>(4'sd2)))}};
+
+ assign y8 = (-(!($signed({3{p9}})<(p4?b4:b5))));
+endmodule
+EOT
+
+
+design -reset
+read_verilog <<EOT
+module expression_00354(a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5, y4);
+ input [3:0] a0;
+ input [4:0] a1;
+ input [5:0] a2;
+ input signed [3:0] a3;
+ input signed [4:0] a4;
+ input signed [5:0] a5;
+
+ input [3:0] b0;
+ input [4:0] b1;
+ input [5:0] b2;
+ input signed [3:0] b3;
+ input signed [4:0] b4;
+ input signed [5:0] b5;
+
+ output wire signed [4:0] y4;
+
+ localparam signed [4:0] p10 = ((3'd0)?(2'd1):(-2'sd1));
+
+ assign y4 = ((p10?a4:b4)&$signed(b3));
+endmodule
+EOT
diff --git a/tests/various/design.ys b/tests/various/design.ys
new file mode 100644
index 000000000..f13ad8171
--- /dev/null
+++ b/tests/various/design.ys
@@ -0,0 +1,9 @@
+read_verilog <<EOT
+module top(input i, output o);
+assign o = i;
+endmodule
+EOT
+design -stash foo
+design -delete foo
+logger -expect error "No saved design 'foo' found!" 1
+design -delete foo
diff --git a/tests/various/design2.ys b/tests/various/design2.ys
new file mode 100644
index 000000000..399999020
--- /dev/null
+++ b/tests/various/design2.ys
@@ -0,0 +1,9 @@
+read_verilog <<EOT
+module top(input i, output o);
+assign o = i;
+endmodule
+EOT
+design -stash foo
+design -delete foo
+logger -expect error "No saved design 'foo' found!" 1
+design -load foo
diff --git a/tests/various/global_scope.ys b/tests/various/global_scope.ys
new file mode 100644
index 000000000..8c8618e10
--- /dev/null
+++ b/tests/various/global_scope.ys
@@ -0,0 +1,18 @@
+read_verilog -sv <<EOT
+parameter A = 10;
+parameter B = A;
+
+typedef enum {
+ CONST_A = A,
+ CONST_B = A+1
+} enum_t;
+
+module top(output [3:0] q, output [3:0] r);
+assign q = 10;
+assign r = CONST_B;
+endmodule
+EOT
+
+hierarchy -top top
+sat -verify -prove q 10 top
+sat -verify -prove r 11 top
diff --git a/tests/various/plugin.cc b/tests/various/plugin.cc
new file mode 100644
index 000000000..be305fbda
--- /dev/null
+++ b/tests/various/plugin.cc
@@ -0,0 +1,15 @@
+#include "kernel/rtlil.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct TestPass : public Pass {
+ TestPass() : Pass("test", "test") { }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ size_t argidx = 1;
+ extra_args(args, argidx, design);
+ log("Plugin test passed!\n");
+ }
+} TestPass;
+
+YOSYS_NAMESPACE_END
diff --git a/tests/various/plugin.sh b/tests/various/plugin.sh
new file mode 100644
index 000000000..d6d4aee59
--- /dev/null
+++ b/tests/various/plugin.sh
@@ -0,0 +1,6 @@
+set -e
+rm -f plugin.so
+CXXFLAGS=$(../../yosys-config --cxxflags)
+CXXFLAGS=${CXXFLAGS// -I\/usr\/local\/share\/yosys\/include/ -I..\/..\/share\/include}
+../../yosys-config --exec --cxx ${CXXFLAGS} --ldflags -shared -o plugin.so plugin.cc
+../../yosys -m ./plugin.so -p "test" | grep -q "Plugin test passed!"