summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Kuzminsky <seb@highlab.com>2016-02-29 21:47:04 -0700
committerSebastian Kuzminsky <seb@highlab.com>2016-02-29 21:47:04 -0700
commit93b1bcd5dec9be1250e89e25405092469a9c8d34 (patch)
tree44fe541737e4c56c1ccafd7bd909b32a96e8ab21
parent0fa23a0fe30e7570f2c8897c137e300af2e017f5 (diff)
parent5869d26da02147741f783a2f379fd49194c7e1ad (diff)
Merge tag 'upstream/0.6' into new
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG88
-rw-r--r--CodeOfConduct73
-rw-r--r--CodingReadme7
-rw-r--r--Makefile44
-rw-r--r--README12
-rw-r--r--backends/blif/blif.cc13
-rw-r--r--backends/btor/btor.cc16
-rw-r--r--backends/smt2/Makefile.inc13
-rw-r--r--backends/smt2/example.v11
-rw-r--r--backends/smt2/example.ys3
-rw-r--r--backends/smt2/smt2.cc31
-rw-r--r--backends/smt2/smtbmc.py225
-rw-r--r--backends/smt2/smtio.py325
-rw-r--r--backends/smv/smv.cc10
-rw-r--r--examples/basys3/README (renamed from techlibs/xilinx/example_basys3/README)3
-rw-r--r--examples/basys3/example.v (renamed from techlibs/xilinx/example_basys3/example.v)0
-rw-r--r--examples/basys3/example.xdc (renamed from techlibs/xilinx/example_basys3/example.xdc)0
-rw-r--r--examples/basys3/run.sh (renamed from techlibs/xilinx/example_basys3/run.sh)0
-rw-r--r--examples/basys3/run_prog.tcl (renamed from techlibs/xilinx/example_basys3/run_prog.tcl)0
-rw-r--r--examples/basys3/run_vivado.tcl (renamed from techlibs/xilinx/example_basys3/run_vivado.tcl)0
-rw-r--r--examples/basys3/run_yosys.ys (renamed from techlibs/xilinx/example_basys3/run_yosys.ys)0
-rw-r--r--examples/cmos/cmos_cells.lib (renamed from techlibs/cmos/cmos_cells.lib)0
-rw-r--r--examples/cmos/cmos_cells.sp (renamed from techlibs/cmos/cmos_cells.sp)0
-rw-r--r--examples/cmos/cmos_cells.v (renamed from techlibs/cmos/cmos_cells.v)0
-rw-r--r--examples/cmos/counter.v (renamed from techlibs/cmos/counter.v)0
-rw-r--r--examples/cmos/counter.ys (renamed from techlibs/cmos/counter.ys)0
-rw-r--r--examples/cmos/testbench.sh (renamed from techlibs/cmos/testbench.sh)0
-rw-r--r--examples/cmos/testbench.sp (renamed from techlibs/cmos/testbench.sp)0
-rw-r--r--examples/cxx-api/demomain.cc (renamed from misc/example.cc)2
-rw-r--r--frontends/ast/ast.cc2
-rw-r--r--frontends/ast/genrtlil.cc53
-rw-r--r--frontends/ast/simplify.cc77
-rw-r--r--frontends/blif/blifparse.cc127
-rw-r--r--frontends/blif/blifparse.h2
-rw-r--r--frontends/ilang/ilang_parser.y24
-rw-r--r--frontends/verific/Makefile.inc5
-rw-r--r--frontends/verific/build_amd64.txt2
-rw-r--r--frontends/verific/verific.cc84
-rw-r--r--frontends/verilog/verilog_parser.y4
-rw-r--r--kernel/calc.cc20
-rw-r--r--kernel/cellaigs.cc2
-rw-r--r--kernel/driver.cc2
-rw-r--r--kernel/hashlib.h149
-rw-r--r--kernel/macc.h4
-rw-r--r--kernel/modtools.h27
-rw-r--r--kernel/register.cc51
-rw-r--r--kernel/rtlil.cc213
-rw-r--r--kernel/rtlil.h16
-rw-r--r--kernel/satgen.h2
-rw-r--r--kernel/sigtools.h166
-rw-r--r--kernel/yosys.cc14
-rw-r--r--kernel/yosys.h11
-rw-r--r--libs/ezsat/ezsat.cc24
-rw-r--r--manual/CHAPTER_Appnotes.tex4
-rwxr-xr-xmanual/clean.sh2
-rw-r--r--manual/command-reference-manual.tex374
-rw-r--r--passes/cmds/Makefile.inc1
-rw-r--r--passes/cmds/edgetypes.cc6
-rw-r--r--passes/cmds/plugin.cc2
-rw-r--r--passes/cmds/qwp.cc20
-rw-r--r--passes/cmds/scc.cc4
-rw-r--r--passes/cmds/select.cc50
-rw-r--r--passes/cmds/show.cc2
-rw-r--r--passes/cmds/splice.cc2
-rw-r--r--passes/cmds/splitnets.cc61
-rw-r--r--passes/cmds/stat.cc70
-rw-r--r--passes/cmds/torder.cc123
-rw-r--r--passes/equiv/Makefile.inc3
-rw-r--r--passes/equiv/equiv_add.cc152
-rw-r--r--passes/equiv/equiv_induct.cc8
-rw-r--r--passes/equiv/equiv_make.cc2
-rw-r--r--passes/equiv/equiv_mark.cc239
-rw-r--r--passes/equiv/equiv_miter.cc2
-rw-r--r--passes/equiv/equiv_purge.cc210
-rw-r--r--passes/equiv/equiv_simple.cc6
-rw-r--r--passes/equiv/equiv_struct.cc367
-rw-r--r--passes/fsm/fsm_opt.cc2
-rw-r--r--passes/fsm/fsm_recode.cc2
-rw-r--r--passes/fsm/fsmdata.h2
-rw-r--r--passes/hierarchy/Makefile.inc1
-rw-r--r--passes/hierarchy/hierarchy.cc10
-rw-r--r--passes/hierarchy/singleton.cc101
-rw-r--r--passes/hierarchy/submod.cc41
-rw-r--r--passes/memory/memory_bram.cc10
-rw-r--r--passes/memory/memory_collect.cc2
-rw-r--r--passes/memory/memory_dff.cc15
-rw-r--r--passes/memory/memory_share.cc2
-rw-r--r--passes/opt/opt_clean.cc2
-rw-r--r--passes/opt/opt_const.cc2
-rw-r--r--passes/opt/opt_muxtree.cc2
-rw-r--r--passes/opt/share.cc58
-rw-r--r--passes/opt/wreduce.cc59
-rw-r--r--passes/proc/proc_mux.cc189
-rw-r--r--passes/sat/eval.cc2
-rw-r--r--passes/sat/expose.cc20
-rw-r--r--passes/sat/freduce.cc2
-rw-r--r--passes/sat/sat.cc12
-rw-r--r--passes/techmap/Makefile.inc3
-rw-r--r--passes/techmap/abc.cc111
-rw-r--r--passes/techmap/alumacc.cc6
-rw-r--r--passes/techmap/dffinit.cc6
-rw-r--r--passes/techmap/dfflibmap.cc76
-rw-r--r--passes/techmap/dffsr2dff.cc213
-rw-r--r--passes/techmap/extract.cc4
-rw-r--r--passes/techmap/maccmap.cc2
-rw-r--r--passes/techmap/muxcover.cc6
-rw-r--r--passes/techmap/simplemap.cc4
-rw-r--r--passes/techmap/techmap.cc4
-rw-r--r--passes/tests/test_cell.cc2
-rw-r--r--techlibs/common/.gitignore2
-rw-r--r--techlibs/common/Makefile.inc16
-rw-r--r--techlibs/common/cellhelp.py34
-rw-r--r--techlibs/common/prep.cc158
-rw-r--r--techlibs/common/simcells.v809
-rw-r--r--techlibs/common/synth.cc2
-rw-r--r--techlibs/ice40/Makefile.inc1
-rw-r--r--techlibs/ice40/brams_map.v16
-rw-r--r--techlibs/ice40/cells_sim.v16
-rw-r--r--techlibs/ice40/ice40_ffinit.cc163
-rw-r--r--techlibs/ice40/ice40_opt.cc21
-rw-r--r--techlibs/ice40/synth_ice40.cc18
-rw-r--r--techlibs/xilinx/synth_xilinx.cc6
-rw-r--r--tests/simple/graphtest.v34
-rw-r--r--tests/simple/memory.v15
-rw-r--r--tests/simple/task_func.v42
-rw-r--r--tests/simple/wreduce.v9
127 files changed, 5276 insertions, 727 deletions
diff --git a/.gitignore b/.gitignore
index 484faf41..93e28cd6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@
/yosys-abc
/yosys-abc.exe
/yosys-config
+/yosys-smtbmc
/yosys-filterlib
/yosys-filterlib.exe
/kernel/version_*.cc
diff --git a/CHANGELOG b/CHANGELOG
index 3fb8f38c..31cd94a5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,94 @@ List of major changes and improvements between releases
=======================================================
+Yosys 0.5 .. Yosys 0.6
+----------------------
+
+ * Various
+ - Added Contributor Covenant Code of Conduct
+ - Various improvements in dict<> and pool<>
+ - Added hashlib::mfp and refactored SigMap
+ - Improved support for reals as module parameters
+ - Various improvements in SMT2 back-end
+ - Added "keep_hierarchy" attribute
+ - Verilog front-end: define `BLACKBOX in -lib mode
+ - Added API for converting internal cells to AIGs
+ - Added ENABLE_LIBYOSYS Makefile option
+ - Removed "techmap -share_map" (use "-map +/filename" instead)
+ - Switched all Python scripts to Python 3
+ - Added support for $display()/$write() and $finish() to Verilog front-end
+ - Added "yosys-smtbmc" formal verification flow
+ - Added options for clang sanitizers to Makefile
+
+ * New commands and options
+ - Added "scc -expect <N> -nofeedback"
+ - Added "proc_dlatch"
+ - Added "check"
+ - Added "select %xe %cie %coe %M %C %R"
+ - Added "sat -dump_json" (WaveJSON format)
+ - Added "sat -tempinduct-baseonly -tempinduct-inductonly"
+ - Added "sat -stepsize" and "sat -tempinduct-step"
+ - Added "sat -show-regs -show-public -show-all"
+ - Added "write_json" (Native Yosys JSON format)
+ - Added "write_blif -attr"
+ - Added "dffinit"
+ - Added "chparam"
+ - Added "muxcover"
+ - Added "pmuxtree"
+ - Added memory_bram "make_outreg" feature
+ - Added "splice -wires"
+ - Added "dff2dffe -direct-match"
+ - Added simplemap $lut support
+ - Added "read_blif"
+ - Added "opt_share -share_all"
+ - Added "aigmap"
+ - Added "write_smt2 -mem -regs -wires"
+ - Added "memory -nordff"
+ - Added "write_smv"
+ - Added "synth -nordff -noalumacc"
+ - Added "rename -top new_name"
+ - Added "opt_const -clkinv"
+ - Added "synth -nofsm"
+ - Added "miter -assert"
+ - Added "read_verilog -noautowire"
+ - Added "read_verilog -nodpi"
+ - Added "tribuf"
+ - Added "lut2mux"
+ - Added "nlutmap"
+ - Added "qwp"
+ - Added "test_cell -noeval"
+ - Added "edgetypes"
+ - Added "equiv_struct"
+ - Added "equiv_purge"
+ - Added "equiv_mark"
+ - Added "equiv_add -try -cell"
+ - Added "singleton"
+ - Added "abc -g -luts"
+ - Added "torder"
+ - Added "write_blif -cname"
+ - Added "submod -copy"
+ - Added "dffsr2dff"
+ - Added "stat -liberty"
+
+ * Synthesis metacommands
+ - Various improvements in synth_xilinx
+ - Added synth_ice40 and synth_greenpak4
+ - Added "prep" metacommand for "synthesis lite"
+
+ * Cell library changes
+ - Added cell types to "help" system
+ - Added $meminit cell type
+ - Added $assume cell type
+ - Added $_MUX4_, $_MUX8_, and $_MUX16_ cells
+ - Added $tribuf and $_TBUF_ cell types
+ - Added read-enable to memory model
+
+ * YosysJS
+ - Various improvements in emscripten build
+ - Added alternative webworker-based JS API
+ - Added a few example applications
+
+
Yosys 0.4 .. Yosys 0.5
----------------------
diff --git a/CodeOfConduct b/CodeOfConduct
new file mode 100644
index 00000000..4f779977
--- /dev/null
+++ b/CodeOfConduct
@@ -0,0 +1,73 @@
+Contributor Covenant Code of Conduct
+
+Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at clifford@clifford.at (and/or
+cliffordvienna@gmail.com if you think your mail to the other address got
+stuck in the spam filter). All complaints will be reviewed and investigated and
+will result in a response that is deemed necessary and appropriate to the
+circumstances. The project team is obligated to maintain confidentiality with
+regard to the reporter of an incident. Further details of specific enforcement
+policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+Attribution
+
+This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
+available at http://contributor-covenant.org/version/1/4/
diff --git a/CodingReadme b/CodingReadme
index f93d2205..ba184be5 100644
--- a/CodingReadme
+++ b/CodingReadme
@@ -93,6 +93,9 @@ creates a bijective map from K to the integers. For example:
It is not possible to remove elements from an idict.
+Finally mfp<K> implements a merge-find set data structure (aka. disjoint-set or
+union-find) over the type K ("mfp" = merge-find-promote).
+
2. Standard STL data types
In Yosys we use std::vector<T> and std::string whenever applicable. When
@@ -342,10 +345,10 @@ Then with default config setting:
./yosys -p 'synth; show' tests/simple/fiedler-cooley.v
./yosys -p 'synth_xilinx -top up3down5; show' tests/simple/fiedler-cooley.v
- cd ~yosys/techlibs/cmos
+ cd ~yosys/examples/cmos
bash testbench.sh
- cd ~yosys/techlibs/xilinx/example_basys3
+ cd ~yosys/examples/basys3
bash run.sh
diff --git a/Makefile b/Makefile
index cc12dc35..ce0c737d 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,14 @@ ENABLE_LIBYOSYS := 0
ENABLE_GPROF := 0
ENABLE_NDEBUG := 0
+# clang sanitizers
+SANITIZER =
+# SANITIZER = address
+# SANITIZER = memory
+# SANITIZER = undefined
+# SANITIZER = cfi
+
+
PREFIX ?= /usr/local
INSTALL_SUDO :=
@@ -54,13 +62,13 @@ ifeq (Darwin,$(findstring Darwin,$(shell uname)))
LDFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --libs libffi)
# use bison installed by homebrew if available
BISON = $(shell (brew list bison | grep -m1 "bin/bison") || echo bison)
- SED = gsed
+ SED = sed
else
LDFLAGS += -rdynamic
LDLIBS += -lrt
endif
-YOSYS_VER := 0.5+$(shell cd $(YOSYS_SRC) && test -d .git && { git log --author=clifford@clifford.at --oneline c3c9fbfb8c678.. | wc -l; })
+YOSYS_VER := 0.6
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
@@ -70,7 +78,7 @@ OBJS = kernel/version_$(GIT_REV).o
# is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC..
-ABCREV = c3698e053a7a
+ABCREV = ae7d65e71adc
ABCPULL = 1
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)"
@@ -86,18 +94,39 @@ endif
ifeq ($(CONFIG),clang)
CXX = clang
+LD = clang++
CXXFLAGS += -std=c++11 -Os
+ifneq ($(SANITIZER),)
+$(info [Clang Sanitizer] $(SANITIZER))
+CXXFLAGS += -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=$(SANITIZER)
+LDFLAGS += -g -fsanitize=$(SANITIZER)
+ifeq ($(SANITIZER),address)
+ENABLE_COVER := 0
+endif
+ifeq ($(SANITIZER),memory)
+CXXFLAGS += -fPIE
+LDFLAGS += -fPIE
+endif
+ifeq ($(SANITIZER),cfi)
+CXXFLAGS += -flto
+LDFLAGS += -flto
+endif
+endif
+
else ifeq ($(CONFIG),gcc)
CXX = gcc
+LD = gcc
CXXFLAGS += -std=gnu++0x -Os
else ifeq ($(CONFIG),gcc-4.6)
CXX = gcc-4.6
+LD = gcc-4.6
CXXFLAGS += -std=gnu++0x -Os
else ifeq ($(CONFIG),emcc)
CXX = emcc
+LD = emcc
CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS))
EMCCFLAGS := -Os -Wno-warn-absolute-paths
EMCCFLAGS += --memory-init-file 0 --embed-file share -s NO_EXIT_RUNTIME=1
@@ -127,12 +156,13 @@ yosys.html: misc/yosys.html
else ifeq ($(CONFIG),mxe)
CXX = /usr/local/src/mxe/usr/bin/i686-pc-mingw32-gcc
+LD = /usr/local/src/mxe/usr/bin/i686-pc-mingw32-gcc
CXXFLAGS += -std=gnu++0x -Os -D_POSIX_SOURCE
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS))
ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -x c++ -fpermissive -w"
-ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" READLINE=0 CC="$(CXX)" CXX="$(CXX)"
+ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="$(CXX)" CXX="$(CXX)"
EXE = .exe
else ifneq ($(CONFIG),none)
@@ -179,7 +209,7 @@ endif
ifeq ($(ENABLE_VERIFIC),1)
VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
-VERIFIC_COMPONENTS ?= verilog vhdl database util containers
+VERIFIC_COMPONENTS ?= verilog vhdl database util containers sdf
CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS))
endif
@@ -300,10 +330,10 @@ yosys.js: $(filter-out yosysjs-$(YOSYS_VER).zip,$(EXTRA_TARGETS))
endif
yosys$(EXE): $(OBJS)
- $(P) $(CXX) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
+ $(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
- $(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
+ $(P) $(LD) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
%.o: %.cc
$(Q) mkdir -p $(dir $@)
diff --git a/README b/README
index 868fd90e..5c649a4e 100644
--- a/README
+++ b/README
@@ -190,15 +190,13 @@ for the given cell library:
clean
If you do not have a liberty file but want to test this synthesis script,
-you can use the file techlibs/cmos/cmos_cells.lib from the yosys sources.
+you can use the file examples/cmos/cmos_cells.lib from the yosys sources.
-Various more complex liberty files (for testing) can be found here:
+Liberty file downloads for and information about free and open ASIC standard
+cell libraries can be found here:
- http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/..
- ../cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib
- ../cadence/lib/ami035/signalstorm/osu035_stdcells.lib
- ../cadence/lib/tsmc018/signalstorm/osu018_stdcells.lib
- ../cadence/lib/ami05/signalstorm/osu05_stdcells.lib
+ http://www.vlsitechnology.org/html/libraries.html
+ http://www.vlsitechnology.org/synopsys/vsclib013.lib
The command "synth" provides a good default synthesis script (see "help synth").
If possible a synthesis script should borrow from "synth". For example:
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index 0a13180a..f3b57765 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -37,6 +37,7 @@ struct BlifDumperConfig
bool conn_mode;
bool impltf_mode;
bool gates_mode;
+ bool cname_mode;
bool param_mode;
bool attr_mode;
bool blackbox_mode;
@@ -45,7 +46,8 @@ struct BlifDumperConfig
std::map<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::IdString>> unbuf_types;
std::string true_type, true_out, false_type, false_out, undef_type, undef_out;
- BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false) { }
+ BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false),
+ cname_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false) { }
};
struct BlifDumper
@@ -349,6 +351,8 @@ struct BlifDumper
}
f << stringf("\n");
+ if (config->cname_mode)
+ f << stringf(".cname %s\n", cstr(cell->name));
if (config->attr_mode)
dump_params(".attr", cell->attributes);
if (config->param_mode)
@@ -426,6 +430,9 @@ struct BlifBackend : public Backend {
log(" -param\n");
log(" use the non-standard .param statement to write cell parameters\n");
log("\n");
+ log(" -cname\n");
+ log(" use the non-standard .cname statement to write cell names\n");
+ log("\n");
log(" -blackbox\n");
log(" write blackbox cells with .blackbox statement.\n");
log("\n");
@@ -490,6 +497,10 @@ struct BlifBackend : public Backend {
config.conn_mode = true;
continue;
}
+ if (args[argidx] == "-cname") {
+ config.cname_mode = true;
+ continue;
+ }
if (args[argidx] == "-param") {
config.param_mode = true;
continue;
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 26585f43..465723f1 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -260,7 +260,7 @@ struct BtorDumper
if(it==std::end(line_ref))
{
++line_num;
- int address_bits = ceil(log(memory->size)/log(2));
+ int address_bits = ceil_log2(memory->size);
str = stringf("%d array %d %d", line_num, memory->width, address_bits);
line_ref[memory->name]=line_num;
f << stringf("%s\n", str.c_str());
@@ -272,7 +272,7 @@ struct BtorDumper
int dump_memory_next(const RTLIL::Memory* memory)
{
auto mem_it = line_ref.find(memory->name);
- int address_bits = ceil(log(memory->size)/log(2));
+ int address_bits = ceil_log2(memory->size);
if(mem_it==std::end(line_ref))
{
log("can not write next of a memory that is not dumped yet\n");
@@ -593,18 +593,18 @@ struct BtorDumper
bool l1_signed = cell->parameters.at(RTLIL::IdString("\\A_SIGNED")).as_bool();
//bool l2_signed = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
- l1_width = pow(2, ceil(log(l1_width)/log(2)));
+ l1_width = 1 << ceil_log2(l1_width);
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
- //log_assert(l2_width <= ceil(log(l1_width)/log(2)) );
+ //log_assert(l2_width <= ceil_log2(l1_width)) );
int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
- int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), ceil(log(l1_width)/log(2)));
+ int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), ceil_log2(l1_width));
int cell_output = ++line_num;
str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), l1_width, l1, l2);
f << stringf("%s\n", str.c_str());
- if(l2_width > ceil(log(l1_width)/log(2)))
+ if(l2_width > ceil_log2(l1_width))
{
- int extra_width = l2_width - ceil(log(l1_width)/log(2));
+ int extra_width = l2_width - ceil_log2(l1_width);
l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
++line_num;
str = stringf ("%d slice %d %d %d %d;6", line_num, extra_width, l2, l2_width-1, l2_width-extra_width);
@@ -821,7 +821,7 @@ struct BtorDumper
++line_num;
str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string();
RTLIL::Memory *memory = module->memories.at(RTLIL::IdString(str.c_str()));
- int address_bits = ceil(log(memory->size)/log(2));
+ int address_bits = ceil_log2(memory->size);
str = stringf("%d array %d %d", line_num, memory->width, address_bits);
f << stringf("%s\n", str.c_str());
++line_num;
diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc
index 4e0a393a..eacda273 100644
--- a/backends/smt2/Makefile.inc
+++ b/backends/smt2/Makefile.inc
@@ -1,3 +1,16 @@
OBJS += backends/smt2/smt2.o
+ifneq ($(CONFIG),mxe)
+ifneq ($(CONFIG),emcc)
+TARGETS += yosys-smtbmc
+
+yosys-smtbmc: backends/smt2/smtbmc.py
+ $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(__file__) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
+ $(Q) chmod +x $@.new
+ $(Q) mv $@.new $@
+
+$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
+endif
+endif
+
diff --git a/backends/smt2/example.v b/backends/smt2/example.v
new file mode 100644
index 00000000..b195266e
--- /dev/null
+++ b/backends/smt2/example.v
@@ -0,0 +1,11 @@
+module main(input clk);
+ reg [3:0] counter = 0;
+ always @(posedge clk) begin
+ if (counter == 10)
+ counter <= 0;
+ else
+ counter <= counter + 1;
+ end
+ assert property (counter != 15);
+ // assert property (counter <= 10);
+endmodule
diff --git a/backends/smt2/example.ys b/backends/smt2/example.ys
new file mode 100644
index 00000000..6fccb344
--- /dev/null
+++ b/backends/smt2/example.ys
@@ -0,0 +1,3 @@
+read_verilog -formal example.v
+hierarchy; proc; opt; memory -nordff -nomap; opt -fast
+write_smt2 -bv -mem -wires example.smt2
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index a544aa7d..c852921e 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -32,7 +32,7 @@ struct Smt2Worker
CellTypes ct;
SigMap sigmap;
RTLIL::Module *module;
- bool bvmode, memmode, regsmode, verbose;
+ bool bvmode, memmode, regsmode, wiresmode, verbose;
int idcounter;
std::vector<std::string> decls, trans;
@@ -44,8 +44,9 @@ struct Smt2Worker
std::map<Cell*, int> memarrays;
std::map<int, int> bvsizes;
- Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool regsmode, bool verbose) :
- ct(module->design), sigmap(module), module(module), bvmode(bvmode), memmode(memmode), regsmode(regsmode), verbose(verbose), idcounter(0)
+ Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool regsmode, bool wiresmode, bool verbose) :
+ ct(module->design), sigmap(module), module(module), bvmode(bvmode), memmode(memmode),
+ regsmode(regsmode), wiresmode(wiresmode), verbose(verbose), idcounter(0)
{
decls.push_back(stringf("(declare-sort |%s_s| 0)\n", log_id(module)));
@@ -132,7 +133,7 @@ struct Smt2Worker
std::string get_bool(RTLIL::SigSpec sig, const char *state_name = "state")
{
- return get_bool(sig.to_single_sigbit(), state_name);
+ return get_bool(sig.as_bit(), state_name);
}
std::string get_bv(RTLIL::SigSpec sig, const char *state_name = "state")
@@ -215,7 +216,7 @@ struct Smt2Worker
void export_gate(RTLIL::Cell *cell, std::string expr)
{
- RTLIL::SigBit bit = sigmap(cell->getPort("\\Y").to_single_sigbit());
+ RTLIL::SigBit bit = sigmap(cell->getPort("\\Y").as_bit());
std::string processed_expr;
for (char ch : expr) {
@@ -243,8 +244,8 @@ struct Smt2Worker
int width = GetSize(sig_y);
if (type == 's' || type == 'd' || type == 'b') {
- width = std::max(width, GetSize(cell->getPort("\\A")));
- width = std::max(width, GetSize(cell->getPort("\\B")));
+ width = max(width, GetSize(cell->getPort("\\A")));
+ width = max(width, GetSize(cell->getPort("\\B")));
}
if (cell->hasPort("\\A")) {
@@ -488,7 +489,7 @@ struct Smt2Worker
for (auto bit : SigSpec(wire))
if (reg_bits.count(bit))
is_register = true;
- if (wire->port_id || is_register || wire->get_bool_attribute("\\keep")) {
+ if (wire->port_id || is_register || wire->get_bool_attribute("\\keep") || (wiresmode && wire->name[0] == '\\')) {
RTLIL::SigSpec sig = sigmap(wire);
if (wire->port_input)
decls.push_back(stringf("; yosys-smt2-input %s %d\n", log_id(wire), wire->width));
@@ -496,7 +497,7 @@ struct Smt2Worker
decls.push_back(stringf("; yosys-smt2-output %s %d\n", log_id(wire), wire->width));
if (is_register)
decls.push_back(stringf("; yosys-smt2-register %s %d\n", log_id(wire), wire->width));
- if (wire->get_bool_attribute("\\keep"))
+ if (wire->get_bool_attribute("\\keep") || (wiresmode && wire->name[0] == '\\'))
decls.push_back(stringf("; yosys-smt2-wire %s %d\n", log_id(wire), wire->width));
if (bvmode && GetSize(sig) > 1) {
decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) (_ BitVec %d) %s)\n",
@@ -630,6 +631,7 @@ struct Smt2Worker
for (auto it : decls)
f << it;
+ f << stringf("; yosys-smt2-module %s\n", log_id(module));
f << stringf("(define-fun |%s_t| ((state |%s_s|) (next_state |%s_s|)) Bool ", log_id(module), log_id(module), log_id(module));
if (GetSize(trans) > 1) {
f << "(and\n";
@@ -695,6 +697,9 @@ struct Smt2Backend : public Backend {
log(" -regs\n");
log(" also create '<mod>_n' functions for all registers.\n");
log("\n");
+ log(" -wires\n");
+ log(" also create '<mod>_n' functions for all public wires.\n");
+ log("\n");
log(" -tpl <template_file>\n");
log(" use the given template file. the line containing only the token '%%%%'\n");
log(" is replaced with the regular output of this command.\n");
@@ -751,7 +756,7 @@ struct Smt2Backend : public Backend {
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::ifstream template_f;
- bool bvmode = false, memmode = false, regsmode = false, verbose = false;
+ bool bvmode = false, memmode = false, regsmode = false, wiresmode = false, verbose = false;
log_header("Executing SMT2 backend.\n");
@@ -777,6 +782,10 @@ struct Smt2Backend : public Backend {
regsmode = true;
continue;
}
+ if (args[argidx] == "-wires") {
+ wiresmode = true;
+ continue;
+ }
if (args[argidx] == "-verbose") {
verbose = true;
continue;
@@ -806,7 +815,7 @@ struct Smt2Backend : public Backend {
log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));
- Smt2Worker worker(module, bvmode, memmode, regsmode, verbose);
+ Smt2Worker worker(module, bvmode, memmode, regsmode, wiresmode, verbose);
worker.run();
worker.write(*f);
}
diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py
new file mode 100644
index 00000000..f2911b3e
--- /dev/null
+++ b/backends/smt2/smtbmc.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python3
+#
+# 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.
+#
+
+import os, sys, getopt, re
+##yosys-sys-path##
+from smtio import smtio, smtopts, mkvcd
+
+skip_steps = 0
+step_size = 1
+num_steps = 20
+vcdfile = None
+tempind = False
+assume_skipped = None
+topmod = None
+so = smtopts()
+
+
+def usage():
+ print("""
+yosys-smtbmc [options] <yosys_smt2_output>
+
+ -t <num_steps>, -t <skip_steps>:<num_steps>
+ default: skip_steps=0, num_steps=20
+
+ -u <start_step>
+ assume asserts in skipped steps in BMC
+
+ -S <step_size>
+ proof <step_size> time steps at once
+
+ -c <vcd_filename>
+ write counter-example to this VCD file
+ (hint: use 'write_smt2 -wires' for maximum
+ coverage of signals in generated VCD file)
+
+ -i
+ instead of BMC run temporal induction
+
+ -m <module_name>
+ name of the top module
+""" + so.helpmsg())
+ sys.exit(1)
+
+
+try:
+ opts, args = getopt.getopt(sys.argv[1:], so.optstr + "t:u:S:c:im:")
+except:
+ usage()
+
+for o, a in opts:
+ if o == "-t":
+ match = re.match(r"(\d+):(.*)", a)
+ if match:
+ skip_steps = int(match.group(1))
+ num_steps = int(match.group(2))
+ else:
+ num_steps = int(a)
+ elif o == "-u":
+ assume_skipped = int(a)
+ elif o == "-S":
+ step_size = int(a)
+ elif o == "-c":
+ vcdfile = a
+ elif o == "-i":
+ tempind = True
+ elif o == "-m":
+ topmod = a
+ elif so.handle(o, a):
+ pass
+ else:
+ usage()
+
+if len(args) != 1:
+ usage()
+
+
+smt = smtio(opts=so)
+
+print("%s Solver: %s" % (smt.timestamp(), so.solver))
+smt.setup("QF_AUFBV")
+
+debug_nets = set()
+debug_nets_re = re.compile(r"^; yosys-smt2-(input|output|register|wire) (\S+) (\d+)")
+
+with open(args[0], "r") as f:
+ for line in f:
+ match = debug_nets_re.match(line)
+ if match:
+ debug_nets.add(match.group(2))
+ if line.startswith("; yosys-smt2-module") and topmod is None:
+ topmod = line.split()[2]
+ smt.write(line)
+
+assert topmod is not None
+
+
+def write_vcd_model(steps):
+ print("%s Writing model to VCD file." % smt.timestamp())
+
+ vcd = mkvcd(open(vcdfile, "w"))
+ for netname in sorted(debug_nets):
+ width = len(smt.get_net_bin(topmod, netname, "s0"))
+ vcd.add_net(netname, width)
+
+ for i in range(steps):
+ vcd.set_time(i)
+ for netname in debug_nets:
+ vcd.set_net(netname, smt.get_net_bin(topmod, netname, "s%d" % i))
+
+ vcd.set_time(steps)
+
+
+if tempind:
+ retstatus = False
+ skip_counter = step_size
+ for step in range(num_steps, -1, -1):
+ smt.write("(declare-fun s%d () %s_s)" % (step, topmod))
+ smt.write("(assert (%s_u s%d))" % (topmod, step))
+
+ if step == num_steps:
+ smt.write("(assert (not (%s_a s%d)))" % (topmod, step))
+
+ else:
+ smt.write("(assert (%s_t s%d s%d))" % (topmod, step, step+1))
+ smt.write("(assert (%s_a s%d))" % (topmod, step))
+
+ if step > num_steps-skip_steps:
+ print("%s Skipping induction in step %d.." % (smt.timestamp(), step))
+ continue
+
+ skip_counter += 1
+ if skip_counter < step_size:
+ print("%s Skipping induction in step %d.." % (smt.timestamp(), step))
+ continue
+
+ skip_counter = 0
+ print("%s Trying induction in step %d.." % (smt.timestamp(), step))
+
+ if smt.check_sat() == "sat":
+ if step == 0:
+ print("%s Temporal induction failed!" % smt.timestamp())
+ if vcdfile is not None:
+ write_vcd_model(num_steps+1)
+
+ else:
+ print("%s Temporal induction successful." % smt.timestamp())
+ retstatus = True
+ break
+
+
+else: # not tempind
+ step = 0
+ retstatus = True
+ while step < num_steps:
+ smt.write("(declare-fun s%d () %s_s)" % (step, topmod))
+ smt.write("(assert (%s_u s%d))" % (topmod, step))
+
+ if step == 0:
+ smt.write("(assert (%s_i s0))" % (topmod))
+
+ else:
+ smt.write("(assert (%s_t s%d s%d))" % (topmod, step-1, step))
+
+ if step < skip_steps:
+ if assume_skipped is not None and step >= assume_skipped:
+ print("%s Skipping step %d (and assuming pass).." % (smt.timestamp(), step))
+ smt.write("(assert (%s_a s%d))" % (topmod, step))
+ else:
+ print("%s Skipping step %d.." % (smt.timestamp(), step))
+ step += 1
+ continue
+
+ last_check_step = step
+ for i in range(1, step_size):
+ if step+i < num_steps:
+ smt.write("(declare-fun s%d () %s_s)" % (step+i, topmod))
+ smt.write("(assert (%s_u s%d))" % (topmod, step+i))
+ smt.write("(assert (%s_t s%d s%d))" % (topmod, step+i-1, step+i))
+ last_check_step = step+i
+
+ if last_check_step == step:
+ print("%s Checking asserts in step %d.." % (smt.timestamp(), step))
+ else:
+ print("%s Checking asserts in steps %d to %d.." % (smt.timestamp(), step, last_check_step))
+ smt.write("(push 1)")
+
+ smt.write("(assert (not (and %s)))" % " ".join(["(%s_a s%d)" % (topmod, i) for i in range(step, last_check_step+1)]))
+
+ if smt.check_sat() == "sat":
+ print("%s BMC failed!" % smt.timestamp())
+ if vcdfile is not None:
+ write_vcd_model(step+step_size)
+ retstatus = False
+ break
+
+ else: # unsat
+ smt.write("(pop 1)")
+ for i in range(step, last_check_step+1):
+ smt.write("(assert (%s_a s%d))" % (topmod, i))
+
+ step += step_size
+
+
+smt.write("(exit)")
+smt.wait()
+
+print("%s Status: %s" % (smt.timestamp(), "PASSED" if retstatus else "FAILED (!)"))
+sys.exit(0 if retstatus else 1)
+
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
new file mode 100644
index 00000000..6e8bded7
--- /dev/null
+++ b/backends/smt2/smtio.py
@@ -0,0 +1,325 @@
+#!/usr/bin/env python3
+#
+# 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.
+#
+
+import sys
+import subprocess
+from select import select
+from time import time
+
+class smtio:
+ def __init__(self, solver=None, debug_print=None, debug_file=None, timeinfo=None, opts=None):
+ if opts is not None:
+ self.solver = opts.solver
+ self.debug_print = opts.debug_print
+ self.debug_file = opts.debug_file
+ self.timeinfo = opts.timeinfo
+
+ else:
+ self.solver = "z3"
+ self.debug_print = False
+ self.debug_file = None
+ self.timeinfo = True
+
+ if solver is not None:
+ self.solver = solver
+
+ if debug_print is not None:
+ self.debug_print = debug_print
+
+ if debug_file is not None:
+ self.debug_file = debug_file
+
+ if timeinfo is not None:
+ self.timeinfo = timeinfo
+
+ if self.solver == "yices":
+ popen_vargs = ['yices-smt2', '--incremental']
+
+ if self.solver == "z3":
+ popen_vargs = ['z3', '-smt2', '-in']
+
+ if self.solver == "cvc4":
+ popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2']
+
+ if self.solver == "mathsat":
+ popen_vargs = ['mathsat']
+
+ self.p = subprocess.Popen(popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ self.start_time = time()
+
+ def setup(self, logic="ALL", info=None):
+ self.write("(set-logic %s)" % logic)
+ if info is not None:
+ self.write("(set-info :source |%s|)" % info)
+ self.write("(set-info :smt-lib-version 2.5)")
+ self.write("(set-info :category \"industrial\")")
+
+ def timestamp(self):
+ secs = int(time() - self.start_time)
+ return "## %6d %3d:%02d:%02d " % (secs, secs // (60*60), (secs // 60) % 60, secs % 60)
+
+ def write(self, stmt):
+ stmt = stmt.strip()
+ if self.debug_print:
+ print("> %s" % stmt)
+ if self.debug_file:
+ print(stmt, file=self.debug_file)
+ self.debug_file.flush()
+ self.p.stdin.write(bytes(stmt + "\n", "ascii"))
+ self.p.stdin.flush()
+
+ def read(self):
+ stmt = []
+ count_brackets = 0
+
+ while True:
+ line = self.p.stdout.readline().decode("ascii").strip()
+ count_brackets += line.count("(")
+ count_brackets -= line.count(")")
+ stmt.append(line)
+ if self.debug_print:
+ print("< %s" % line)
+ if count_brackets == 0:
+ break
+ if not self.p.poll():
+ print("SMT Solver terminated unexpectedly: %s" % "".join(stmt))
+ sys.exit(1)
+
+ stmt = "".join(stmt)
+ if stmt.startswith("(error"):
+ print("SMT Solver Error: %s" % stmt, file=sys.stderr)
+ sys.exit(1)
+
+ return stmt
+
+ def check_sat(self):
+ if self.debug_print:
+ print("> (check-sat)")
+ if self.debug_file:
+ print("; running check-sat..", file=self.debug_file)
+ self.debug_file.flush()
+
+ self.p.stdin.write(bytes("(check-sat)\n", "ascii"))
+ self.p.stdin.flush()
+
+ if self.timeinfo:
+ i = 0
+ s = "/-\|"
+
+ count = 0
+ num_bs = 0
+ while select([self.p.stdout], [], [], 0.1) == ([], [], []):
+ count += 1
+
+ if count < 25:
+ continue
+
+ if count % 10 == 0 or count == 25:
+ secs = count // 10
+
+ if secs < 60:
+ m = "(%d seconds)" % secs
+ elif secs < 60*60:
+ m = "(%d seconds -- %d:%02d)" % (secs, secs // 60, secs % 60)
+ else:
+ m = "(%d seconds -- %d:%02d:%02d)" % (secs, secs // (60*60), (secs // 60) % 60, secs % 60)
+
+ print("%s %s %c" % ("\b \b" * num_bs, m, s[i]), end="", file=sys.stderr)
+ num_bs = len(m) + 3
+
+ else:
+ print("\b" + s[i], end="", file=sys.stderr)
+
+ sys.stderr.flush()
+ i = (i + 1) % len(s)
+
+ if num_bs != 0:
+ print("\b \b" * num_bs, end="", file=sys.stderr)
+ sys.stderr.flush()
+
+ result = self.read()
+ if self.debug_file:
+ print("(set-info :status %s)" % result, file=self.debug_file)
+ print("(check-sat)", file=self.debug_file)
+ self.debug_file.flush()
+ return result
+
+ def parse(self, stmt):
+ def worker(stmt):
+ if stmt[0] == '(':
+ expr = []
+ cursor = 1
+ while stmt[cursor] != ')':
+ el, le = worker(stmt[cursor:])
+ expr.append(el)
+ cursor += le
+ return expr, cursor+1
+
+ if stmt[0] == '|':
+ expr = "|"
+ cursor = 1
+ while stmt[cursor] != '|':
+ expr += stmt[cursor]
+ cursor += 1
+ expr += "|"
+ return expr, cursor+1
+
+ if stmt[0] in [" ", "\t", "\r", "\n"]:
+ el, le = worker(stmt[1:])
+ return el, le+1
+
+ expr = ""
+ cursor = 0
+ while stmt[cursor] not in ["(", ")", "|", " ", "\t", "\r", "\n"]:
+ expr += stmt[cursor]
+ cursor += 1
+ return expr, cursor
+ return worker(stmt)[0]
+
+ def bv2hex(self, v):
+ h = ""
+ v = bv2bin(v)
+ while len(v) > 0:
+ d = 0
+ if len(v) > 0 and v[-1] == "1": d += 1
+ if len(v) > 1 and v[-2] == "1": d += 2
+ if len(v) > 2 and v[-3] == "1": d += 4
+ if len(v) > 3 and v[-4] == "1": d += 8
+ h = hex(d)[2:] + h
+ if len(v) < 4: break
+ v = v[:-4]
+ return h
+
+ def bv2bin(self, v):
+ if v == "true": return "1"
+ if v == "false": return "0"
+ if v.startswith("#b"):
+ return v[2:]
+ if v.startswith("#x"):
+ digits = []
+ for d in v[2:]:
+ if d == "0": digits.append("0000")
+ if d == "1": digits.append("0001")
+ if d == "2": digits.append("0010")
+ if d == "3": digits.append("0011")
+ if d == "4": digits.append("0100")
+ if d == "5": digits.append("0101")
+ if d == "6": digits.append("0110")
+ if d == "7": digits.append("0111")
+ if d == "8": digits.append("1000")
+ if d == "9": digits.append("1001")
+ if d in ("a", "A"): digits.append("1010")
+ if d in ("b", "B"): digits.append("1011")
+ if d in ("c", "C"): digits.append("1100")
+ if d in ("d", "D"): digits.append("1101")
+ if d in ("e", "E"): digits.append("1110")
+ if d in ("f", "F"): digits.append("1111")
+ return "".join(digits)
+ assert False
+
+ def get(self, expr):
+ self.write("(get-value (%s))" % (expr))
+ return self.parse(self.read())[0][1]
+
+ def get_net(self, mod_name, net_name, state_name):
+ return self.get("(|%s_n %s| %s)" % (mod_name, net_name, state_name))
+
+ def get_net_bool(self, mod_name, net_name, state_name):
+ v = self.get_net(mod_name, net_name, state_name)
+ assert v in ["true", "false"]
+ return 1 if v == "true" else 0
+
+ def get_net_hex(self, mod_name, net_name, state_name):
+ return self.bv2hex(self.get_net(mod_name, net_name, state_name))
+
+ def get_net_bin(self, mod_name, net_name, state_name):
+ return self.bv2bin(self.get_net(mod_name, net_name, state_name))
+
+ def wait(self):
+ self.p.wait()
+
+
+class smtopts:
+ def __init__(self):
+ self.optstr = "s:d:vp"
+ self.solver = "z3"
+ self.debug_print = False
+ self.debug_file = None
+ self.timeinfo = True
+
+ def handle(self, o, a):
+ if o == "-s":
+ self.solver = a
+ elif o == "-v":
+ self.debug_print = True
+ elif o == "-p":
+ self.timeinfo = True
+ elif o == "-d":
+ self.debug_file = open(a, "w")
+ else:
+ return False
+ return True
+
+ def helpmsg(self):
+ return """
+ -s <solver>
+ set SMT solver: z3, cvc4, yices, mathsat
+ default: z3
+
+ -v
+ enable debug output
+
+ -p
+ disable timer display during solving
+
+ -d <filename>
+ write smt2 statements to file
+"""
+
+
+class mkvcd:
+ def __init__(self, f):
+ self.f = f
+ self.t = -1
+ self.nets = dict()
+
+ def add_net(self, name, width):
+ assert self.t == -1
+ key = "n%d" % len(self.nets)
+ self.nets[name] = (key, width)
+
+ def set_net(self, name, bits):
+ assert name in self.nets
+ assert self.t >= 0
+ print("b%s %s" % (bits, self.nets[name][0]), file=self.f)
+
+ def set_time(self, t):
+ assert t >= self.t
+ if t != self.t:
+ if self.t == -1:
+ print("$var event 1 ! smt_clock $end", file=self.f)
+ for name in sorted(self.nets):
+ key, width = self.nets[name]
+ print("$var wire %d %s %s $end" % (width, key, name), file=self.f)
+ print("$enddefinitions $end", file=self.f)
+ self.t = t
+ assert self.t >= 0
+ print("#%d" % self.t, file=self.f)
+ print("1!", file=self.f)
+
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index fdf022c5..b29a88ac 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -244,13 +244,13 @@ struct SmvWorker
int width_y = GetSize(cell->getPort("\\Y"));
int shift_b_width = GetSize(sig_b);
- int width_ay = std::max(GetSize(sig_a), width_y);
+ int width_ay = max(GetSize(sig_a), width_y);
int width = width_ay;
for (int i = 1, j = 0;; i <<= 1, j++)
if (width_ay < i) {
width = i-1;
- shift_b_width = std::min(shift_b_width, j);
+ shift_b_width = min(shift_b_width, j);
break;
}
@@ -361,8 +361,8 @@ struct SmvWorker
if (cell->type.in("$div", "$mod"))
{
int width_y = GetSize(cell->getPort("\\Y"));
- int width = std::max(width_y, GetSize(cell->getPort("\\A")));
- width = std::max(width, GetSize(cell->getPort("\\B")));
+ int width = max(width_y, GetSize(cell->getPort("\\A")));
+ width = max(width, GetSize(cell->getPort("\\B")));
string expr_a, expr_b, op;
if (cell->type == "$div") op = "/";
@@ -384,7 +384,7 @@ struct SmvWorker
if (cell->type.in("$eq", "$ne", "$eqx", "$nex", "$lt", "$le", "$ge", "$gt"))
{
- int width = std::max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B")));
+ int width = max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B")));
string expr_a, expr_b, op;
if (cell->type == "$eq") op = "=";
diff --git a/techlibs/xilinx/example_basys3/README b/examples/basys3/README
index 85b6eab1..0ce71729 100644
--- a/techlibs/xilinx/example_basys3/README
+++ b/examples/basys3/README
@@ -2,6 +2,9 @@
A simple example design, based on the Digilent BASYS3 board
===========================================================
+This example uses Yosys for synthesis and Xilinx Vivado
+for place&route and bit-stream creation.
+
Running Yosys:
yosys run_yosys.ys
diff --git a/techlibs/xilinx/example_basys3/example.v b/examples/basys3/example.v
index 2b01a22a..2b01a22a 100644
--- a/techlibs/xilinx/example_basys3/example.v
+++ b/examples/basys3/example.v
diff --git a/techlibs/xilinx/example_basys3/example.xdc b/examples/basys3/example.xdc
index c1fd0e92..c1fd0e92 100644
--- a/techlibs/xilinx/example_basys3/example.xdc
+++ b/examples/basys3/example.xdc
diff --git a/techlibs/xilinx/example_basys3/run.sh b/examples/basys3/run.sh
index 10f05910..10f05910 100644
--- a/techlibs/xilinx/example_basys3/run.sh
+++ b/examples/basys3/run.sh
diff --git a/techlibs/xilinx/example_basys3/run_prog.tcl b/examples/basys3/run_prog.tcl
index d711af84..d711af84 100644
--- a/techlibs/xilinx/example_basys3/run_prog.tcl
+++ b/examples/basys3/run_prog.tcl
diff --git a/techlibs/xilinx/example_basys3/run_vivado.tcl b/examples/basys3/run_vivado.tcl
index c3b6a610..c3b6a610 100644
--- a/techlibs/xilinx/example_basys3/run_vivado.tcl
+++ b/examples/basys3/run_vivado.tcl
diff --git a/techlibs/xilinx/example_basys3/run_yosys.ys b/examples/basys3/run_yosys.ys
index 4541826d..4541826d 100644
--- a/techlibs/xilinx/example_basys3/run_yosys.ys
+++ b/examples/basys3/run_yosys.ys
diff --git a/techlibs/cmos/cmos_cells.lib b/examples/cmos/cmos_cells.lib
index 1b0bf845..1b0bf845 100644
--- a/techlibs/cmos/cmos_cells.lib
+++ b/examples/cmos/cmos_cells.lib
diff --git a/techlibs/cmos/cmos_cells.sp b/examples/cmos/cmos_cells.sp
index 673b20d0..673b20d0 100644
--- a/techlibs/cmos/cmos_cells.sp
+++ b/examples/cmos/cmos_cells.sp
diff --git a/techlibs/cmos/cmos_cells.v b/examples/cmos/cmos_cells.v
index 27278fac..27278fac 100644
--- a/techlibs/cmos/cmos_cells.v
+++ b/examples/cmos/cmos_cells.v
diff --git a/techlibs/cmos/counter.v b/examples/cmos/counter.v
index f2165872..f2165872 100644
--- a/techlibs/cmos/counter.v
+++ b/examples/cmos/counter.v
diff --git a/techlibs/cmos/counter.ys b/examples/cmos/counter.ys
index a784f346..a784f346 100644
--- a/techlibs/cmos/counter.ys
+++ b/examples/cmos/counter.ys
diff --git a/techlibs/cmos/testbench.sh b/examples/cmos/testbench.sh
index 061704b6..061704b6 100644
--- a/techlibs/cmos/testbench.sh
+++ b/examples/cmos/testbench.sh
diff --git a/techlibs/cmos/testbench.sp b/examples/cmos/testbench.sp
index 95d2f67c..95d2f67c 100644
--- a/techlibs/cmos/testbench.sp
+++ b/examples/cmos/testbench.sp
diff --git a/misc/example.cc b/examples/cxx-api/demomain.cc
index 2e35bcd4..a6459330 100644
--- a/misc/example.cc
+++ b/examples/cxx-api/demomain.cc
@@ -1,5 +1,5 @@
// Note: Set ENABLE_LIBYOSYS=1 in Makefile or Makefile.conf to build libyosys.so
-// yosys-config --exec --cxx -o example --cxxflags --ldflags example.cc -lyosys -lstdc++
+// yosys-config --exec --cxx -o demomain --cxxflags --ldflags demomain.cc -lyosys -lstdc++
#include <kernel/yosys.h>
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 3e163bae..834ee82a 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -820,7 +820,7 @@ uint64_t AstNode::asInt(bool is_signed)
}
if (type == AST_REALVALUE)
- return realvalue;
+ return uint64_t(realvalue);
log_abort();
}
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index c322faf7..9fc59037 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -379,7 +379,7 @@ struct AST_INTERNAL::ProcessGenerator
// e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this
// function is called to clean up the first two assignments as they are overwritten by
// the third assignment.
- void removeSignalFromCaseTree(const std::set<RTLIL::SigBit> &pattern, RTLIL::CaseRule *cs)
+ void removeSignalFromCaseTree(const RTLIL::SigSpec &pattern, RTLIL::CaseRule *cs)
{
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
it->first.remove2(pattern, &it->second);
@@ -434,7 +434,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
}
- removeSignalFromCaseTree(lvalue.to_sigbit_set(), current_case);
+ removeSignalFromCaseTree(lvalue, current_case);
remove_unwanted_lvalue_bits(lvalue, rvalue);
current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue));
}
@@ -511,7 +511,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
- removeSignalFromCaseTree(this_case_eq_lvalue.to_sigbit_set(), current_case);
+ removeSignalFromCaseTree(this_case_eq_lvalue, current_case);
addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp);
}
break;
@@ -520,6 +520,11 @@ struct AST_INTERNAL::ProcessGenerator
log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
break;
+ case AST_PARAMETER:
+ case AST_LOCALPARAM:
+ log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
+ break;
+
case AST_TCALL:
case AST_FOR:
break;
@@ -547,14 +552,14 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
switch (type)
{
case AST_CONSTANT:
- width_hint = std::max(width_hint, int(bits.size()));
+ width_hint = max(width_hint, int(bits.size()));
if (!is_signed)
sign_hint = false;
break;
case AST_REALVALUE:
*found_real = true;
- width_hint = std::max(width_hint, 32);
+ width_hint = max(width_hint, 32);
break;
case AST_IDENTIFIER:
@@ -617,7 +622,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
this_width = range->range_left - range->range_right + 1;
sign_hint = false;
}
- width_hint = std::max(width_hint, this_width);
+ width_hint = max(width_hint, this_width);
if (!id_ast->is_signed)
sign_hint = false;
break;
@@ -627,7 +632,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sign_hint);
- width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int());
+ width_hint = max(width_hint, children[0]->bitsAsConst().as_int());
break;
case AST_TO_SIGNED:
@@ -646,7 +651,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
child->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
this_width += sub_width_hint;
}
- width_hint = std::max(width_hint, this_width);
+ width_hint = max(width_hint, this_width);
sign_hint = false;
break;
@@ -655,7 +660,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
- width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
+ width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
sign_hint = false;
break;
@@ -678,7 +683,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_REDUCE_XOR:
case AST_REDUCE_XNOR:
case AST_REDUCE_BOOL:
- width_hint = std::max(width_hint, 1);
+ width_hint = max(width_hint, 1);
sign_hint = false;
break;
@@ -698,7 +703,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_NEX:
case AST_GE:
case AST_GT:
- width_hint = std::max(width_hint, 1);
+ width_hint = max(width_hint, 1);
sign_hint = false;
break;
@@ -714,7 +719,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_LOGIC_AND:
case AST_LOGIC_OR:
case AST_LOGIC_NOT:
- width_hint = std::max(width_hint, 1);
+ width_hint = max(width_hint, 1);
sign_hint = false;
break;
@@ -729,7 +734,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id2ast->children[0]->range_valid)
log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1;
- width_hint = std::max(width_hint, this_width);
+ width_hint = max(width_hint, this_width);
break;
// everything should have been handled above -> print error if not.
@@ -1054,7 +1059,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
detectSignWidth(width_hint, sign_hint);
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint);
- int width = std::max(left.size(), right.size());
+ int width = max(left.size(), right.size());
if (width_hint > 0)
width = width_hint;
is_signed = children[0]->is_signed && children[1]->is_signed;
@@ -1068,7 +1073,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (0) { case AST_REDUCE_XNOR: type_name = "$reduce_xnor"; }
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- RTLIL::SigSpec sig = uniop2rtlil(this, type_name, std::max(width_hint, 1), arg);
+ RTLIL::SigSpec sig = uniop2rtlil(this, type_name, max(width_hint, 1), arg);
return sig;
}
@@ -1077,7 +1082,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (0) { case AST_REDUCE_BOOL: type_name = "$reduce_bool"; }
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, std::max(width_hint, 1), arg) : arg;
+ RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, max(width_hint, 1), arg) : arg;
return sig;
}
@@ -1123,7 +1128,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (0) { case AST_GE: type_name = "$ge"; }
if (0) { case AST_GT: type_name = "$gt"; }
{
- int width = std::max(width_hint, 1);
+ int width = max(width_hint, 1);
width_hint = -1, sign_hint = true;
children[0]->detectSignWidthWorker(width_hint, sign_hint);
children[1]->detectSignWidthWorker(width_hint, sign_hint);
@@ -1145,7 +1150,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint);
#if 0
- int width = std::max(left.size(), right.size());
+ int width = max(left.size(), right.size());
if (width > width_hint && width_hint > 0)
width = width_hint;
if (width < width_hint) {
@@ -1154,10 +1159,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (type == AST_SUB && (!children[0]->is_signed || !children[1]->is_signed))
width = width_hint;
if (type == AST_MUL)
- width = std::min(left.size() + right.size(), width_hint);
+ width = min(left.size() + right.size(), width_hint);
}
#else
- int width = std::max(std::max(left.size(), right.size()), width_hint);
+ int width = max(max(left.size(), right.size()), width_hint);
#endif
is_signed = children[0]->is_signed && children[1]->is_signed;
return binop2rtlil(this, type_name, width, left, right);
@@ -1169,14 +1174,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
{
RTLIL::SigSpec left = children[0]->genRTLIL();
RTLIL::SigSpec right = children[1]->genRTLIL();
- return binop2rtlil(this, type_name, std::max(width_hint, 1), left, right);
+ return binop2rtlil(this, type_name, max(width_hint, 1), left, right);
}
// generate cells for unary operations: $logic_not
case AST_LOGIC_NOT:
{
RTLIL::SigSpec arg = children[0]->genRTLIL();
- return uniop2rtlil(this, "$logic_not", std::max(width_hint, 1), arg);
+ return uniop2rtlil(this, "$logic_not", max(width_hint, 1), arg);
}
// generate multiplexer for ternary operator (aka ?:-operator)
@@ -1192,7 +1197,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (cond.size() > 1)
cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false);
- int width = std::max(val1.size(), val2.size());
+ int width = max(val1.size(), val2.size());
is_signed = children[1]->is_signed && children[2]->is_signed;
widthExtend(this, val1, width, is_signed);
widthExtend(this, val2, width, is_signed);
@@ -1252,7 +1257,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (type == AST_MEMINIT) {
if (children[2]->type != AST_CONSTANT)
log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum);
- num_words = children[2]->asInt(false);
+ num_words = int(children[2]->asInt(false));
cell->parameters["\\WORDS"] = RTLIL::Const(num_words);
}
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 861c3bcc..2621be49 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -398,7 +398,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
children[0]->detectSignWidth(backup_width_hint, backup_sign_hint);
children[1]->detectSignWidth(width_hint, sign_hint);
- width_hint = std::max(width_hint, backup_width_hint);
+ width_hint = max(width_hint, backup_width_hint);
child_0_is_self_determined = true;
break;
@@ -412,7 +412,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
if (!children[1]->range_valid)
log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
- width_hint = std::max(width_hint, children[1]->range_left - children[1]->range_right + 1);
+ width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);
}
break;
@@ -733,8 +733,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (auto range : children[1]->children) {
if (!range->range_valid)
log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum);
- multirange_dimensions.push_back(std::min(range->range_left, range->range_right));
- multirange_dimensions.push_back(std::max(range->range_left, range->range_right) - std::min(range->range_left, range->range_right) + 1);
+ multirange_dimensions.push_back(min(range->range_left, range->range_right));
+ multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);
total_size *= multirange_dimensions.back();
}
delete children[1];
@@ -1013,7 +1013,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::vector<AstNode*> new_children;
for (size_t i = 0; i < children.size(); i++)
- if (children[i]->type == AST_WIRE) {
+ if (children[i]->type == AST_WIRE || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) {
children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(children[i]);
current_scope[children[i]->str] = children[i];
@@ -1169,7 +1169,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum);
newNode = new AstNode(AST_GENBLOCK);
- int num = std::max(children.at(0)->range_left, children.at(0)->range_right) - std::min(children.at(0)->range_left, children.at(0)->range_right) + 1;
+ int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1;
for (int i = 0; i < num; i++) {
int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i;
@@ -1705,7 +1705,7 @@ skip_dynamic_range_lvalue_expansion:;
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_addr->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
- start_addr = node_addr->asInt(false);
+ start_addr = int(node_addr->asInt(false));
}
if (GetSize(children) > 3) {
@@ -1713,7 +1713,7 @@ skip_dynamic_range_lvalue_expansion:;
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_addr->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
- finish_addr = node_addr->asInt(false);
+ finish_addr = int(node_addr->asInt(false));
}
bool unconditional_init = false;
@@ -1773,6 +1773,8 @@ skip_dynamic_range_lvalue_expansion:;
size_t arg_count = 0;
std::map<std::string, std::string> replace_rules;
+ vector<AstNode*> added_mod_children;
+ dict<std::string, AstNode*> wire_cache;
if (current_block == NULL)
{
@@ -1865,17 +1867,39 @@ skip_dynamic_range_lvalue_expansion:;
}
for (auto child : decl->children)
- if (child->type == AST_WIRE)
+ if (child->type == AST_WIRE || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
{
- AstNode *wire = child->clone();
- wire->str = prefix + wire->str;
- wire->port_id = 0;
- wire->is_input = false;
- wire->is_output = false;
- current_ast_mod->children.push_back(wire);
- while (wire->simplify(true, false, false, 1, -1, false, false)) { }
+ AstNode *wire = nullptr;
+
+ if (wire_cache.count(child->str))
+ {
+ wire = wire_cache.at(child->str);
+ if (wire->children.empty()) {
+ for (auto c : child->children)
+ wire->children.push_back(c->clone());
+ } else {
+ if (!child->children.empty())
+ log_error("Incompatible re-declaration of wire %s at %s:%d.\n", child->str.c_str(), filename.c_str(), linenum);
+ }
+ }
+ else
+ {
+ wire = child->clone();
+ wire->str = prefix + wire->str;
+ wire->port_id = 0;
+ wire->is_input = false;
+ wire->is_output = false;
+ wire_cache[child->str] = wire;
+
+ current_ast_mod->children.push_back(wire);
+ added_mod_children.push_back(wire);
+ }
+
+ if (child->type == AST_WIRE)
+ while (wire->simplify(true, false, false, 1, -1, false, false)) { }
replace_rules[child->str] = wire->str;
+ current_scope[wire->str] = wire;
if ((child->is_input || child->is_output) && arg_count < children.size())
{
@@ -1895,8 +1919,13 @@ skip_dynamic_range_lvalue_expansion:;
}
}
+ for (auto child : added_mod_children) {
+ child->replace_ids(prefix, replace_rules);
+ while (child->simplify(true, false, false, 1, -1, false, false)) { }
+ }
+
for (auto child : decl->children)
- if (child->type != AST_WIRE)
+ if (child->type != AST_WIRE && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM)
{
AstNode *stmt = child->clone();
stmt->replace_ids(prefix, replace_rules);
@@ -2043,7 +2072,7 @@ skip_dynamic_range_lvalue_expansion:;
if (0) { case AST_GE: const_func = RTLIL::const_ge; }
if (0) { case AST_GT: const_func = RTLIL::const_gt; }
if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) {
- int cmp_width = std::max(children[0]->bits.size(), children[1]->bits.size());
+ int cmp_width = max(children[0]->bits.size(), children[1]->bits.size());
bool cmp_signed = children[0]->is_signed && children[1]->is_signed;
RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed),
children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1);
@@ -2236,7 +2265,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid);
int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right;
- int range_min = std::min(range_left, range_right), range_max = std::max(range_left, range_right);
+ int range_min = min(range_left, range_right), range_max = max(range_left, range_right);
if (start_addr < 0)
start_addr = range_min;
@@ -2720,7 +2749,7 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
if (mem_size < 0)
mem_size *= -1;
- mem_size += std::min(children[1]->range_left, children[1]->range_right) + 1;
+ mem_size += min(children[1]->range_left, children[1]->range_right) + 1;
addr_bits = 1;
while ((1 << addr_bits) < mem_size)
@@ -2756,8 +2785,8 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia
if (!children.at(0)->range_valid)
log_error("Non-constant range in %s:%d (called from %s:%d).\n",
filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum);
- offset = std::min(children.at(0)->range_left, children.at(0)->range_right);
- width = std::min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
+ offset = min(children.at(0)->range_left, children.at(0)->range_right);
+ width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
}
offset -= variables.at(str).offset;
std::vector<RTLIL::State> &var_bits = variables.at(str).val.bits;
@@ -2797,7 +2826,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
log_error("Can't determine size of variable %s in %s:%d (called from %s:%d).\n",
child->str.c_str(), child->filename.c_str(), child->linenum, fcall->filename.c_str(), fcall->linenum);
variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1);
- variables[child->str].offset = std::min(child->range_left, child->range_right);
+ variables[child->str].offset = min(child->range_left, child->range_right);
variables[child->str].is_signed = child->is_signed;
if (child->is_input && argidx < fcall->children.size())
variables[child->str].val = fcall->children.at(argidx++)->bitsAsConst(variables[child->str].val.bits.size());
@@ -2856,7 +2885,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (!range->range_valid)
log_error("Non-constant range in %s:%d (called from %s:%d).\n",
range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum);
- int offset = std::min(range->range_left, range->range_right);
+ int offset = min(range->range_left, range->range_right);
int width = std::abs(range->range_left - range->range_right) + 1;
varinfo_t &v = variables[stmt->children.at(0)->str];
RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size());
diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc
index 9f2e08df..ee0e771e 100644
--- a/frontends/blif/blifparse.cc
+++ b/frontends/blif/blifparse.cc
@@ -49,11 +49,42 @@ static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count,
}
}
-void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name)
+void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean)
{
RTLIL::Module *module = nullptr;
RTLIL::Const *lutptr = NULL;
RTLIL::State lut_default_state = RTLIL::State::Sx;
+ int blif_maxnum = 0;
+
+ auto blif_wire = [&](const std::string &wire_name) -> Wire*
+ {
+ if (wire_name[0] == '$')
+ {
+ for (int i = 0; i+1 < GetSize(wire_name); i++)
+ {
+ if (wire_name[i] != '$')
+ continue;
+
+ int len = 0;
+ while (i+len+1 < GetSize(wire_name) && '0' <= wire_name[i+len+1] && wire_name[i+len+1] <= '9')
+ len++;
+
+ if (len > 0) {
+ string num_str = wire_name.substr(i+1, len);
+ int num = atoi(num_str.c_str()) & 0x0fffffff;
+ blif_maxnum = std::max(blif_maxnum, num);
+ }
+ }
+ }
+
+ IdString wire_id = RTLIL::escape_id(wire_name);
+ Wire *wire = module->wire(wire_id);
+
+ if (wire == nullptr)
+ wire = module->addWire(wire_id);
+
+ return wire;
+ };
dict<RTLIL::IdString, RTLIL::Const> *obj_attributes = nullptr;
dict<RTLIL::IdString, RTLIL::Const> *obj_parameters = nullptr;
@@ -103,8 +134,41 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name)
if (module == nullptr)
goto error;
- if (!strcmp(cmd, ".end")) {
+ if (!strcmp(cmd, ".end"))
+ {
module->fixup_ports();
+
+ if (run_clean)
+ {
+ Const buffer_lut(vector<RTLIL::State>({State::S0, State::S1}));
+ vector<Cell*> remove_cells;
+
+ for (auto cell : module->cells())
+ if (cell->type == "$lut" && cell->getParam("\\LUT") == buffer_lut) {
+ module->connect(cell->getPort("\\Y"), cell->getPort("\\A"));
+ remove_cells.push_back(cell);
+ }
+
+ for (auto cell : remove_cells)
+ module->remove(cell);
+
+ Wire *true_wire = module->wire("$true");
+ Wire *false_wire = module->wire("$false");
+ Wire *undef_wire = module->wire("$undef");
+
+ if (true_wire != nullptr)
+ module->rename(true_wire, stringf("$true$%d", ++blif_maxnum));
+
+ if (false_wire != nullptr)
+ module->rename(false_wire, stringf("$false$%d", ++blif_maxnum));
+
+ if (undef_wire != nullptr)
+ module->rename(undef_wire, stringf("$undef$%d", ++blif_maxnum));
+
+ autoidx = std::max(autoidx, blif_maxnum+1);
+ blif_maxnum = 0;
+ }
+
module = nullptr;
obj_attributes = nullptr;
obj_parameters = nullptr;
@@ -114,7 +178,10 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name)
if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) {
char *p;
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
- RTLIL::Wire *wire = module->addWire(stringf("\\%s", p));
+ RTLIL::IdString wire_name(stringf("\\%s", p));
+ RTLIL::Wire *wire = module->wire(wire_name);
+ if (wire == nullptr)
+ wire = module->addWire(wire_name);
if (!strcmp(cmd, ".inputs"))
wire->port_input = true;
else
@@ -162,37 +229,26 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name)
char *init = strtok(NULL, " \t\r\n");
RTLIL::Cell *cell = nullptr;
- if (module->wires_.count(RTLIL::escape_id(d)) == 0)
- module->addWire(RTLIL::escape_id(d));
-
- if (module->wires_.count(RTLIL::escape_id(q)) == 0)
- module->addWire(RTLIL::escape_id(q));
-
if (clock == nullptr && edge != nullptr) {
init = edge;
edge = nullptr;
}
if (init != nullptr && (init[0] == '0' || init[0] == '1'))
- module->wire(RTLIL::escape_id(d))->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1);
+ blif_wire(d)->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1);
if (clock == nullptr)
goto no_latch_clock;
- if (module->wires_.count(RTLIL::escape_id(clock)) == 0)
- module->addWire(RTLIL::escape_id(clock));
-
if (!strcmp(edge, "re"))
- cell = module->addDff(NEW_ID, module->wire(RTLIL::escape_id(clock)),
- module->wire(RTLIL::escape_id(d)), module->wire(RTLIL::escape_id(q)));
+ cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
else if (!strcmp(edge, "fe"))
- cell = module->addDff(NEW_ID, module->wire(RTLIL::escape_id(clock)),
- module->wire(RTLIL::escape_id(d)), module->wire(RTLIL::escape_id(q)), false);
+ cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
else {
no_latch_clock:
cell = module->addCell(NEW_ID, dff_name);
- cell->setPort("\\D", module->wires_.at(RTLIL::escape_id(d)));
- cell->setPort("\\Q", module->wires_.at(RTLIL::escape_id(q)));
+ cell->setPort("\\D", blif_wire(d));
+ cell->setPort("\\Q", blif_wire(q));
}
obj_attributes = &cell->attributes;
@@ -211,12 +267,10 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name)
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
char *q = strchr(p, '=');
- if (q == NULL || !q[0] || !q[1])
+ if (q == NULL || !q[0])
goto error;
*(q++) = 0;
- if (module->wires_.count(RTLIL::escape_id(q)) == 0)
- module->addWire(RTLIL::escape_id(q));
- cell->setPort(RTLIL::escape_id(p), module->wires_.at(RTLIL::escape_id(q)));
+ cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec());
}
obj_attributes = &cell->attributes;
@@ -237,13 +291,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name)
if (q == NULL)
goto error;
- if (module->wires_.count(RTLIL::escape_id(p)) == 0)
- module->addWire(RTLIL::escape_id(p));
-
- if (module->wires_.count(RTLIL::escape_id(q)) == 0)
- module->addWire(RTLIL::escape_id(q));
-
- module->connect(module->wires_.at(RTLIL::escape_id(q)), module->wires_.at(RTLIL::escape_id(p)));
+ module->connect(blif_wire(q), blif_wire(p));
continue;
}
@@ -251,19 +299,13 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name)
{
char *p;
RTLIL::SigSpec input_sig, output_sig;
- while ((p = strtok(NULL, " \t\r\n")) != NULL) {
- RTLIL::Wire *wire;
- if (module->wires_.count(RTLIL::escape_id(p)) > 0) {
- wire = module->wires_.at(RTLIL::escape_id(p));
- } else {
- wire = module->addWire(RTLIL::escape_id(p));
- }
- input_sig.append(wire);
- }
+ while ((p = strtok(NULL, " \t\r\n")) != NULL)
+ input_sig.append(blif_wire(p));
output_sig = input_sig.extract(input_sig.size()-1, 1);
input_sig = input_sig.extract(0, input_sig.size()-1);
- if (input_sig.size() == 0) {
+ if (input_sig.size() == 0)
+ {
RTLIL::State state = RTLIL::State::Sa;
while (1) {
if (!read_next_line(buffer, buffer_size, line_count, f))
@@ -288,9 +330,12 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name)
goto error;
}
}
+
finished_parsing_constval:
if (state == RTLIL::State::Sa)
state = RTLIL::State::S0;
+ if (output_sig.as_wire()->name == "$undef")
+ state = RTLIL::State::Sx;
module->connect(RTLIL::SigSig(output_sig, state));
goto continue_without_read;
}
@@ -367,7 +412,7 @@ struct BlifFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
- parse_blif(design, *f, "\\DFF");
+ parse_blif(design, *f, "\\DFF", true);
}
} BlifFrontend;
diff --git a/frontends/blif/blifparse.h b/frontends/blif/blifparse.h
index 4d7f59d6..3c01ed37 100644
--- a/frontends/blif/blifparse.h
+++ b/frontends/blif/blifparse.h
@@ -24,7 +24,7 @@
YOSYS_NAMESPACE_BEGIN
-extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name);
+extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean = false);
YOSYS_NAMESPACE_END
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index 6090fabe..cc31c864 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -50,6 +50,7 @@ USING_YOSYS_NAMESPACE
int integer;
YOSYS_NAMESPACE_PREFIX RTLIL::Const *data;
YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec;
+ std::vector<YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec> *rsigspec;
}
%token <string> TOK_ID TOK_VALUE TOK_STRING
@@ -60,6 +61,7 @@ USING_YOSYS_NAMESPACE
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
+%type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list
%type <integer> sync_type
%type <data> constant
@@ -121,7 +123,7 @@ attr_stmt:
autoidx_stmt:
TOK_AUTOIDX TOK_INT EOL {
- autoidx = std::max(autoidx, $2);
+ autoidx = max(autoidx, $2);
};
wire_stmt:
@@ -274,8 +276,8 @@ compare_list:
/* empty */;
case_body:
- switch_stmt case_body |
- assign_stmt case_body |
+ case_body switch_stmt |
+ case_body assign_stmt |
/* empty */;
assign_stmt:
@@ -389,16 +391,20 @@ sigspec:
$$ = $2;
};
-sigspec_list:
- sigspec_list sigspec {
- $$ = new RTLIL::SigSpec;
- $$->append(*$2);
- $$->append(*$1);
- delete $1;
+sigspec_list_reversed:
+ sigspec_list_reversed sigspec {
+ $$->push_back(*$2);
delete $2;
} |
/* empty */ {
+ $$ = new std::vector<RTLIL::SigSpec>;
+ };
+
+sigspec_list: sigspec_list_reversed {
$$ = new RTLIL::SigSpec;
+ for (auto it = $1->rbegin(); it != $1->rend(); it++)
+ $$->append(*it);
+ delete $1;
};
conn_stmt:
diff --git a/frontends/verific/Makefile.inc b/frontends/verific/Makefile.inc
index 13f242c4..68ef9aed 100644
--- a/frontends/verific/Makefile.inc
+++ b/frontends/verific/Makefile.inc
@@ -8,8 +8,9 @@ EXTRA_TARGETS += share/verific
share/verific:
$(P) rm -rf share/verific.new
$(Q) mkdir -p share/verific.new
- $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs share/verific.new/vhdl_vdbs_1993
- $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008 share/verific.new/vhdl_vdbs_2008
+ $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1987/. share/verific.new/vhdl_vdbs_1987
+ $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1993/. share/verific.new/vhdl_vdbs_1993
+ $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008/. share/verific.new/vhdl_vdbs_2008
$(Q) mv share/verific.new share/verific
endif
diff --git a/frontends/verific/build_amd64.txt b/frontends/verific/build_amd64.txt
index 0a220475..d6952820 100644
--- a/frontends/verific/build_amd64.txt
+++ b/frontends/verific/build_amd64.txt
@@ -8,8 +8,6 @@ only have the i386 eval version of Verific:
--snip--
CONFIG := clang
ENABLE_TCL := 0
-ENABLE_QT4 := 0
-ENABLE_ABC := 0
ENABLE_PLUGINS := 0
ENABLE_VERIFIC := 1
CXXFLAGS += -m32
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 793c0684..b0fdedcc 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -186,6 +186,16 @@ static bool import_netlist_instance_gates(RTLIL::Module *module, std::map<Net*,
return true;
}
+ if (inst->Type() == PRIM_XNOR) {
+ module->addXnorGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == PRIM_BUF) {
+ module->addBufGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
if (inst->Type() == PRIM_INV) {
module->addNotGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
return true;
@@ -314,6 +324,16 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
return true;
}
+ if (inst->Type() == PRIM_DLATCHRS)
+ {
+ if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
+ module->addDlatch(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetControl()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ else
+ module->addDlatchsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetControl()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()),
+ net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ return true;
+ }
+
#define IN operatorInput(inst, net_map)
#define IN1 operatorInput1(inst, net_map)
#define IN2 operatorInput2(inst, net_map)
@@ -359,6 +379,26 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
return true;
}
+ if (inst->Type() == OPER_ENABLED_DECODER) {
+ RTLIL::SigSpec vec;
+ vec.append(net_map.at(inst->GetControl()));
+ for (unsigned i = 1; i < inst->OutputSize(); i++) {
+ vec.append(RTLIL::State::S0);
+ }
+ module->addShl(RTLIL::escape_id(inst->Name()), vec, IN, OUT, false);
+ return true;
+ }
+
+ if (inst->Type() == OPER_DECODER) {
+ RTLIL::SigSpec vec;
+ vec.append(RTLIL::State::S1);
+ for (unsigned i = 1; i < inst->OutputSize(); i++) {
+ vec.append(RTLIL::State::S0);
+ }
+ module->addShl(RTLIL::escape_id(inst->Name()), vec, IN, OUT, false);
+ return true;
+ }
+
if (inst->Type() == OPER_SHIFT_RIGHT) {
Net *net_cin = inst->GetCin();
Net *net_a_msb = inst->GetInput1Bit(0);
@@ -541,7 +581,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
// log(" importing portbus %s.\n", portbus->Name());
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size());
- wire->start_offset = std::min(portbus->LeftIndex(), portbus->RightIndex());
+ wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
import_attributes(wire->attributes, portbus);
if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN)
@@ -580,11 +620,11 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
int bits_in_word = number_of_bits;
FOREACH_PORTREF_OF_NET(net, si, pr) {
if (pr->GetInst()->Type() == OPER_READ_PORT) {
- bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->OutputSize());
+ bits_in_word = min<int>(bits_in_word, pr->GetInst()->OutputSize());
continue;
}
if (pr->GetInst()->Type() == OPER_WRITE_PORT || pr->GetInst()->Type() == OPER_CLOCKED_WRITE_PORT) {
- bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->Input2Size());
+ bits_in_word = min<int>(bits_in_word, pr->GetInst()->Input2Size());
continue;
}
log_error("Verific RamNet %s is connected to unsupported instance type %s (%s).\n",
@@ -630,7 +670,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
RTLIL::IdString wire_name = module->uniquify(RTLIL::escape_id(netbus->Name()));
RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size());
- wire->start_offset = std::min(netbus->LeftIndex(), netbus->RightIndex());
+ wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex());
import_attributes(wire->attributes, netbus);
for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) {
@@ -666,6 +706,11 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
continue;
}
+ if (inst->Type() == PRIM_BUF) {
+ module->addBufGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ continue;
+ }
+
if (inst->Type() == PRIM_X) {
module->connect(net_map.at(inst->GetOutput()), RTLIL::State::Sx);
continue;
@@ -738,13 +783,15 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
}
if (inst->IsPrimitive())
- log_error("Unsupported Verific primitive: %s\n", inst->View()->Owner()->Name());
+ log_error("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name());
nl_todo.insert(inst->View());
RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), inst->IsOperator() ?
std::string("$verific$") + inst->View()->Owner()->Name() : RTLIL::escape_id(inst->View()->Owner()->Name()));
+ dict<IdString, vector<SigBit>> cell_port_conns;
+
FOREACH_PORTREF_OF_INST(inst, mi2, pr) {
// log(" .%s(%s)\n", pr->GetPort()->Name(), pr->GetNet()->Name());
const char *port_name = pr->GetPort()->Name();
@@ -752,18 +799,21 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
if (pr->GetPort()->Bus()) {
port_name = pr->GetPort()->Bus()->Name();
port_offset = pr->GetPort()->Bus()->IndexOf(pr->GetPort()) -
- std::min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex());
+ min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex());
}
- RTLIL::SigSpec conn;
- if (cell->hasPort(RTLIL::escape_id(port_name)))
- conn = cell->getPort(RTLIL::escape_id(port_name));
- while (GetSize(conn) <= port_offset) {
- if (pr->GetPort()->GetDir() != DIR_IN)
- conn.append(module->addWire(NEW_ID, port_offset - GetSize(conn)));
- conn.append(RTLIL::State::Sz);
+ IdString port_name_id = RTLIL::escape_id(port_name);
+ auto &sigvec = cell_port_conns[port_name_id];
+ if (GetSize(sigvec) <= port_offset) {
+ SigSpec zwires = module->addWire(NEW_ID, port_offset+1-GetSize(sigvec));
+ for (auto bit : zwires)
+ sigvec.push_back(bit);
}
- conn.replace(port_offset, net_map.at(pr->GetNet()));
- cell->setPort(RTLIL::escape_id(port_name), conn);
+ sigvec[port_offset] = net_map.at(pr->GetNet());
+ }
+
+ for (auto &it : cell_port_conns) {
+ // log(" .%s(%s)\n", log_id(it.first), log_signal(it.second));
+ cell->setPort(it.first, it.second);
}
}
}
@@ -841,7 +891,7 @@ struct VerificPass : public Pass {
}
if (args.size() > 1 && args[1] == "-vhdl87") {
- vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
+ vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str());
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_87))
log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str());
@@ -918,10 +968,12 @@ struct VerificPass : public Pass {
for (; argidx < args.size(); argidx++) {
if (veri_file::GetModule(args[argidx].c_str())) {
+ log("Running veri_file::Elaborate(\"%s\").\n", args[argidx].c_str());
if (!veri_file::Elaborate(args[argidx].c_str()))
log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
nl_todo.insert(Netlist::PresentDesign());
} else {
+ log("Running vhdl_file::Elaborate(\"%s\").\n", args[argidx].c_str());
if (!vhdl_file::Elaborate(args[argidx].c_str()))
log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
nl_todo.insert(Netlist::PresentDesign());
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index e0446e08..863fee59 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -759,7 +759,7 @@ assign_expr_list:
assign_expr | assign_expr_list ',' assign_expr;
assign_expr:
- expr '=' expr {
+ lvalue '=' expr {
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3));
};
@@ -963,7 +963,7 @@ simple_behavioral_stmt:
// this production creates the obligatory if-else shift/reduce conflict
behavioral_stmt:
- defattr | assert | wire_decl |
+ defattr | assert | wire_decl | param_decl | localparam_decl |
non_opt_delay behavioral_stmt |
simple_behavioral_stmt ';' | ';' |
hierarchical_id attr {
diff --git a/kernel/calc.cc b/kernel/calc.cc
index 32c06c18..a24fa2ab 100644
--- a/kernel/calc.cc
+++ b/kernel/calc.cc
@@ -154,7 +154,7 @@ static RTLIL::Const logic_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL:
RTLIL::Const arg1, RTLIL::Const arg2, bool signed1, bool signed2, int result_len = -1)
{
if (result_len < 0)
- result_len = std::max(arg1.bits.size(), arg2.bits.size());
+ result_len = max(arg1.bits.size(), arg2.bits.size());
extend_u0(arg1, result_len, signed1);
extend_u0(arg2, result_len, signed2);
@@ -310,7 +310,7 @@ RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
- extend_u0(arg1_ext, std::max(result_len, GetSize(arg1)), signed1);
+ extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1);
return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
}
@@ -389,7 +389,7 @@ RTLIL::Const RTLIL::const_eq(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
RTLIL::Const arg2_ext = arg2;
RTLIL::Const result(RTLIL::State::S0, result_len);
- int width = std::max(arg1_ext.bits.size(), arg2_ext.bits.size());
+ int width = max(arg1_ext.bits.size(), arg2_ext.bits.size());
extend_u0(arg1_ext, width, signed1 && signed2);
extend_u0(arg2_ext, width, signed1 && signed2);
@@ -423,7 +423,7 @@ RTLIL::Const RTLIL::const_eqx(const RTLIL::Const &arg1, const RTLIL::Const &arg2
RTLIL::Const arg2_ext = arg2;
RTLIL::Const result(RTLIL::State::S0, result_len);
- int width = std::max(arg1_ext.bits.size(), arg2_ext.bits.size());
+ int width = max(arg1_ext.bits.size(), arg2_ext.bits.size());
extend_u0(arg1_ext, width, signed1 && signed2);
extend_u0(arg2_ext, width, signed1 && signed2);
@@ -472,21 +472,21 @@ RTLIL::Const RTLIL::const_add(const RTLIL::Const &arg1, const RTLIL::Const &arg2
{
int undef_bit_pos = -1;
BigInteger y = const2big(arg1, signed1, undef_bit_pos) + const2big(arg2, signed2, undef_bit_pos);
- return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
}
RTLIL::Const RTLIL::const_sub(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
int undef_bit_pos = -1;
BigInteger y = const2big(arg1, signed1, undef_bit_pos) - const2big(arg2, signed2, undef_bit_pos);
- return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
}
RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
int undef_bit_pos = -1;
BigInteger y = const2big(arg1, signed1, undef_bit_pos) * const2big(arg2, signed2, undef_bit_pos);
- return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+ return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
}
RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
@@ -499,7 +499,7 @@ RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2
bool result_neg = (a.getSign() == BigInteger::negative) != (b.getSign() == BigInteger::negative);
a = a.getSign() == BigInteger::negative ? -a : a;
b = b.getSign() == BigInteger::negative ? -b : b;
- return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+ return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
}
RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
@@ -512,7 +512,7 @@ RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2
bool result_neg = a.getSign() == BigInteger::negative;
a = a.getSign() == BigInteger::negative ? -a : a;
b = b.getSign() == BigInteger::negative ? -b : b;
- return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+ return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
}
RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
@@ -563,7 +563,7 @@ RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2
y *= -1;
}
- return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+ return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0));
}
RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc
index be2e7bbb..41f81355 100644
--- a/kernel/cellaigs.cc
+++ b/kernel/cellaigs.cc
@@ -392,7 +392,7 @@ Aig::Aig(Cell *cell)
if (cell->type.in("$eq", "$ne"))
{
- int width = std::max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B")));
+ int width = max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B")));
vector<int> A = mk.inport_vec("\\A", width);
vector<int> B = mk.inport_vec("\\B", width);
int Y = mk.bool_node(false);
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 95835951..02e332f9 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -404,7 +404,7 @@ int main(int argc, char **argv)
log("%s\n", yosys_version_str);
int64_t total_ns = 0;
- std::set<std::tuple<int64_t, int, std::string>> timedat;
+ std::set<tuple<int64_t, int, std::string>> timedat;
for (auto &it : pass_register)
if (it.second->call_counter) {
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
index 3cc95b6e..280b1693 100644
--- a/kernel/hashlib.h
+++ b/kernel/hashlib.h
@@ -74,7 +74,7 @@ template<> struct hash_ops<int32_t> : hash_int_ops
template<> struct hash_ops<int64_t> : hash_int_ops
{
static inline unsigned int hash(int64_t a) {
- return mkhash(a, a >> 32);
+ return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
}
};
@@ -95,9 +95,7 @@ template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
return a == b;
}
static inline unsigned int hash(std::pair<P, Q> a) {
- hash_ops<P> p_ops;
- hash_ops<Q> q_ops;
- return mkhash(p_ops.hash(a.first), q_ops.hash(a.second));
+ return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
}
};
@@ -111,8 +109,8 @@ template<typename... T> struct hash_ops<std::tuple<T...>> {
}
template<size_t I = 0>
static inline typename std::enable_if<I != sizeof...(T), unsigned int>::type hash(std::tuple<T...> a) {
- hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops;
- return mkhash(hash<I+1>(a), element_ops.hash(std::get<I>(a)));
+ typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
+ return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
}
};
@@ -162,6 +160,11 @@ struct hash_obj_ops {
}
};
+template<typename T>
+inline unsigned int mkhash(const T &v) {
+ return hash_ops<T>().hash(v);
+}
+
inline int hashtable_size(int min_size)
{
static std::vector<int> zero_and_some_primes = {
@@ -190,6 +193,7 @@ inline int hashtable_size(int min_size)
template<typename K, typename T, typename OPS = hash_ops<K>> class dict;
template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
template<typename K, typename OPS = hash_ops<K>> class pool;
+template<typename K, typename OPS = hash_ops<K>> class mfp;
template<typename K, typename T, typename OPS>
class dict
@@ -227,7 +231,7 @@ class dict
void do_rehash()
{
hashtable.clear();
- hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
+ hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
for (int i = 0; i < int(entries.size()); i++) {
do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
@@ -500,6 +504,15 @@ public:
return entries[i].udata.second;
}
+ T at(const K &key, const T &defval) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return defval;
+ return entries[i].udata.second;
+ }
+
T& operator[](const K &key)
{
int hash = do_hash(key);
@@ -537,6 +550,7 @@ public:
return !operator==(other);
}
+ void reserve(size_t n) { entries.reserve(n); }
size_t size() const { return entries.size(); }
bool empty() const { return entries.empty(); }
void clear() { hashtable.clear(); entries.clear(); }
@@ -586,7 +600,7 @@ protected:
void do_rehash()
{
hashtable.clear();
- hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
+ hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
for (int i = 0; i < int(entries.size()); i++) {
do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
@@ -853,6 +867,7 @@ public:
return !operator==(other);
}
+ void reserve(size_t n) { entries.reserve(n); }
size_t size() const { return entries.size(); }
bool empty() const { return entries.empty(); }
void clear() { hashtable.clear(); entries.clear(); }
@@ -890,6 +905,15 @@ public:
return i + offset;
}
+ int at(const K &key, int defval) const
+ {
+ int hash = database.do_hash(key);
+ int i = database.do_lookup(key, hash);
+ if (i < 0)
+ return defval;
+ return i + offset;
+ }
+
int count(const K &key) const
{
int hash = database.do_hash(key);
@@ -909,6 +933,115 @@ public:
return database.entries.at(index - offset).udata;
}
+ void swap(idict &other)
+ {
+ database.swap(other.database);
+ }
+
+ void reserve(size_t n) { database.reserve(n); }
+ size_t size() const { return database.size(); }
+ bool empty() const { return database.empty(); }
+ void clear() { database.clear(); }
+
+ const_iterator begin() const { return database.begin(); }
+ const_iterator end() const { return database.end(); }
+};
+
+template<typename K, typename OPS>
+class mfp
+{
+ mutable idict<K, 0, OPS> database;
+ mutable std::vector<int> parents;
+
+public:
+ typedef typename idict<K, 0, OPS>::const_iterator const_iterator;
+
+ int operator()(const K &key) const
+ {
+ int i = database(key);
+ parents.resize(database.size(), -1);
+ return i;
+ }
+
+ const K &operator[](int index) const
+ {
+ return database[index];
+ }
+
+ int ifind(int i) const
+ {
+ int p = i, k = i;
+
+ while (parents[p] != -1)
+ p = parents[p];
+
+ while (k != p) {
+ int next_k = parents[k];
+ parents[k] = p;
+ k = next_k;
+ }
+
+ return p;
+ }
+
+ void imerge(int i, int j)
+ {
+ i = ifind(i);
+ j = ifind(j);
+
+ if (i != j)
+ parents[i] = j;
+ }
+
+ void ipromote(int i)
+ {
+ int k = i;
+
+ while (k != -1) {
+ int next_k = parents[k];
+ parents[k] = i;
+ k = next_k;
+ }
+
+ parents[i] = -1;
+ }
+
+ int lookup(const K &a) const
+ {
+ return ifind((*this)(a));
+ }
+
+ const K &find(const K &a) const
+ {
+ int i = database.at(a, -1);
+ if (i < 0)
+ return a;
+ return (*this)[ifind(i)];
+ }
+
+ void merge(const K &a, const K &b)
+ {
+ imerge((*this)(a), (*this)(b));
+ }
+
+ void promote(const K &a)
+ {
+ int i = database.at(a, -1);
+ if (i >= 0)
+ ipromote(i);
+ }
+
+ void swap(mfp &other)
+ {
+ database.swap(other.database);
+ parents.swap(other.parents);
+ }
+
+ void reserve(size_t n) { database.reserve(n); }
+ size_t size() const { return database.size(); }
+ bool empty() const { return database.empty(); }
+ void clear() { database.clear(); parents.clear(); }
+
const_iterator begin() const { return database.begin(); }
const_iterator end() const { return database.end(); }
};
diff --git a/kernel/macc.h b/kernel/macc.h
index 7efd0228..286ce567 100644
--- a/kernel/macc.h
+++ b/kernel/macc.h
@@ -158,8 +158,8 @@ struct Macc
int max_size = 0, num_bits = 0;
for (auto &port : ports) {
- max_size = std::max(max_size, GetSize(port.in_a));
- max_size = std::max(max_size, GetSize(port.in_b));
+ max_size = max(max_size, GetSize(port.in_a));
+ max_size = max(max_size, GetSize(port.in_b));
}
while (max_size)
diff --git a/kernel/modtools.h b/kernel/modtools.h
index 44c1bde1..ffcb48d4 100644
--- a/kernel/modtools.h
+++ b/kernel/modtools.h
@@ -180,8 +180,8 @@ struct ModIndex : public RTLIL::Monitor
{
RTLIL::SigBit lhs = sigmap(sigsig.first[i]);
RTLIL::SigBit rhs = sigmap(sigsig.second[i]);
- bool has_lhs = database.count(lhs);
- bool has_rhs = database.count(rhs);
+ bool has_lhs = database.count(lhs) != 0;
+ bool has_rhs = database.count(rhs) != 0;
if (!has_lhs && !has_rhs) {
sigmap.add(lhs, rhs);
@@ -226,7 +226,7 @@ struct ModIndex : public RTLIL::Monitor
auto_reload_module = true;
}
- ModIndex(RTLIL::Module *_m) : module(_m)
+ ModIndex(RTLIL::Module *_m) : sigmap(_m), module(_m)
{
auto_reload_counter = 0;
auto_reload_module = true;
@@ -274,6 +274,27 @@ struct ModIndex : public RTLIL::Monitor
return empty_result_set;
return info->ports;
}
+
+ void dump_db()
+ {
+ log("--- ModIndex Dump ---\n");
+
+ if (auto_reload_module) {
+ log("AUTO-RELOAD\n");
+ reload_module();
+ }
+
+ for (auto &it : database) {
+ log("BIT %s:\n", log_signal(it.first));
+ if (it.second.is_input)
+ log(" PRIMARY INPUT\n");
+ if (it.second.is_output)
+ log(" PRIMARY OUTPUT\n");
+ for (auto &port : it.second.ports)
+ log(" PORT: %s.%s[%d] (%s)\n", log_id(port.cell),
+ log_id(port.port), port.offset, log_id(port.cell->type));
+ }
+ }
};
struct ModWalker
diff --git a/kernel/register.cc b/kernel/register.cc
index 179d064f..49a67324 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -209,7 +209,7 @@ void Pass::call(RTLIL::Design *design, std::string command)
void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
{
- if (args.size() == 0 || args[0][0] == '#')
+ if (args.size() == 0 || args[0][0] == '#' || args[0][0] == ':')
return;
if (echo_mode) {
@@ -534,14 +534,28 @@ void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string f
design->check();
}
+static struct CellHelpMessages {
+ dict<string, string> cell_help, cell_code;
+ CellHelpMessages() {
+#include "techlibs/common/simlib_help.inc"
+#include "techlibs/common/simcells_help.inc"
+ cell_help.sort();
+ cell_code.sort();
+ }
+} cell_help_messages;
+
struct HelpPass : public Pass {
HelpPass() : Pass("help", "display help messages") { }
virtual void help()
{
log("\n");
- log(" help ............. list all commands\n");
- log(" help <command> ... print help message for given command\n");
- log(" help -all ........ print complete command reference\n");
+ log(" help ................ list all commands\n");
+ log(" help <command> ...... print help message for given command\n");
+ log(" help -all ........... print complete command reference\n");
+ log("\n");
+ log(" help -cells .......... list all cell types\n");
+ log(" help <celltype> ..... print help message for given cell type\n");
+ log(" help <celltype>+ .... print verilog code for given cell type\n");
log("\n");
}
void escape_tex(std::string &tex)
@@ -609,6 +623,7 @@ struct HelpPass : public Pass {
log(" %-20s %s\n", it.first.c_str(), it.second->short_help.c_str());
log("\n");
log("Type 'help <command>' for more information on a command.\n");
+ log("Type 'help -cells' for a list of all cell types.\n");
log("\n");
return;
}
@@ -624,6 +639,18 @@ struct HelpPass : public Pass {
it.second->help();
}
}
+ else if (args[1] == "-cells") {
+ log("\n");
+ for (auto &it : cell_help_messages.cell_help) {
+ string line = split_tokens(it.second, "\n").at(0);
+ string cell_name = next_token(line);
+ log(" %-15s %s\n", cell_name.c_str(), line.c_str());
+ }
+ log("\n");
+ log("Type 'help <cell_type>' for more information on a cell type.\n");
+ log("\n");
+ return;
+ }
// this option is undocumented as it is for internal use only
else if (args[1] == "-write-tex-command-reference-manual") {
FILE *f = fopen("command-reference-manual.tex", "wt");
@@ -649,10 +676,20 @@ struct HelpPass : public Pass {
}
fclose(f);
}
- else if (pass_register.count(args[1]) == 0)
- log("No such command: %s\n", args[1].c_str());
- else
+ else if (pass_register.count(args[1])) {
pass_register.at(args[1])->help();
+ }
+ else if (cell_help_messages.cell_help.count(args[1])) {
+ log("%s", cell_help_messages.cell_help.at(args[1]).c_str());
+ log("Run 'help %s+' to display the Verilog model for this cell type.\n", args[1].c_str());
+ log("\n");
+ }
+ else if (cell_help_messages.cell_code.count(args[1])) {
+ log("\n");
+ log("%s", cell_help_messages.cell_code.at(args[1]).c_str());
+ }
+ else
+ log("No such command or cell type: %s\n", args[1].c_str());
return;
}
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 7090fe91..a706491e 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -981,11 +981,11 @@ namespace {
param("\\SIZE");
param("\\OFFSET");
param("\\INIT");
- param_bits("\\RD_CLK_ENABLE", std::max(1, param("\\RD_PORTS")));
- param_bits("\\RD_CLK_POLARITY", std::max(1, param("\\RD_PORTS")));
- param_bits("\\RD_TRANSPARENT", std::max(1, param("\\RD_PORTS")));
- param_bits("\\WR_CLK_ENABLE", std::max(1, param("\\WR_PORTS")));
- param_bits("\\WR_CLK_POLARITY", std::max(1, param("\\WR_PORTS")));
+ param_bits("\\RD_CLK_ENABLE", max(1, param("\\RD_PORTS")));
+ param_bits("\\RD_CLK_POLARITY", max(1, param("\\RD_PORTS")));
+ param_bits("\\RD_TRANSPARENT", max(1, param("\\RD_PORTS")));
+ param_bits("\\WR_CLK_ENABLE", max(1, param("\\WR_PORTS")));
+ param_bits("\\WR_CLK_POLARITY", max(1, param("\\WR_PORTS")));
port("\\RD_CLK", param("\\RD_PORTS"));
port("\\RD_EN", param("\\RD_PORTS"));
port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS"));
@@ -1448,6 +1448,19 @@ void RTLIL::Module::connect(const RTLIL::SigSig &conn)
for (auto mon : design->monitors)
mon->notify_connect(this, conn);
+ // ignore all attempts to assign constants to other constants
+ if (conn.first.has_const()) {
+ RTLIL::SigSig new_conn;
+ for (int i = 0; i < GetSize(conn.first); i++)
+ if (conn.first[i].wire) {
+ new_conn.first.append(conn.first[i]);
+ new_conn.second.append(conn.second[i]);
+ }
+ if (GetSize(new_conn.first))
+ connect(new_conn);
+ return;
+ }
+
if (yosys_xtrace) {
log("#X# Connect (SigSig) in %s: %s = %s (%d bits)\n", log_id(this), log_signal(conn.first), log_signal(conn.second), GetSize(conn.first));
log_backtrace("-X- ", yosys_xtrace-1);
@@ -1588,10 +1601,10 @@ DEF_METHOD(LogicNot, 1, "$logic_not")
add ## _func(name, sig_a, sig_b, sig_y, is_signed); \
return sig_y; \
}
-DEF_METHOD(And, std::max(sig_a.size(), sig_b.size()), "$and")
-DEF_METHOD(Or, std::max(sig_a.size(), sig_b.size()), "$or")
-DEF_METHOD(Xor, std::max(sig_a.size(), sig_b.size()), "$xor")
-DEF_METHOD(Xnor, std::max(sig_a.size(), sig_b.size()), "$xnor")
+DEF_METHOD(And, max(sig_a.size(), sig_b.size()), "$and")
+DEF_METHOD(Or, max(sig_a.size(), sig_b.size()), "$or")
+DEF_METHOD(Xor, max(sig_a.size(), sig_b.size()), "$xor")
+DEF_METHOD(Xnor, max(sig_a.size(), sig_b.size()), "$xnor")
DEF_METHOD(Shl, sig_a.size(), "$shl")
DEF_METHOD(Shr, sig_a.size(), "$shr")
DEF_METHOD(Sshl, sig_a.size(), "$sshl")
@@ -1606,11 +1619,11 @@ DEF_METHOD(Eqx, 1, "$eqx")
DEF_METHOD(Nex, 1, "$nex")
DEF_METHOD(Ge, 1, "$ge")
DEF_METHOD(Gt, 1, "$gt")
-DEF_METHOD(Add, std::max(sig_a.size(), sig_b.size()), "$add")
-DEF_METHOD(Sub, std::max(sig_a.size(), sig_b.size()), "$sub")
-DEF_METHOD(Mul, std::max(sig_a.size(), sig_b.size()), "$mul")
-DEF_METHOD(Div, std::max(sig_a.size(), sig_b.size()), "$div")
-DEF_METHOD(Mod, std::max(sig_a.size(), sig_b.size()), "$mod")
+DEF_METHOD(Add, max(sig_a.size(), sig_b.size()), "$add")
+DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), "$sub")
+DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), "$mul")
+DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), "$div")
+DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), "$mod")
DEF_METHOD(LogicAnd, 1, "$logic_and")
DEF_METHOD(LogicOr, 1, "$logic_or")
#undef DEF_METHOD
@@ -1689,6 +1702,7 @@ DEF_METHOD(Pmux, "$pmux", 1)
add ## _func(name, sig1, sig2, sig3, sig4, sig5); \
return sig5; \
}
+DEF_METHOD_2(BufGate, "$_BUF_", A, Y)
DEF_METHOD_2(NotGate, "$_NOT_", A, Y)
DEF_METHOD_3(AndGate, "$_AND_", A, B, Y)
DEF_METHOD_3(NandGate, "$_NAND_", A, B, Y)
@@ -2560,8 +2574,18 @@ void RTLIL::SigSpec::sort()
void RTLIL::SigSpec::sort_and_unify()
{
+ unpack();
cover("kernel.rtlil.sigspec.sort_and_unify");
- *this = this->to_sigbit_set();
+
+ // A copy of the bits vector is used to prevent duplicating the logic from
+ // SigSpec::SigSpec(std::vector<SigBit>). This incurrs an extra copy but
+ // that isn't showing up as significant in profiles.
+ std::vector<SigBit> unique_bits = bits_;
+ std::sort(unique_bits.begin(), unique_bits.end());
+ auto last = std::unique(unique_bits.begin(), unique_bits.end());
+ unique_bits.erase(last, unique_bits.end());
+
+ *this = unique_bits;
}
void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
@@ -2571,18 +2595,26 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec
void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const
{
+ log_assert(other != NULL);
+ log_assert(width_ == other->width_);
log_assert(pattern.width_ == with.width_);
pattern.unpack();
with.unpack();
+ unpack();
+ other->unpack();
- dict<RTLIL::SigBit, RTLIL::SigBit> rules;
-
- for (int i = 0; i < GetSize(pattern.bits_); i++)
- if (pattern.bits_[i].wire != NULL)
- rules[pattern.bits_[i]] = with.bits_[i];
+ for (int i = 0; i < GetSize(pattern.bits_); i++) {
+ if (pattern.bits_[i].wire != NULL) {
+ for (int j = 0; j < GetSize(bits_); j++) {
+ if (bits_[j] == pattern.bits_[i]) {
+ other->bits_[j] = with.bits_[i];
+ }
+ }
+ }
+ }
- replace(rules, other);
+ other->check();
}
void RTLIL::SigSpec::replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules)
@@ -2646,8 +2678,35 @@ void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other
void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other)
{
- pool<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_pool();
- remove2(pattern_bits, other);
+ if (other)
+ cover("kernel.rtlil.sigspec.remove_other");
+ else
+ cover("kernel.rtlil.sigspec.remove");
+
+ unpack();
+ if (other != NULL) {
+ log_assert(width_ == other->width_);
+ other->unpack();
+ }
+
+ for (int i = GetSize(bits_) - 1; i >= 0; i--) {
+ if (bits_[i].wire == NULL) continue;
+
+ for (auto &pattern_chunk : pattern.chunks()) {
+ if (bits_[i].wire == pattern_chunk.wire &&
+ bits_[i].offset >= pattern_chunk.offset &&
+ bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) {
+ bits_.erase(bits_.begin() + i);
+ width_--;
+ if (other != NULL) {
+ other->bits_.erase(other->bits_.begin() + i);
+ other->width_--;
+ }
+ }
+ }
+ }
+
+ check();
}
void RTLIL::SigSpec::remove(const pool<RTLIL::SigBit> &pattern)
@@ -2675,31 +2734,43 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec
other->unpack();
}
- std::vector<RTLIL::SigBit> new_bits, new_other_bits;
-
- new_bits.resize(GetSize(bits_));
- if (other != NULL)
- new_other_bits.resize(GetSize(bits_));
-
- int k = 0;
- for (int i = 0; i < GetSize(bits_); i++) {
- if (bits_[i].wire != NULL && pattern.count(bits_[i]))
- continue;
- if (other != NULL)
- new_other_bits[k] = other->bits_[i];
- new_bits[k++] = bits_[i];
+ for (int i = GetSize(bits_) - 1; i >= 0; i--) {
+ if (bits_[i].wire != NULL && pattern.count(bits_[i])) {
+ bits_.erase(bits_.begin() + i);
+ width_--;
+ if (other != NULL) {
+ other->bits_.erase(other->bits_.begin() + i);
+ other->width_--;
+ }
+ }
}
- new_bits.resize(k);
- if (other != NULL)
- new_other_bits.resize(k);
+ check();
+}
+
+void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other)
+{
+ if (other)
+ cover("kernel.rtlil.sigspec.remove_other");
+ else
+ cover("kernel.rtlil.sigspec.remove");
- bits_.swap(new_bits);
- width_ = GetSize(bits_);
+ unpack();
if (other != NULL) {
- other->bits_.swap(new_other_bits);
- other->width_ = GetSize(other->bits_);
+ log_assert(width_ == other->width_);
+ other->unpack();
+ }
+
+ for (int i = GetSize(bits_) - 1; i >= 0; i--) {
+ if (bits_[i].wire != NULL && pattern.count(bits_[i])) {
+ bits_.erase(bits_.begin() + i);
+ width_--;
+ if (other != NULL) {
+ other->bits_.erase(other->bits_.begin() + i);
+ other->width_--;
+ }
+ }
}
check();
@@ -2707,8 +2778,37 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec
RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const
{
- pool<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_pool();
- return extract(pattern_bits, other);
+ if (other)
+ cover("kernel.rtlil.sigspec.extract_other");
+ else
+ cover("kernel.rtlil.sigspec.extract");
+
+ log_assert(other == NULL || width_ == other->width_);
+
+ RTLIL::SigSpec ret;
+ std::vector<RTLIL::SigBit> bits_match = to_sigbit_vector();
+
+ for (auto& pattern_chunk : pattern.chunks()) {
+ if (other) {
+ std::vector<RTLIL::SigBit> bits_other = other->to_sigbit_vector();
+ for (int i = 0; i < width_; i++)
+ if (bits_match[i].wire &&
+ bits_match[i].wire == pattern_chunk.wire &&
+ bits_match[i].offset >= pattern_chunk.offset &&
+ bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width)
+ ret.append_bit(bits_other[i]);
+ } else {
+ for (int i = 0; i < width_; i++)
+ if (bits_match[i].wire &&
+ bits_match[i].wire == pattern_chunk.wire &&
+ bits_match[i].offset >= pattern_chunk.offset &&
+ bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width)
+ ret.append_bit(bits_match[i]);
+ }
+ }
+
+ ret.check();
+ return ret;
}
RTLIL::SigSpec RTLIL::SigSpec::extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other) const
@@ -3184,6 +3284,17 @@ RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const
return chunks_[0];
}
+RTLIL::SigBit RTLIL::SigSpec::as_bit() const
+{
+ cover("kernel.rtlil.sigspec.as_bit");
+
+ log_assert(width_ == 1);
+ if (packed())
+ return RTLIL::SigBit(*chunks_.begin());
+ else
+ return bits_[0];
+}
+
bool RTLIL::SigSpec::match(std::string pattern) const
{
cover("kernel.rtlil.sigspec.match");
@@ -3271,18 +3382,6 @@ dict<RTLIL::SigBit, RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_dict(const RTLIL::S
return new_map;
}
-RTLIL::SigBit RTLIL::SigSpec::to_single_sigbit() const
-{
- cover("kernel.rtlil.sigspec.to_single_sigbit");
-
- pack();
- log_assert(width_ == 1);
- for (auto &c : chunks_)
- if (c.width)
- return RTLIL::SigBit(c);
- log_abort();
-}
-
static void sigspec_parse_split(std::vector<std::string> &tokens, const std::string &text, char sep)
{
size_t start = 0, end = 0;
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 43ef5806..940e36ab 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -192,12 +192,12 @@ namespace RTLIL
return std::string(global_id_storage_.at(index_));
}
- bool operator<(IdString rhs) const {
+ bool operator<(const IdString &rhs) const {
return index_ < rhs.index_;
}
- bool operator==(IdString rhs) const { return index_ == rhs.index_; }
- bool operator!=(IdString rhs) const { return index_ != rhs.index_; }
+ bool operator==(const IdString &rhs) const { return index_ == rhs.index_; }
+ bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; }
// The methods below are just convenience functions for better compatibility with std::string.
@@ -460,7 +460,7 @@ struct RTLIL::Const
Const(std::string str);
Const(int val, int width = 32);
Const(RTLIL::State bit, int width = 1);
- Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; };
+ Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }
Const(const std::vector<bool> &bits);
bool operator <(const RTLIL::Const &other) const;
@@ -476,7 +476,7 @@ struct RTLIL::Const
inline int size() const { return bits.size(); }
inline RTLIL::State &operator[](int index) { return bits.at(index); }
- inline const RTLIL::State &operator[](int index) const { return bits.at(index); };
+ inline const RTLIL::State &operator[](int index) const { return bits.at(index); }
inline RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const {
RTLIL::Const ret;
@@ -669,6 +669,7 @@ public:
void remove(const pool<RTLIL::SigBit> &pattern);
void remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;
void remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
+ void remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
void remove(int offset, int length = 1);
void remove_const();
@@ -690,6 +691,7 @@ public:
bool is_wire() const;
bool is_chunk() const;
+ inline bool is_bit() const { return width_ == 1; }
bool is_fully_const() const;
bool is_fully_zero() const;
@@ -704,6 +706,7 @@ public:
RTLIL::Const as_const() const;
RTLIL::Wire *as_wire() const;
RTLIL::SigChunk as_chunk() const;
+ RTLIL::SigBit as_bit() const;
bool match(std::string pattern) const;
@@ -712,7 +715,6 @@ public:
std::vector<RTLIL::SigBit> to_sigbit_vector() const;
std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;
dict<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_dict(const RTLIL::SigSpec &other) const;
- RTLIL::SigBit to_single_sigbit() const;
static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
@@ -1014,6 +1016,7 @@ public:
RTLIL::Cell* addDlatchsr (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true);
+ RTLIL::Cell* addBufGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y);
RTLIL::Cell* addNotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y);
RTLIL::Cell* addAndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
RTLIL::Cell* addNandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
@@ -1085,6 +1088,7 @@ public:
RTLIL::SigSpec Mux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s);
RTLIL::SigSpec Pmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s);
+ RTLIL::SigBit BufGate (RTLIL::IdString name, RTLIL::SigBit sig_a);
RTLIL::SigBit NotGate (RTLIL::IdString name, RTLIL::SigBit sig_a);
RTLIL::SigBit AndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
RTLIL::SigBit NandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
diff --git a/kernel/satgen.h b/kernel/satgen.h
index 7b099444..d44d61f1 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -980,7 +980,7 @@ struct SatGen
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
}
} else {
- int copy_a_bits = std::min(cell->getPort("\\A").size(), cell->getPort("\\B").size());
+ int copy_a_bits = min(cell->getPort("\\A").size(), cell->getPort("\\B").size());
div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits);
if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool())
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back());
diff --git a/kernel/sigtools.h b/kernel/sigtools.h
index a9419f87..4e97bb77 100644
--- a/kernel/sigtools.h
+++ b/kernel/sigtools.h
@@ -222,18 +222,7 @@ struct SigSet
struct SigMap
{
- struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
- bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
- bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
- unsigned int hash() const { return first->name.hash() + second; }
- };
-
- struct shared_bit_data_t {
- RTLIL::SigBit map_to;
- std::set<bitDef_t> bits;
- };
-
- dict<bitDef_t, shared_bit_data_t*> bits;
+ mfp<SigBit> database;
SigMap(RTLIL::Module *module = NULL)
{
@@ -241,119 +230,27 @@ struct SigMap
set(module);
}
- SigMap(const SigMap &other)
- {
- copy(other);
- }
-
- const SigMap &operator=(const SigMap &other)
- {
- copy(other);
- return *this;
- }
-
- void copy(const SigMap &other)
- {
- clear();
- for (auto &bit : other.bits) {
- bits[bit.first] = new shared_bit_data_t;
- bits[bit.first]->map_to = bit.second->map_to;
- bits[bit.first]->bits = bit.second->bits;
- }
- }
-
void swap(SigMap &other)
{
- bits.swap(other.bits);
- }
-
- ~SigMap()
- {
- clear();
+ database.swap(other.database);
}
void clear()
{
- std::set<shared_bit_data_t*> all_bd_ptr;
- for (auto &it : bits)
- all_bd_ptr.insert(it.second);
- for (auto bd_ptr : all_bd_ptr)
- delete bd_ptr;
- bits.clear();
+ database.clear();
}
void set(RTLIL::Module *module)
{
- clear();
+ int bitcount = 0;
for (auto &it : module->connections())
- add(it.first, it.second);
- }
+ bitcount += it.first.size();
- // internal helper function
- void register_bit(const RTLIL::SigBit &bit)
- {
- if (bit.wire && bits.count(bit) == 0) {
- shared_bit_data_t *bd = new shared_bit_data_t;
- bd->map_to = bit;
- bd->bits.insert(bit);
- bits[bit] = bd;
- }
- }
+ database.clear();
+ database.reserve(bitcount);
- // internal helper function
- void unregister_bit(const RTLIL::SigBit &bit)
- {
- if (bit.wire && bits.count(bit) > 0) {
- shared_bit_data_t *bd = bits[bit];
- bd->bits.erase(bit);
- if (bd->bits.size() == 0)
- delete bd;
- bits.erase(bit);
- }
- }
-
- // internal helper function
- void merge_bit(const RTLIL::SigBit &bit1, const RTLIL::SigBit &bit2)
- {
- log_assert(bit1.wire != NULL && bit2.wire != NULL);
-
- shared_bit_data_t *bd1 = bits[bit1];
- shared_bit_data_t *bd2 = bits[bit2];
- log_assert(bd1 != NULL && bd2 != NULL);
-
- if (bd1 == bd2)
- return;
-
- if (bd1->bits.size() < bd2->bits.size())
- {
- for (auto &bit : bd1->bits)
- bits[bit] = bd2;
- bd2->bits.insert(bd1->bits.begin(), bd1->bits.end());
- delete bd1;
- }
- else
- {
- bd1->map_to = bd2->map_to;
- for (auto &bit : bd2->bits)
- bits[bit] = bd1;
- bd1->bits.insert(bd2->bits.begin(), bd2->bits.end());
- delete bd2;
- }
- }
-
- // internal helper function
- void set_bit(const RTLIL::SigBit &bit1, const RTLIL::SigBit &bit2)
- {
- log_assert(bit1.wire != NULL);
- log_assert(bits.count(bit1) > 0);
- bits[bit1]->map_to = bit2;
- }
-
- // internal helper function
- void map_bit(RTLIL::SigBit &bit) const
- {
- if (bit.wire && bits.count(bit) > 0)
- bit = bits.at(bit)->map_to;
+ for (auto &it : module->connections())
+ add(it.first, it.second);
}
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
@@ -362,45 +259,43 @@ struct SigMap
for (int i = 0; i < GetSize(from); i++)
{
- RTLIL::SigBit &bf = from[i];
- RTLIL::SigBit &bt = to[i];
+ int bfi = database.lookup(from[i]);
+ int bti = database.lookup(to[i]);
+
+ const RTLIL::SigBit &bf = database[bfi];
+ const RTLIL::SigBit &bt = database[bti];
- if (bf.wire == NULL)
- continue;
+ if (bf.wire || bt.wire)
+ {
+ database.imerge(bfi, bti);
- register_bit(bf);
- register_bit(bt);
+ if (bf.wire == nullptr)
+ database.ipromote(bfi);
- if (bt.wire != NULL)
- merge_bit(bf, bt);
- else
- set_bit(bf, bt);
+ if (bt.wire == nullptr)
+ database.ipromote(bti);
+ }
}
}
void add(RTLIL::SigSpec sig)
{
for (auto &bit : sig) {
- register_bit(bit);
- set_bit(bit, bit);
+ RTLIL::SigBit b = database.find(bit);
+ if (b.wire != nullptr)
+ database.promote(bit);
}
}
- void del(RTLIL::SigSpec sig)
- {
- for (auto &bit : sig)
- unregister_bit(bit);
- }
-
void apply(RTLIL::SigBit &bit) const
{
- map_bit(bit);
+ bit = database.find(bit);
}
void apply(RTLIL::SigSpec &sig) const
{
for (auto &bit : sig)
- map_bit(bit);
+ apply(bit);
}
RTLIL::SigBit operator()(RTLIL::SigBit bit) const
@@ -417,7 +312,7 @@ struct SigMap
RTLIL::SigSpec operator()(RTLIL::Wire *wire) const
{
- RTLIL::SigSpec sig(wire);
+ SigSpec sig(wire);
apply(sig);
return sig;
}
@@ -425,8 +320,9 @@ struct SigMap
RTLIL::SigSpec allbits() const
{
RTLIL::SigSpec sig;
- for (auto &it : bits)
- sig.append(SigBit(it.first.first, it.first.second));
+ for (auto &bit : database)
+ if (bit.wire != nullptr)
+ sig.append(bit);
return sig;
}
};
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 10991881..eba1aef1 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -124,6 +124,18 @@ void yosys_banner()
log("\n");
}
+int ceil_log2(int x)
+{
+ if (x <= 0)
+ return 0;
+
+ for (int i = 0; i < 32; i++)
+ if (((x-1) >> i) == 0)
+ return i;
+
+ log_abort();
+}
+
std::string stringf(const char *fmt, ...)
{
std::string string;
@@ -168,7 +180,7 @@ std::string vstringf(const char *fmt, va_list ap)
int readsome(std::istream &f, char *s, int n)
{
- int rc = f.readsome(s, n);
+ int rc = int(f.readsome(s, n));
// f.readsome() sometimes returns 0 on a non-empty stream..
if (rc == 0) {
diff --git a/kernel/yosys.h b/kernel/yosys.h
index 6aacd4d5..c8bc46b6 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -41,6 +41,7 @@
#include <map>
#include <set>
+#include <tuple>
#include <vector>
#include <string>
#include <algorithm>
@@ -138,8 +139,14 @@ YOSYS_NAMESPACE_BEGIN
using std::vector;
using std::string;
+using std::tuple;
using std::pair;
+using std::make_tuple;
+using std::make_pair;
+using std::min;
+using std::max;
+
// A primitive shared string implementation that does not
// move its .c_str() when the object is copied or moved.
struct shared_str {
@@ -164,6 +171,7 @@ using hashlib::hash_obj_ops;
using hashlib::dict;
using hashlib::idict;
using hashlib::pool;
+using hashlib::mfp;
namespace RTLIL {
struct IdString;
@@ -214,6 +222,7 @@ extern bool memhasher_active;
inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner();
+int ceil_log2(int x);
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
std::string vstringf(const char *fmt, va_list ap);
int readsome(std::istream &f, char *s, int n);
@@ -242,6 +251,8 @@ YOSYS_NAMESPACE_END
YOSYS_NAMESPACE_BEGIN
using RTLIL::State;
+using RTLIL::SigChunk;
+using RTLIL::SigSig;
namespace hashlib {
template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
diff --git a/libs/ezsat/ezsat.cc b/libs/ezsat/ezsat.cc
index da36fb74..177bcd8a 100644
--- a/libs/ezsat/ezsat.cc
+++ b/libs/ezsat/ezsat.cc
@@ -1337,6 +1337,28 @@ void ezSAT::printInternalState(FILE *f) const
fprintf(f, "--8<-- snap --8<--\n");
}
+static int clog2(int x)
+{
+ int y = (x & (x - 1));
+ y = (y | -y) >> 31;
+
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+
+ x >>= 1;
+ x -= ((x >> 1) & 0x55555555);
+ x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
+ x = (((x >> 4) + x) & 0x0f0f0f0f);
+ x += (x >> 8);
+ x += (x >> 16);
+ x = x & 0x0000003f;
+
+ return x - y;
+}
+
int ezSAT::onehot(const std::vector<int> &vec, bool max_only)
{
// Mixed one-hot/binary encoding as described by Claessen in Sec. 4.2 of
@@ -1350,7 +1372,7 @@ int ezSAT::onehot(const std::vector<int> &vec, bool max_only)
formula.push_back(expression(OpOr, vec));
// create binary vector
- int num_bits = ceil(log2(vec.size()));
+ int num_bits = clog2(vec.size());
std::vector<int> bits;
for (int k = 0; k < num_bits; k++)
bits.push_back(literal());
diff --git a/manual/CHAPTER_Appnotes.tex b/manual/CHAPTER_Appnotes.tex
index cbb01ed1..e0d09329 100644
--- a/manual/CHAPTER_Appnotes.tex
+++ b/manual/CHAPTER_Appnotes.tex
@@ -15,6 +15,7 @@ This appendix contains copies of the Yosys application notes.
\begin{itemize}
\item Yosys AppNote 010: Converting Verilog to BLIF \dotfill Page \pageref{app:010} \hskip2cm\null
\item Yosys AppNote 011: Interactive Design Investigation \dotfill Page \pageref{app:011} \hskip2cm\null
+\item Yosys AppNote 012: Converting Verilog to BTOR \dotfill Page \pageref{app:012} \hskip2cm\null
\end{itemize}
\eject\label{app:010}
@@ -23,3 +24,6 @@ This appendix contains copies of the Yosys application notes.
\eject\label{app:011}
\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_011_Design_Investigation.pdf}
+\eject\label{app:012}
+\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_012_Verilog_to_BTOR.pdf}
+
diff --git a/manual/clean.sh b/manual/clean.sh
index f4a2ea83..11c2e7bf 100755
--- a/manual/clean.sh
+++ b/manual/clean.sh
@@ -1,2 +1,2 @@
#!/bin/bash
-for f in $( find . -name .gitignore ); do sed -re "s,^,find ${f%.gitignore} -name ',; s,$,' | xargs -r rm -f,;" $f; done | bash -v
+for f in $( find . -name .gitignore ); do sed -re "s,^,find ${f%.gitignore} -name ',; s,$,' | xargs rm -f,;" $f; done | bash -v
diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex
index dfef1bb0..99d4a1fa 100644
--- a/manual/command-reference-manual.tex
+++ b/manual/command-reference-manual.tex
@@ -79,6 +79,15 @@ library to a target architecture.
the area cost doubles with each additional input bit. the delay cost
is still constant for all lut widths.
+ -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..
+ generate netlist using luts. Use the specified costs for luts with 1,
+ 2, 3, .. inputs.
+
+ -g type1,type2,...
+ Map the the specified list of gate types. Supported gates types are:
+ AND, NAND, OR, NOR, XOR, XNOR, MUX, AOI3, OAI3, AOI4, OAI4.
+ (The NOT gate is always added to this list automatically.)
+
-dff
also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many
clock domains are automatically partitioned in clock domains and each
@@ -450,6 +459,15 @@ 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]
@@ -485,12 +503,26 @@ Print all commands to log before executing them.
Do not print all commands to log before executing them. (default)
\end{lstlisting}
+\section{edgetypes -- list all types of edges in selection}
+\label{cmd:edgetypes}
+\begin{lstlisting}[numbers=left,frame=single]
+ edgetypes [options] [selection]
+
+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{equiv\_add -- add a \$equiv cell}
\label{cmd:equiv_add}
\begin{lstlisting}[numbers=left,frame=single]
- equiv_add gold_sig gate_sig
+ equiv_add [-try] gold_sig gate_sig
This command adds an $equiv cell for the specified signals.
+
+
+ equiv_add [-try] -cell gold_cell gate_cell
+
+This command adds $equiv cells for the ports of the specified cells.
\end{lstlisting}
\section{equiv\_induct -- proving \$equiv cells using temporal induction}
@@ -546,6 +578,17 @@ a trigger output), but instead uses $equiv cells to encode the equivalence
checking problem. Use 'miter -equiv' if you want to create a miter circuit.
\end{lstlisting}
+\section{equiv\_mark -- mark equivalence checking regions}
+\label{cmd:equiv_mark}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_mark [options] [selection]
+
+This command marks the regions in an equivalence checking module. Region 0 is
+the proven part of the circuit. Regions with higher numbers are connected
+unproven subcricuits. The integer attribute 'equiv_region' is set on all
+wires and cells.
+\end{lstlisting}
+
\section{equiv\_miter -- extract miter from equiv circuit}
\label{cmd:equiv_miter}
\begin{lstlisting}[numbers=left,frame=single]
@@ -566,6 +609,16 @@ This creates a miter module for further analysis of the selected $equiv cells.
Create compare logic that handles undefs correctly
\end{lstlisting}
+\section{equiv\_purge -- purge equivalence checking module}
+\label{cmd:equiv_purge}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_purge [options] [selection]
+
+This command removes the proven part of an equivalence checking module, leaving
+only the unproven segments in the design. This will also remove and add module
+ports as needed.
+\end{lstlisting}
+
\section{equiv\_remove -- remove \$equiv cells}
\label{cmd:equiv_remove}
\begin{lstlisting}[numbers=left,frame=single]
@@ -612,6 +665,36 @@ This command prints status information for all selected $equiv cells.
produce an error if any unproven $equiv cell is found
\end{lstlisting}
+\section{equiv\_struct -- structural equivalence checking}
+\label{cmd:equiv_struct}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_struct [options] [selection]
+
+This command adds additional $equiv cells based on the assumption that the
+gold and gate circuit are structurally equivalent. Note that this can introduce
+bad $equiv cells in cases where the netlists are not structurally equivalent,
+for example when analyzing circuits with cells with commutative inputs. This
+command will also de-duplicate gates.
+
+ -fwd
+ by default this command performans forward sweeps until nothing can
+ be merged by forwards sweeps, then backward sweeps until forward
+ sweeps are effective again. with this option set only forward sweeps
+ are performed.
+
+ -fwonly <cell_type>
+ add the specified cell type to the list of cell types that are only
+ merged in forward sweeps and never in backward sweeps. $equiv is in
+ this list automatically.
+
+ -icells
+ by default, the internal RTL and gate cell types are ignored. add
+ this option to also process those cell types with this command.
+
+ -maxiter <N>
+ maximum number of iterations to run before aborting
+\end{lstlisting}
+
\section{eval -- evaluate the circuit given an input}
\label{cmd:eval}
\begin{lstlisting}[numbers=left,frame=single]
@@ -949,9 +1032,13 @@ one-hot encoding and binary encoding is supported.
\section{help -- display help messages}
\label{cmd:help}
\begin{lstlisting}[numbers=left,frame=single]
- help ............. list all commands
- help <command> ... print help message for given command
- help -all ........ print complete command reference
+ help ................ list all commands
+ help <command> ...... print help message for given command
+ help -all ........... print complete command reference
+
+ help -cells .......... list all cell types
+ help <celltype> ..... print help message for given cell type
+ help <celltype>+ .... print verilog code for given cell type
\end{lstlisting}
\section{hierarchy -- check, expand and clean up design hierarchy}
@@ -1044,6 +1131,15 @@ all commands executed in an interactive session, but not the commands
from executed scripts.
\end{lstlisting}
+\section{ice40\_ffinit -- iCE40: handle FF init values}
+\label{cmd:ice40_ffinit}
+\begin{lstlisting}[numbers=left,frame=single]
+ ice40_ffinit [options] [selection]
+
+Remove zero init values for FF output signals. Add inverters to implement
+nonzero init values.
+\end{lstlisting}
+
\section{ice40\_ffssr -- iCE40: merge synchronous set/reset into FF cells}
\label{cmd:ice40_ffssr}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1078,10 +1174,10 @@ can only map to very simple PAD cells. Use 'techmap' to further map
the resulting cells to more sophisticated PAD cells.
-inpad <celltype> <portname>[:<portname>]
- Map module input ports to the given cell type with
- the given port name. if a 2nd portname is given, the
+ Map module input ports to the given cell type with the
+ given output port name. if a 2nd portname is given, the
signal is passed through the pad call, using the 2nd
- portname as output.
+ portname as input.
-outpad <celltype> <portname>[:<portname>]
-inoutpad <celltype> <portname>[:<portname>]
@@ -1149,6 +1245,14 @@ When no active module is selected, this prints a list of modules.
When an active module is selected, this prints a list of objects in the module.
\end{lstlisting}
+\section{lut2mux -- convert \$lut to \$\_MUX\_}
+\label{cmd:lut2mux}
+\begin{lstlisting}[numbers=left,frame=single]
+ lut2mux [options] [selection]
+
+This pass converts $lut cells to $_MUX_ gates.
+\end{lstlisting}
+
\section{maccmap -- mapping macc cells}
\label{cmd:maccmap}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1196,7 +1300,7 @@ rules. A block ram description looks like this:
groups 2 # number of port groups
ports 1 1 # number of ports in each group
wrmode 1 0 # set to '1' if this groups is write ports
- enable 4 0 # number of enable bits (for write ports)
+ enable 4 1 # number of enable bits
transp 0 2 # transparent (for read ports)
clocks 1 2 # clock configuration
clkpol 2 2 # clock polarity configuration
@@ -1391,6 +1495,22 @@ Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells
less efficient than the original circuit.
\end{lstlisting}
+\section{nlutmap -- map to LUTs of different sizes}
+\label{cmd:nlutmap}
+\begin{lstlisting}[numbers=left,frame=single]
+ nlutmap [options] [selection]
+
+This pass uses successive calls to 'abc' to map to an architecture. That
+provides a small number of differently sized LUTs.
+
+ -luts N_1,N_2,N_3,...
+ The number of LUTs with 1, 2, 3, ... inputs that are
+ available in the target architecture.
+
+Excess logic that does not fit into the specified LUTs is mapped back
+to generic logic gates ($_AND_, etc.).
+\end{lstlisting}
+
\section{opt -- perform simple optimizations}
\label{cmd:opt}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1554,6 +1674,49 @@ Load and list loaded plugins.
This pass transforms $pmux cells to a trees of $mux cells.
\end{lstlisting}
+\section{prep -- generic synthesis script}
+\label{cmd:prep}
+\begin{lstlisting}[numbers=left,frame=single]
+ prep [options]
+
+This command runs a conservative RTL synthesis. A typical application for this
+is the preparation stage of a verification flow. This command does not operate
+on partly selected designs.
+
+ -top <module>
+ use the specified module as top module (default='top')
+
+ -nordff
+ passed to 'memory_dff'. prohibits merging of FFs into memory read ports
+
+ -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.
+
+
+The following commands are executed by this synthesis command:
+
+ begin:
+ hierarchy -check [-top <top>]
+
+ prep:
+ proc
+ opt_const
+ opt_clean
+ check
+ opt -keepdc
+ wreduce
+ memory_dff [-nordff]
+ opt_clean
+ memory_collect
+ opt -keepdc -fast
+
+ check:
+ stat
+ check
+\end{lstlisting}
+
\section{proc -- translate processes to netlists}
\label{cmd:proc}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1650,6 +1813,32 @@ and case statements) to trees of multiplexer cells.
This pass identifies unreachable branches in decision trees and removes them.
\end{lstlisting}
+\section{qwp -- quadratic wirelength placer}
+\label{cmd:qwp}
+\begin{lstlisting}[numbers=left,frame=single]
+ qwp [options] [selection]
+
+This command runs quadratic wirelength placement on the selected modules and
+annotates the cells in the design with 'qwp_position' attributes.
+
+ -ltr
+ Add left-to-right constraints: constrain all inputs on the left border
+ outputs to the right border.
+
+ -alpha
+ Add constraints for inputs/outputs to be placed in alphanumerical
+ order along the y-axis (top-to-bottom).
+
+ -grid N
+ Number of grid divisions in x- and y-direction. (default=16)
+
+ -dump <html_file_name>
+ Dump a protocol of the placement algorithm to the html file.
+
+Note: This implementation of a quadratic wirelength placer uses exact
+dense matrix operations. It is only a toy-placer for small circuits.
+\end{lstlisting}
+
\section{read\_blif -- read BLIF file}
\label{cmd:read_blif}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1705,8 +1894,8 @@ Verilog-2005 is supported.
of SystemVerilog is supported)
-formal
- enable support for assert() and assume() statements
- (assert support is also enabled with -sv)
+ enable support for assert() and assume() from SystemVerilog
+ replace the implicit -D SYNTHESIS with -D FORMAL
-dump_ast1
dump abstract syntax tree (before simplification)
@@ -1757,6 +1946,9 @@ Verilog-2005 is supported.
-nopp
do not run the pre-processor
+ -nodpi
+ disable DPI-C support
+
-lib
only create empty blackbox modules. This implies -DBLACKBOX.
@@ -1870,6 +2062,9 @@ and additional constraints passed as parameters.
-show-inputs, -show-outputs, -show-ports
add all module (input/output) ports to the list of shown signals
+ -show-regs, -show-public, -show-all
+ show all registers, show signals with 'public' names, show all signals
+
-ignore_div_by_zero
ignore all solutions that involve a division by zero
@@ -2254,6 +2449,9 @@ The following actions can be performed on the top sets on the stack:
%C
select cells that implement selected modules
+ %R[<num>]
+ select <num> random objects from top selection (default 1)
+
Example: the following command selects all wires that are connected to a
'GATE' input of a 'SWITCH' cell:
@@ -2455,10 +2653,26 @@ primitives. The following internal cell types are mapped by this pass:
$not, $pos, $and, $or, $xor, $xnor
$reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool
- $logic_not, $logic_and, $logic_or, $mux
+ $logic_not, $logic_and, $logic_or, $mux, $tribuf
$sr, $dff, $dffsr, $adff, $dlatch
\end{lstlisting}
+\section{singleton -- create singleton modules}
+\label{cmd:singleton}
+\begin{lstlisting}[numbers=left,frame=single]
+ singleton [selection]
+
+By default, a module that is instantiated by several other modules is only
+kept once in the design. This preserves the original modularity of the design
+and reduces the overall size of the design in memory. But it prevents certain
+optimizations and other operations on the design. This pass creates singleton
+modules for all selected cells. The created modules are marked with the
+'singleton' attribute.
+
+This commands only operates on modules that by themself have the 'singleton'
+attribute set (the 'top' module is a singleton implicitly).
+\end{lstlisting}
+
\section{splice -- create explicit splicing cells}
\label{cmd:splice}
\begin{lstlisting}[numbers=left,frame=single]
@@ -2533,6 +2747,9 @@ design.
selected and a module has the 'top' attribute set, this module is used
default value for this option.
+ -liberty <liberty_file>
+ use cell area information from the provided liberty file
+
-width
annotate internal cell types with their word width.
e.g. $add_8 for an 8 bit wide $add cell.
@@ -2541,7 +2758,7 @@ design.
\section{submod -- moving part of a module to a new submodule}
\label{cmd:submod}
\begin{lstlisting}[numbers=left,frame=single]
- submod [selection]
+ submod [-copy] [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
@@ -2554,11 +2771,15 @@ This pass only operates on completely selected modules with no processes
or memories.
- submod -name <name> [selection]
+ submod -name <name> [-copy] [selection]
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.
+
+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.
\end{lstlisting}
\section{synth -- generic synthesis script}
@@ -2601,6 +2822,7 @@ The following commands are executed by this synthesis command:
coarse:
proc
+ opt_const
opt_clean
check
opt
@@ -2628,6 +2850,79 @@ The following commands are executed by this synthesis command:
check
\end{lstlisting}
+\section{synth\_greenpak4 -- synthesis for GreenPAK4 FPGAs}
+\label{cmd:synth_greenpak4}
+\begin{lstlisting}[numbers=left,frame=single]
+ synth_greenpak4 [options]
+
+This command runs synthesis for GreenPAK4 FPGAs. This work is experimental.
+
+ -top <module>
+ use the specified module as top module (default='top')
+
+ -blif <file>
+ write the design to the specified BLIF file. writing of an output file
+ is omitted if this parameter is not specified.
+
+ -edif <file>
+ write the design to the specified edif 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 option
+
+
+The following commands are executed by this synthesis command:
+
+ begin:
+ read_verilog -lib +/greenpak4/cells_sim.v
+ hierarchy -check -top <top>
+
+ flatten: (unless -noflatten)
+ proc
+ flatten
+ tribuf -logic
+
+ coarse:
+ synth -run coarse
+
+ fine:
+ opt -fast -mux_undef -undriven -fine
+ memory_map
+ opt -undriven -fine
+ techmap
+ dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib
+ opt -fast
+ abc -dff (only if -retime)
+
+ map_luts:
+ nlutmap -luts 0,8,16,2
+ clean
+
+ map_cells:
+ techmap -map +/greenpak4/cells_map.v
+ clean
+
+ check:
+ hierarchy -check
+ stat
+ check -noinit
+
+ blif:
+ write_blif -gates -attr -param <file-name>
+
+ edif:
+ write_edif <file-name>
+\end{lstlisting}
+
\section{synth\_ice40 -- synthesis for iCE40 FPGAs}
\label{cmd:synth_ice40}
\begin{lstlisting}[numbers=left,frame=single]
@@ -2663,6 +2958,9 @@ This command runs synthesis for iCE40 FPGAs. This work is experimental.
-nobram
do not use SB_RAM40_4K* cells in output netlist
+ -abc2
+ run two passes of 'abc' for slightly improved logic density
+
The following commands are executed by this synthesis command:
@@ -2673,6 +2971,7 @@ The following commands are executed by this synthesis command:
flatten: (unless -noflatten)
proc
flatten
+ tribuf -logic
coarse:
synth -run coarse
@@ -2690,14 +2989,18 @@ The following commands are executed by this synthesis command:
ice40_opt
map_ffs:
+ dffsr2dff
dff2dffe -direct-match $_DFF_*
techmap -map +/ice40/cells_map.v
opt_const -mux_undef
simplemap
+ ice40_ffinit
ice40_ffssr
ice40_opt -full
map_luts:
+ abc (only if -abc2)
+ ice40_opt (only if -abc2)
abc -lut 4
clean
@@ -2759,7 +3062,6 @@ The following commands are executed by this synthesis command:
coarse:
synth -run coarse
- dff2dffe
bram:
memory_bram -rules +/xilinx/brams.txt
@@ -2772,12 +3074,14 @@ The following commands are executed by this synthesis command:
fine:
opt -fast -full
memory_map
+ dffsr2dff
+ dff2dffe
opt -full
techmap -map +/techmap.v -map +/xilinx/arith_map.v
opt -fast
map_luts:
- abc -lut 5:8 [-dff]
+ abc -luts 2:2,3,6:5,10,20 [-dff]
clean
map_cells:
@@ -3040,6 +3344,9 @@ cell types. Use for example 'all /$add' for all cell types except $add.
-nosat
do not check SAT model or run SAT equivalence checking
+ -noeval
+ do not check const-eval models
+
-v
print additional debug information to the console
@@ -3047,6 +3354,21 @@ 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{torder -- print cells in topological order}
+\label{cmd:torder}
+\begin{lstlisting}[numbers=left,frame=single]
+ torder [options] [selection]
+
+This command prints the selected cells in topological order.
+
+ -stop <cell_type> <cell_port>
+ do not use the specified cell port in topological sorting
+
+ -noautostop
+ by default Q outputs of internal FF cells and memory read port outputs
+ are not used in topological sorting. this option deactivates that.
+\end{lstlisting}
+
\section{trace -- redirect command output to file}
\label{cmd:trace}
\begin{lstlisting}[numbers=left,frame=single]
@@ -3056,6 +3378,22 @@ Execute the specified command, logging all changes the command performs on
the design in real time.
\end{lstlisting}
+\section{tribuf -- infer tri-state buffers}
+\label{cmd:tribuf}
+\begin{lstlisting}[numbers=left,frame=single]
+ tribuf [options] [selection]
+
+This pass transforms $mux cells with 'z' inputs to tristate buffers.
+
+ -merge
+ merge multiple tri-state buffers driving the same net
+ into a single buffer.
+
+ -logic
+ convert tri-state buffers that do not drive output ports
+ to non-tristate logic. this option implies -merge.
+\end{lstlisting}
+
\section{verific -- load Verilog and VHDL designs using Verific}
\label{cmd:verific}
\begin{lstlisting}[numbers=left,frame=single]
@@ -3191,6 +3529,9 @@ file *.blif when any of this options is used.
-param
use the non-standard .param statement to write cell parameters
+ -cname
+ use the non-standard .cname statement to write cell names
+
-blackbox
write blackbox cells with .blackbox statement.
@@ -3526,6 +3867,9 @@ to the initial state.
-regs
also create '<mod>_n' functions for all registers.
+ -wires
+ also create '<mod>_n' functions for all public wires.
+
-tpl <template_file>
use the given template file. the line containing only the token '%%'
is replaced with the regular output of this command.
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index ce2f0388..01ada773 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -14,6 +14,7 @@ OBJS += passes/cmds/setattr.o
OBJS += passes/cmds/copy.o
OBJS += passes/cmds/splice.o
OBJS += passes/cmds/scc.o
+OBJS += passes/cmds/torder.o
OBJS += passes/cmds/logcmd.o
OBJS += passes/cmds/tee.o
OBJS += passes/cmds/write_file.o
diff --git a/passes/cmds/edgetypes.cc b/passes/cmds/edgetypes.cc
index 5f062c6e..7b75a009 100644
--- a/passes/cmds/edgetypes.cc
+++ b/passes/cmds/edgetypes.cc
@@ -52,7 +52,7 @@ struct EdgetypePass : public Pass {
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
- dict<SigBit, pool<std::tuple<IdString, IdString, int>>> bit_sources, bit_sinks;
+ dict<SigBit, pool<tuple<IdString, IdString, int>>> bit_sources, bit_sinks;
pool<std::pair<IdString, IdString>> multibit_ports;
for (auto cell : module->selected_cells())
@@ -67,9 +67,9 @@ struct EdgetypePass : public Pass {
for (int i = 0; i < GetSize(sig); i++) {
if (cell->output(port_name))
- bit_sources[sig[i]].insert(std::tuple<IdString, IdString, int>(cell_type, port_name, i));
+ bit_sources[sig[i]].insert(tuple<IdString, IdString, int>(cell_type, port_name, i));
if (cell->input(port_name))
- bit_sinks[sig[i]].insert(std::tuple<IdString, IdString, int>(cell_type, port_name, i));
+ bit_sinks[sig[i]].insert(tuple<IdString, IdString, int>(cell_type, port_name, i));
}
}
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
index f7c65bbd..e2d80d9b 100644
--- a/passes/cmds/plugin.cc
+++ b/passes/cmds/plugin.cc
@@ -115,7 +115,7 @@ struct PluginPass : public Pass {
log("\n");
int max_alias_len = 1;
for (auto &it : loaded_plugin_aliases)
- max_alias_len = std::max(max_alias_len, GetSize(it.first));
+ max_alias_len = max(max_alias_len, GetSize(it.first));
for (auto &it : loaded_plugin_aliases)
log("Alias: %-*s %s\n", max_alias_len, it.first.c_str(), it.second.c_str());
}
diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc
index 784076c3..8ec815a7 100644
--- a/passes/cmds/qwp.cc
+++ b/passes/cmds/qwp.cc
@@ -342,8 +342,8 @@ struct QwpWorker
double r = alt_mode ? alt_radius : radius;
if (std::isfinite(v)) {
- v = std::min(v, c+r);
- v = std::max(v, c-r);
+ v = min(v, c+r);
+ v = max(v, c-r);
} else {
v = c;
}
@@ -524,15 +524,15 @@ struct QwpWorker
if (rel_pos < 0) {
node.pos = midpos + left_scale*rel_pos;
if (std::isfinite(node.pos)) {
- node.pos = std::min(node.pos, midpos);
- node.pos = std::max(node.pos, midpos - radius);
+ node.pos = min(node.pos, midpos);
+ node.pos = max(node.pos, midpos - radius);
} else
node.pos = midpos - radius/2;
} else {
node.pos = midpos + right_scale*rel_pos;
if (std::isfinite(node.pos)) {
- node.pos = std::max(node.pos, midpos);
- node.pos = std::min(node.pos, midpos + radius);
+ node.pos = max(node.pos, midpos);
+ node.pos = min(node.pos, midpos + radius);
} else
node.pos = midpos + radius/2;
}
@@ -666,8 +666,8 @@ struct QwpWorker
double max_value = values.front();
for (auto &v : values) {
- min_value = std::min(min_value, v);
- max_value = std::max(max_value, v);
+ min_value = min(min_value, v);
+ max_value = max(max_value, v);
}
if (fabs(max_value - min_value) < 0.001) {
@@ -679,8 +679,8 @@ struct QwpWorker
int max_bucket_val = 0;
for (auto &v : values) {
- int idx = std::min(int(GetSize(buckets) * (v - min_value) / (max_value - min_value)), GetSize(buckets)-1);
- max_bucket_val = std::max(max_bucket_val, ++buckets.at(idx));
+ int idx = min(int(GetSize(buckets) * (v - min_value) / (max_value - min_value)), GetSize(buckets)-1);
+ max_bucket_val = max(max_bucket_val, ++buckets.at(idx));
}
for (int i = 4; i >= 0; i--) {
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index 43a43b4f..532026f2 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -69,10 +69,10 @@ struct SccWorker
for (auto nextCell : cellToNextCell[cell])
if (cellLabels.count(nextCell) == 0) {
run(nextCell, depth+1, maxDepth);
- cellLabels[cell].second = std::min(cellLabels[cell].second, cellLabels[nextCell].second);
+ cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
} else
if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
- cellLabels[cell].second = std::min(cellLabels[cell].second, cellLabels[nextCell].second);
+ cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
}
if (cellLabels[cell].first == cellLabels[cell].second)
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index d05000eb..3e64dd84 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -180,6 +180,47 @@ static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
lhs.selected_members.swap(new_sel.selected_members);
}
+static int my_xorshift32_rng() {
+ static uint32_t x32 = 314159265;
+ x32 ^= x32 << 13;
+ x32 ^= x32 >> 17;
+ x32 ^= x32 << 5;
+ return x32 & 0x0fffffff;
+}
+
+static void select_op_random(RTLIL::Design *design, RTLIL::Selection &lhs, int count)
+{
+ vector<pair<IdString, IdString>> objects;
+
+ for (auto mod : design->modules())
+ {
+ if (!lhs.selected_module(mod->name))
+ continue;
+
+ for (auto cell : mod->cells()) {
+ if (lhs.selected_member(mod->name, cell->name))
+ objects.push_back(make_pair(mod->name, cell->name));
+ }
+
+ for (auto wire : mod->wires()) {
+ if (lhs.selected_member(mod->name, wire->name))
+ objects.push_back(make_pair(mod->name, wire->name));
+ }
+ }
+
+ lhs = RTLIL::Selection(false);
+
+ while (!objects.empty() && count-- > 0)
+ {
+ int idx = my_xorshift32_rng() % GetSize(objects);
+ lhs.selected_members[objects[idx].first].insert(objects[idx].second);
+ objects[idx] = objects.back();
+ objects.pop_back();
+ }
+
+ lhs.optimize(design);
+}
+
static void select_op_submod(RTLIL::Design *design, RTLIL::Selection &lhs)
{
for (auto &mod_it : design->modules_)
@@ -634,6 +675,12 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
select_op_intersect(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
work_stack.pop_back();
} else
+ if (arg.size() >= 2 && arg[0] == '%' && arg[1] == 'R') {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on the stack for operator %%R.\n");
+ int count = arg.size() > 2 ? atoi(arg.c_str() + 2) : 1;
+ select_op_random(design, work_stack[work_stack.size()-1], count);
+ } else
if (arg == "%s") {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%s.\n");
@@ -1100,6 +1147,9 @@ struct SelectPass : public Pass {
log(" %%C\n");
log(" select cells that implement selected modules\n");
log("\n");
+ log(" %%R[<num>]\n");
+ log(" select <num> random objects from top selection (default 1)\n");
+ log("\n");
log("Example: the following command selects all wires that are connected to a\n");
log("'GATE' input of a 'SWITCH' cell:\n");
log("\n");
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 3035e730..3b03d680 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -552,7 +552,7 @@ struct ShowWorker
continue;
if (design->selected_whole_module(module->name)) {
if (module->get_bool_attribute("\\blackbox")) {
- log("Skipping blackbox module %s.\n", id2cstr(module->name));
+ // log("Skipping blackbox module %s.\n", id2cstr(module->name));
continue;
} else
if (module->cells_.empty() && module->connections().empty() && module->processes.empty()) {
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index 4ce2ec11..2556fb74 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -64,7 +64,7 @@ struct SpliceWorker
return sliced_signals_cache.at(sig);
int offset = 0;
- int p = driven_bits_map.at(sig.extract(0, 1).to_single_sigbit()) - 1;
+ int p = driven_bits_map.at(sig.extract(0, 1).as_bit()) - 1;
while (driven_bits.at(p) != RTLIL::State::Sm)
p--, offset++;
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index 3b6ad014..0d7892d7 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -130,6 +130,9 @@ struct SplitnetsPass : public Pass {
}
extra_args(args, argidx, design);
+ // module_ports_db[module_name][old_port_name] = new_port_name_list
+ dict<IdString, dict<IdString, vector<IdString>>> module_ports_db;
+
for (auto module : design->selected_modules())
{
SplitnetsWorker worker;
@@ -140,8 +143,8 @@ struct SplitnetsPass : public Pass {
for (auto wire : module->wires())
if (wire->port_id != 0) {
- normalized_port_factor = std::max(normalized_port_factor, wire->port_id+1);
- normalized_port_factor = std::max(normalized_port_factor, GetSize(wire)+1);
+ normalized_port_factor = max(normalized_port_factor, wire->port_id+1);
+ normalized_port_factor = max(normalized_port_factor, GetSize(wire)+1);
}
for (auto wire : module->wires())
@@ -199,6 +202,26 @@ struct SplitnetsPass : public Pass {
module->rewrite_sigspecs(worker);
+ if (flag_ports)
+ {
+ for (auto wire : module->wires())
+ {
+ if (wire->port_id == 0)
+ continue;
+
+ SigSpec sig(wire);
+ worker(sig);
+
+ if (sig == wire)
+ continue;
+
+ vector<IdString> &new_ports = module_ports_db[module->name][wire->name];
+
+ for (SigSpec c : sig.chunks())
+ new_ports.push_back(c.as_wire()->name);
+ }
+ }
+
pool<RTLIL::Wire*> delete_wires;
for (auto &it : worker.splitmap)
delete_wires.insert(it.first);
@@ -207,6 +230,40 @@ struct SplitnetsPass : public Pass {
if (flag_ports)
module->fixup_ports();
}
+
+ if (!module_ports_db.empty())
+ {
+ for (auto module : design->modules())
+ for (auto cell : module->cells())
+ {
+ if (module_ports_db.count(cell->type) == 0)
+ continue;
+
+ for (auto &it : module_ports_db.at(cell->type))
+ {
+ IdString port_id = it.first;
+ const auto &new_port_ids = it.second;
+
+ if (!cell->hasPort(port_id))
+ continue;
+
+ int offset = 0;
+ SigSpec sig = cell->getPort(port_id);
+
+ for (auto nid : new_port_ids)
+ {
+ int nlen = GetSize(design->module(cell->type)->wire(nid));
+ if (offset + nlen > GetSize(sig))
+ nlen = GetSize(sig) - offset;
+ if (nlen > 0)
+ cell->setPort(nid, sig.extract(offset, nlen));
+ offset += nlen;
+ }
+
+ cell->unsetPort(port_id);
+ }
+ }
+ }
}
} SplitnetsPass;
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 0aa76467..048933fc 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -19,6 +19,8 @@
#include "kernel/register.h"
#include "kernel/celltypes.h"
+#include "passes/techmap/libparse.h"
+
#include "kernel/log.h"
USING_YOSYS_NAMESPACE
@@ -29,17 +31,21 @@ struct statdata_t
#define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
+ #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area)
+
#define X(_name) int _name;
STAT_INT_MEMBERS
#undef X
+ double area;
std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
+ std::set<RTLIL::IdString> unknown_cell_area;
statdata_t operator+(const statdata_t &other) const
{
statdata_t sum = other;
#define X(_name) sum._name += _name;
- STAT_INT_MEMBERS
+ STAT_NUMERIC_MEMBERS
#undef X
for (auto &it : num_cells_by_type)
sum.num_cells_by_type[it.first] += it.second;
@@ -50,7 +56,7 @@ struct statdata_t
{
statdata_t sum = *this;
#define X(_name) sum._name *= other;
- STAT_INT_MEMBERS
+ STAT_NUMERIC_MEMBERS
#undef X
for (auto &it : sum.num_cells_by_type)
it.second *= other;
@@ -60,14 +66,14 @@ struct statdata_t
statdata_t()
{
#define X(_name) _name = 0;
- STAT_INT_MEMBERS
+ STAT_NUMERIC_MEMBERS
#undef X
}
- statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode)
+ statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area)
{
#define X(_name) _name = 0;
- STAT_INT_MEMBERS
+ STAT_NUMERIC_MEMBERS
#undef X
for (auto &it : mod->wires_)
@@ -110,7 +116,7 @@ struct statdata_t
int width_a = it.second->hasPort("\\A") ? GetSize(it.second->getPort("\\A")) : 0;
int width_b = it.second->hasPort("\\B") ? GetSize(it.second->getPort("\\B")) : 0;
int width_y = it.second->hasPort("\\Y") ? GetSize(it.second->getPort("\\Y")) : 0;
- cell_type = stringf("%s_%d", cell_type.c_str(), std::max<int>({width_a, width_b, width_y}));
+ cell_type = stringf("%s_%d", cell_type.c_str(), max<int>({width_a, width_b, width_y}));
}
else if (cell_type.in("$mux", "$pmux"))
cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort("\\Y")));
@@ -118,6 +124,13 @@ struct statdata_t
cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort("\\Q")));
}
+ if (!cell_area.empty()) {
+ if (cell_area.count(cell_type))
+ area += cell_area.at(cell_type);
+ else
+ unknown_cell_area.insert(cell_type);
+ }
+
num_cells++;
num_cells_by_type[cell_type]++;
}
@@ -141,6 +154,17 @@ struct statdata_t
log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type)
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
+
+ if (!unknown_cell_area.empty()) {
+ log("\n");
+ for (auto cell_type : unknown_cell_area)
+ log(" Area for cell type %s is unknown!\n", cell_type.c_str());
+ }
+
+ if (area != 0) {
+ log("\n");
+ log(" Chip area for this module: %f\n", area);
+ }
}
};
@@ -162,6 +186,26 @@ statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTL
return mod_data;
}
+void read_liberty_cellarea(dict<IdString, double> &cell_area, string liberty_file)
+{
+ std::ifstream f;
+ f.open(liberty_file.c_str());
+ if (f.fail())
+ log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
+ LibertyParser libparser(f);
+ f.close();
+
+ for (auto cell : libparser.ast->children)
+ {
+ if (cell->id != "cell" || cell->args.size() != 1)
+ continue;
+
+ LibertyAst *ar = cell->find("area");
+ if (ar != NULL && !ar->value.empty())
+ cell_area["\\" + cell->args[0]] = atof(ar->value.c_str());
+ }
+}
+
struct StatPass : public Pass {
StatPass() : Pass("stat", "print some statistics") { }
virtual void help()
@@ -178,6 +222,9 @@ struct StatPass : public Pass {
log(" selected and a module has the 'top' attribute set, this module is used\n");
log(" default value for this option.\n");
log("\n");
+ log(" -liberty <liberty_file>\n");
+ log(" use cell area information from the provided liberty file\n");
+ log("\n");
log(" -width\n");
log(" annotate internal cell types with their word width.\n");
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
@@ -190,6 +237,7 @@ struct StatPass : public Pass {
bool width_mode = false;
RTLIL::Module *top_mod = NULL;
std::map<RTLIL::IdString, statdata_t> mod_stat;
+ dict<IdString, double> cell_area;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -198,6 +246,12 @@ struct StatPass : public Pass {
width_mode = true;
continue;
}
+ if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
+ string liberty_file = args[++argidx];
+ rewrite_filename(liberty_file);
+ read_liberty_cellarea(cell_area, liberty_file);
+ continue;
+ }
if (args[argidx] == "-top" && argidx+1 < args.size()) {
if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
@@ -214,7 +268,7 @@ struct StatPass : public Pass {
if (mod->get_bool_attribute("\\top"))
top_mod = mod;
- statdata_t data(design, mod, width_mode);
+ statdata_t data(design, mod, width_mode, cell_area);
mod_stat[mod->name] = data;
log("\n");
@@ -223,7 +277,7 @@ struct StatPass : public Pass {
data.log_data();
}
- if (top_mod != NULL)
+ if (top_mod != NULL && GetSize(mod_stat) > 1)
{
log("\n");
log("=== design hierarchy ===\n");
diff --git a/passes/cmds/torder.cc b/passes/cmds/torder.cc
new file mode 100644
index 00000000..50317c02
--- /dev/null
+++ b/passes/cmds/torder.cc
@@ -0,0 +1,123 @@
+/*
+ * 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/celltypes.h"
+#include "kernel/sigtools.h"
+#include "kernel/utils.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct TorderPass : public Pass {
+ TorderPass() : Pass("torder", "print cells in topological order") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" torder [options] [selection]\n");
+ log("\n");
+ log("This command prints the selected cells in topological order.\n");
+ log("\n");
+ log(" -stop <cell_type> <cell_port>\n");
+ log(" do not use the specified cell port in topological sorting\n");
+ log("\n");
+ log(" -noautostop\n");
+ log(" by default Q outputs of internal FF cells and memory read port outputs\n");
+ log(" are not used in topological sorting. this option deactivates that.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool noautostop = false;
+ dict<IdString, pool<IdString>> stop_db;
+
+ log_header("Executing TORDER pass (print cells in topological order).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-stop" && argidx+2 < args.size()) {
+ IdString cell_type = RTLIL::escape_id(args[++argidx]);
+ IdString cell_port = RTLIL::escape_id(args[++argidx]);
+ stop_db[cell_type].insert(cell_port);
+ continue;
+ }
+ if (args[argidx] == "-noautostop") {
+ noautostop = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ log("module %s\n", log_id(module));
+
+ SigMap sigmap(module);
+ dict<SigBit, pool<IdString>> bit_drivers, bit_users;
+ TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
+
+ for (auto cell : module->selected_cells())
+ for (auto conn : cell->connections())
+ {
+ if (stop_db.count(cell->type) && stop_db.at(cell->type).count(conn.first))
+ continue;
+
+ if (!noautostop && yosys_celltypes.cell_known(cell->type)) {
+ if (conn.first.in("\\Q", "\\CTRL_OUT", "\\RD_DATA"))
+ continue;
+ if (cell->type == "$memrd" && conn.first == "\\DATA")
+ continue;
+ }
+
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ bit_users[bit].insert(cell->name);
+
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ bit_drivers[bit].insert(cell->name);
+
+ toposort.node(cell->name);
+ }
+
+ for (auto &it : bit_users)
+ if (bit_drivers.count(it.first))
+ for (auto driver_cell : bit_drivers.at(it.first))
+ for (auto user_cell : it.second)
+ toposort.edge(driver_cell, user_cell);
+
+ toposort.analyze_loops = true;
+ toposort.sort();
+
+ for (auto &it : toposort.loops) {
+ log(" loop");
+ for (auto cell : it)
+ log(" %s", log_id(cell));
+ log("\n");
+ }
+
+ for (auto cell : toposort.sorted)
+ log(" cell %s\n", log_id(cell));
+ }
+ }
+} TorderPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/Makefile.inc b/passes/equiv/Makefile.inc
index 548eaca3..dd7b3be0 100644
--- a/passes/equiv/Makefile.inc
+++ b/passes/equiv/Makefile.inc
@@ -6,4 +6,7 @@ OBJS += passes/equiv/equiv_status.o
OBJS += passes/equiv/equiv_add.o
OBJS += passes/equiv/equiv_remove.o
OBJS += passes/equiv/equiv_induct.o
+OBJS += passes/equiv/equiv_struct.o
+OBJS += passes/equiv/equiv_purge.o
+OBJS += passes/equiv/equiv_mark.o
diff --git a/passes/equiv/equiv_add.cc b/passes/equiv/equiv_add.cc
index 4ce750b1..0494a724 100644
--- a/passes/equiv/equiv_add.cc
+++ b/passes/equiv/equiv_add.cc
@@ -29,15 +29,19 @@ struct EquivAddPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" equiv_add gold_sig gate_sig\n");
+ log(" equiv_add [-try] gold_sig gate_sig\n");
log("\n");
log("This command adds an $equiv cell for the specified signals.\n");
log("\n");
+ log("\n");
+ log(" equiv_add [-try] -cell gold_cell gate_cell\n");
+ log("\n");
+ log("This command adds $equiv cells for the ports of the specified cells.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, Design *design)
{
- if (GetSize(args) != 3)
- cmd_error(args, GetSize(args)-1, "Invalid number of arguments.");
+ bool try_mode = false;
if (design->selected_active_module.empty())
log_cmd_error("This command must be executed in module context!\n");
@@ -45,44 +49,128 @@ struct EquivAddPass : public Pass {
Module *module = design->module(design->selected_active_module);
log_assert(module != nullptr);
- SigSpec gold_signal, gate_signal;
+ if (GetSize(args) > 1 && args[1] == "-try") {
+ args.erase(args.begin() + 1);
+ try_mode = true;
+ }
- if (!SigSpec::parse(gate_signal, module, args[2]))
- log_cmd_error("Error in gate signal: %s\n", args[2].c_str());
+ if (GetSize(args) == 4 && args[1] == "-cell")
+ {
+ Cell *gold_cell = module->cell(RTLIL::escape_id(args[2]));
+ Cell *gate_cell = module->cell(RTLIL::escape_id(args[3]));
- if (!SigSpec::parse_rhs(gate_signal, gold_signal, module, args[1]))
- log_cmd_error("Error in gold signal: %s\n", args[1].c_str());
+ if (gold_cell == nullptr) {
+ if (try_mode) {
+ log_warning("Can't find gold cell '%s'.\n", args[2].c_str());
+ return;
+ }
+ log_cmd_error("Can't find gold cell '%s'.\n", args[2].c_str());
+ }
- log_assert(GetSize(gold_signal) == GetSize(gate_signal));
- SigSpec equiv_signal = module->addWire(NEW_ID, GetSize(gold_signal));
+ if (gate_cell == nullptr) {
+ if (try_mode) {
+ log_warning("Can't find gate cell '%s'.\n", args[3].c_str());
+ return;
+ }
+ log_cmd_error("Can't find gate cell '%s'.\n", args[3].c_str());
+ }
- SigMap sigmap(module);
- sigmap.apply(gold_signal);
- sigmap.apply(gate_signal);
+ for (auto conn : gold_cell->connections())
+ {
+ auto port = conn.first;
+ SigSpec gold_sig = gold_cell->getPort(port);
+ SigSpec gate_sig = gate_cell->getPort(port);
+ int width = min(GetSize(gold_sig), GetSize(gate_sig));
- dict<SigBit, SigBit> to_equiv_bits;
- pool<Cell*> added_equiv_cells;
+ if (gold_cell->input(port) && gate_cell->input(port))
+ {
+ SigSpec combined_sig = module->addWire(NEW_ID, width);
- for (int i = 0; i < GetSize(gold_signal); i++) {
- Cell *equiv_cell = module->addEquiv(NEW_ID, gold_signal[i], gate_signal[i], equiv_signal[i]);
- equiv_cell->set_bool_attribute("\\keep");
- to_equiv_bits[gold_signal[i]] = equiv_signal[i];
- to_equiv_bits[gate_signal[i]] = equiv_signal[i];
- added_equiv_cells.insert(equiv_cell);
+ for (int i = 0; i < width; i++) {
+ module->addEquiv(NEW_ID, gold_sig[i], gate_sig[i], combined_sig[i]);
+ gold_sig[i] = gate_sig[i] = combined_sig[i];
+ }
+
+ gold_cell->setPort(port, gold_sig);
+ gate_cell->setPort(port, gate_sig);
+ continue;
+ }
+
+ if (gold_cell->output(port) && gate_cell->output(port))
+ {
+ SigSpec new_gold_wire = module->addWire(NEW_ID, width);
+ SigSpec new_gate_wire = module->addWire(NEW_ID, width);
+ SigSig gg_conn;
+
+ for (int i = 0; i < width; i++) {
+ module->addEquiv(NEW_ID, new_gold_wire[i], new_gold_wire[i], gold_sig[i]);
+ gg_conn.first.append(gate_sig[i]);
+ gg_conn.second.append(gold_sig[i]);
+ gold_sig[i] = new_gold_wire[i];
+ gate_sig[i] = new_gate_wire[i];
+ }
+
+ module->connect(gg_conn);
+ gold_cell->setPort(port, gold_sig);
+ gate_cell->setPort(port, gate_sig);
+ continue;
+ }
+ }
}
+ else
+ {
+ if (GetSize(args) != 3)
+ cmd_error(args, GetSize(args)-1, "Invalid number of arguments.");
- for (auto cell : module->cells())
- for (auto conn : cell->connections())
- if (!added_equiv_cells.count(cell) && cell->input(conn.first)) {
- SigSpec new_sig;
- for (auto bit : conn.second)
- if (to_equiv_bits.count(sigmap(bit)))
- new_sig.append(to_equiv_bits.at(sigmap(bit)));
- else
- new_sig.append(bit);
- if (conn.second != new_sig)
- cell->setPort(conn.first, new_sig);
+ SigSpec gold_signal, gate_signal;
+
+ if (!SigSpec::parse(gate_signal, module, args[2])) {
+ if (try_mode) {
+ log_warning("Error in gate signal: %s\n", args[2].c_str());
+ return;
+ }
+ log_cmd_error("Error in gate signal: %s\n", args[2].c_str());
+ }
+
+ if (!SigSpec::parse_rhs(gate_signal, gold_signal, module, args[1])) {
+ if (try_mode) {
+ log_warning("Error in gold signal: %s\n", args[1].c_str());
+ return;
+ }
+ log_cmd_error("Error in gold signal: %s\n", args[1].c_str());
+ }
+
+ log_assert(GetSize(gold_signal) == GetSize(gate_signal));
+ SigSpec equiv_signal = module->addWire(NEW_ID, GetSize(gold_signal));
+
+ SigMap sigmap(module);
+ sigmap.apply(gold_signal);
+ sigmap.apply(gate_signal);
+
+ dict<SigBit, SigBit> to_equiv_bits;
+ pool<Cell*> added_equiv_cells;
+
+ for (int i = 0; i < GetSize(gold_signal); i++) {
+ Cell *equiv_cell = module->addEquiv(NEW_ID, gold_signal[i], gate_signal[i], equiv_signal[i]);
+ equiv_cell->set_bool_attribute("\\keep");
+ to_equiv_bits[gold_signal[i]] = equiv_signal[i];
+ to_equiv_bits[gate_signal[i]] = equiv_signal[i];
+ added_equiv_cells.insert(equiv_cell);
}
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections())
+ if (!added_equiv_cells.count(cell) && cell->input(conn.first)) {
+ SigSpec new_sig;
+ for (auto bit : conn.second)
+ if (to_equiv_bits.count(sigmap(bit)))
+ new_sig.append(to_equiv_bits.at(sigmap(bit)));
+ else
+ new_sig.append(bit);
+ if (conn.second != new_sig)
+ cell->setPort(conn.first, new_sig);
+ }
+ }
}
} EquivAddPass;
diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc
index a536fe30..cdb951ec 100644
--- a/passes/equiv/equiv_induct.cc
+++ b/passes/equiv/equiv_induct.cc
@@ -59,8 +59,8 @@ struct EquivInductWorker
cell_warn_cache.insert(cell);
}
if (cell->type == "$equiv") {
- SigBit bit_a = sigmap(cell->getPort("\\A")).to_single_sigbit();
- SigBit bit_b = sigmap(cell->getPort("\\B")).to_single_sigbit();
+ SigBit bit_a = sigmap(cell->getPort("\\A")).as_bit();
+ SigBit bit_b = sigmap(cell->getPort("\\B")).as_bit();
if (bit_a != bit_b) {
int ez_a = satgen.importSigBit(bit_a, step);
int ez_b = satgen.importSigBit(bit_b, step);
@@ -137,8 +137,8 @@ struct EquivInductWorker
for (auto cell : workset)
{
- SigBit bit_a = sigmap(cell->getPort("\\A")).to_single_sigbit();
- SigBit bit_b = sigmap(cell->getPort("\\B")).to_single_sigbit();
+ SigBit bit_a = sigmap(cell->getPort("\\A")).as_bit();
+ SigBit bit_b = sigmap(cell->getPort("\\B")).as_bit();
log(" Trying to prove $equiv for %s:", log_signal(sigmap(cell->getPort("\\Y"))));
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
index c001fdbf..8b063c54 100644
--- a/passes/equiv/equiv_make.cc
+++ b/passes/equiv/equiv_make.cc
@@ -280,7 +280,7 @@ struct EquivMakeWorker
for (auto c : cells_list)
for (auto &conn : c->connections())
- if (ct.cell_input(c->type, conn.first)) {
+ if (!ct.cell_output(c->type, conn.first)) {
SigSpec old_sig = assign_map(conn.second);
SigSpec new_sig = rd_signal_map(old_sig);
if (old_sig != new_sig) {
diff --git a/passes/equiv/equiv_mark.cc b/passes/equiv/equiv_mark.cc
new file mode 100644
index 00000000..3e9819d1
--- /dev/null
+++ b/passes/equiv/equiv_mark.cc
@@ -0,0 +1,239 @@
+/*
+ * 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
+
+struct EquivMarkWorker
+{
+ Module *module;
+ SigMap sigmap;
+
+ // cache for traversing signal flow graph
+ dict<SigBit, pool<IdString>> up_bit2cells;
+ dict<IdString, pool<SigBit>> up_cell2bits;
+ pool<IdString> edge_cells, equiv_cells;
+
+ // graph traversal state
+ pool<SigBit> queue, visited;
+
+ // assigned regions
+ dict<IdString, int> cell_regions;
+ dict<SigBit, int> bit_regions;
+ int next_region;
+
+ // merge-find
+ mfp<int> region_mf;
+
+ EquivMarkWorker(Module *module) : module(module), sigmap(module)
+ {
+ for (auto cell : module->cells())
+ {
+ if (cell->type == "$equiv")
+ equiv_cells.insert(cell->name);
+
+ for (auto &port : cell->connections())
+ {
+ if (cell->input(port.first))
+ for (auto bit : sigmap(port.second))
+ up_cell2bits[cell->name].insert(bit);
+
+ if (cell->output(port.first))
+ for (auto bit : sigmap(port.second))
+ up_bit2cells[bit].insert(cell->name);
+ }
+ }
+
+ next_region = 0;
+ }
+
+ void mark()
+ {
+ while (!queue.empty())
+ {
+ pool<IdString> cells;
+
+ for (auto &bit : queue)
+ {
+ // log_assert(bit_regions.count(bit) == 0);
+ bit_regions[bit] = next_region;
+ visited.insert(bit);
+
+ for (auto cell : up_bit2cells[bit])
+ if (edge_cells.count(cell) == 0)
+ cells.insert(cell);
+ }
+
+ queue.clear();
+
+ for (auto cell : cells)
+ {
+ if (next_region == 0 && equiv_cells.count(cell))
+ continue;
+
+ if (cell_regions.count(cell)) {
+ if (cell_regions.at(cell) != 0)
+ region_mf.merge(cell_regions.at(cell), next_region);
+ continue;
+ }
+
+ cell_regions[cell] = next_region;
+
+ for (auto bit : up_cell2bits[cell])
+ if (visited.count(bit) == 0)
+ queue.insert(bit);
+ }
+ }
+
+ next_region++;
+ }
+
+ void run()
+ {
+ log("Running equiv_mark on module %s:\n", log_id(module));
+
+ // marking region 0
+
+ for (auto wire : module->wires())
+ if (wire->port_id > 0)
+ for (auto bit : sigmap(wire))
+ queue.insert(bit);
+
+ for (auto cell_name : equiv_cells)
+ {
+ auto cell = module->cell(cell_name);
+
+ SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = sigmap(cell->getPort("\\B"));
+
+ if (sig_a == sig_b) {
+ for (auto bit : sig_a)
+ queue.insert(bit);
+ edge_cells.insert(cell_name);
+ cell_regions[cell_name] = 0;
+ }
+ }
+
+ mark();
+
+ // marking unsolved regions
+
+ for (auto cell : module->cells())
+ {
+ if (cell_regions.count(cell->name) || cell->type != "$equiv")
+ continue;
+
+ SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = sigmap(cell->getPort("\\B"));
+
+ log_assert(sig_a != sig_b);
+
+ for (auto bit : sig_a)
+ queue.insert(bit);
+
+ for (auto bit : sig_b)
+ queue.insert(bit);
+
+ cell_regions[cell->name] = next_region;
+ mark();
+ }
+
+ // setting attributes
+
+ dict<int, int> final_region_map;
+ int next_final_region = 0;
+
+ dict<int, int> region_cell_count;
+ dict<int, int> region_wire_count;
+
+ for (int i = 0; i < next_region; i++) {
+ int r = region_mf.find(i);
+ if (final_region_map.count(r) == 0)
+ final_region_map[r] = next_final_region++;
+ final_region_map[i] = final_region_map[r];
+ }
+
+ for (auto cell : module->cells())
+ {
+ if (cell_regions.count(cell->name)) {
+ int r = final_region_map.at(cell_regions.at(cell->name));
+ cell->attributes["\\equiv_region"] = Const(r);
+ region_cell_count[r]++;
+ } else
+ cell->attributes.erase("\\equiv_region");
+ }
+
+ for (auto wire : module->wires())
+ {
+ pool<int> regions;
+ for (auto bit : sigmap(wire))
+ if (bit_regions.count(bit))
+ regions.insert(region_mf.find(bit_regions.at(bit)));
+
+ if (GetSize(regions) == 1) {
+ int r = final_region_map.at(*regions.begin());
+ wire->attributes["\\equiv_region"] = Const(r);
+ region_wire_count[r]++;
+ } else
+ wire->attributes.erase("\\equiv_region");
+ }
+
+ for (int i = 0; i < next_final_region; i++)
+ log(" region %d: %d cells, %d wires\n", i, region_wire_count[i], region_cell_count[i]);
+ }
+};
+
+struct EquivMarkPass : public Pass {
+ EquivMarkPass() : Pass("equiv_mark", "mark equivalence checking regions") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_mark [options] [selection]\n");
+ log("\n");
+ log("This command marks the regions in an equivalence checking module. Region 0 is\n");
+ log("the proven part of the circuit. Regions with higher numbers are connected\n");
+ log("unproven subcricuits. The integer attribute 'equiv_region' is set on all\n");
+ log("wires and cells.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ log_header("Executing EQUIV_MARK pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ // if (args[argidx] == "-foobar") {
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_whole_modules_warn()) {
+ EquivMarkWorker worker(module);
+ worker.run();
+ }
+ }
+} EquivMarkPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc
index 34318dec..982176c4 100644
--- a/passes/equiv/equiv_miter.cc
+++ b/passes/equiv/equiv_miter.cc
@@ -156,7 +156,7 @@ struct EquivMiterWorker
struct RewriteSigSpecWorker {
RTLIL::Module * mod;
void operator()(SigSpec &sig) {
- vector<RTLIL::SigChunk> chunks = sig.chunks();
+ vector<SigChunk> chunks = sig.chunks();
for (auto &c : chunks)
if (c.wire != NULL)
c.wire = mod->wires_.at(c.wire->name);
diff --git a/passes/equiv/equiv_purge.cc b/passes/equiv/equiv_purge.cc
new file mode 100644
index 00000000..f4141ad4
--- /dev/null
+++ b/passes/equiv/equiv_purge.cc
@@ -0,0 +1,210 @@
+/*
+ * 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
+
+struct EquivPurgeWorker
+{
+ Module *module;
+ SigMap sigmap;
+ int name_cnt;
+
+ EquivPurgeWorker(Module *module) : module(module), sigmap(module), name_cnt(0) { }
+
+ SigSpec make_output(SigSpec sig, IdString cellname)
+ {
+ if (sig.is_wire()) {
+ Wire *wire = sig.as_wire();
+ if (wire->name[0] == '\\') {
+ if (!wire->port_output) {
+ log(" Module output: %s (%s)\n", log_signal(wire), log_id(cellname));
+ wire->port_output = true;
+ }
+ return wire;
+ }
+ }
+
+ while (1)
+ {
+ IdString name = stringf("\\equiv_%d", name_cnt++);
+ if (module->count_id(name))
+ continue;
+
+ Wire *wire = module->addWire(name, GetSize(sig));
+ wire->port_output = true;
+ module->connect(wire, sig);
+ log(" Module output: %s (%s)\n", log_signal(wire), log_id(cellname));
+ return wire;
+ }
+ }
+
+ SigSpec make_input(SigSpec sig)
+ {
+ if (sig.is_wire()) {
+ Wire *wire = sig.as_wire();
+ if (wire->name[0] == '\\') {
+ if (!wire->port_output) {
+ log(" Module input: %s\n", log_signal(wire));
+ wire->port_input = true;
+ }
+ return module->addWire(NEW_ID, GetSize(sig));
+ }
+ }
+
+ while (1)
+ {
+ IdString name = stringf("\\equiv_%d", name_cnt++);
+ if (module->count_id(name))
+ continue;
+
+ Wire *wire = module->addWire(name, GetSize(sig));
+ wire->port_input = true;
+ module->connect(sig, wire);
+ log(" Module input: %s\n", log_signal(wire));
+ return module->addWire(NEW_ID, GetSize(sig));
+ }
+ }
+
+ void run()
+ {
+ log("Running equiv_purge on module %s:\n", log_id(module));
+
+ for (auto wire : module->wires()) {
+ wire->port_input = false;
+ wire->port_output = false;
+ }
+
+ pool<SigBit> queue, visited;
+
+ // cache for traversing signal flow graph
+ dict<SigBit, pool<IdString>> up_bit2cells;
+ dict<IdString, pool<SigBit>> up_cell2bits;
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type != "$equiv") {
+ for (auto &port : cell->connections()) {
+ if (cell->input(port.first))
+ for (auto bit : sigmap(port.second))
+ up_cell2bits[cell->name].insert(bit);
+ if (cell->output(port.first))
+ for (auto bit : sigmap(port.second))
+ up_bit2cells[bit].insert(cell->name);
+ }
+ continue;
+ }
+
+ SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = sigmap(cell->getPort("\\B"));
+ SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+
+ if (sig_a == sig_b)
+ continue;
+
+ for (auto bit : sig_a)
+ queue.insert(bit);
+
+ for (auto bit : sig_b)
+ queue.insert(bit);
+
+ for (auto bit : sig_y)
+ visited.insert(bit);
+
+ cell->setPort("\\Y", make_output(sig_y, cell->name));
+ }
+
+ SigSpec srcsig;
+ SigMap rewrite_sigmap(module);
+
+ while (!queue.empty())
+ {
+ pool<SigBit> next_queue;
+
+ for (auto bit : queue)
+ visited.insert(bit);
+
+ for (auto bit : queue)
+ {
+ auto &cells = up_bit2cells[bit];
+
+ if (cells.empty()) {
+ srcsig.append(bit);
+ } else {
+ for (auto cell : cells)
+ for (auto bit : up_cell2bits[cell])
+ if (visited.count(bit) == 0)
+ next_queue.insert(bit);
+ }
+ }
+
+ next_queue.swap(queue);
+ }
+
+ srcsig.sort_and_unify();
+
+ for (SigChunk chunk : srcsig.chunks())
+ if (chunk.wire != nullptr)
+ rewrite_sigmap.add(chunk, make_input(chunk));
+
+ for (auto cell : module->cells())
+ if (cell->type == "$equiv")
+ cell->setPort("\\Y", rewrite_sigmap(sigmap(cell->getPort("\\Y"))));
+
+ module->fixup_ports();
+ }
+};
+
+struct EquivPurgePass : public Pass {
+ EquivPurgePass() : Pass("equiv_purge", "purge equivalence checking module") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_purge [options] [selection]\n");
+ log("\n");
+ log("This command removes the proven part of an equivalence checking module, leaving\n");
+ log("only the unproven segments in the design. This will also remove and add module\n");
+ log("ports as needed.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ log_header("Executing EQUIV_PURGE pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ // if (args[argidx] == "-foobar") {
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_whole_modules_warn()) {
+ EquivPurgeWorker worker(module);
+ worker.run();
+ }
+ }
+} EquivPurgePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc
index 1f52a632..fa22dc62 100644
--- a/passes/equiv/equiv_simple.cc
+++ b/passes/equiv/equiv_simple.cc
@@ -89,8 +89,8 @@ struct EquivSimpleWorker
bool run_cell()
{
- SigBit bit_a = sigmap(equiv_cell->getPort("\\A")).to_single_sigbit();
- SigBit bit_b = sigmap(equiv_cell->getPort("\\B")).to_single_sigbit();
+ SigBit bit_a = sigmap(equiv_cell->getPort("\\A")).as_bit();
+ SigBit bit_b = sigmap(equiv_cell->getPort("\\B")).as_bit();
int ez_context = ez->frozen_literal();
if (satgen.model_undef)
@@ -314,7 +314,7 @@ struct EquivSimplePass : public Pass {
for (auto cell : module->selected_cells())
if (cell->type == "$equiv" && cell->getPort("\\A") != cell->getPort("\\B")) {
- auto bit = sigmap(cell->getPort("\\Y").to_single_sigbit());
+ auto bit = sigmap(cell->getPort("\\Y").as_bit());
auto bit_group = bit;
if (!nogroup && bit_group.wire)
bit_group.offset = 0;
diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc
new file mode 100644
index 00000000..2c85d2d3
--- /dev/null
+++ b/passes/equiv/equiv_struct.cc
@@ -0,0 +1,367 @@
+/*
+ * 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
+
+struct EquivStructWorker
+{
+ Module *module;
+ SigMap sigmap;
+ SigMap equiv_bits;
+ bool mode_fwd;
+ bool mode_icells;
+ int merge_count;
+
+ const pool<IdString> &fwonly_cells;
+
+ struct merge_key_t
+ {
+ IdString type;
+ vector<pair<IdString, Const>> parameters;
+ vector<pair<IdString, int>> port_sizes;
+ vector<tuple<IdString, int, SigBit>> connections;
+
+ bool operator==(const merge_key_t &other) const {
+ return type == other.type && connections == other.connections &&
+ parameters == other.parameters && port_sizes == other.port_sizes;
+ }
+
+ unsigned int hash() const {
+ unsigned int h = mkhash_init;
+ h = mkhash(h, mkhash(type));
+ h = mkhash(h, mkhash(parameters));
+ h = mkhash(h, mkhash(connections));
+ return h;
+ }
+ };
+
+ dict<merge_key_t, pool<IdString>> merge_cache;
+ pool<merge_key_t> fwd_merge_cache, bwd_merge_cache;
+
+ void merge_cell_pair(Cell *cell_a, Cell *cell_b)
+ {
+ SigMap merged_map;
+ merge_count++;
+
+ SigSpec inputs_a, inputs_b;
+ vector<string> input_names;
+
+ for (auto &port_a : cell_a->connections())
+ {
+ SigSpec bits_a = sigmap(port_a.second);
+ SigSpec bits_b = sigmap(cell_b->getPort(port_a.first));
+
+ log_assert(GetSize(bits_a) == GetSize(bits_b));
+
+ if (!cell_a->output(port_a.first))
+ for (int i = 0; i < GetSize(bits_a); i++)
+ if (bits_a[i] != bits_b[i]) {
+ inputs_a.append(bits_a[i]);
+ inputs_b.append(bits_b[i]);
+ input_names.push_back(GetSize(bits_a) == 1 ? port_a.first.str() :
+ stringf("%s[%d]", log_id(port_a.first), i));
+ }
+ }
+
+ for (int i = 0; i < GetSize(inputs_a); i++) {
+ SigBit bit_a = inputs_a[i], bit_b = inputs_b[i];
+ SigBit bit_y = module->addWire(NEW_ID);
+ log(" New $equiv for input %s: A: %s, B: %s, Y: %s\n",
+ input_names[i].c_str(), log_signal(bit_a), log_signal(bit_b), log_signal(bit_y));
+ module->addEquiv(NEW_ID, bit_a, bit_b, bit_y);
+ merged_map.add(bit_a, bit_y);
+ merged_map.add(bit_b, bit_y);
+ }
+
+ std::vector<IdString> outport_names, inport_names;
+
+ for (auto &port_a : cell_a->connections())
+ if (cell_a->output(port_a.first))
+ outport_names.push_back(port_a.first);
+ else
+ inport_names.push_back(port_a.first);
+
+ for (auto &pn : inport_names)
+ cell_a->setPort(pn, merged_map(sigmap(cell_a->getPort(pn))));
+
+ for (auto &pn : outport_names) {
+ SigSpec sig_a = cell_a->getPort(pn);
+ SigSpec sig_b = cell_b->getPort(pn);
+ module->connect(sig_b, sig_a);
+ }
+
+ auto merged_attr = cell_b->get_strpool_attribute("\\equiv_merged");
+ merged_attr.insert(log_id(cell_b));
+ cell_a->add_strpool_attribute("\\equiv_merged", merged_attr);
+ module->remove(cell_b);
+ }
+
+ EquivStructWorker(Module *module, bool mode_fwd, bool mode_icells, const pool<IdString> &fwonly_cells, int iter_num) :
+ module(module), sigmap(module), equiv_bits(module),
+ mode_fwd(mode_fwd), mode_icells(mode_icells), merge_count(0), fwonly_cells(fwonly_cells)
+ {
+ log(" Starting iteration %d.\n", iter_num);
+
+ pool<SigBit> equiv_inputs;
+ pool<IdString> cells;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv") {
+ SigBit sig_a = sigmap(cell->getPort("\\A").as_bit());
+ SigBit sig_b = sigmap(cell->getPort("\\B").as_bit());
+ equiv_bits.add(sig_b, sig_a);
+ equiv_inputs.insert(sig_a);
+ equiv_inputs.insert(sig_b);
+ cells.insert(cell->name);
+ } else {
+ if (mode_icells || module->design->module(cell->type))
+ cells.insert(cell->name);
+ }
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv") {
+ SigBit sig_a = sigmap(cell->getPort("\\A").as_bit());
+ SigBit sig_b = sigmap(cell->getPort("\\B").as_bit());
+ SigBit sig_y = sigmap(cell->getPort("\\Y").as_bit());
+ if (sig_a == sig_b && equiv_inputs.count(sig_y)) {
+ log(" Purging redundant $equiv cell %s.\n", log_id(cell));
+ module->connect(sig_y, sig_a);
+ module->remove(cell);
+ merge_count++;
+ }
+ }
+
+ if (merge_count > 0)
+ return;
+
+ for (auto cell_name : cells)
+ {
+ merge_key_t key;
+ vector<tuple<IdString, int, SigBit>> fwd_connections;
+
+ Cell *cell = module->cell(cell_name);
+ key.type = cell->type;
+
+ for (auto &it : cell->parameters)
+ key.parameters.push_back(it);
+ std::sort(key.parameters.begin(), key.parameters.end());
+
+ for (auto &it : cell->connections())
+ key.port_sizes.push_back(make_pair(it.first, GetSize(it.second)));
+ std::sort(key.port_sizes.begin(), key.port_sizes.end());
+
+ for (auto &conn : cell->connections())
+ {
+ if (cell->input(conn.first)) {
+ SigSpec sig = sigmap(conn.second);
+ for (int i = 0; i < GetSize(sig); i++)
+ fwd_connections.push_back(make_tuple(conn.first, i, sig[i]));
+ }
+
+ if (cell->output(conn.first)) {
+ SigSpec sig = equiv_bits(conn.second);
+ for (int i = 0; i < GetSize(sig); i++) {
+ key.connections.clear();
+ key.connections.push_back(make_tuple(conn.first, i, sig[i]));
+
+ if (merge_cache.count(key))
+ bwd_merge_cache.insert(key);
+ merge_cache[key].insert(cell_name);
+ }
+ }
+ }
+
+ std::sort(fwd_connections.begin(), fwd_connections.end());
+ key.connections.swap(fwd_connections);
+
+ if (merge_cache.count(key))
+ fwd_merge_cache.insert(key);
+ merge_cache[key].insert(cell_name);
+ }
+
+ for (int phase = 0; phase < 2; phase++)
+ {
+ auto &queue = phase ? bwd_merge_cache : fwd_merge_cache;
+
+ for (auto &key : queue)
+ {
+ const char *strategy = nullptr;
+ vector<Cell*> gold_cells, gate_cells, other_cells;
+ vector<pair<Cell*, Cell*>> cell_pairs;
+ IdString cells_type;
+
+ for (auto cell_name : merge_cache[key]) {
+ Cell *c = module->cell(cell_name);
+ if (c != nullptr) {
+ string n = cell_name.str();
+ cells_type = c->type;
+ if (GetSize(n) > 5 && n.substr(GetSize(n)-5) == "_gold")
+ gold_cells.push_back(c);
+ else if (GetSize(n) > 5 && n.substr(GetSize(n)-5) == "_gate")
+ gate_cells.push_back(c);
+ else
+ other_cells.push_back(c);
+ }
+ }
+
+ if (phase && fwonly_cells.count(cells_type))
+ continue;
+
+ if (GetSize(gold_cells) > 1 || GetSize(gate_cells) > 1 || GetSize(other_cells) > 1)
+ {
+ strategy = "deduplicate";
+ for (int i = 0; i+1 < GetSize(gold_cells); i += 2)
+ cell_pairs.push_back(make_pair(gold_cells[i], gold_cells[i+1]));
+ for (int i = 0; i+1 < GetSize(gate_cells); i += 2)
+ cell_pairs.push_back(make_pair(gate_cells[i], gate_cells[i+1]));
+ for (int i = 0; i+1 < GetSize(other_cells); i += 2)
+ cell_pairs.push_back(make_pair(other_cells[i], other_cells[i+1]));
+ goto run_strategy;
+ }
+
+ if (GetSize(gold_cells) == 1 && GetSize(gate_cells) == 1)
+ {
+ strategy = "gold-gate-pairs";
+ cell_pairs.push_back(make_pair(gold_cells[0], gate_cells[0]));
+ goto run_strategy;
+ }
+
+ if (GetSize(gold_cells) == 1 && GetSize(other_cells) == 1)
+ {
+ strategy = "gold-guess";
+ cell_pairs.push_back(make_pair(gold_cells[0], other_cells[0]));
+ goto run_strategy;
+ }
+
+ if (GetSize(other_cells) == 1 && GetSize(gate_cells) == 1)
+ {
+ strategy = "gate-guess";
+ cell_pairs.push_back(make_pair(other_cells[0], gate_cells[0]));
+ goto run_strategy;
+ }
+
+ log_assert(GetSize(gold_cells) + GetSize(gate_cells) + GetSize(other_cells) < 2);
+ continue;
+
+ run_strategy:
+ int total_group_size = GetSize(gold_cells) + GetSize(gate_cells) + GetSize(other_cells);
+ log(" %s merging %d %s cells (from group of %d) using strategy %s:\n", phase ? "Bwd" : "Fwd",
+ 2*GetSize(cell_pairs), log_id(cells_type), total_group_size, strategy);
+ for (auto it : cell_pairs) {
+ log(" Merging cells %s and %s.\n", log_id(it.first), log_id(it.second));
+ merge_cell_pair(it.first, it.second);
+ }
+ }
+
+ if (merge_count > 0)
+ return;
+ }
+
+ log(" Nothing to merge.\n");
+ }
+};
+
+struct EquivStructPass : public Pass {
+ EquivStructPass() : Pass("equiv_struct", "structural equivalence checking") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_struct [options] [selection]\n");
+ log("\n");
+ log("This command adds additional $equiv cells based on the assumption that the\n");
+ log("gold and gate circuit are structurally equivalent. Note that this can introduce\n");
+ log("bad $equiv cells in cases where the netlists are not structurally equivalent,\n");
+ log("for example when analyzing circuits with cells with commutative inputs. This\n");
+ log("command will also de-duplicate gates.\n");
+ log("\n");
+ log(" -fwd\n");
+ log(" by default this command performans forward sweeps until nothing can\n");
+ log(" be merged by forwards sweeps, then backward sweeps until forward\n");
+ log(" sweeps are effective again. with this option set only forward sweeps\n");
+ log(" are performed.\n");
+ log("\n");
+ log(" -fwonly <cell_type>\n");
+ log(" add the specified cell type to the list of cell types that are only\n");
+ log(" merged in forward sweeps and never in backward sweeps. $equiv is in\n");
+ log(" this list automatically.\n");
+ log("\n");
+ log(" -icells\n");
+ log(" by default, the internal RTL and gate cell types are ignored. add\n");
+ log(" this option to also process those cell types with this command.\n");
+ log("\n");
+ log(" -maxiter <N>\n");
+ log(" maximum number of iterations to run before aborting\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ pool<IdString> fwonly_cells({ "$equiv" });
+ bool mode_icells = false;
+ bool mode_fwd = false;
+ int max_iter = -1;
+
+ log_header("Executing EQUIV_STRUCT pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-fwd") {
+ mode_fwd = true;
+ continue;
+ }
+ if (args[argidx] == "-icells") {
+ mode_icells = true;
+ continue;
+ }
+ if (args[argidx] == "-fwonly" && argidx+1 < args.size()) {
+ fwonly_cells.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ if (args[argidx] == "-maxiter" && argidx+1 < args.size()) {
+ max_iter = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules()) {
+ int module_merge_count = 0;
+ log("Running equiv_struct on module %s:\n", log_id(module));
+ for (int iter = 0;; iter++) {
+ if (iter == max_iter) {
+ log(" Reached iteration limit of %d.\n", iter);
+ break;
+ }
+ EquivStructWorker worker(module, mode_fwd, mode_icells, fwonly_cells, iter+1);
+ if (worker.merge_count == 0)
+ break;
+ module_merge_count += worker.merge_count;
+ }
+ if (module_merge_count)
+ log(" Performed a total of %d merges in module %s.\n", module_merge_count, log_id(module));
+ }
+ }
+} EquivStructPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index 7322368c..a7cc95ff 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -78,7 +78,7 @@ struct FsmOpt
bool signal_is_unused(RTLIL::SigSpec sig)
{
- RTLIL::SigBit bit = sig.to_single_sigbit();
+ RTLIL::SigBit bit = sig.as_bit();
if (bit.wire == NULL || bit.wire->attributes.count("\\unused_bits") == 0)
return false;
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index aa1e99be..a4b45295 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -85,7 +85,7 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
fsm_data.state_bits = fsm_data.state_table.size();
} else
if (encoding == "binary") {
- int new_num_state_bits = ceil(log2(fsm_data.state_table.size()));
+ int new_num_state_bits = ceil_log2(fsm_data.state_table.size());
if (fsm_data.state_bits == new_num_state_bits) {
log(" existing encoding is already a packed binary encoding.\n");
return;
diff --git a/passes/fsm/fsmdata.h b/passes/fsm/fsmdata.h
index 1b98ccba..68222769 100644
--- a/passes/fsm/fsmdata.h
+++ b/passes/fsm/fsmdata.h
@@ -39,7 +39,7 @@ struct FsmData
int state_num_log2 = 0;
for (int i = state_table.size(); i > 0; i = i >> 1)
state_num_log2++;
- state_num_log2 = std::max(state_num_log2, 1);
+ state_num_log2 = max(state_num_log2, 1);
cell->parameters["\\STATE_BITS"] = RTLIL::Const(state_bits);
cell->parameters["\\STATE_NUM"] = RTLIL::Const(state_table.size());
diff --git a/passes/hierarchy/Makefile.inc b/passes/hierarchy/Makefile.inc
index 99aa1e11..1fb669c1 100644
--- a/passes/hierarchy/Makefile.inc
+++ b/passes/hierarchy/Makefile.inc
@@ -1,4 +1,5 @@
OBJS += passes/hierarchy/hierarchy.o
+OBJS += passes/hierarchy/singleton.o
OBJS += passes/hierarchy/submod.o
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 598fe939..fcc30d17 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -66,7 +66,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
for (auto &conn : i2.second->connections()) {
if (conn.first[0] != '$')
portnames.insert(conn.first);
- portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.size());
+ portwidths[conn.first] = max(portwidths[conn.first], conn.second.size());
}
for (auto &para : i2.second->parameters)
parameters.insert(para.first);
@@ -84,8 +84,8 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
for (auto &decl : portdecls)
if (decl.index > 0) {
- portwidths[decl.portname] = std::max(portwidths[decl.portname], 1);
- portwidths[decl.portname] = std::max(portwidths[decl.portname], portwidths[stringf("$%d", decl.index)]);
+ portwidths[decl.portname] = max(portwidths[decl.portname], 1);
+ portwidths[decl.portname] = max(portwidths[decl.portname], portwidths[stringf("$%d", decl.index)]);
log(" port %d: %s [%d:0] %s\n", decl.index, decl.input ? decl.output ? "inout" : "input" : "output", portwidths[decl.portname]-1, RTLIL::id2cstr(decl.portname));
if (indices.count(decl.index) > ports.size())
log_error("Port index (%d) exceeds number of found ports (%d).\n", decl.index, int(ports.size()));
@@ -106,7 +106,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
log_assert(!indices.empty());
indices.erase(d.index);
ports[d.index-1] = d;
- portwidths[d.portname] = std::max(portwidths[d.portname], 1);
+ portwidths[d.portname] = max(portwidths[d.portname], 1);
log(" port %d: %s [%d:0] %s\n", d.index, d.input ? d.output ? "inout" : "input" : "output", portwidths[d.portname]-1, RTLIL::id2cstr(d.portname));
goto found_matching_decl;
}
@@ -327,7 +327,7 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
db[module] = 0;
for (auto cell : module->cells())
if (design->module(cell->type))
- db[module] = std::max(db[module], find_top_mod_score(design, design->module(cell->type), db) + 1);
+ db[module] = max(db[module], find_top_mod_score(design, design->module(cell->type), db) + 1);
}
return db.at(module);
}
diff --git a/passes/hierarchy/singleton.cc b/passes/hierarchy/singleton.cc
new file mode 100644
index 00000000..5715c0eb
--- /dev/null
+++ b/passes/hierarchy/singleton.cc
@@ -0,0 +1,101 @@
+/*
+ * 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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SingletonPass : public Pass {
+ SingletonPass() : Pass("singleton", "create singleton modules") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" singleton [selection]\n");
+ log("\n");
+ log("By default, a module that is instantiated by several other modules is only\n");
+ log("kept once in the design. This preserves the original modularity of the design\n");
+ log("and reduces the overall size of the design in memory. But it prevents certain\n");
+ log("optimizations and other operations on the design. This pass creates singleton\n");
+ log("modules for all selected cells. The created modules are marked with the\n");
+ log("'singleton' attribute.\n");
+ log("\n");
+ log("This commands only operates on modules that by themself have the 'singleton'\n");
+ log("attribute set (the 'top' module is a singleton implicitly).\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing SINGLETON pass (creating singleton modules).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-check") {
+ // flag_check = true;
+ // continue;
+ // }
+ }
+ extra_args(args, argidx, design);
+
+ bool did_something = true;
+ int singleton_cnt = 0;
+
+ while (did_something)
+ {
+ did_something = false;
+
+ for (auto module : design->selected_modules())
+ {
+ if (!module->get_bool_attribute("\\singleton") && !module->get_bool_attribute("\\top"))
+ continue;
+
+ for (auto cell : module->selected_cells())
+ {
+ auto tmod = design->module(cell->type);
+
+ if (tmod == nullptr)
+ continue;
+
+ if (tmod->get_bool_attribute("\\blackbox"))
+ continue;
+
+ if (tmod->get_bool_attribute("\\singleton"))
+ continue;
+
+ cell->type = module->name.str() + "." + log_id(cell->name);
+ log("Creating singleton '%s'.\n", log_id(cell->type));
+
+ auto smod = tmod->clone();
+ smod->name = cell->type;
+ smod->set_bool_attribute("\\singleton");
+ design->add(smod);
+
+ did_something = true;
+ singleton_cnt++;
+ }
+ }
+ }
+
+ log("Created %d singleton modules.\n", singleton_cnt);
+ }
+} SingletonPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index be46d882..d4e8c96c 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -32,6 +32,8 @@ struct SubmodWorker
CellTypes ct;
RTLIL::Design *design;
RTLIL::Module *module;
+
+ bool copy_mode;
std::string opt_name;
struct SubModule
@@ -177,21 +179,25 @@ struct SubmodWorker
bit.wire = wire_flags[bit.wire].new_wire;
}
log(" cell %s (%s)\n", new_cell->name.c_str(), new_cell->type.c_str());
- module->remove(cell);
+ if (!copy_mode)
+ module->remove(cell);
}
submod.cells.clear();
- RTLIL::Cell *new_cell = module->addCell(submod.full_name, submod.full_name);
- for (auto &it : wire_flags)
- {
- RTLIL::Wire *old_wire = it.first;
- RTLIL::Wire *new_wire = it.second.new_wire;
- if (new_wire->port_id > 0)
- new_cell->setPort(new_wire->name, RTLIL::SigSpec(old_wire));
+ if (!copy_mode) {
+ RTLIL::Cell *new_cell = module->addCell(submod.full_name, submod.full_name);
+ for (auto &it : wire_flags)
+ {
+ RTLIL::Wire *old_wire = it.first;
+ RTLIL::Wire *new_wire = it.second.new_wire;
+ if (new_wire->port_id > 0)
+ new_cell->setPort(new_wire->name, RTLIL::SigSpec(old_wire));
+ }
}
}
- SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, std::string opt_name = std::string()) : design(design), module(module), opt_name(opt_name)
+ SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, bool copy_mode = false, std::string opt_name = std::string()) :
+ design(design), module(module), copy_mode(copy_mode), opt_name(opt_name)
{
if (!design->selected_whole_module(module->name) && opt_name.empty())
return;
@@ -266,7 +272,7 @@ struct SubmodPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" submod [selection]\n");
+ log(" submod [-copy] [selection]\n");
log("\n");
log("This pass identifies all cells with the 'submod' attribute and moves them to\n");
log("a newly created module. The value of the attribute is used as name for the\n");
@@ -279,12 +285,16 @@ struct SubmodPass : public Pass {
log("or memories.\n");
log("\n");
log("\n");
- log(" submod -name <name> [selection]\n");
+ log(" submod -name <name> [-copy] [selection]\n");
log("\n");
log("As above, but don't use the 'submod' attribute but instead use the selection.\n");
log("Only objects from one module might be selected. The value of the -name option\n");
log("is used as the value of the 'submod' attribute above.\n");
log("\n");
+ log("By default the cells are 'moved' from the source module and the source module\n");
+ log("will use an instance of the new module after this command is finished. Call\n");
+ log("with -copy to not modify the source module.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -292,6 +302,7 @@ struct SubmodPass : public Pass {
log_push();
std::string opt_name;
+ bool copy_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -299,6 +310,10 @@ struct SubmodPass : public Pass {
opt_name = args[++argidx];
continue;
}
+ if (args[argidx] == "-copy") {
+ copy_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -319,7 +334,7 @@ struct SubmodPass : public Pass {
queued_modules.push_back(mod_it.first);
for (auto &modname : queued_modules)
if (design->modules_.count(modname) != 0) {
- SubmodWorker worker(design, design->modules_[modname]);
+ SubmodWorker worker(design, design->modules_[modname], copy_mode);
handled_modules.insert(modname);
did_something = true;
}
@@ -342,7 +357,7 @@ struct SubmodPass : public Pass {
else {
Pass::call_on_module(design, module, "opt_clean");
log_header("Continuing SUBMOD pass.\n");
- SubmodWorker worker(design, module, opt_name);
+ SubmodWorker worker(design, module, copy_mode, opt_name);
}
}
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index b371578d..f2d9b584 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -387,9 +387,9 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
if (pi.clkpol > 1)
clkpol_wr_ports.insert(pi.clkpol);
}
- clocks_max = std::max(clocks_max, pi.clocks);
- clkpol_max = std::max(clkpol_max, pi.clkpol);
- transp_max = std::max(transp_max, pi.transp);
+ clocks_max = max(clocks_max, pi.clocks);
+ clkpol_max = max(clkpol_max, pi.clkpol);
+ transp_max = max(transp_max, pi.transp);
}
log(" Mapping to bram type %s (variant %d):\n", log_id(bram.name), bram.variant);
@@ -977,7 +977,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
log("\n");
pool<pair<IdString, int>> failed_brams;
- dict<pair<int, int>, std::tuple<int, int, int>> best_rule_cache;
+ dict<pair<int, int>, tuple<int, int, int>> best_rule_cache;
for (int i = 0; i < GetSize(rules.matches); i++)
{
@@ -1078,7 +1078,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
}
log(" Storing for later selection.\n");
- best_rule_cache[pair<int, int>(i, vi)] = std::tuple<int, int, int>(match_properties["efficiency"], -match_properties["cells"], -match_properties["acells"]);
+ best_rule_cache[pair<int, int>(i, vi)] = tuple<int, int, int>(match_properties["efficiency"], -match_properties["cells"], -match_properties["acells"]);
next_match_rule:
if (or_next_if_better || best_rule_cache.empty())
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index abd4b124..5c0acb3e 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -64,7 +64,7 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
for (auto &cell_it : module->cells_) {
Cell *cell = cell_it.second;
if (cell->type.in("$memrd", "$memwr", "$meminit") && memory->name == cell->parameters["\\MEMID"].decode_string()) {
- addr_bits = std::max(addr_bits, cell->getParam("\\ABITS").as_int());
+ addr_bits = max(addr_bits, cell->getParam("\\ABITS").as_int());
memcells.push_back(cell);
}
}
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 3373369f..beb2016a 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -32,6 +32,7 @@ struct MemoryDffWorker
dict<SigBit, SigBit> invbits;
dict<SigBit, int> sigbit_users_count;
dict<SigSpec, Cell*> mux_cells_a, mux_cells_b;
+ pool<Cell*> forward_merged_dffs, candidate_dffs;
MemoryDffWorker(Module *module) : module(module), sigmap(module) { }
@@ -46,6 +47,9 @@ struct MemoryDffWorker
for (auto cell : dff_cells)
{
+ if (after && forward_merged_dffs.count(cell))
+ continue;
+
SigSpec this_clk = cell->getPort("\\CLK");
bool this_clk_polarity = cell->parameters["\\CLK_POLARITY"].as_bool();
@@ -71,6 +75,7 @@ struct MemoryDffWorker
bit = d;
clk = this_clk;
clk_polarity = this_clk_polarity;
+ candidate_dffs.insert(cell);
goto replaced_this_bit;
}
@@ -87,6 +92,7 @@ struct MemoryDffWorker
RTLIL::SigSpec clk = RTLIL::SigSpec(RTLIL::State::Sx);
bool clk_polarity = 0;
+ candidate_dffs.clear();
RTLIL::SigSpec sig_addr = cell->getPort("\\ADDR");
if (!find_sig_before_dff(sig_addr, clk, clk_polarity)) {
@@ -106,13 +112,18 @@ struct MemoryDffWorker
return;
}
- if (clk != RTLIL::SigSpec(RTLIL::State::Sx)) {
+ if (clk != RTLIL::SigSpec(RTLIL::State::Sx))
+ {
+ for (auto cell : candidate_dffs)
+ forward_merged_dffs.insert(cell);
+
cell->setPort("\\CLK", clk);
cell->setPort("\\ADDR", sig_addr);
cell->setPort("\\DATA", sig_data);
cell->setPort("\\EN", sig_en);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
+
log("merged $dff to cell.\n");
return;
}
@@ -153,7 +164,7 @@ struct MemoryDffWorker
if (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data))
{
- bool enable_invert = mux_cells_a.count(sig_data);
+ bool enable_invert = mux_cells_a.count(sig_data) != 0;
Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data);
SigSpec check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A"));
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index b8f27025..3a6fd0b4 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -210,7 +210,7 @@ struct MemoryShareWorker
if (non_feedback_nets.count(sig_data[i]))
goto not_pure_feedback_port;
- async_rd_bits[sig_addr].resize(std::max(async_rd_bits.size(), sig_data.size()));
+ async_rd_bits[sig_addr].resize(max(async_rd_bits.size(), sig_data.size()));
for (int i = 0; i < int(sig_data.size()); i++)
async_rd_bits[sig_addr][i].insert(sig_data[i]);
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 49615d9d..175e8e11 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -177,7 +177,7 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPoo
if (attrs1 != attrs2)
return attrs2 > attrs1;
- return w2->name < w1->name;
+ return strcmp(w2->name.c_str(), w1->name.c_str()) < 0;
}
bool check_public_name(RTLIL::IdString id)
diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc
index 85e4c4c1..0fcacf0a 100644
--- a/passes/opt/opt_const.cc
+++ b/passes/opt/opt_const.cc
@@ -589,7 +589,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec b = cell->getPort("\\B");
if (cell->parameters["\\A_WIDTH"].as_int() != cell->parameters["\\B_WIDTH"].as_int()) {
- int width = std::max(cell->parameters["\\A_WIDTH"].as_int(), cell->parameters["\\B_WIDTH"].as_int());
+ int width = max(cell->parameters["\\A_WIDTH"].as_int(), cell->parameters["\\B_WIDTH"].as_int());
a.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool());
b.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool());
}
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 15d59202..905a0162 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -136,7 +136,7 @@ struct OptMuxtreeWorker
}
}
for (auto wire : module->wires()) {
- if (wire->port_output)
+ if (wire->port_output || wire->get_bool_attribute("\\keep"))
for (int idx : sig2bits(RTLIL::SigSpec(wire)))
bit2info[idx].seen_non_mux = true;
}
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 9dd0dc0a..1d9b1006 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -113,8 +113,8 @@ struct ShareWorker
static int bits_macc_port(const Macc::port_t &p, int width)
{
if (GetSize(p.in_a) == 0 || GetSize(p.in_b) == 0)
- return std::min(std::max(GetSize(p.in_a), GetSize(p.in_b)), width);
- return std::min(GetSize(p.in_a), width) * std::min(GetSize(p.in_b), width) / 2;
+ return min(max(GetSize(p.in_a), GetSize(p.in_b)), width);
+ return min(GetSize(p.in_a), width) * min(GetSize(p.in_b), width) / 2;
}
static int bits_macc(const Macc &m, int width)
@@ -224,13 +224,13 @@ struct ShareWorker
supermacc->ports.push_back(p);
}
- int score = 1000 + abs(GetSize(p1.in_a) - GetSize(p2.in_a)) * std::max(abs(GetSize(p1.in_b) - GetSize(p2.in_b)), 1);
+ int score = 1000 + abs(GetSize(p1.in_a) - GetSize(p2.in_a)) * max(abs(GetSize(p1.in_b) - GetSize(p2.in_b)), 1);
- for (int i = 0; i < std::min(GetSize(p1.in_a), GetSize(p2.in_a)); i++)
+ for (int i = 0; i < min(GetSize(p1.in_a), GetSize(p2.in_a)); i++)
if (p1.in_a[i] == p2.in_a[i] && score > 0)
score--;
- for (int i = 0; i < std::min(GetSize(p1.in_b), GetSize(p2.in_b)); i++)
+ for (int i = 0; i < min(GetSize(p1.in_b), GetSize(p2.in_b)); i++)
if (p1.in_b[i] == p2.in_b[i] && score > 0)
score--;
@@ -243,7 +243,7 @@ struct ShareWorker
Macc m1(c1), m2(c2), supermacc;
int w1 = GetSize(c1->getPort("\\Y")), w2 = GetSize(c2->getPort("\\Y"));
- int width = std::max(w1, w2);
+ int width = max(w1, w2);
m1.optimize(w1);
m2.optimize(w2);
@@ -419,8 +419,8 @@ struct ShareWorker
int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
- if (std::max(a1_width, a2_width) > 2 * std::min(a1_width, a2_width)) return false;
- if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ if (max(a1_width, a2_width) > 2 * min(a1_width, a2_width)) return false;
+ if (max(y1_width, y2_width) > 2 * min(y1_width, y2_width)) return false;
}
return true;
@@ -438,9 +438,9 @@ struct ShareWorker
int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
- if (std::max(a1_width, a2_width) > 2 * std::min(a1_width, a2_width)) return false;
- if (std::max(b1_width, b2_width) > 2 * std::min(b1_width, b2_width)) return false;
- if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ if (max(a1_width, a2_width) > 2 * min(a1_width, a2_width)) return false;
+ if (max(b1_width, b2_width) > 2 * min(b1_width, b2_width)) return false;
+ if (max(y1_width, y2_width) > 2 * min(y1_width, y2_width)) return false;
}
return true;
@@ -458,15 +458,15 @@ struct ShareWorker
int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
- int min1_width = std::min(a1_width, b1_width);
- int max1_width = std::max(a1_width, b1_width);
+ int min1_width = min(a1_width, b1_width);
+ int max1_width = max(a1_width, b1_width);
- int min2_width = std::min(a2_width, b2_width);
- int max2_width = std::max(a2_width, b2_width);
+ int min2_width = min(a2_width, b2_width);
+ int max2_width = max(a2_width, b2_width);
- if (std::max(min1_width, min2_width) > 2 * std::min(min1_width, min2_width)) return false;
- if (std::max(max1_width, max2_width) > 2 * std::min(max1_width, max2_width)) return false;
- if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ if (max(min1_width, min2_width) > 2 * min(min1_width, min2_width)) return false;
+ if (max(max1_width, max2_width) > 2 * min(max1_width, max2_width)) return false;
+ if (max(y1_width, y2_width) > 2 * min(y1_width, y2_width)) return false;
}
return true;
@@ -475,7 +475,7 @@ struct ShareWorker
if (c1->type == "$macc")
{
if (!config.opt_aggressive)
- if (share_macc(c1, c2) > 2 * std::min(bits_macc(c1), bits_macc(c2))) return false;
+ if (share_macc(c1, c2) > 2 * min(bits_macc(c1), bits_macc(c2))) return false;
return true;
}
@@ -532,8 +532,8 @@ struct ShareWorker
RTLIL::SigSpec a2 = c2->getPort("\\A");
RTLIL::SigSpec y2 = c2->getPort("\\Y");
- int a_width = std::max(a1.size(), a2.size());
- int y_width = std::max(y1.size(), y2.size());
+ int a_width = max(a1.size(), a2.size());
+ int y_width = max(y1.size(), y2.size());
a1.extend_u0(a_width, a_signed);
a2.extend_u0(a_width, a_signed);
@@ -563,11 +563,11 @@ struct ShareWorker
if (config.generic_cbin_ops.count(c1->type))
{
- int score_unflipped = std::max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int()) +
- std::max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int());
+ int score_unflipped = max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int()) +
+ max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int());
- int score_flipped = std::max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int()) +
- std::max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int());
+ int score_flipped = max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int()) +
+ max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int());
if (score_flipped < score_unflipped)
{
@@ -630,13 +630,13 @@ struct ShareWorker
RTLIL::SigSpec b2 = c2->getPort("\\B");
RTLIL::SigSpec y2 = c2->getPort("\\Y");
- int a_width = std::max(a1.size(), a2.size());
- int b_width = std::max(b1.size(), b2.size());
- int y_width = std::max(y1.size(), y2.size());
+ int a_width = max(a1.size(), a2.size());
+ int b_width = max(b1.size(), b2.size());
+ int y_width = max(y1.size(), y2.size());
if (c1->type == "$shr" && a_signed)
{
- a_width = std::max(y_width, a_width);
+ a_width = max(y_width, a_width);
if (a1.size() < y1.size()) a1.extend_u0(y1.size(), true);
if (a2.size() < y2.size()) a2.extend_u0(y2.size(), true);
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index e551443f..4f08da67 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -51,6 +51,7 @@ struct WreduceWorker
std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
std::set<SigBit> work_queue_bits;
+ pool<SigBit> keep_bits;
WreduceWorker(WreduceConfig *config, Module *module) :
config(config), module(module), mi(module) { }
@@ -65,10 +66,13 @@ struct WreduceWorker
SigSpec sig_y = mi.sigmap(cell->getPort("\\Y"));
std::vector<SigBit> bits_removed;
+ if (sig_y.has_const())
+ return;
+
for (int i = GetSize(sig_y)-1; i >= 0; i--)
{
auto info = mi.query(sig_y[i]);
- if (!info->is_output && GetSize(info->ports) <= 1) {
+ if (!info->is_output && GetSize(info->ports) <= 1 && !keep_bits.count(mi.sigmap(sig_y[i]))) {
bits_removed.push_back(Sx);
continue;
}
@@ -172,6 +176,11 @@ struct WreduceWorker
if (cell->type.in("$mux", "$pmux"))
return run_cell_mux(cell);
+ SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
+
+ if (sig.has_const())
+ return;
+
// Reduce size of ports A and B based on constant input bits and size of output port
@@ -179,8 +188,8 @@ struct WreduceWorker
int max_port_b_size = cell->hasPort("\\B") ? GetSize(cell->getPort("\\B")) : -1;
if (cell->type.in("$not", "$pos", "$neg", "$and", "$or", "$xor", "$add", "$sub")) {
- max_port_a_size = std::min(max_port_a_size, GetSize(cell->getPort("\\Y")));
- max_port_b_size = std::min(max_port_b_size, GetSize(cell->getPort("\\Y")));
+ max_port_a_size = min(max_port_a_size, GetSize(sig));
+ max_port_b_size = min(max_port_b_size, GetSize(sig));
}
bool port_a_signed = false;
@@ -192,10 +201,33 @@ struct WreduceWorker
if (max_port_b_size >= 0)
run_reduce_inport(cell, 'B', max_port_b_size, port_b_signed, did_something);
+ if (cell->hasPort("\\A") && cell->hasPort("\\B") && port_a_signed && port_b_signed) {
+ SigSpec sig_a = mi.sigmap(cell->getPort("\\A")), sig_b = mi.sigmap(cell->getPort("\\B"));
+ if (GetSize(sig_a) > 0 && sig_a[GetSize(sig_a)-1] == State::S0 &&
+ GetSize(sig_b) > 0 && sig_b[GetSize(sig_b)-1] == State::S0) {
+ log("Converting cell %s.%s (%s) from signed to unsigned.\n",
+ log_id(module), log_id(cell), log_id(cell->type));
+ cell->setParam("\\A_SIGNED", 0);
+ cell->setParam("\\B_SIGNED", 0);
+ port_a_signed = false;
+ port_b_signed = false;
+ did_something = true;
+ }
+ }
+
+ if (cell->hasPort("\\A") && !cell->hasPort("\\B") && port_a_signed) {
+ SigSpec sig_a = mi.sigmap(cell->getPort("\\A"));
+ if (GetSize(sig_a) > 0 && sig_a[GetSize(sig_a)-1] == State::S0) {
+ log("Converting cell %s.%s (%s) from signed to unsigned.\n",
+ log_id(module), log_id(cell), log_id(cell->type));
+ cell->setParam("\\A_SIGNED", 0);
+ port_a_signed = false;
+ did_something = true;
+ }
+ }
- // Reduce size of port Y based on sizes for A and B and unused bits in Y
- SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
+ // Reduce size of port Y based on sizes for A and B and unused bits in Y
int bits_removed = 0;
if (port_a_signed && cell->type == "$shr") {
@@ -221,7 +253,7 @@ struct WreduceWorker
if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A"));
if (cell->hasPort("\\B")) b_size = GetSize(cell->getPort("\\B"));
- int max_y_size = std::max(a_size, b_size);
+ int max_y_size = max(a_size, b_size);
if (cell->type == "$add")
max_y_size++;
@@ -265,6 +297,11 @@ struct WreduceWorker
void run()
{
+ for (auto w : module->wires())
+ if (w->get_bool_attribute("\\keep"))
+ for (auto bit : mi.sigmap(w))
+ keep_bits.insert(bit);
+
for (auto c : module->selected_cells())
work_queue_cells.insert(c);
@@ -352,10 +389,12 @@ struct WreducePass : public Pass {
"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
"$logic_not", "$logic_and", "$logic_or") && GetSize(c->getPort("\\Y")) > 1) {
SigSpec sig = c->getPort("\\Y");
- c->setPort("\\Y", sig[0]);
- c->setParam("\\Y_WIDTH", 1);
- sig.remove(0);
- module->connect(sig, Const(0, GetSize(sig)));
+ if (!sig.has_const()) {
+ c->setPort("\\Y", sig[0]);
+ c->setParam("\\Y_WIDTH", 1);
+ sig.remove(0);
+ module->connect(sig, Const(0, GetSize(sig)));
+ }
}
WreduceWorker worker(&config, module);
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index 904d9211..943e8c56 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -27,35 +27,121 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
+struct SigSnippets
{
- for (auto &action : cs->actions) {
- if (action.first.size())
- return action.first;
- }
+ idict<SigSpec> sigidx;
+ dict<SigBit, int> bit2snippet;
+ pool<int> snippets;
- for (auto sw : cs->switches)
- for (auto cs2 : sw->cases) {
- RTLIL::SigSpec sig = find_any_lvalue(cs2);
- if (sig.size())
- return sig;
+ void insert(SigSpec sig)
+ {
+ if (sig.empty())
+ return;
+
+ int key = sigidx(sig);
+ if (snippets.count(key))
+ return;
+
+ SigSpec new_sig;
+
+ for (int i = 0; i < GetSize(sig); i++)
+ {
+ int other_key = bit2snippet.at(sig[i], -1);
+
+ if (other_key < 0) {
+ new_sig.append(sig[i]);
+ continue;
+ }
+
+ if (!new_sig.empty()) {
+ int new_key = sigidx(new_sig);
+ snippets.insert(new_key);
+ for (auto bit : new_sig)
+ bit2snippet[bit] = new_key;
+ new_sig = SigSpec();
+ }
+
+ SigSpec other_sig = sigidx[other_key];
+ int k = 0, n = 1;
+
+ while (other_sig[k] != sig[i]) {
+ k++;
+ log_assert(k < GetSize(other_sig));
+ }
+
+ while (i+n < GetSize(sig) && k+n < GetSize(other_sig) && sig[i+n] == other_sig[k+n])
+ n++;
+
+ SigSpec sig1 = other_sig.extract(0, k);
+ SigSpec sig2 = other_sig.extract(k, n);
+ SigSpec sig3 = other_sig.extract(k+n, GetSize(other_sig)-k-n);
+
+ for (auto bit : other_sig)
+ bit2snippet.erase(bit);
+ snippets.erase(other_key);
+
+ insert(sig1);
+ insert(sig2);
+ insert(sig3);
+
+ i += n-1;
+ }
+
+ if (!new_sig.empty()) {
+ int new_key = sigidx(new_sig);
+ snippets.insert(new_key);
+ for (auto bit : new_sig)
+ bit2snippet[bit] = new_key;
+ }
}
- return RTLIL::SigSpec();
-}
+ void insert(const RTLIL::CaseRule *cs)
+ {
+ for (auto &action : cs->actions)
+ insert(action.first);
-void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
+ for (auto sw : cs->switches)
+ for (auto cs2 : sw->cases)
+ insert(cs2);
+ }
+};
+
+struct SnippetSwCache
{
- for (auto &action : cs->actions) {
- RTLIL::SigSpec lvalue = action.first.extract(sig);
- if (lvalue.size())
- sig = lvalue;
+ dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache;
+ const SigSnippets *snippets;
+ int current_snippet;
+
+ bool check(RTLIL::SwitchRule *sw)
+ {
+ return cache[sw].count(current_snippet) != 0;
}
- for (auto sw : cs->switches)
- for (auto cs2 : sw->cases)
- extract_core_signal(cs2, sig);
-}
+ void insert(const RTLIL::CaseRule *cs, vector<RTLIL::SwitchRule*> &sw_stack)
+ {
+ for (auto &action : cs->actions)
+ for (auto bit : action.first) {
+ int sn = snippets->bit2snippet.at(bit, -1);
+ if (sn < 0)
+ continue;
+ for (auto sw : sw_stack)
+ cache[sw].insert(sn);
+ }
+
+ for (auto sw : cs->switches) {
+ sw_stack.push_back(sw);
+ for (auto cs2 : sw->cases)
+ insert(cs2, sw_stack);
+ sw_stack.pop_back();
+ }
+ }
+
+ void insert(const RTLIL::CaseRule *cs)
+ {
+ vector<RTLIL::SwitchRule*> sw_stack;
+ insert(cs, sw_stack);
+ }
+};
RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
{
@@ -179,7 +265,8 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve
last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size();
}
-RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
+RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara,
+ RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
{
RTLIL::SigSpec result = defval;
@@ -190,9 +277,37 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const
for (auto sw : cs->switches)
{
+ if (!swcache.check(sw))
+ continue;
+
// detect groups of parallel cases
std::vector<int> pgroups(sw->cases.size());
+ bool is_simple_parallel_case = true;
+
if (!sw->get_bool_attribute("\\parallel_case")) {
+ if (!swpara.count(sw)) {
+ pool<Const> case_values;
+ for (size_t i = 0; i < sw->cases.size(); i++) {
+ RTLIL::CaseRule *cs2 = sw->cases[i];
+ for (auto pat : cs2->compare) {
+ if (!pat.is_fully_def())
+ goto not_simple_parallel_case;
+ Const cpat = pat.as_const();
+ if (case_values.count(cpat))
+ goto not_simple_parallel_case;
+ case_values.insert(cpat);
+ }
+ }
+ if (0)
+ not_simple_parallel_case:
+ is_simple_parallel_case = false;
+ swpara[sw] = is_simple_parallel_case;
+ } else {
+ is_simple_parallel_case = swpara.at(sw);
+ }
+ }
+
+ if (!is_simple_parallel_case) {
BitPatternPool pool(sw->signal.size());
bool extra_group_for_next_case = false;
for (size_t i = 0; i < sw->cases.size(); i++) {
@@ -225,7 +340,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const
for (size_t i = 0; i < sw->cases.size(); i++) {
int case_idx = sw->cases.size() - i - 1;
RTLIL::CaseRule *cs2 = sw->cases[case_idx];
- RTLIL::SigSpec value = signal_to_mux_tree(mod, cs2, sig, initial_val);
+ RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val);
if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1])
append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw);
else
@@ -238,24 +353,26 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const
void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
{
- bool first = true;
- while (1)
- {
- RTLIL::SigSpec sig = find_any_lvalue(&proc->root_case);
+ log("Creating decoders for process `%s.%s'.\n", mod->name.c_str(), proc->name.c_str());
- if (sig.size() == 0)
- break;
+ SigSnippets sigsnip;
+ sigsnip.insert(&proc->root_case);
- if (first) {
- log("Creating decoders for process `%s.%s'.\n", mod->name.c_str(), proc->name.c_str());
- first = false;
- }
+ SnippetSwCache swcache;
+ swcache.snippets = &sigsnip;
+ swcache.insert(&proc->root_case);
+
+ dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> swpara;
- extract_core_signal(&proc->root_case, sig);
+ int cnt = 0;
+ for (int idx : sigsnip.snippets)
+ {
+ swcache.current_snippet = idx;
+ RTLIL::SigSpec sig = sigsnip.sigidx[idx];
- log(" creating decoder for signal `%s'.\n", log_signal(sig));
+ log("%6d/%d: %s\n", ++cnt, GetSize(sigsnip.snippets), log_signal(sig));
- RTLIL::SigSpec value = signal_to_mux_tree(mod, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()));
+ RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()));
mod->connect(RTLIL::SigSig(sig, value));
}
}
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index 52266403..614a1bd3 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -568,7 +568,7 @@ struct EvalPass : public Pass {
if (tab_column_width.size() < row.size())
tab_column_width.resize(row.size());
for (size_t i = 0; i < row.size(); i++)
- tab_column_width[i] = std::max(tab_column_width[i], int(row[i].size()));
+ tab_column_width[i] = max(tab_column_width[i], int(row[i].size()));
}
log("\n");
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index ca784890..ebdf2ed5 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -116,7 +116,7 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De
info.cell = it.second;
if (info.cell->type == "$dff") {
- info.bit_clk = sigmap(info.cell->getPort("\\CLK")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\CLK")).as_bit();
info.clk_polarity = info.cell->parameters.at("\\CLK_POLARITY").as_bool();
std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->getPort("\\D")).to_sigbit_vector();
std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->getPort("\\Q")).to_sigbit_vector();
@@ -128,8 +128,8 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De
}
if (info.cell->type == "$adff") {
- info.bit_clk = sigmap(info.cell->getPort("\\CLK")).to_single_sigbit();
- info.bit_arst = sigmap(info.cell->getPort("\\ARST")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\CLK")).as_bit();
+ info.bit_arst = sigmap(info.cell->getPort("\\ARST")).as_bit();
info.clk_polarity = info.cell->parameters.at("\\CLK_POLARITY").as_bool();
info.arst_polarity = info.cell->parameters.at("\\ARST_POLARITY").as_bool();
std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->getPort("\\D")).to_sigbit_vector();
@@ -144,21 +144,21 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De
}
if (info.cell->type == "$_DFF_N_" || info.cell->type == "$_DFF_P_") {
- info.bit_clk = sigmap(info.cell->getPort("\\C")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\C")).as_bit();
info.clk_polarity = info.cell->type == "$_DFF_P_";
- info.bit_d = sigmap(info.cell->getPort("\\D")).to_single_sigbit();
- bit_info[sigmap(info.cell->getPort("\\Q")).to_single_sigbit()] = info;
+ info.bit_d = sigmap(info.cell->getPort("\\D")).as_bit();
+ bit_info[sigmap(info.cell->getPort("\\Q")).as_bit()] = info;
continue;
}
if (info.cell->type.size() == 10 && info.cell->type.substr(0, 6) == "$_DFF_") {
- info.bit_clk = sigmap(info.cell->getPort("\\C")).to_single_sigbit();
- info.bit_arst = sigmap(info.cell->getPort("\\R")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\C")).as_bit();
+ info.bit_arst = sigmap(info.cell->getPort("\\R")).as_bit();
info.clk_polarity = info.cell->type[6] == 'P';
info.arst_polarity = info.cell->type[7] == 'P';
info.arst_value = info.cell->type[0] == '1' ? RTLIL::State::S1 : RTLIL::State::S0;
- info.bit_d = sigmap(info.cell->getPort("\\D")).to_single_sigbit();
- bit_info[sigmap(info.cell->getPort("\\Q")).to_single_sigbit()] = info;
+ info.bit_d = sigmap(info.cell->getPort("\\D")).as_bit();
+ bit_info[sigmap(info.cell->getPort("\\Q")).as_bit()] = info;
continue;
}
}
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index e0d11243..373b8048 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -265,7 +265,7 @@ struct PerformReduction
}
int max_child_depth = 0;
for (auto &bit : drv.second)
- max_child_depth = std::max(register_cone_worker(celldone, sigdepth, bit), max_child_depth);
+ max_child_depth = max(register_cone_worker(celldone, sigdepth, bit), max_child_depth);
sigdepth[out] = max_child_depth + 1;
} else {
pi_bits.push_back(out);
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index e72eddf3..2e9c6d2f 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -606,8 +606,8 @@ struct SatHelper
int maxModelWidth = 10;
for (auto &info : modelInfo) {
- maxModelName = std::max(maxModelName, int(info.description.size()));
- maxModelWidth = std::max(maxModelWidth, info.width);
+ maxModelName = max(maxModelName, int(info.description.size()));
+ maxModelWidth = max(maxModelWidth, info.width);
}
log("\n");
@@ -781,9 +781,9 @@ struct SatHelper
wavedata[info.description].first = info.width;
wavedata[info.description].second[info.timestep] = value;
- mintime = std::min(mintime, info.timestep);
- maxtime = std::max(maxtime, info.timestep);
- maxwidth = std::max(maxwidth, info.width);
+ mintime = min(mintime, info.timestep);
+ maxtime = max(maxtime, info.timestep);
+ maxwidth = max(maxwidth, info.width);
}
fprintf(f, "{ \"signal\": [");
@@ -1116,7 +1116,7 @@ struct SatPass : public Pass {
continue;
}
if (args[argidx] == "-stepsize" && argidx+1 < args.size()) {
- stepsize = std::max(1, atoi(args[++argidx].c_str()));
+ stepsize = max(1, atoi(args[++argidx].c_str()));
continue;
}
if (args[argidx] == "-ignore_div_by_zero") {
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 674cb77c..8112516c 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -22,6 +22,7 @@ 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
endif
GENFILES += passes/techmap/techmap.inc
@@ -42,6 +43,6 @@ EXTRA_OBJS += passes/techmap/filterlib.o
yosys-filterlib$(EXE): passes/techmap/filterlib.o
$(Q) mkdir -p $(dir $@)
- $(P) $(CXX) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS)
+ $(P) $(LD) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS)
endif
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 64586927..7da26602 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -100,6 +100,7 @@ SigMap assign_map;
RTLIL::Module *module;
std::vector<gate_t> signal_list;
std::map<RTLIL::SigBit, int> signal_map;
+pool<std::string> enabled_gates;
bool clk_polarity, en_polarity;
RTLIL::SigSpec clk_sig, en_sig;
@@ -591,7 +592,7 @@ struct abc_output_filter
};
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
- std::string liberty_file, std::string constr_file, bool cleanup, int lut_mode, int lut_mode2, bool dff_mode, std::string clk_str,
+ std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
bool keepff, std::string delay_target, bool fast_mode, const std::vector<RTLIL::Cell*> &cells, bool show_tempdir)
{
module = current_module;
@@ -625,7 +626,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (!constr_file.empty())
abc_script += stringf("read_constr -v %s; ", constr_file.c_str());
} else
- if (lut_mode)
+ if (!lut_costs.empty())
abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
else
abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str());
@@ -641,7 +642,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
abc_script += script_file[i];
} else
abc_script += stringf("source %s", script_file.c_str());
- } else if (lut_mode)
+ } else if (!lut_costs.empty())
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
else if (!liberty_file.empty())
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
@@ -837,17 +838,28 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "GATE ONE 1 Y=CONST1;\n");
fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
- fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
- fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
- fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
- fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
- fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
- fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
- fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
- fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
- fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
- fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
- fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
+ if (enabled_gates.empty() || enabled_gates.count("AND"))
+ fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
+ if (enabled_gates.empty() || enabled_gates.count("NAND"))
+ fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
+ if (enabled_gates.empty() || enabled_gates.count("OR"))
+ fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
+ if (enabled_gates.empty() || enabled_gates.count("NOR"))
+ fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
+ if (enabled_gates.empty() || enabled_gates.count("XOR"))
+ fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
+ if (enabled_gates.empty() || enabled_gates.count("XNOR"))
+ fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
+ if (enabled_gates.empty() || enabled_gates.count("AOI3"))
+ fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
+ if (enabled_gates.empty() || enabled_gates.count("OAI3"))
+ fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
+ if (enabled_gates.empty() || enabled_gates.count("AOI4"))
+ fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
+ if (enabled_gates.empty() || enabled_gates.count("OAI4"))
+ fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
+ if (enabled_gates.empty() || enabled_gates.count("MUX"))
+ fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
if (map_mux4)
fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*get_cell_cost("$_MUX_"));
if (map_mux8)
@@ -856,15 +868,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_"));
fclose(f);
- if (lut_mode) {
+ if (!lut_costs.empty()) {
buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt");
if (f == NULL)
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
- for (int i = 0; i < lut_mode; i++)
- fprintf(f, "%d 1.00 1.00\n", i+1);
- for (int i = lut_mode; i < lut_mode2; i++)
- fprintf(f, "%d %d.00 1.00\n", i+1, 2 << (i - lut_mode));
+ for (int i = 0; i < GetSize(lut_costs); i++)
+ fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i));
fclose(f);
}
@@ -882,7 +892,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (ifs.fail())
log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
- bool builtin_lib = liberty_file.empty() && script_file.empty() && !lut_mode;
+ bool builtin_lib = liberty_file.empty() && script_file.empty() && lut_costs.empty();
RTLIL::Design *mapped_design = new RTLIL::Design;
parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_");
@@ -1226,10 +1236,19 @@ struct AbcPass : public Pass {
log(" the area cost doubles with each additional input bit. the delay cost\n");
log(" is still constant for all lut widths.\n");
log("\n");
+ log(" -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\n");
+ log(" generate netlist using luts. Use the specified costs for luts with 1,\n");
+ log(" 2, 3, .. inputs.\n");
+ log("\n");
// log(" -mux4, -mux8, -mux16\n");
// log(" try to extract 4-input, 8-input, and/or 16-input muxes\n");
// log(" (ignored when used with -liberty or -lut)\n");
// log("\n");
+ log(" -g type1,type2,...\n");
+ log(" Map the the specified list of gate types. Supported gates types are:\n");
+ log(" AND, NAND, OR, NOR, XOR, XNOR, MUX, AOI3, OAI3, AOI4, OAI4.\n");
+ log(" (The NOT gate is always added to this list automatically.)\n");
+ log("\n");
log(" -dff\n");
log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
log(" clock domains are automatically partitioned in clock domains and each\n");
@@ -1274,12 +1293,13 @@ struct AbcPass : public Pass {
std::string script_file, liberty_file, constr_file, clk_str, delay_target;
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
bool show_tempdir = false;
- int lut_mode = 0, lut_mode2 = 0;
+ vector<int> lut_costs;
markgroups = false;
map_mux4 = false;
map_mux8 = false;
map_mux16 = false;
+ enabled_gates.clear();
#ifdef _WIN32
if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
@@ -1323,6 +1343,7 @@ struct AbcPass : public Pass {
if (arg == "-lut" && argidx+1 < args.size()) {
string arg = args[++argidx];
size_t pos = arg.find_first_of(':');
+ int lut_mode = 0, lut_mode2 = 0;
if (pos != string::npos) {
lut_mode = atoi(arg.substr(0, pos).c_str());
lut_mode2 = atoi(arg.substr(pos+1).c_str());
@@ -1330,6 +1351,27 @@ struct AbcPass : public Pass {
lut_mode = atoi(arg.c_str());
lut_mode2 = lut_mode;
}
+ lut_costs.clear();
+ for (int i = 0; i < lut_mode; i++)
+ lut_costs.push_back(1);
+ for (int i = lut_mode; i < lut_mode2; i++)
+ lut_costs.push_back(2 << (i - lut_mode));
+ continue;
+ }
+ if (arg == "-luts" && argidx+1 < args.size()) {
+ lut_costs.clear();
+ for (auto &tok : split_tokens(args[++argidx], ",")) {
+ auto parts = split_tokens(tok, ":");
+ if (GetSize(parts) == 0 && !lut_costs.empty())
+ lut_costs.push_back(lut_costs.back());
+ else if (GetSize(parts) == 1)
+ lut_costs.push_back(atoi(parts.at(0).c_str()));
+ else if (GetSize(parts) == 2)
+ while (GetSize(lut_costs) < atoi(parts.at(0).c_str()))
+ lut_costs.push_back(atoi(parts.at(1).c_str()));
+ else
+ log_cmd_error("Invalid -luts syntax.\n");
+ }
continue;
}
if (arg == "-mux4") {
@@ -1344,6 +1386,25 @@ struct AbcPass : public Pass {
map_mux16 = true;
continue;
}
+ if (arg == "-g" && argidx+1 < args.size()) {
+ for (auto g : split_tokens(args[++argidx], ",")) {
+ if (g == "AND") goto ok_gate;
+ if (g == "NAND") goto ok_gate;
+ if (g == "OR") goto ok_gate;
+ if (g == "NOR") goto ok_gate;
+ if (g == "XOR") goto ok_gate;
+ if (g == "XNOR") goto ok_gate;
+ if (g == "MUX") goto ok_gate;
+ if (g == "AOI3") goto ok_gate;
+ if (g == "OAI3") goto ok_gate;
+ if (g == "AOI4") goto ok_gate;
+ if (g == "OAI4") goto ok_gate;
+ cmd_error(args, argidx, stringf("Unsupported gate type: %s", g.c_str()));
+ ok_gate:
+ enabled_gates.insert(g);
+ }
+ continue;
+ }
if (arg == "-fast") {
fast_mode = true;
continue;
@@ -1377,7 +1438,7 @@ struct AbcPass : public Pass {
}
extra_args(args, argidx, design);
- if (lut_mode != 0 && !liberty_file.empty())
+ if (!lut_costs.empty() && !liberty_file.empty())
log_cmd_error("Got -lut and -liberty! This two options are exclusive.\n");
if (!constr_file.empty() && liberty_file.empty())
log_cmd_error("Got -constr but no -liberty!\n");
@@ -1386,7 +1447,7 @@ struct AbcPass : public Pass {
if (mod->processes.size() > 0)
log("Skipping module %s as it contains processes.\n", log_id(mod));
else if (!dff_mode || !clk_str.empty())
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, lut_mode2, dff_mode, clk_str, keepff, delay_target, fast_mode, mod->selected_cells(), show_tempdir);
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, fast_mode, mod->selected_cells(), show_tempdir);
else
{
assign_map.set(mod);
@@ -1399,7 +1460,7 @@ struct AbcPass : public Pass {
std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
- typedef std::tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
+ typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
@@ -1530,7 +1591,7 @@ struct AbcPass : public Pass {
clk_sig = assign_map(std::get<1>(it.first));
en_polarity = std::get<2>(it.first);
en_sig = assign_map(std::get<3>(it.first));
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, lut_mode2,
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs,
!clk_sig.empty(), "$", keepff, delay_target, fast_mode, it.second, show_tempdir);
assign_map.set(mod);
}
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index 90563c86..3c7ff4b9 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -40,7 +40,7 @@ struct AlumaccWorker
{
std::vector<RTLIL::Cell*> cells;
RTLIL::SigSpec a, b, c, y;
- std::vector<std::tuple<bool, bool, bool, bool, RTLIL::SigSpec>> cmp;
+ std::vector<tuple<bool, bool, bool, bool, RTLIL::SigSpec>> cmp;
bool is_signed, invert_b;
RTLIL::Cell *alu_cell;
@@ -138,7 +138,7 @@ struct AlumaccWorker
n->users = 0;
for (auto bit : n->y)
- n->users = std::max(n->users, bit_users.at(bit) - 1);
+ n->users = max(n->users, bit_users.at(bit) - 1);
if (cell->type.in("$pos", "$neg"))
{
@@ -409,7 +409,7 @@ struct AlumaccWorker
n->a = A;
n->b = B;
n->c = RTLIL::S1;
- n->y = module->addWire(NEW_ID, std::max(GetSize(A), GetSize(B)));
+ n->y = module->addWire(NEW_ID, max(GetSize(A), GetSize(B)));
n->is_signed = is_signed;
n->invert_b = true;
sig_alu[RTLIL::SigSig(A, B)].insert(n);
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index 84770ff3..e0273f43 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -68,7 +68,7 @@ struct DffinitPass : public Pass {
for (auto wire : module->selected_wires()) {
if (wire->attributes.count("\\init")) {
Const value = wire->attributes.at("\\init");
- for (int i = 0; i < std::min(GetSize(value), GetSize(wire)); i++)
+ for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
init_bits[sigmap(SigBit(wire, i))] = value[i];
}
if (wire->port_output)
@@ -100,7 +100,7 @@ struct DffinitPass : public Pass {
for (int i = 0; i < GetSize(sig); i++) {
if (init_bits.count(sig[i]) == 0)
continue;
- while (GetSize(value.bits) < i)
+ while (GetSize(value.bits) <= i)
value.bits.push_back(State::S0);
value.bits[i] = init_bits.at(sig[i]);
cleanup_bits.insert(sig[i]);
@@ -116,7 +116,7 @@ struct DffinitPass : public Pass {
if (wire->attributes.count("\\init")) {
Const &value = wire->attributes.at("\\init");
bool do_cleanup = true;
- for (int i = 0; i < std::min(GetSize(value), GetSize(wire)); i++) {
+ for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) {
SigBit bit = sigmap(SigBit(wire, i));
if (cleanup_bits.count(bit) || !used_bits.count(bit))
value[i] = State::Sx;
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 693651bf..4d7a1a70 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -17,8 +17,8 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
#include "libparse.h"
#include <string.h>
#include <errno.h>
@@ -173,8 +173,12 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
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);
- if ((cell_next_pol == true && value == ff->args[0]) || (cell_next_pol == false && value == ff->args[1])) {
- this_cell_ports[pin->args[0]] = 'Q';
+ if (value == ff->args[0]) {
+ this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q';
+ found_output = true;
+ } else
+ if (value == ff->args[1]) {
+ this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q';
found_output = true;
}
}
@@ -274,8 +278,12 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
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);
- if ((cell_next_pol == true && value == ff->args[0]) || (cell_next_pol == false && value == ff->args[1])) {
- this_cell_ports[pin->args[0]] = 'Q';
+ if (value == ff->args[0]) {
+ this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q';
+ found_output = true;
+ } else
+ if (value == ff->args[1]) {
+ this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q';
found_output = true;
}
}
@@ -410,14 +418,42 @@ static void map_sr_to_arst(const char *from, const char *to)
}
}
+static void map_adff_to_dff(const char *from, const char *to)
+{
+ if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
+ return;
+
+ char from_clk_pol YS_ATTRIBUTE(unused) = from[6];
+ char from_rst_pol = from[7];
+ char to_clk_pol YS_ATTRIBUTE(unused) = to[6];
+
+ log_assert(from_clk_pol == to_clk_pol);
+
+ log(" create mapping for %s from mapping for %s.\n", to, from);
+ cell_mappings[to].cell_name = cell_mappings[from].cell_name;
+ cell_mappings[to].ports = cell_mappings[from].ports;
+
+ for (auto &it : cell_mappings[to].ports) {
+ if (it.second == 'S' || it.second == 'R')
+ it.second = from_rst_pol == 'P' ? '0' : '1';
+ if (it.second == 's' || it.second == 'r')
+ it.second = from_rst_pol == 'P' ? '1' : '0';
+ }
+}
+
static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode)
{
log("Mapping DFF cells in module `%s':\n", module->name.c_str());
+ dict<SigBit, pool<Cell*>> notmap;
+ 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 == "$_NOT_")
+ notmap[sigmap(it.second->getPort("\\A"))].insert(it.second);
}
std::map<std::string, int> stats;
@@ -431,6 +467,12 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
cell_mapping &cm = cell_mappings[cell_type];
RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : "\\" + cm.cell_name);
+ bool has_q = false, has_qn = false;
+ for (auto &port : cm.ports) {
+ if (port.second == 'Q') has_q = true;
+ if (port.second == 'q') has_qn = true;
+ }
+
for (auto &port : cm.ports) {
RTLIL::SigSpec sig;
if ('A' <= port.second && port.second <= 'Z') {
@@ -439,7 +481,14 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
if (port.second == 'q') {
RTLIL::SigSpec old_sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))];
sig = module->addWire(NEW_ID, GetSize(old_sig));
- module->addNotGate(NEW_ID, sig, old_sig);
+ if (has_q && has_qn) {
+ for (auto &it : notmap[sigmap(old_sig)]) {
+ module->connect(it->getPort("\\Y"), sig);
+ it->setPort("\\Y", module->addWire(NEW_ID, GetSize(old_sig)));
+ }
+ } else {
+ module->addNotGate(NEW_ID, sig, old_sig);
+ }
} else
if ('a' <= port.second && port.second <= 'z') {
sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))];
@@ -448,7 +497,9 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
if (port.second == '0' || port.second == '1') {
sig = RTLIL::SigSpec(port.second == '0' ? 0 : 1, 1);
} else
- if (port.second != 0)
+ if (port.second == 0) {
+ sig = module->addWire(NEW_ID);
+ } else
log_abort();
new_cell->setPort("\\" + port.first, sig);
}
@@ -564,6 +615,15 @@ struct DfflibmapPass : public Pass {
map_sr_to_arst("$_DFFSR_PPP_", "$_DFF_PP0_");
map_sr_to_arst("$_DFFSR_PPP_", "$_DFF_PP1_");
+ map_adff_to_dff("$_DFF_NN0_", "$_DFF_N_");
+ map_adff_to_dff("$_DFF_NN1_", "$_DFF_N_");
+ map_adff_to_dff("$_DFF_NP0_", "$_DFF_N_");
+ map_adff_to_dff("$_DFF_NP1_", "$_DFF_N_");
+ map_adff_to_dff("$_DFF_PN0_", "$_DFF_P_");
+ map_adff_to_dff("$_DFF_PN1_", "$_DFF_P_");
+ map_adff_to_dff("$_DFF_PP0_", "$_DFF_P_");
+ map_adff_to_dff("$_DFF_PP1_", "$_DFF_P_");
+
log(" final dff cell mappings:\n");
logmap_all();
diff --git a/passes/techmap/dffsr2dff.cc b/passes/techmap/dffsr2dff.cc
new file mode 100644
index 00000000..8dcbb4ed
--- /dev/null
+++ b/passes/techmap/dffsr2dff.cc
@@ -0,0 +1,213 @@
+/*
+ * 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 == "$dffsr")
+ {
+ int width = cell->getParam("\\WIDTH").as_int();
+ bool setpol = cell->getParam("\\SET_POLARITY").as_bool();
+ bool clrpol = cell->getParam("\\CLR_POLARITY").as_bool();
+
+ SigBit setunused = setpol ? State::S0 : State::S1;
+ SigBit clrunused = clrpol ? State::S0 : State::S1;
+
+ SigSpec setsig = sigmap(cell->getPort("\\SET"));
+ SigSpec clrsig = sigmap(cell->getPort("\\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("\\ARST", setctrl);
+ cell->setParam("\\ARST_POLARITY", setpol);
+ } else {
+ cell->setPort("\\ARST", clrctrl);
+ cell->setParam("\\ARST_POLARITY", clrpol);
+ }
+
+ cell->type = "$adff";
+ cell->unsetPort("\\SET");
+ cell->unsetPort("\\CLR");
+ cell->setParam("\\ARST_VALUE", reset_val);
+ cell->unsetParam("\\SET_POLARITY");
+ cell->unsetParam("\\CLR_POLARITY");
+
+ return;
+ }
+
+ if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
+ "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_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("\\S"));
+ SigBit clrbit = sigmap(cell->getPort("\\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("\\S");
+ goto converted_gate;
+ }
+
+ if (clrbit == clrunused) {
+ cell->type = stringf("$_DFF_%c%c1_", clkpol, setpol);
+ cell->setPort("\\R", cell->getPort("\\S"));
+ cell->unsetPort("\\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 == "$adff")
+ {
+ bool rstpol = cell->getParam("\\ARST_POLARITY").as_bool();
+ SigBit rstunused = rstpol ? State::S0 : State::S1;
+ SigSpec rstsig = sigmap(cell->getPort("\\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 = "$dff";
+ cell->unsetPort("\\ARST");
+ cell->unsetParam("\\ARST_VALUE");
+ cell->unsetParam("\\ARST_POLARITY");
+
+ return;
+ }
+
+ if (cell->type.in("$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
+ "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_"))
+ {
+ char clkpol = cell->type.c_str()[6];
+ char rstpol = cell->type.c_str()[7];
+
+ SigBit rstbit = sigmap(cell->getPort("\\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("\\R");
+
+ return;
+ }
+}
+
+struct Dffsr2dffPass : public Pass {
+ Dffsr2dffPass() : Pass("dffsr2dff", "convert DFFSR cells to simpler FF cell types") { }
+ virtual void help()
+ {
+ // |---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");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("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 68a7fc1f..fc73177c 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -130,7 +130,7 @@ public:
RTLIL::SigSpec needleSig = conn.second;
RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str()));
- for (int i = 0; i < std::min(needleSig.size(), haystackSig.size()); i++) {
+ for (int i = 0; i < min(needleSig.size(), haystackSig.size()); i++) {
RTLIL::Wire *needleWire = needleSig[i].wire, *haystackWire = haystackSig[i].wire;
if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire)
if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr))
@@ -737,7 +737,7 @@ struct ExtractPass : public Pass {
RTLIL::Cell *newCell = newMod->addCell(cell->name, cell->type);
newCell->parameters = cell->parameters;
for (auto &conn : cell->connections()) {
- std::vector<RTLIL::SigChunk> chunks = sigmap(conn.second);
+ std::vector<SigChunk> chunks = sigmap(conn.second);
for (auto &chunk : chunks)
if (chunk.wire != NULL)
chunk.wire = newMod->wires_.at(chunk.wire->name);
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index dad1c06a..d5b8fe80 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -134,7 +134,7 @@ struct MaccmapWorker
}
return retval;
#else
- return std::max(n - 1, 0);
+ return max(n - 1, 0);
#endif
}
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index b250c568..514c3365 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -49,8 +49,8 @@ struct MuxcoverWorker
vector<tree_t> tree_list;
- dict<std::tuple<SigBit, SigBit, SigBit>, std::tuple<SigBit, pool<SigBit>, bool>> decode_mux_cache;
- dict<SigBit, std::tuple<SigBit, SigBit, SigBit>> decode_mux_reverse_cache;
+ dict<tuple<SigBit, SigBit, SigBit>, tuple<SigBit, pool<SigBit>, bool>> decode_mux_cache;
+ dict<SigBit, tuple<SigBit, SigBit, SigBit>> decode_mux_reverse_cache;
int decode_mux_counter;
bool use_mux4;
@@ -142,7 +142,7 @@ struct MuxcoverWorker
if (A == B)
return 0;
- std::tuple<SigBit, SigBit, SigBit> key(A, B, sel);
+ tuple<SigBit, SigBit, SigBit> key(A, B, sel);
if (decode_mux_cache.count(key) == 0) {
auto &entry = decode_mux_cache[key];
std::get<0>(entry) = module->addWire(NEW_ID);
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index 0fb5b374..f6ac3964 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -247,7 +247,7 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell)
bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
bool is_ne = cell->type == "$ne" || cell->type == "$nex";
- RTLIL::SigSpec xor_out = module->addWire(NEW_ID, std::max(GetSize(sig_a), GetSize(sig_b)));
+ RTLIL::SigSpec xor_out = module->addWire(NEW_ID, max(GetSize(sig_a), GetSize(sig_b)));
RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed);
xor_cell->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
simplemap_bitop(module, xor_cell);
@@ -293,7 +293,7 @@ void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell)
RTLIL::Cell *gate = module->addCell(NEW_ID, "$_TBUF_");
gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
gate->setPort("\\A", sig_a[i]);
- gate->setPort("\\E", sig_e[i]);
+ gate->setPort("\\E", sig_e);
gate->setPort("\\Y", sig_y[i]);
}
}
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 592710ed..5334ebfa 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -49,7 +49,7 @@ void apply_prefix(std::string prefix, std::string &id)
void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{
- std::vector<RTLIL::SigChunk> chunks = sig;
+ vector<SigChunk> chunks = sig;
for (auto &chunk : chunks)
if (chunk.wire != NULL) {
std::string wire_name = chunk.wire->name.str();
@@ -313,7 +313,7 @@ struct TechmapWorker
if (c->type == "$memrd" || c->type == "$memwr" || c->type == "$meminit") {
IdString memid = c->getParam("\\MEMID").decode_string();
- log_assert(memory_renames.count(memid));
+ log_assert(memory_renames.count(memid) != 0);
c->setParam("\\MEMID", Const(memory_renames[memid].str()));
}
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index fd5a32e4..a8fcac9b 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -256,7 +256,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
case 2:
n = xorshift32(GetSize(sig));
m = xorshift32(GetSize(sig));
- for (int i = std::min(n, m); i < std::max(n, m); i++)
+ for (int i = min(n, m); i < max(n, m); i++)
sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
break;
}
diff --git a/techlibs/common/.gitignore b/techlibs/common/.gitignore
new file mode 100644
index 00000000..0a1e7b68
--- /dev/null
+++ b/techlibs/common/.gitignore
@@ -0,0 +1,2 @@
+simlib_help.inc
+simcells_help.inc
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc
index f222a028..236d6c55 100644
--- a/techlibs/common/Makefile.inc
+++ b/techlibs/common/Makefile.inc
@@ -1,8 +1,24 @@
ifneq ($(SMALL),1)
OBJS += techlibs/common/synth.o
+OBJS += techlibs/common/prep.o
endif
+GENFILES += techlibs/common/simlib_help.inc
+GENFILES += techlibs/common/simcells_help.inc
+
+techlibs/common/simlib_help.inc: techlibs/common/cellhelp.py techlibs/common/simlib.v
+ $(Q) mkdir -p techlibs/common
+ $(P) python3 $^ > $@.new
+ $(Q) mv $@.new $@
+
+techlibs/common/simcells_help.inc: techlibs/common/cellhelp.py techlibs/common/simcells.v
+ $(Q) mkdir -p techlibs/common
+ $(P) python3 $^ > $@.new
+ $(Q) mv $@.new $@
+
+kernel/register.o: techlibs/common/simlib_help.inc techlibs/common/simcells_help.inc
+
$(eval $(call add_share_file,share,techlibs/common/simlib.v))
$(eval $(call add_share_file,share,techlibs/common/simcells.v))
$(eval $(call add_share_file,share,techlibs/common/techmap.v))
diff --git a/techlibs/common/cellhelp.py b/techlibs/common/cellhelp.py
new file mode 100644
index 00000000..5c44cb80
--- /dev/null
+++ b/techlibs/common/cellhelp.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+
+import fileinput
+import json
+
+current_help_msg = []
+current_module_code = []
+current_module_name = None
+current_module_signature = None
+
+def print_current_cell():
+ print("cell_help[\"%s\"] = %s;" % (current_module_name, "\n".join([json.dumps(line) for line in current_help_msg])))
+ print("cell_code[\"%s+\"] = %s;" % (current_module_name, "\n".join([json.dumps(line) for line in current_module_code])))
+
+for line in fileinput.input():
+ if line.startswith("//-"):
+ current_help_msg.append(line[4:] if len(line) > 4 else "\n")
+ if line.startswith("module "):
+ current_module_name = line.split()[1].strip("\\")
+ current_module_signature = " ".join(line.replace("\\", "").replace(";", "").split()[1:])
+ current_module_code = []
+ elif not line.startswith("endmodule"):
+ line = " " + line
+ current_module_code.append(line.replace("\t", " "))
+ if line.startswith("endmodule"):
+ if len(current_help_msg) == 0:
+ current_help_msg.append("\n")
+ current_help_msg.append(" %s\n" % current_module_signature)
+ current_help_msg.append("\n")
+ current_help_msg.append("No help message for this cell type found.\n")
+ current_help_msg.append("\n")
+ print_current_cell()
+ current_help_msg = []
+
diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc
new file mode 100644
index 00000000..8bae920d
--- /dev/null
+++ b/techlibs/common/prep.cc
@@ -0,0 +1,158 @@
+/*
+ * 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/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
+{
+ if (!run_from.empty() && run_from == run_to) {
+ active = (label == run_from);
+ } else {
+ if (label == run_from)
+ active = true;
+ if (label == run_to)
+ active = false;
+ }
+ return active;
+}
+
+struct PrepPass : public Pass {
+ PrepPass() : Pass("prep", "generic synthesis script") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" prep [options]\n");
+ log("\n");
+ log("This command runs a conservative RTL synthesis. A typical application for this\n");
+ log("is the preparation stage of a verification flow. This command does not operate\n");
+ log("on partly selected designs.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module (default='top')\n");
+ log("\n");
+ log(" -nordff\n");
+ log(" passed to 'memory_dff'. prohibits merging of FFs into memory read ports\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("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ log("\n");
+ log(" begin:\n");
+ log(" hierarchy -check [-top <top>]\n");
+ log("\n");
+ log(" prep:\n");
+ log(" proc\n");
+ log(" opt_const\n");
+ log(" opt_clean\n");
+ log(" check\n");
+ log(" opt -keepdc\n");
+ log(" wreduce\n");
+ log(" memory_dff [-nordff]\n");
+ log(" opt_clean\n");
+ log(" memory_collect\n");
+ log(" opt -keepdc -fast\n");
+ log("\n");
+ log(" check:\n");
+ log(" stat\n");
+ log(" check\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::string top_module, memory_opts;
+ std::string run_from, run_to;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_module = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos) {
+ run_from = args[++argidx];
+ run_to = args[argidx];
+ } else {
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ }
+ continue;
+ }
+ if (args[argidx] == "-nordff") {
+ memory_opts += " -nordff";
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This comannd only operates on fully selected designs!\n");
+
+ bool active = run_from.empty();
+
+ log_header("Executing PREP pass.\n");
+ log_push();
+
+ if (check_label(active, run_from, run_to, "begin"))
+ {
+ if (top_module.empty())
+ Pass::call(design, stringf("hierarchy -check"));
+ else
+ Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str()));
+ }
+
+ if (check_label(active, run_from, run_to, "coarse"))
+ {
+ Pass::call(design, "proc");
+ Pass::call(design, "opt_const");
+ Pass::call(design, "opt_clean");
+ Pass::call(design, "check");
+ Pass::call(design, "opt -keepdc");
+ Pass::call(design, "wreduce");
+ Pass::call(design, "memory_dff" + memory_opts);
+ Pass::call(design, "opt_clean");
+ Pass::call(design, "memory_collect");
+ Pass::call(design, "opt -keepdc -fast");
+ }
+
+ if (check_label(active, run_from, run_to, "check"))
+ {
+ Pass::call(design, "stat");
+ Pass::call(design, "check");
+ }
+
+ log_pop();
+ }
+} PrepPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index 3b7d55c6..c4f170a3 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -25,60 +25,184 @@
*
*/
-module \$_BUF_ (A, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_BUF_ (A, Y)
+//-
+//- A buffer. This cell type is always optimized away by the opt_clean pass.
+//-
+//- Truth table: A | Y
+//- ---+---
+//- 0 | 0
+//- 1 | 1
+//-
+module \$_BUF_ (A, Y);
input A;
output Y;
assign Y = A;
endmodule
-module \$_NOT_ (A, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_NOT_ (A, Y)
+//-
+//- An inverter gate.
+//-
+//- Truth table: A | Y
+//- ---+---
+//- 0 | 1
+//- 1 | 0
+//-
+module \$_NOT_ (A, Y);
input A;
output Y;
assign Y = ~A;
endmodule
-module \$_AND_ (A, B, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_AND_ (A, B, Y)
+//-
+//- A 2-input AND gate.
+//-
+//- Truth table: A B | Y
+//- -----+---
+//- 0 0 | 0
+//- 0 1 | 0
+//- 1 0 | 0
+//- 1 1 | 1
+//-
+module \$_AND_ (A, B, Y);
input A, B;
output Y;
assign Y = A & B;
endmodule
-module \$_NAND_ (A, B, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_NAND_ (A, B, Y)
+//-
+//- A 2-input NAND gate.
+//-
+//- Truth table: A B | Y
+//- -----+---
+//- 0 0 | 1
+//- 0 1 | 1
+//- 1 0 | 1
+//- 1 1 | 0
+//-
+module \$_NAND_ (A, B, Y);
input A, B;
output Y;
assign Y = ~(A & B);
endmodule
-module \$_OR_ (A, B, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_OR_ (A, B, Y)
+//-
+//- A 2-input OR gate.
+//-
+//- Truth table: A B | Y
+//- -----+---
+//- 0 0 | 0
+//- 0 1 | 1
+//- 1 0 | 1
+//- 1 1 | 1
+//-
+module \$_OR_ (A, B, Y);
input A, B;
output Y;
assign Y = A | B;
endmodule
-module \$_NOR_ (A, B, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_NOR_ (A, B, Y)
+//-
+//- A 2-input NOR gate.
+//-
+//- Truth table: A B | Y
+//- -----+---
+//- 0 0 | 1
+//- 0 1 | 0
+//- 1 0 | 0
+//- 1 1 | 0
+//-
+module \$_NOR_ (A, B, Y);
input A, B;
output Y;
assign Y = ~(A | B);
endmodule
-module \$_XOR_ (A, B, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_XOR_ (A, B, Y)
+//-
+//- A 2-input XOR gate.
+//-
+//- Truth table: A B | Y
+//- -----+---
+//- 0 0 | 0
+//- 0 1 | 1
+//- 1 0 | 1
+//- 1 1 | 0
+//-
+module \$_XOR_ (A, B, Y);
input A, B;
output Y;
assign Y = A ^ B;
endmodule
-module \$_XNOR_ (A, B, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_XNOR_ (A, B, Y)
+//-
+//- A 2-input XNOR gate.
+//-
+//- Truth table: A B | Y
+//- -----+---
+//- 0 0 | 1
+//- 0 1 | 0
+//- 1 0 | 0
+//- 1 1 | 1
+//-
+module \$_XNOR_ (A, B, Y);
input A, B;
output Y;
assign Y = ~(A ^ B);
endmodule
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_MUX_ (A, B, S, Y)
+//-
+//- A 2-input MUX gate.
+//-
+//- Truth table: A B S | Y
+//- -------+---
+//- a - 0 | a
+//- - b 1 | b
+//-
module \$_MUX_ (A, B, S, Y);
input A, B, S;
output Y;
assign Y = S ? B : A;
endmodule
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_MUX4_ (A, B, C, D, S, T, Y)
+//-
+//- A 4-input MUX gate.
+//-
+//- Truth table: A B C D S T | Y
+//- -------------+---
+//- a - - - 0 0 | a
+//- - b - - 1 0 | b
+//- - - c - 0 1 | c
+//- - - - d 1 1 | d
+//-
module \$_MUX4_ (A, B, C, D, S, T, Y);
input A, B, C, D, S, T;
output Y;
@@ -86,6 +210,23 @@ assign Y = T ? (S ? D : C) :
(S ? B : A);
endmodule
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_MUX8_ (A, B, C, D, E, F, G, H, S, T, U, Y)
+//-
+//- An 8-input MUX gate.
+//-
+//- Truth table: A B C D E F G H S T U | Y
+//- -----------------------+---
+//- a - - - - - - - 0 0 0 | a
+//- - b - - - - - - 1 0 0 | b
+//- - - c - - - - - 0 1 0 | c
+//- - - - d - - - - 1 1 0 | d
+//- - - - - e - - - 0 0 1 | e
+//- - - - - - f - - 1 0 1 | f
+//- - - - - - - g - 0 1 1 | g
+//- - - - - - - - h 1 1 1 | h
+//-
module \$_MUX8_ (A, B, C, D, E, F, G, H, S, T, U, Y);
input A, B, C, D, E, F, G, H, S, T, U;
output Y;
@@ -95,6 +236,31 @@ assign Y = U ? T ? (S ? H : G) :
(S ? B : A);
endmodule
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_MUX16_ (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V, Y)
+//-
+//- A 16-input MUX gate.
+//-
+//- Truth table: A B C D E F G H I J K L M N O P S T U V | Y
+//- -----------------------------------------+---
+//- a - - - - - - - - - - - - - - - 0 0 0 0 | a
+//- - b - - - - - - - - - - - - - - 1 0 0 0 | b
+//- - - c - - - - - - - - - - - - - 0 1 0 0 | c
+//- - - - d - - - - - - - - - - - - 1 1 0 0 | d
+//- - - - - e - - - - - - - - - - - 0 0 1 0 | e
+//- - - - - - f - - - - - - - - - - 1 0 1 0 | f
+//- - - - - - - g - - - - - - - - - 0 1 1 0 | g
+//- - - - - - - - h - - - - - - - - 1 1 1 0 | h
+//- - - - - - - - - i - - - - - - - 0 0 0 1 | i
+//- - - - - - - - - - j - - - - - - 1 0 0 1 | j
+//- - - - - - - - - - - k - - - - - 0 1 0 1 | k
+//- - - - - - - - - - - - l - - - - 1 1 0 1 | l
+//- - - - - - - - - - - - - m - - - 0 0 1 1 | m
+//- - - - - - - - - - - - - - n - - 1 0 1 1 | n
+//- - - - - - - - - - - - - - - o - 0 1 1 1 | o
+//- - - - - - - - - - - - - - - - p 1 1 1 1 | p
+//-
module \$_MUX16_ (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V, Y);
input A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V;
output Y;
@@ -108,37 +274,145 @@ assign Y = V ? U ? T ? (S ? P : O) :
(S ? B : A);
endmodule
-module \$_AOI3_ (A, B, C, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_AOI3_ (A, B, C, Y)
+//-
+//- A 3-input And-Or-Invert gate.
+//-
+//- Truth table: A B C | Y
+//- -------+---
+//- 0 0 0 | 1
+//- 0 0 1 | 0
+//- 0 1 0 | 1
+//- 0 1 1 | 0
+//- 1 0 0 | 1
+//- 1 0 1 | 0
+//- 1 1 0 | 0
+//- 1 1 1 | 0
+//-
+module \$_AOI3_ (A, B, C, Y);
input A, B, C;
output Y;
assign Y = ~((A & B) | C);
endmodule
-module \$_OAI3_ (A, B, C, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_OAI3_ (A, B, C, Y)
+//-
+//- A 3-input Or-And-Invert gate.
+//-
+//- Truth table: A B C | Y
+//- -------+---
+//- 0 0 0 | 1
+//- 0 0 1 | 1
+//- 0 1 0 | 1
+//- 0 1 1 | 0
+//- 1 0 0 | 1
+//- 1 0 1 | 0
+//- 1 1 0 | 1
+//- 1 1 1 | 0
+//-
+module \$_OAI3_ (A, B, C, Y);
input A, B, C;
output Y;
assign Y = ~((A | B) & C);
endmodule
-module \$_AOI4_ (A, B, C, D, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_AOI4_ (A, B, C, Y)
+//-
+//- A 4-input And-Or-Invert gate.
+//-
+//- Truth table: A B C D | Y
+//- ---------+---
+//- 0 0 0 0 | 1
+//- 0 0 0 1 | 1
+//- 0 0 1 0 | 1
+//- 0 0 1 1 | 0
+//- 0 1 0 0 | 1
+//- 0 1 0 1 | 1
+//- 0 1 1 0 | 1
+//- 0 1 1 1 | 0
+//- 1 0 0 0 | 1
+//- 1 0 0 1 | 1
+//- 1 0 1 0 | 1
+//- 1 0 1 1 | 0
+//- 1 1 0 0 | 0
+//- 1 1 0 1 | 0
+//- 1 1 1 0 | 0
+//- 1 1 1 1 | 0
+//-
+module \$_AOI4_ (A, B, C, D, Y);
input A, B, C, D;
output Y;
assign Y = ~((A & B) | (C & D));
endmodule
-module \$_OAI4_ (A, B, C, D, Y);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_OAI4_ (A, B, C, Y)
+//-
+//- A 4-input Or-And-Invert gate.
+//-
+//- Truth table: A B C D | Y
+//- ---------+---
+//- 0 0 0 0 | 1
+//- 0 0 0 1 | 1
+//- 0 0 1 0 | 1
+//- 0 0 1 1 | 1
+//- 0 1 0 0 | 1
+//- 0 1 0 1 | 0
+//- 0 1 1 0 | 0
+//- 0 1 1 1 | 0
+//- 1 0 0 0 | 1
+//- 1 0 0 1 | 0
+//- 1 0 1 0 | 0
+//- 1 0 1 1 | 0
+//- 1 1 0 0 | 1
+//- 1 1 0 1 | 0
+//- 1 1 1 0 | 0
+//- 1 1 1 1 | 0
+//-
+module \$_OAI4_ (A, B, C, D, Y);
input A, B, C, D;
output Y;
assign Y = ~((A | B) & (C | D));
endmodule
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_TBUF_ (A, E, Y)
+//-
+//- A tri-state buffer.
+//-
+//- Truth table: A E | Y
+//- -----+---
+//- a 1 | a
+//- - 0 | z
+//-
module \$_TBUF_ (A, E, Y);
input A, E;
output Y;
assign Y = E ? A : 1'bz;
endmodule
-module \$_SR_NN_ (S, R, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_SR_NN_ (S, R, Q)
+//-
+//- A set-reset latch with negative polarity SET and RESET.
+//-
+//- Truth table: S R | Q
+//- -----+---
+//- 0 0 | x
+//- 0 1 | 1
+//- 1 0 | 0
+//- 1 1 | y
+//-
+module \$_SR_NN_ (S, R, Q);
input S, R;
output reg Q;
always @(negedge S, negedge R) begin
@@ -149,7 +423,20 @@ always @(negedge S, negedge R) begin
end
endmodule
-module \$_SR_NP_ (S, R, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_SR_NP_ (S, R, Q)
+//-
+//- A set-reset latch with negative polarity SET and positive polarioty RESET.
+//-
+//- Truth table: S R | Q
+//- -----+---
+//- 0 1 | x
+//- 0 0 | 1
+//- 1 1 | 0
+//- 1 0 | y
+//-
+module \$_SR_NP_ (S, R, Q);
input S, R;
output reg Q;
always @(negedge S, posedge R) begin
@@ -160,7 +447,20 @@ always @(negedge S, posedge R) begin
end
endmodule
-module \$_SR_PN_ (S, R, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_SR_PN_ (S, R, Q)
+//-
+//- A set-reset latch with positive polarity SET and negative polarioty RESET.
+//-
+//- Truth table: S R | Q
+//- -----+---
+//- 1 0 | x
+//- 1 1 | 1
+//- 0 0 | 0
+//- 0 1 | y
+//-
+module \$_SR_PN_ (S, R, Q);
input S, R;
output reg Q;
always @(posedge S, negedge R) begin
@@ -171,7 +471,20 @@ always @(posedge S, negedge R) begin
end
endmodule
-module \$_SR_PP_ (S, R, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_SR_PP_ (S, R, Q)
+//-
+//- A set-reset latch with positive polarity SET and RESET.
+//-
+//- Truth table: S R | Q
+//- -----+---
+//- 1 1 | x
+//- 1 0 | 1
+//- 0 1 | 0
+//- 0 0 | y
+//-
+module \$_SR_PP_ (S, R, Q);
input S, R;
output reg Q;
always @(posedge S, posedge R) begin
@@ -182,7 +495,18 @@ always @(posedge S, posedge R) begin
end
endmodule
-module \$_DFF_N_ (D, Q, C);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_N_ (D, C, Q)
+//-
+//- A negative edge D-type flip-flop.
+//-
+//- Truth table: D C | Q
+//- -----+---
+//- d \ | d
+//- - - | q
+//-
+module \$_DFF_N_ (D, C, Q);
input D, C;
output reg Q;
always @(negedge C) begin
@@ -190,7 +514,18 @@ always @(negedge C) begin
end
endmodule
-module \$_DFF_P_ (D, Q, C);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_P_ (D, C, Q)
+//-
+//- A positive edge D-type flip-flop.
+//-
+//- Truth table: D C | Q
+//- -----+---
+//- d / | d
+//- - - | q
+//-
+module \$_DFF_P_ (D, C, Q);
input D, C;
output reg Q;
always @(posedge C) begin
@@ -198,7 +533,18 @@ always @(posedge C) begin
end
endmodule
-module \$_DFFE_NN_ (D, Q, C, E);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFE_NN_ (D, C, E, Q)
+//-
+//- A negative edge D-type flip-flop with negative polarity enable.
+//-
+//- Truth table: D C E | Q
+//- -------+---
+//- d \ 0 | d
+//- - - - | q
+//-
+module \$_DFFE_NN_ (D, C, E, Q);
input D, C, E;
output reg Q;
always @(negedge C) begin
@@ -206,7 +552,18 @@ always @(negedge C) begin
end
endmodule
-module \$_DFFE_NP_ (D, Q, C, E);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFE_NP_ (D, C, E, Q)
+//-
+//- A negative edge D-type flip-flop with positive polarity enable.
+//-
+//- Truth table: D C E | Q
+//- -------+---
+//- d \ 1 | d
+//- - - - | q
+//-
+module \$_DFFE_NP_ (D, C, E, Q);
input D, C, E;
output reg Q;
always @(negedge C) begin
@@ -214,7 +571,18 @@ always @(negedge C) begin
end
endmodule
-module \$_DFFE_PN_ (D, Q, C, E);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFE_PN_ (D, C, E, Q)
+//-
+//- A positive edge D-type flip-flop with negative polarity enable.
+//-
+//- Truth table: D C E | Q
+//- -------+---
+//- d / 0 | d
+//- - - - | q
+//-
+module \$_DFFE_PN_ (D, C, E, Q);
input D, C, E;
output reg Q;
always @(posedge C) begin
@@ -222,7 +590,18 @@ always @(posedge C) begin
end
endmodule
-module \$_DFFE_PP_ (D, Q, C, E);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFE_PP_ (D, C, E, Q)
+//-
+//- A positive edge D-type flip-flop with positive polarity enable.
+//-
+//- Truth table: D C E | Q
+//- -------+---
+//- d / 1 | d
+//- - - - | q
+//-
+module \$_DFFE_PP_ (D, C, E, Q);
input D, C, E;
output reg Q;
always @(posedge C) begin
@@ -230,7 +609,19 @@ always @(posedge C) begin
end
endmodule
-module \$_DFF_NN0_ (D, Q, C, R);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_NN0_ (D, C, R, Q)
+//-
+//- A negative edge D-type flip-flop with negative polarity reset.
+//-
+//- Truth table: D C R | Q
+//- -------+---
+//- - - 0 | 0
+//- d \ - | d
+//- - - - | q
+//-
+module \$_DFF_NN0_ (D, C, R, Q);
input D, C, R;
output reg Q;
always @(negedge C or negedge R) begin
@@ -241,7 +632,19 @@ always @(negedge C or negedge R) begin
end
endmodule
-module \$_DFF_NN1_ (D, Q, C, R);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_NN1_ (D, C, R, Q)
+//-
+//- A negative edge D-type flip-flop with negative polarity set.
+//-
+//- Truth table: D C R | Q
+//- -------+---
+//- - - 0 | 1
+//- d \ - | d
+//- - - - | q
+//-
+module \$_DFF_NN1_ (D, C, R, Q);
input D, C, R;
output reg Q;
always @(negedge C or negedge R) begin
@@ -252,7 +655,19 @@ always @(negedge C or negedge R) begin
end
endmodule
-module \$_DFF_NP0_ (D, Q, C, R);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_NP0_ (D, C, R, Q)
+//-
+//- A negative edge D-type flip-flop with positive polarity reset.
+//-
+//- Truth table: D C R | Q
+//- -------+---
+//- - - 1 | 0
+//- d \ - | d
+//- - - - | q
+//-
+module \$_DFF_NP0_ (D, C, R, Q);
input D, C, R;
output reg Q;
always @(negedge C or posedge R) begin
@@ -263,7 +678,19 @@ always @(negedge C or posedge R) begin
end
endmodule
-module \$_DFF_NP1_ (D, Q, C, R);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_NP1_ (D, C, R, Q)
+//-
+//- A negative edge D-type flip-flop with positive polarity set.
+//-
+//- Truth table: D C R | Q
+//- -------+---
+//- - - 1 | 1
+//- d \ - | d
+//- - - - | q
+//-
+module \$_DFF_NP1_ (D, C, R, Q);
input D, C, R;
output reg Q;
always @(negedge C or posedge R) begin
@@ -274,7 +701,19 @@ always @(negedge C or posedge R) begin
end
endmodule
-module \$_DFF_PN0_ (D, Q, C, R);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_PN0_ (D, C, R, Q)
+//-
+//- A positive edge D-type flip-flop with negative polarity reset.
+//-
+//- Truth table: D C R | Q
+//- -------+---
+//- - - 0 | 0
+//- d / - | d
+//- - - - | q
+//-
+module \$_DFF_PN0_ (D, C, R, Q);
input D, C, R;
output reg Q;
always @(posedge C or negedge R) begin
@@ -285,7 +724,19 @@ always @(posedge C or negedge R) begin
end
endmodule
-module \$_DFF_PN1_ (D, Q, C, R);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_PN1_ (D, C, R, Q)
+//-
+//- A positive edge D-type flip-flop with negative polarity set.
+//-
+//- Truth table: D C R | Q
+//- -------+---
+//- - - 0 | 1
+//- d / - | d
+//- - - - | q
+//-
+module \$_DFF_PN1_ (D, C, R, Q);
input D, C, R;
output reg Q;
always @(posedge C or negedge R) begin
@@ -296,7 +747,19 @@ always @(posedge C or negedge R) begin
end
endmodule
-module \$_DFF_PP0_ (D, Q, C, R);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_PP0_ (D, C, R, Q)
+//-
+//- A positive edge D-type flip-flop with positive polarity reset.
+//-
+//- Truth table: D C R | Q
+//- -------+---
+//- - - 1 | 0
+//- d / - | d
+//- - - - | q
+//-
+module \$_DFF_PP0_ (D, C, R, Q);
input D, C, R;
output reg Q;
always @(posedge C or posedge R) begin
@@ -307,7 +770,19 @@ always @(posedge C or posedge R) begin
end
endmodule
-module \$_DFF_PP1_ (D, Q, C, R);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFF_PP1_ (D, C, R, Q)
+//-
+//- A positive edge D-type flip-flop with positive polarity set.
+//-
+//- Truth table: D C R | Q
+//- -------+---
+//- - - 1 | 1
+//- d / - | d
+//- - - - | q
+//-
+module \$_DFF_PP1_ (D, C, R, Q);
input D, C, R;
output reg Q;
always @(posedge C or posedge R) begin
@@ -318,7 +793,20 @@ always @(posedge C or posedge R) begin
end
endmodule
-module \$_DFFSR_NNN_ (C, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFSR_NNN_ (C, S, R, D, Q)
+//-
+//- A negative edge D-type flip-flop with negative polarity set and reset.
+//-
+//- Truth table: C S R D | Q
+//- ---------+---
+//- - - 0 - | 0
+//- - 0 - - | 1
+//- \ - - d | d
+//- - - - - | q
+//-
+module \$_DFFSR_NNN_ (C, S, R, D, Q);
input C, S, R, D;
output reg Q;
always @(negedge C, negedge S, negedge R) begin
@@ -331,7 +819,21 @@ always @(negedge C, negedge S, negedge R) begin
end
endmodule
-module \$_DFFSR_NNP_ (C, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFSR_NNP_ (C, S, R, D, Q)
+//-
+//- A negative edge D-type flip-flop with negative polarity set and positive
+//- polarity reset.
+//-
+//- Truth table: C S R D | Q
+//- ---------+---
+//- - - 1 - | 0
+//- - 0 - - | 1
+//- \ - - d | d
+//- - - - - | q
+//-
+module \$_DFFSR_NNP_ (C, S, R, D, Q);
input C, S, R, D;
output reg Q;
always @(negedge C, negedge S, posedge R) begin
@@ -344,7 +846,21 @@ always @(negedge C, negedge S, posedge R) begin
end
endmodule
-module \$_DFFSR_NPN_ (C, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFSR_NPN_ (C, S, R, D, Q)
+//-
+//- A negative edge D-type flip-flop with positive polarity set and negative
+//- polarity reset.
+//-
+//- Truth table: C S R D | Q
+//- ---------+---
+//- - - 0 - | 0
+//- - 1 - - | 1
+//- \ - - d | d
+//- - - - - | q
+//-
+module \$_DFFSR_NPN_ (C, S, R, D, Q);
input C, S, R, D;
output reg Q;
always @(negedge C, posedge S, negedge R) begin
@@ -357,7 +873,20 @@ always @(negedge C, posedge S, negedge R) begin
end
endmodule
-module \$_DFFSR_NPP_ (C, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFSR_NPP_ (C, S, R, D, Q)
+//-
+//- A negative edge D-type flip-flop with positive polarity set and reset.
+//-
+//- Truth table: C S R D | Q
+//- ---------+---
+//- - - 1 - | 0
+//- - 1 - - | 1
+//- \ - - d | d
+//- - - - - | q
+//-
+module \$_DFFSR_NPP_ (C, S, R, D, Q);
input C, S, R, D;
output reg Q;
always @(negedge C, posedge S, posedge R) begin
@@ -370,7 +899,20 @@ always @(negedge C, posedge S, posedge R) begin
end
endmodule
-module \$_DFFSR_PNN_ (C, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFSR_PNN_ (C, S, R, D, Q)
+//-
+//- A positive edge D-type flip-flop with negative polarity set and reset.
+//-
+//- Truth table: C S R D | Q
+//- ---------+---
+//- - - 0 - | 0
+//- - 0 - - | 1
+//- / - - d | d
+//- - - - - | q
+//-
+module \$_DFFSR_PNN_ (C, S, R, D, Q);
input C, S, R, D;
output reg Q;
always @(posedge C, negedge S, negedge R) begin
@@ -383,7 +925,21 @@ always @(posedge C, negedge S, negedge R) begin
end
endmodule
-module \$_DFFSR_PNP_ (C, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFSR_PNP_ (C, S, R, D, Q)
+//-
+//- A positive edge D-type flip-flop with negative polarity set and positive
+//- polarity reset.
+//-
+//- Truth table: C S R D | Q
+//- ---------+---
+//- - - 1 - | 0
+//- - 0 - - | 1
+//- / - - d | d
+//- - - - - | q
+//-
+module \$_DFFSR_PNP_ (C, S, R, D, Q);
input C, S, R, D;
output reg Q;
always @(posedge C, negedge S, posedge R) begin
@@ -396,7 +952,21 @@ always @(posedge C, negedge S, posedge R) begin
end
endmodule
-module \$_DFFSR_PPN_ (C, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFSR_PPN_ (C, S, R, D, Q)
+//-
+//- A positive edge D-type flip-flop with positive polarity set and negative
+//- polarity reset.
+//-
+//- Truth table: C S R D | Q
+//- ---------+---
+//- - - 0 - | 0
+//- - 1 - - | 1
+//- / - - d | d
+//- - - - - | q
+//-
+module \$_DFFSR_PPN_ (C, S, R, D, Q);
input C, S, R, D;
output reg Q;
always @(posedge C, posedge S, negedge R) begin
@@ -409,7 +979,20 @@ always @(posedge C, posedge S, negedge R) begin
end
endmodule
-module \$_DFFSR_PPP_ (C, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DFFSR_PPP_ (C, S, R, D, Q)
+//-
+//- A positive edge D-type flip-flop with positive polarity set and reset.
+//-
+//- Truth table: C S R D | Q
+//- ---------+---
+//- - - 1 - | 0
+//- - 1 - - | 1
+//- / - - d | d
+//- - - - - | q
+//-
+module \$_DFFSR_PPP_ (C, S, R, D, Q);
input C, S, R, D;
output reg Q;
always @(posedge C, posedge S, posedge R) begin
@@ -422,7 +1005,18 @@ always @(posedge C, posedge S, posedge R) begin
end
endmodule
-module \$_DLATCH_N_ (E, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCH_N_ (E, D, Q)
+//-
+//- A negative enable D-type latch.
+//-
+//- Truth table: E D | Q
+//- -----+---
+//- 0 d | d
+//- - - | q
+//-
+module \$_DLATCH_N_ (E, D, Q);
input E, D;
output reg Q;
always @* begin
@@ -431,7 +1025,18 @@ always @* begin
end
endmodule
-module \$_DLATCH_P_ (E, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCH_P_ (E, D, Q)
+//-
+//- A positive enable D-type latch.
+//-
+//- Truth table: E D | Q
+//- -----+---
+//- 1 d | d
+//- - - | q
+//-
+module \$_DLATCH_P_ (E, D, Q);
input E, D;
output reg Q;
always @* begin
@@ -440,7 +1045,20 @@ always @* begin
end
endmodule
-module \$_DLATCHSR_NNN_ (E, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCHSR_NNN_ (E, S, R, D, Q)
+//-
+//- A negative enable D-type latch with negative polarity set and reset.
+//-
+//- Truth table: E S R D | Q
+//- ---------+---
+//- - - 0 - | 0
+//- - 0 - - | 1
+//- 0 - - d | d
+//- - - - - | q
+//-
+module \$_DLATCHSR_NNN_ (E, S, R, D, Q);
input E, S, R, D;
output reg Q;
always @* begin
@@ -453,7 +1071,21 @@ always @* begin
end
endmodule
-module \$_DLATCHSR_NNP_ (E, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCHSR_NNP_ (E, S, R, D, Q)
+//-
+//- A negative enable D-type latch with negative polarity set and positive polarity
+//- reset.
+//-
+//- Truth table: E S R D | Q
+//- ---------+---
+//- - - 1 - | 0
+//- - 0 - - | 1
+//- 0 - - d | d
+//- - - - - | q
+//-
+module \$_DLATCHSR_NNP_ (E, S, R, D, Q);
input E, S, R, D;
output reg Q;
always @* begin
@@ -466,7 +1098,21 @@ always @* begin
end
endmodule
-module \$_DLATCHSR_NPN_ (E, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCHSR_NPN_ (E, S, R, D, Q)
+//-
+//- A negative enable D-type latch with positive polarity set and negative polarity
+//- reset.
+//-
+//- Truth table: E S R D | Q
+//- ---------+---
+//- - - 0 - | 0
+//- - 1 - - | 1
+//- 0 - - d | d
+//- - - - - | q
+//-
+module \$_DLATCHSR_NPN_ (E, S, R, D, Q);
input E, S, R, D;
output reg Q;
always @* begin
@@ -479,7 +1125,20 @@ always @* begin
end
endmodule
-module \$_DLATCHSR_NPP_ (E, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCHSR_NPP_ (E, S, R, D, Q)
+//-
+//- A negative enable D-type latch with positive polarity set and reset.
+//-
+//- Truth table: E S R D | Q
+//- ---------+---
+//- - - 1 - | 0
+//- - 1 - - | 1
+//- 0 - - d | d
+//- - - - - | q
+//-
+module \$_DLATCHSR_NPP_ (E, S, R, D, Q);
input E, S, R, D;
output reg Q;
always @* begin
@@ -492,7 +1151,20 @@ always @* begin
end
endmodule
-module \$_DLATCHSR_PNN_ (E, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCHSR_PNN_ (E, S, R, D, Q)
+//-
+//- A positive enable D-type latch with negative polarity set and reset.
+//-
+//- Truth table: E S R D | Q
+//- ---------+---
+//- - - 0 - | 0
+//- - 0 - - | 1
+//- 1 - - d | d
+//- - - - - | q
+//-
+module \$_DLATCHSR_PNN_ (E, S, R, D, Q);
input E, S, R, D;
output reg Q;
always @* begin
@@ -505,7 +1177,21 @@ always @* begin
end
endmodule
-module \$_DLATCHSR_PNP_ (E, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCHSR_PNP_ (E, S, R, D, Q)
+//-
+//- A positive enable D-type latch with negative polarity set and positive polarity
+//- reset.
+//-
+//- Truth table: E S R D | Q
+//- ---------+---
+//- - - 1 - | 0
+//- - 0 - - | 1
+//- 1 - - d | d
+//- - - - - | q
+//-
+module \$_DLATCHSR_PNP_ (E, S, R, D, Q);
input E, S, R, D;
output reg Q;
always @* begin
@@ -518,7 +1204,21 @@ always @* begin
end
endmodule
-module \$_DLATCHSR_PPN_ (E, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCHSR_PPN_ (E, S, R, D, Q)
+//-
+//- A positive enable D-type latch with positive polarity set and negative polarity
+//- reset.
+//-
+//- Truth table: E S R D | Q
+//- ---------+---
+//- - - 0 - | 0
+//- - 1 - - | 1
+//- 1 - - d | d
+//- - - - - | q
+//-
+module \$_DLATCHSR_PPN_ (E, S, R, D, Q);
input E, S, R, D;
output reg Q;
always @* begin
@@ -531,7 +1231,20 @@ always @* begin
end
endmodule
-module \$_DLATCHSR_PPP_ (E, S, R, D, Q);
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_DLATCHSR_PPP_ (E, S, R, D, Q)
+//-
+//- A positive enable D-type latch with positive polarity set and reset.
+//-
+//- Truth table: E S R D | Q
+//- ---------+---
+//- - - 1 - | 0
+//- - 1 - - | 1
+//- 1 - - d | d
+//- - - - - | q
+//-
+module \$_DLATCHSR_PPP_ (E, S, R, D, Q);
input E, S, R, D;
output reg Q;
always @* begin
diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc
index 9d71feef..83d00f32 100644
--- a/techlibs/common/synth.cc
+++ b/techlibs/common/synth.cc
@@ -81,6 +81,7 @@ struct SynthPass : public Pass {
log("\n");
log(" coarse:\n");
log(" proc\n");
+ log(" opt_const\n");
log(" opt_clean\n");
log(" check\n");
log(" opt\n");
@@ -179,6 +180,7 @@ struct SynthPass : public Pass {
if (check_label(active, run_from, run_to, "coarse"))
{
Pass::call(design, "proc");
+ Pass::call(design, "opt_const");
Pass::call(design, "opt_clean");
Pass::call(design, "check");
Pass::call(design, "opt");
diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc
index 63d6086a..83009d17 100644
--- a/techlibs/ice40/Makefile.inc
+++ b/techlibs/ice40/Makefile.inc
@@ -1,6 +1,7 @@
OBJS += techlibs/ice40/synth_ice40.o
OBJS += techlibs/ice40/ice40_ffssr.o
+OBJS += techlibs/ice40/ice40_ffinit.o
OBJS += techlibs/ice40/ice40_opt.o
GENFILES += techlibs/ice40/brams_init1.vh
diff --git a/techlibs/ice40/brams_map.v b/techlibs/ice40/brams_map.v
index a82161c9..19a61d73 100644
--- a/techlibs/ice40/brams_map.v
+++ b/techlibs/ice40/brams_map.v
@@ -213,14 +213,14 @@ module \$__ICE40_RAM4K_M0 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1E
.RDATA(A1DATA),
.RADDR(A1ADDR_11),
.RCLK(CLK2),
- .RCLKE(1'b1),
- .RE(A1EN),
+ .RCLKE(A1EN),
+ .RE(1'b1),
.WDATA(B1DATA),
.WADDR(B1ADDR_11),
.MASK(~B1EN),
.WCLK(CLK3),
- .WCLKE(1'b1),
- .WE(|B1EN)
+ .WCLKE(|B1EN),
+ .WE(1'b1)
);
endmodule
@@ -299,13 +299,13 @@ module \$__ICE40_RAM4K_M123 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B
.RDATA(A1DATA_16),
.RADDR(A1ADDR_11),
.RCLK(CLK2),
- .RCLKE(1'b1),
- .RE(A1EN),
+ .RCLKE(A1EN),
+ .RE(1'b1),
.WDATA(B1DATA_16),
.WADDR(B1ADDR_11),
.WCLK(CLK3),
- .WCLKE(1'b1),
- .WE(|B1EN)
+ .WCLKE(|B1EN),
+ .WE(1'b1)
);
endmodule
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index 998ad3a1..7778b551 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -47,19 +47,25 @@ module SB_IO (
din_1 = din_q_1;
end
+ // work around simulation glitches on dout in DDR mode
+ reg outclk_delayed_1;
+ reg outclk_delayed_2;
+ always @* outclk_delayed_1 <= OUTPUT_CLK;
+ always @* outclk_delayed_2 <= outclk_delayed_1;
+
always @* begin
if (PIN_TYPE[3])
dout = PIN_TYPE[2] ? !dout_q_0 : D_OUT_0;
else
- dout = (OUTPUT_CLK ^ NEG_TRIGGER) || PIN_TYPE[2] ? dout_q_0 : dout_q_1;
+ dout = (outclk_delayed_2 ^ NEG_TRIGGER) || PIN_TYPE[2] ? dout_q_0 : dout_q_1;
end
assign D_IN_0 = din_0, D_IN_1 = din_1;
generate
if (PIN_TYPE[5:4] == 2'b01) assign PACKAGE_PIN = dout;
- if (PIN_TYPE[5:4] == 2'b10) assign PACKAGE_PIN = outena_q ? dout : 1'bz;
- if (PIN_TYPE[5:4] == 2'b11) assign PACKAGE_PIN = OUTPUT_ENABLE ? dout : 1'bz;
+ if (PIN_TYPE[5:4] == 2'b10) assign PACKAGE_PIN = OUTPUT_ENABLE ? dout : 1'bz;
+ if (PIN_TYPE[5:4] == 2'b11) assign PACKAGE_PIN = outena_q ? dout : 1'bz;
endgenerate
`endif
endmodule
@@ -661,7 +667,7 @@ endmodule
module ICESTORM_LC (
input I0, I1, I2, I3, CIN, CLK, CEN, SR,
- output O, COUT
+ output LO, O, COUT
);
parameter [15:0] LUT_INIT = 0;
@@ -678,6 +684,8 @@ module ICESTORM_LC (
wire [1:0] lut_s1 = I1 ? lut_s2[ 3:2] : lut_s2[1:0];
wire lut_o = I0 ? lut_s1[ 1] : lut_s1[ 0];
+ assign LO = lut_o;
+
wire polarized_clk;
assign polarized_clk = CLK ^ NEG_CLK;
diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc
new file mode 100644
index 00000000..8c4b9a37
--- /dev/null
+++ b/techlibs/ice40/ice40_ffinit.cc
@@ -0,0 +1,163 @@
+/*
+ * 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
+
+struct Ice40FfinitPass : public Pass {
+ Ice40FfinitPass() : Pass("ice40_ffinit", "iCE40: handle FF init values") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ice40_ffinit [options] [selection]\n");
+ log("\n");
+ log("Remove zero init values for FF output signals. Add inverters to implement\n");
+ log("nonzero init values.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing ICE40_FFINIT pass (implement FF init values).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ log("Handling FF init values in %s.\n", log_id(module));
+
+ SigMap sigmap(module);
+ pool<Wire*> init_wires;
+ dict<SigBit, State> initbits;
+ pool<SigBit> handled_initbits;
+
+ for (auto wire : module->selected_wires())
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec wirebits = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ init_wires.insert(wire);
+
+ for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
+ {
+ SigBit bit = wirebits[i];
+ State val = initval[i];
+
+ if (val != State::S0 && val != State::S1)
+ continue;
+
+ if (initbits.count(bit)) {
+ if (initbits.at(bit) != val)
+ log_error("Conflicting init values for signal %s.\n", log_signal(bit));
+ continue;
+ }
+
+ initbits[bit] = val;
+ }
+ }
+
+ pool<IdString> sb_dff_types = {
+ "\\SB_DFF", "\\SB_DFFE", "\\SB_DFFSR", "\\SB_DFFR", "\\SB_DFFSS", "\\SB_DFFS", "\\SB_DFFESR",
+ "\\SB_DFFER", "\\SB_DFFESS", "\\SB_DFFES", "\\SB_DFFN", "\\SB_DFFNE", "\\SB_DFFNSR", "\\SB_DFFNR",
+ "\\SB_DFFNSS", "\\SB_DFFNS", "\\SB_DFFNESR", "\\SB_DFFNER", "\\SB_DFFNESS", "\\SB_DFFNES"
+ };
+
+ for (auto cell : module->selected_cells())
+ {
+ if (!sb_dff_types.count(cell->type))
+ continue;
+
+ SigBit sig_d = sigmap(cell->getPort("\\D"));
+ SigBit sig_q = sigmap(cell->getPort("\\Q"));
+
+ if (!initbits.count(sig_q))
+ continue;
+
+ State val = initbits.at(sig_q);
+ handled_initbits.insert(sig_q);
+
+ log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type),
+ log_signal(sig_q), val != State::S0 ? '1' : '0');
+
+ if (val == State::S0)
+ continue;
+
+ string type_str = cell->type.str();
+
+ if (type_str.back() == 'S') {
+ type_str.back() = 'R';
+ cell->type = type_str;
+ cell->setPort("\\R", cell->getPort("\\S"));
+ cell->unsetPort("\\S");
+ } else
+ if (type_str.back() == 'R') {
+ type_str.back() = 'S';
+ cell->type = type_str;
+ cell->setPort("\\S", cell->getPort("\\R"));
+ cell->unsetPort("\\R");
+ }
+
+ Wire *new_sig_d = module->addWire(NEW_ID);
+ Wire *new_sig_q = module->addWire(NEW_ID);
+
+ module->addNotGate(NEW_ID, sig_d, new_sig_d);
+ module->addNotGate(NEW_ID, new_sig_q, sig_q);
+
+ cell->setPort("\\D", new_sig_d);
+ cell->setPort("\\Q", new_sig_q);
+ }
+
+ for (auto wire : init_wires)
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec wirebits = sigmap(wire);
+ Const &initval = wire->attributes.at("\\init");
+ bool remove_attribute = true;
+
+ for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) {
+ if (handled_initbits.count(wirebits[i]))
+ initval[i] = State::Sx;
+ else if (initval[i] != State::Sx)
+ remove_attribute = false;
+ }
+
+ if (remove_attribute)
+ wire->attributes.erase("\\init");
+ }
+ }
+ }
+} Ice40FfinitPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc
index 6acefaf4..677ac8d7 100644
--- a/techlibs/ice40/ice40_opt.cc
+++ b/techlibs/ice40/ice40_opt.cc
@@ -76,13 +76,24 @@ static void run_ice40_opts(Module *module)
for (auto cell : sb_lut_cells)
{
- if (optimized_co.count(sigmap(cell->getPort("\\I0")))) goto remap_lut;
- if (optimized_co.count(sigmap(cell->getPort("\\I1")))) goto remap_lut;
- if (optimized_co.count(sigmap(cell->getPort("\\I2")))) goto remap_lut;
- if (optimized_co.count(sigmap(cell->getPort("\\I3")))) goto remap_lut;
- continue;
+ SigSpec inbits;
+
+ inbits.append(cell->getPort("\\I0"));
+ inbits.append(cell->getPort("\\I1"));
+ inbits.append(cell->getPort("\\I2"));
+ inbits.append(cell->getPort("\\I3"));
+ sigmap.apply(inbits);
+
+ if (optimized_co.count(inbits[0])) goto remap_lut;
+ if (optimized_co.count(inbits[1])) goto remap_lut;
+ if (optimized_co.count(inbits[2])) goto remap_lut;
+ if (optimized_co.count(inbits[3])) goto remap_lut;
+
+ if (!sigmap(inbits).is_fully_const())
+ continue;
remap_lut:
+ module->design->scratchpad_set_bool("opt.did_something", true);
log("Mapping SB_LUT4 cell %s.%s back to logic.\n", log_id(module), log_id(cell));
cell->type ="$lut";
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index 788835f1..92d53f4a 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -72,6 +72,9 @@ struct SynthIce40Pass : public Pass {
log(" -nobram\n");
log(" do not use SB_RAM40_4K* cells in output netlist\n");
log("\n");
+ log(" -abc2\n");
+ log(" run two passes of 'abc' for slightly improved logic density\n");
+ log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
log("\n");
@@ -100,14 +103,18 @@ struct SynthIce40Pass : public Pass {
log(" ice40_opt\n");
log("\n");
log(" map_ffs:\n");
+ log(" dffsr2dff\n");
log(" dff2dffe -direct-match $_DFF_*\n");
log(" techmap -map +/ice40/cells_map.v\n");
log(" opt_const -mux_undef\n");
log(" simplemap\n");
+ log(" ice40_ffinit\n");
log(" ice40_ffssr\n");
log(" ice40_opt -full\n");
log("\n");
log(" map_luts:\n");
+ log(" abc (only if -abc2)\n");
+ log(" ice40_opt (only if -abc2)\n");
log(" abc -lut 4\n");
log(" clean\n");
log("\n");
@@ -136,6 +143,7 @@ struct SynthIce40Pass : public Pass {
bool nobram = false;
bool flatten = true;
bool retime = false;
+ bool abc2 = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -180,6 +188,10 @@ struct SynthIce40Pass : public Pass {
nobram = true;
continue;
}
+ if (args[argidx] == "-abc2") {
+ abc2 = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -232,16 +244,22 @@ struct SynthIce40Pass : public Pass {
if (check_label(active, run_from, run_to, "map_ffs"))
{
+ Pass::call(design, "dffsr2dff");
Pass::call(design, "dff2dffe -direct-match $_DFF_*");
Pass::call(design, "techmap -map +/ice40/cells_map.v");
Pass::call(design, "opt_const -mux_undef");
Pass::call(design, "simplemap");
+ Pass::call(design, "ice40_ffinit");
Pass::call(design, "ice40_ffssr");
Pass::call(design, "ice40_opt -full");
}
if (check_label(active, run_from, run_to, "map_luts"))
{
+ if (abc2) {
+ Pass::call(design, "abc");
+ Pass::call(design, "ice40_opt");
+ }
Pass::call(design, "abc -lut 4");
Pass::call(design, "clean");
}
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index ee67beba..21d1fb1e 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -91,13 +91,14 @@ struct SynthXilinxPass : public Pass {
log(" fine:\n");
log(" opt -fast -full\n");
log(" memory_map\n");
+ log(" dffsr2dff\n");
log(" dff2dffe\n");
log(" opt -full\n");
log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n");
log(" opt -fast\n");
log("\n");
log(" map_luts:\n");
- log(" abc -lut 5:8 [-dff]\n");
+ log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n");
log(" clean\n");
log("\n");
log(" map_cells:\n");
@@ -196,6 +197,7 @@ struct SynthXilinxPass : public Pass {
{
Pass::call(design, "opt -fast -full");
Pass::call(design, "memory_map");
+ Pass::call(design, "dffsr2dff");
Pass::call(design, "dff2dffe");
Pass::call(design, "opt -full");
Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v");
@@ -204,7 +206,7 @@ struct SynthXilinxPass : public Pass {
if (check_label(active, run_from, run_to, "map_luts"))
{
- Pass::call(design, "abc -lut 5:8" + string(retime ? " -dff" : ""));
+ Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
Pass::call(design, "clean");
}
diff --git a/tests/simple/graphtest.v b/tests/simple/graphtest.v
new file mode 100644
index 00000000..74788dbb
--- /dev/null
+++ b/tests/simple/graphtest.v
@@ -0,0 +1,34 @@
+module graphtest (A,B,X,Y,Z);
+
+input [3:0] A;
+input [3:0] B;
+output reg [3:0] X;
+output [9:0] Y;
+output [7:0] Z;
+
+wire [4:0] t;
+
+assign t[4] = 1'b0; // Constant connects to wire
+assign t[2:0] = A[2:0] & { 2'b10, B[3]}; // Concatenation of intermediate wire
+assign t[3] = A[2] ^ B[3]; // Bitwise-XOR
+
+// assign Y[2:0] = 3'b111;
+// assign Y[6:3] = A;
+// assign Y[9:7] = t[0:2];
+assign Y = {3'b111, A, t[2:0]}; // Direct assignment of concatenation
+
+assign Z[0] = 1'b0; // Constant connects to PO
+assign Z[1] = t[3]; // Intermediate sig connects to PO
+assign Z[3:2] = A[2:1]; // PI connects to PO
+assign Z[7:4] = {1'b0, B[2:0]}; // Concat of CV and PI connect to PO
+
+always @* begin
+ if (A == 4'b1111) begin // All-Const at port (eq)
+ X = B;
+ end
+ else begin
+ X = 4'b0000; // All-Const at port (mux)
+ end
+end
+
+endmodule
diff --git a/tests/simple/memory.v b/tests/simple/memory.v
index 67f89cd7..d58ed9d1 100644
--- a/tests/simple/memory.v
+++ b/tests/simple/memory.v
@@ -228,3 +228,18 @@ module memtest09 (
end
endmodule
+// ----------------------------------------------------------
+
+module memtest10(input clk, input [5:0] din, output [5:0] dout);
+ reg [5:0] queue [0:3];
+ integer i;
+
+ always @(posedge clk) begin
+ queue[0] <= din;
+ for (i = 1; i < 4; i=i+1) begin
+ queue[i] <= queue[i-1];
+ end
+ end
+
+ assign dout = queue[3];
+endmodule
diff --git a/tests/simple/task_func.v b/tests/simple/task_func.v
index 9b8e26e5..fa50c1d5 100644
--- a/tests/simple/task_func.v
+++ b/tests/simple/task_func.v
@@ -68,7 +68,7 @@ endmodule
// -------------------------------------------------------------------
-module task_func_test03( input [7:0] din_a, input [7:0] din_b, output [7:0] dout_a);
+module task_func_test03(input [7:0] din_a, input [7:0] din_b, output [7:0] dout_a);
assign dout_a = test(din_a,din_b);
function [7:0] test;
input [7:0] a;
@@ -80,3 +80,43 @@ module task_func_test03( input [7:0] din_a, input [7:0] din_b, output [7:0] dout
end
endfunction
endmodule
+
+// -------------------------------------------------------------------
+
+module task_func_test04(input [7:0] in, output [7:0] out1, out2, out3, out4);
+ parameter p = 23;
+ parameter px = 42;
+ function [7:0] test1;
+ input [7:0] i;
+ parameter p = 42;
+ begin
+ test1 = i + p;
+ end
+ endfunction
+ function [7:0] test2;
+ input [7:0] i;
+ parameter p2 = p+42;
+ begin
+ test2 = i + p2;
+ end
+ endfunction
+ function [7:0] test3;
+ input [7:0] i;
+ begin
+ test3 = i + p;
+ end
+ endfunction
+ function [7:0] test4;
+ input [7:0] i;
+ parameter px = p + 13;
+ parameter p3 = px - 37;
+ parameter p4 = p3 ^ px;
+ begin
+ test4 = i + p4;
+ end
+ endfunction
+ assign out1 = test1(in);
+ assign out2 = test2(in);
+ assign out3 = test3(in);
+ assign out4 = test4(in);
+endmodule
diff --git a/tests/simple/wreduce.v b/tests/simple/wreduce.v
new file mode 100644
index 00000000..ba548438
--- /dev/null
+++ b/tests/simple/wreduce.v
@@ -0,0 +1,9 @@
+module wreduce_test0(input [7:0] a, b, output [15:0] x, y, z);
+ assign x = -$signed({1'b0, a});
+ assign y = $signed({1'b0, a}) + $signed({1'b0, b});
+ assign z = x ^ y;
+endmodule
+
+module wreduce_test1(input [31:0] a, b, output [7:0] x, y, z, w);
+ assign x = a - b, y = a * b, z = a >> b, w = a << b;
+endmodule