aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml42
-rwxr-xr-x.travis/build-and-test.sh2
-rwxr-xr-x.travis/setup.sh2
-rw-r--r--Brewfile1
-rw-r--r--CHANGELOG43
-rw-r--r--COPYING2
-rw-r--r--Dockerfile74
-rw-r--r--Makefile39
-rw-r--r--README.md99
-rw-r--r--backends/aiger/Makefile.inc1
-rw-r--r--backends/aiger/aiger.cc53
-rw-r--r--backends/aiger/xaiger.cc841
-rw-r--r--backends/blif/blif.cc9
-rw-r--r--backends/btor/btor.cc42
-rw-r--r--backends/firrtl/firrtl.cc308
-rw-r--r--backends/ilang/ilang_backend.cc13
-rw-r--r--backends/intersynth/intersynth.cc4
-rw-r--r--backends/json/json.cc58
-rw-r--r--backends/simplec/simplec.cc6
-rw-r--r--backends/smt2/smt2.cc5
-rw-r--r--backends/smt2/smtio.py11
-rw-r--r--backends/smv/smv.cc9
-rw-r--r--backends/verilog/verilog_backend.cc72
-rw-r--r--examples/mimas2/README8
-rw-r--r--examples/mimas2/example.ucf13
-rw-r--r--examples/mimas2/example.v14
-rw-r--r--examples/mimas2/run.sh8
-rw-r--r--examples/mimas2/run_yosys.ys4
-rw-r--r--frontends/aiger/aigerparse.cc746
-rw-r--r--frontends/aiger/aigerparse.h10
-rw-r--r--frontends/ast/ast.cc27
-rw-r--r--frontends/ast/genrtlil.cc3
-rw-r--r--frontends/ast/simplify.cc30
-rw-r--r--frontends/blif/blifparse.cc2
-rw-r--r--frontends/blif/blifparse.h2
-rw-r--r--frontends/ilang/ilang_parser.y13
-rw-r--r--frontends/json/jsonparse.cc81
-rw-r--r--frontends/liberty/liberty.cc2
-rw-r--r--frontends/verific/verific.cc72
-rw-r--r--frontends/verific/verific.h4
-rw-r--r--frontends/verific/verificsva.cc2
-rw-r--r--frontends/verilog/const2ast.cc38
-rw-r--r--frontends/verilog/verilog_lexer.l5
-rw-r--r--frontends/verilog/verilog_parser.y112
-rw-r--r--kernel/cellaigs.cc196
-rw-r--r--kernel/celledges.cc42
-rw-r--r--kernel/celltypes.h273
-rw-r--r--kernel/consteval.h91
-rw-r--r--kernel/cost.h124
-rw-r--r--kernel/driver.cc6
-rw-r--r--kernel/log.cc17
-rw-r--r--kernel/log.h2
-rw-r--r--kernel/macc.h62
-rw-r--r--kernel/register.cc132
-rw-r--r--kernel/rtlil.cc1187
-rw-r--r--kernel/rtlil.h173
-rw-r--r--kernel/satgen.h526
-rw-r--r--kernel/yosys.cc128
-rw-r--r--kernel/yosys.h18
-rw-r--r--manual/CHAPTER_CellLib.tex2
-rw-r--r--manual/CHAPTER_Overview.tex5
-rw-r--r--misc/launcher.c3
-rw-r--r--misc/py_wrap_generator.py3
-rw-r--r--passes/cmds/blackbox.cc2
-rw-r--r--passes/cmds/bugpoint.cc90
-rw-r--r--passes/cmds/cover.cc2
-rw-r--r--passes/cmds/delete.cc2
-rw-r--r--passes/cmds/select.cc50
-rw-r--r--passes/cmds/setattr.cc2
-rw-r--r--passes/cmds/show.cc6
-rw-r--r--passes/cmds/stat.cc33
-rw-r--r--passes/cmds/write_file.cc2
-rw-r--r--passes/equiv/equiv_make.cc4
-rw-r--r--passes/equiv/equiv_opt.cc2
-rw-r--r--passes/equiv/equiv_struct.cc4
-rw-r--r--passes/fsm/fsm_expand.cc2
-rw-r--r--passes/fsm/fsm_extract.cc28
-rw-r--r--passes/fsm/fsm_map.cc4
-rw-r--r--passes/hierarchy/hierarchy.cc20
-rw-r--r--passes/memory/memory_bram.cc4
-rw-r--r--passes/memory/memory_collect.cc10
-rw-r--r--passes/memory/memory_dff.cc22
-rw-r--r--passes/memory/memory_map.cc2
-rw-r--r--passes/memory/memory_share.cc6
-rw-r--r--passes/opt/Makefile.inc3
-rw-r--r--passes/opt/muxpack.cc368
-rw-r--r--passes/opt/opt.cc13
-rw-r--r--passes/opt/opt_clean.cc64
-rw-r--r--passes/opt/opt_demorgan.cc24
-rw-r--r--passes/opt/opt_expr.cc821
-rw-r--r--passes/opt/opt_lut.cc148
-rw-r--r--passes/opt/opt_merge.cc102
-rw-r--r--passes/opt/opt_muxtree.cc42
-rw-r--r--passes/opt/opt_reduce.cc110
-rw-r--r--passes/opt/opt_rmdff.cc369
-rw-r--r--passes/opt/opt_share.cc649
-rw-r--r--passes/opt/pmux2shiftx.cc92
-rw-r--r--passes/opt/rmports.cc2
-rw-r--r--passes/opt/share.cc346
-rw-r--r--passes/opt/wreduce.cc157
-rw-r--r--passes/pmgen/.gitignore3
-rw-r--r--passes/pmgen/Makefile.inc25
-rw-r--r--passes/pmgen/README.md162
-rw-r--r--passes/pmgen/ice40_dsp.pmg1
-rw-r--r--passes/pmgen/ice40_wrapcarry.cc90
-rw-r--r--passes/pmgen/ice40_wrapcarry.pmg11
-rw-r--r--passes/pmgen/peepopt_muldiv.pmg2
-rw-r--r--passes/pmgen/peepopt_shiftmul.pmg4
-rw-r--r--passes/pmgen/pmgen.py359
-rw-r--r--passes/pmgen/test_pmgen.cc379
-rw-r--r--passes/pmgen/test_pmgen.pmg189
-rw-r--r--passes/proc/Makefile.inc2
-rw-r--r--passes/proc/proc.cc2
-rw-r--r--passes/proc/proc_arst.cc6
-rw-r--r--passes/proc/proc_clean.cc35
-rw-r--r--passes/proc/proc_init.cc26
-rw-r--r--passes/proc/proc_mux.cc26
-rw-r--r--passes/proc/proc_prune.cc165
-rw-r--r--passes/sat/assertpmux.cc6
-rw-r--r--passes/sat/clk2fflogic.cc7
-rw-r--r--passes/sat/cutpoint.cc2
-rw-r--r--passes/sat/eval.cc4
-rw-r--r--passes/sat/expose.cc4
-rw-r--r--passes/sat/miter.cc6
-rw-r--r--passes/sat/sat.cc10
-rw-r--r--passes/techmap/Makefile.inc2
-rw-r--r--passes/techmap/abc.cc521
-rw-r--r--passes/techmap/abc9.cc1310
-rw-r--r--passes/techmap/aigmap.cc4
-rw-r--r--passes/techmap/alumacc.cc94
-rw-r--r--passes/techmap/attrmap.cc19
-rw-r--r--passes/techmap/deminout.cc6
-rw-r--r--passes/techmap/dff2dffe.cc118
-rw-r--r--passes/techmap/dff2dffs.cc48
-rw-r--r--passes/techmap/dffinit.cc10
-rw-r--r--passes/techmap/dfflibmap.cc144
-rw-r--r--passes/techmap/dffsr2dff.cc68
-rw-r--r--passes/techmap/extract.cc72
-rw-r--r--passes/techmap/extract_counter.cc152
-rw-r--r--passes/techmap/extract_fa.cc66
-rw-r--r--passes/techmap/extract_reduce.cc44
-rw-r--r--passes/techmap/flowmap.cc18
-rw-r--r--passes/techmap/iopadmap.cc16
-rw-r--r--passes/techmap/lut2mux.cc8
-rw-r--r--passes/techmap/maccmap.cc62
-rw-r--r--passes/techmap/muxcover.cc306
-rw-r--r--passes/techmap/nlutmap.cc6
-rw-r--r--passes/techmap/pmuxtree.cc12
-rw-r--r--passes/techmap/shregmap.cc154
-rw-r--r--passes/techmap/simplemap.cc464
-rw-r--r--passes/techmap/techmap.cc137
-rw-r--r--passes/techmap/tribuf.cc46
-rw-r--r--passes/techmap/zinit.cc30
-rw-r--r--passes/tests/test_cell.cc40
-rw-r--r--techlibs/anlogic/Makefile.inc2
-rw-r--r--techlibs/anlogic/anlogic_determine_init.cc72
-rw-r--r--techlibs/anlogic/anlogic_eqn.cc4
-rw-r--r--techlibs/anlogic/anlogic_fixcarry.cc130
-rw-r--r--techlibs/anlogic/arith_map.v52
-rw-r--r--techlibs/anlogic/synth_anlogic.cc7
-rw-r--r--techlibs/common/cmp2lut.v2
-rw-r--r--techlibs/common/simcells.v19
-rw-r--r--techlibs/common/simlib.v44
-rw-r--r--techlibs/common/synth.cc21
-rw-r--r--techlibs/coolrunner2/coolrunner2_sop.cc22
-rw-r--r--techlibs/ecp5/Makefile.inc8
-rw-r--r--techlibs/ecp5/abc_5g.box43
-rw-r--r--techlibs/ecp5/abc_5g.lut25
-rw-r--r--techlibs/ecp5/abc_5g_nowide.lut12
-rw-r--r--techlibs/ecp5/arith_map.v9
-rw-r--r--techlibs/ecp5/cells_map.v171
-rw-r--r--techlibs/ecp5/cells_sim.v482
-rw-r--r--techlibs/ecp5/lutram.txt (renamed from techlibs/ecp5/dram.txt)0
-rw-r--r--techlibs/ecp5/lutrams_map.v (renamed from techlibs/ecp5/drams_map.v)0
-rw-r--r--techlibs/ecp5/synth_ecp5.cc66
-rw-r--r--techlibs/efinix/Makefile.inc10
-rw-r--r--techlibs/efinix/arith_map.v79
-rw-r--r--techlibs/efinix/bram.txt32
-rw-r--r--techlibs/efinix/brams_map.v65
-rw-r--r--techlibs/efinix/cells_map.v45
-rw-r--r--techlibs/efinix/cells_sim.v107
-rw-r--r--techlibs/efinix/efinix_fixcarry.cc122
-rw-r--r--techlibs/efinix/efinix_gbuf.cc119
-rw-r--r--techlibs/efinix/synth_efinix.cc219
-rw-r--r--techlibs/gowin/determine_init.cc4
-rw-r--r--techlibs/ice40/Makefile.inc7
-rw-r--r--techlibs/ice40/abc_hx.box13
-rw-r--r--techlibs/ice40/abc_hx.lut6
-rw-r--r--techlibs/ice40/abc_lp.box13
-rw-r--r--techlibs/ice40/abc_lp.lut6
-rw-r--r--techlibs/ice40/abc_u.box13
-rw-r--r--techlibs/ice40/abc_u.lut6
-rw-r--r--techlibs/ice40/arith_map.v24
-rw-r--r--techlibs/ice40/cells_map.v39
-rw-r--r--techlibs/ice40/cells_sim.v49
-rw-r--r--techlibs/ice40/ice40_braminit.cc6
-rw-r--r--techlibs/ice40/ice40_opt.cc45
-rw-r--r--techlibs/ice40/ice40_unlut.cc106
-rw-r--r--techlibs/ice40/synth_ice40.cc71
-rw-r--r--techlibs/ice40/tests/test_arith.ys9
-rw-r--r--techlibs/ice40/tests/test_dsp_model.sh9
-rw-r--r--techlibs/ice40/tests/test_dsp_model.v225
-rw-r--r--techlibs/intel/Makefile.inc24
-rw-r--r--techlibs/intel/common/brams_m9k.txt (renamed from techlibs/intel/common/brams.txt)0
-rw-r--r--techlibs/intel/common/brams_map_m9k.v (renamed from techlibs/intel/common/brams_map.v)0
-rw-r--r--techlibs/intel/synth_intel.cc78
-rw-r--r--techlibs/xilinx/Makefile.inc24
-rw-r--r--techlibs/xilinx/abc_xc7.box58
-rw-r--r--techlibs/xilinx/abc_xc7.lut15
-rw-r--r--techlibs/xilinx/abc_xc7_nowide.lut10
-rw-r--r--techlibs/xilinx/arith_map.v4
-rw-r--r--techlibs/xilinx/brams_init.py16
-rw-r--r--techlibs/xilinx/cells_map.v295
-rw-r--r--techlibs/xilinx/cells_sim.v61
-rw-r--r--techlibs/xilinx/cells_xtra.sh6
-rw-r--r--techlibs/xilinx/cells_xtra.v25
-rw-r--r--techlibs/xilinx/ff_map.v8
-rw-r--r--techlibs/xilinx/lut_map.v97
-rw-r--r--techlibs/xilinx/lutrams.txt (renamed from techlibs/xilinx/drams.txt)20
-rw-r--r--techlibs/xilinx/lutrams_map.v (renamed from techlibs/xilinx/drams_map.v)34
-rw-r--r--techlibs/xilinx/mux_map.v71
-rw-r--r--techlibs/xilinx/synth_xilinx.cc259
-rw-r--r--techlibs/xilinx/xc6s_brams.txt84
-rw-r--r--techlibs/xilinx/xc6s_brams_bb.v211
-rw-r--r--techlibs/xilinx/xc6s_brams_map.v255
-rw-r--r--techlibs/xilinx/xc7_brams.txt (renamed from techlibs/xilinx/brams.txt)0
-rw-r--r--techlibs/xilinx/xc7_brams_bb.v (renamed from techlibs/xilinx/brams_bb.v)0
-rw-r--r--techlibs/xilinx/xc7_brams_map.v (renamed from techlibs/xilinx/brams_map.v)0
-rw-r--r--tests/aiger/.gitignore3
-rwxr-xr-xtests/aiger/run-test.sh14
-rwxr-xr-xtests/arch/run-test.sh18
-rwxr-xr-xtests/fsm/run-test.sh2
-rw-r--r--tests/lut/check_map_lut6.ys7
-rw-r--r--tests/lut/map_cmp.v47
-rwxr-xr-xtests/lut/run-test.sh5
-rw-r--r--tests/memories/issue00335.v28
-rw-r--r--tests/memories/issue00710.v17
-rw-r--r--tests/memories/read_two_mux.v16
-rwxr-xr-xtests/memories/run-test.sh16
-rw-r--r--tests/opt/opt_expr.ys293
-rw-r--r--tests/opt/opt_ff.v21
-rw-r--r--tests/opt/opt_ff.ys3
-rw-r--r--tests/opt/opt_lut.ys4
-rw-r--r--tests/opt/opt_rmdff.v (renamed from tests/various/opt_rmdff.v)0
-rw-r--r--tests/opt/opt_rmdff.ys (renamed from tests/various/opt_rmdff.ys)10
-rw-r--r--tests/opt/opt_rmdff_sat.v12
-rw-r--r--tests/opt/opt_rmdff_sat.ys5
-rw-r--r--tests/opt/opt_share_add_sub.v10
-rw-r--r--tests/opt/opt_share_add_sub.ys13
-rw-r--r--tests/opt/opt_share_cat.v15
-rw-r--r--tests/opt/opt_share_cat.ys13
-rw-r--r--tests/opt/opt_share_cat_multiuser.v22
-rw-r--r--tests/opt/opt_share_cat_multiuser.ys13
-rw-r--r--tests/opt/opt_share_diff_port_widths.v21
-rw-r--r--tests/opt/opt_share_diff_port_widths.ys13
-rw-r--r--tests/opt/opt_share_extend.v18
-rw-r--r--tests/opt/opt_share_extend.ys13
-rw-r--r--tests/opt/opt_share_large_pmux_cat.v21
-rw-r--r--tests/opt/opt_share_large_pmux_cat.ys13
-rw-r--r--tests/opt/opt_share_large_pmux_cat_multipart.v25
-rw-r--r--tests/opt/opt_share_large_pmux_cat_multipart.ys14
-rw-r--r--tests/opt/opt_share_large_pmux_multipart.v23
-rw-r--r--tests/opt/opt_share_large_pmux_multipart.ys13
-rw-r--r--tests/opt/opt_share_large_pmux_part.v21
-rw-r--r--tests/opt/opt_share_large_pmux_part.ys13
-rw-r--r--tests/opt/opt_share_mux_tree.v18
-rw-r--r--tests/opt/opt_share_mux_tree.ys13
-rw-r--r--tests/opt_share/.gitignore1
-rw-r--r--tests/opt_share/generate.py86
-rwxr-xr-xtests/opt_share/run-test.sh39
-rw-r--r--tests/proc/.gitignore1
-rw-r--r--tests/proc/bug_1268.v23
-rw-r--r--tests/proc/bug_1268.ys5
-rwxr-xr-xtests/proc/run-test.sh6
-rw-r--r--tests/simple/arrays02.sv16
-rw-r--r--tests/simple/generate.v11
-rw-r--r--tests/simple/realexpr.v11
-rw-r--r--tests/simple/xfirrtl4
-rw-r--r--tests/simple_abc9/.gitignore4
-rw-r--r--tests/simple_abc9/abc.box2
-rw-r--r--tests/simple_abc9/abc9.v269
-rwxr-xr-xtests/simple_abc9/run-test.sh23
-rw-r--r--tests/techmap/recursive.v8
-rw-r--r--tests/techmap/recursive_map.v4
-rw-r--r--tests/techmap/recursive_runtest.sh3
-rwxr-xr-xtests/tools/autotest.sh9
-rw-r--r--tests/various/.gitignore6
-rw-r--r--tests/various/abc9.v9
-rw-r--r--tests/various/abc9.ys24
-rw-r--r--tests/various/async.sh11
-rw-r--r--tests/various/async.v108
-rw-r--r--tests/various/gzip_verilog.v.gzbin0 -> 82 bytes
-rw-r--r--tests/various/gzip_verilog.ys2
-rw-r--r--tests/various/mem2reg.ys14
-rw-r--r--tests/various/muxcover.ys461
-rw-r--r--tests/various/muxpack.v259
-rw-r--r--tests/various/muxpack.ys268
-rw-r--r--tests/various/pmgen_reduce.ys21
-rw-r--r--tests/various/pmux2shiftx.v10
-rw-r--r--tests/various/pmux2shiftx.ys21
-rwxr-xr-xtests/various/run-test.sh26
-rw-r--r--tests/various/script.ys20
-rw-r--r--tests/various/shregmap.v48
-rw-r--r--tests/various/shregmap.ys66
-rw-r--r--tests/various/signext.ys33
-rw-r--r--tests/various/specify.v11
-rw-r--r--tests/various/specify.ys2
-rw-r--r--tests/various/wreduce.ys79
-rw-r--r--tests/various/write_gzip.ys16
309 files changed, 16926 insertions, 5287 deletions
diff --git a/.travis.yml b/.travis.yml
index 957735f1d..09f380831 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -36,37 +36,10 @@ matrix:
- libboost-system-dev
- libboost-python-dev
- libboost-filesystem-dev
+ - zlib1g-dev
env:
- MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8"
- # Latest gcc-6 on Travis Linux
- - os: linux
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - g++-6
- - gperf
- - build-essential
- - bison
- - flex
- - libreadline-dev
- - gawk
- - tcl-dev
- - libffi-dev
- - git
- - graphviz
- - xdot
- - pkg-config
- - python
- - python3
- - libboost-system-dev
- - libboost-python-dev
- - libboost-filesystem-dev
- env:
- - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6"
-
# Latest gcc supported on Travis Linux
- os: linux
addons:
@@ -74,7 +47,7 @@ matrix:
sources:
- ubuntu-toolchain-r-test
packages:
- - g++-7
+ - g++-9
- gperf
- build-essential
- bison
@@ -92,8 +65,9 @@ matrix:
- libboost-system-dev
- libboost-python-dev
- libboost-filesystem-dev
+ - zlib1g-dev
env:
- - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
+ - MATRIX_EVAL="CONFIG=gcc && CC=gcc-9 && CXX=g++-9"
# Clang which ships on Trusty Linux
- os: linux
@@ -121,6 +95,7 @@ matrix:
- libboost-system-dev
- libboost-python-dev
- libboost-filesystem-dev
+ - zlib1g-dev
env:
- MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8"
@@ -129,9 +104,9 @@ matrix:
addons:
apt:
sources:
- - llvm-toolchain-trusty-5.0
+ - llvm-toolchain-xenial-8
packages:
- - clang-5.0
+ - clang-8
- gperf
- build-essential
- bison
@@ -149,8 +124,9 @@ matrix:
- libboost-system-dev
- libboost-python-dev
- libboost-filesystem-dev
+ - zlib1g-dev
env:
- - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"
+ - MATRIX_EVAL="CONFIG=clang && CC=clang-8 && CXX=clang++-8"
# # Latest clang on Mac OS X
# - os: osx
diff --git a/.travis/build-and-test.sh b/.travis/build-and-test.sh
index b8c35041d..801407d1e 100755
--- a/.travis/build-and-test.sh
+++ b/.travis/build-and-test.sh
@@ -28,7 +28,7 @@ echo
echo 'Building...' && echo -en 'travis_fold:start:script.build\\r'
echo
-make
+make CC=$CC CXX=$CC LD=$CC
echo
echo -en 'travis_fold:end:script.build\\r'
diff --git a/.travis/setup.sh b/.travis/setup.sh
index 4af0b8ee9..02879b974 100755
--- a/.travis/setup.sh
+++ b/.travis/setup.sh
@@ -51,7 +51,7 @@ fi
git clone git://github.com/steveicarus/iverilog.git
cd iverilog
autoconf
- ./configure --prefix=$HOME/.local-bin
+ CC=gcc CXX=g++ ./configure --prefix=$HOME/.local-bin
make
make install
echo
diff --git a/Brewfile b/Brewfile
index 0c58ce161..4ffe50e86 100644
--- a/Brewfile
+++ b/Brewfile
@@ -6,3 +6,4 @@ brew "git"
brew "graphviz"
brew "pkg-config"
brew "python3"
+brew "tcl-tk"
diff --git a/CHANGELOG b/CHANGELOG
index 4c38f6e6e..dd94c76ed 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,32 @@ List of major changes and improvements between releases
=======================================================
+Yosys 0.9 .. Yosys 0.9-dev
+--------------------------
+
+ * Various
+ - Added "write_xaiger" backend
+ - Added "abc9" pass for timing-aware techmapping (experimental, FPGA only, no FFs)
+ - Added "synth_xilinx -abc9" (experimental)
+ - Added "synth_ice40 -abc9" (experimental)
+ - Added "synth -abc9" (experimental)
+ - Added "script -scriptwire
+ - "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
+ - Renamed labels/options in synth_ice40 (e.g. dram -> map_lutram; -nodram -> -nolutram)
+ - Renamed labels/options in synth_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram)
+ - Renamed labels in synth_intel (e.g. bram -> map_bram)
+ - Renamed labels/options in synth_xilinx (e.g. dram -> map_lutram; -nodram -> -nolutram)
+ - Added automatic gzip decompression for frontends
+ - Added $_NMUX_ cell type
+ - Added automatic gzip compression (based on filename extension) for backends
+ - Improve attribute and parameter encoding in JSON to avoid ambiguities between
+ bit vectors and strings containing [01xz]*
+ - Improvements in pmgen: subpattern and recursive matches
+ - Added "opt_share" pass, run as part of "opt -full"
+ - Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping
+ - Removed "ice40_unlut"
+ - Improvements in pmgen: slices, choices, define, generate
+
Yosys 0.8 .. Yosys 0.8-dev
--------------------------
@@ -16,9 +42,18 @@ Yosys 0.8 .. Yosys 0.8-dev
- Added "gate2lut.v" techmap rule
- Added "rename -src"
- Added "equiv_opt" pass
+ - Added "shregmap -tech xilinx"
- Added "read_aiger" frontend
- - Extended "muxcover -mux{4,8,16}=<cost>"
- - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
+ - Added "muxcover -mux{4,8,16}=<cost>"
+ - Added "muxcover -dmux=<cost>"
+ - Added "muxcover -nopartial"
+ - Added "muxpack" pass
+ - Added "pmux2shiftx -norange"
+ - Added "synth_xilinx -nocarry"
+ - Added "synth_xilinx -nowidelut"
+ - Added "synth_ecp5 -nowidelut"
+ - "synth_xilinx" to now infer hard shift registers (-nosrl to disable)
+ - Fixed sign extension of unsized constants with 'bx and 'bz MSB
Yosys 0.7 .. Yosys 0.8
@@ -32,7 +67,7 @@ Yosys 0.7 .. Yosys 0.8
- Added "write_verilog -decimal"
- Added "scc -set_attr"
- Added "verilog_defines" command
- - Remeber defines from one read_verilog to next
+ - Remember defines from one read_verilog to next
- Added support for hierarchical defparam
- Added FIRRTL back-end
- Improved ABC default scripts
@@ -41,7 +76,7 @@ Yosys 0.7 .. Yosys 0.8
- Added Verilog $rtoi and $itor support
- Added "check -initdrv"
- Added "read_blif -wideports"
- - Added support for systemVerilog "++" and "--" operators
+ - Added support for SystemVerilog "++" and "--" operators
- Added support for SystemVerilog unique, unique0, and priority case
- Added "write_edif" options for edif "flavors"
- Added support for resetall compiler directive
diff --git a/COPYING b/COPYING
index a121cdfe9..0839088c3 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at>
+Copyright (C) 2012 - 2019 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
diff --git a/Dockerfile b/Dockerfile
index 3c7188d82..549c73c97 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,33 +1,57 @@
-FROM ubuntu:18.04 as builder
-LABEL author="Abdelrahman Hosny <abdelrahman.hosny@hotmail.com>"
-ENV DEBIAN_FRONTEND=noninteractive
-RUN apt-get update && apt-get install -y build-essential \
+ARG IMAGE="python:3-slim-buster"
+
+#---
+
+FROM $IMAGE AS base
+
+RUN apt-get update -qq \
+ && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
+ ca-certificates \
clang \
+ curl \
+ libffi-dev \
+ libreadline-dev \
+ tcl-dev \
+ graphviz \
+ xdot \
+ && apt-get autoclean && apt-get clean && apt-get -y autoremove \
+ && update-ca-certificates \
+ && rm -rf /var/lib/apt/lists
+
+#---
+
+FROM base AS build
+
+RUN apt-get update -qq \
+ && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
bison \
flex \
- libreadline-dev \
gawk \
- tcl-dev \
- libffi-dev \
+ gcc \
git \
+ iverilog \
pkg-config \
- python3 && \
- rm -rf /var/lib/apt/lists
-COPY . /
-RUN make && \
- make install
-
-FROM ubuntu:18.04
-ENV DEBIAN_FRONTEND=noninteractive
-RUN apt-get update && apt-get install -y libreadline-dev tcl-dev
-
-COPY --from=builder /yosys /build/yosys
-COPY --from=builder /yosys-abc /build/yosys-abc
-COPY --from=builder /yosys-config /build/yosys-config
-COPY --from=builder /yosys-filterlib /build/yosys-filterlib
-COPY --from=builder /yosys-smtbmc /build/yosys-smtbmc
-
-ENV PATH /build:$PATH
+ && apt-get autoclean && apt-get clean && apt-get -y autoremove \
+ && rm -rf /var/lib/apt/lists
+
+COPY . /yosys
+
+ENV PREFIX /opt/yosys
+
+RUN cd /yosys \
+ && make \
+ && make install \
+ && make test
+
+#---
+
+FROM base
+
+COPY --from=build /opt/yosys /opt/yosys
+
+ENV PATH /opt/yosys/bin:$PATH
+
RUN useradd -m yosys
USER yosys
-ENTRYPOINT ["yosys"]
+
+CMD ["yosys"]
diff --git a/Makefile b/Makefile
index 76dac48a5..a742f2e50 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,7 @@ ENABLE_VERIFIC := 0
ENABLE_COVER := 1
ENABLE_LIBYOSYS := 0
ENABLE_PROTOBUF := 0
+ENABLE_ZLIB := 1
# python wrappers
ENABLE_PYOSYS := 0
@@ -90,8 +91,10 @@ PLUGIN_LDFLAGS += -undefined dynamic_lookup
ifneq ($(shell which brew),)
BREW_PREFIX := $(shell brew --prefix)/opt
$(info $$BREW_PREFIX is [${BREW_PREFIX}])
+ifeq ($(ENABLE_PYOSYS),1)
CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost
LDFLAGS += -L$(BREW_PREFIX)/boost/lib
+endif
CXXFLAGS += -I$(BREW_PREFIX)/readline/include
LDFLAGS += -L$(BREW_PREFIX)/readline/lib
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
@@ -122,7 +125,7 @@ OBJS = kernel/version_$(GIT_REV).o
# is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC..
-ABCREV = 3709744
+ABCREV = 5776ad0
ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
@@ -260,7 +263,8 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS))
ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
-ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
+# TODO: Try to solve pthread linking issue in more appropriate way
+ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" LDFLAGS="-Wl,--allow-multiple-definition" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
EXE = .exe
else ifeq ($(CONFIG),msys2)
@@ -384,6 +388,12 @@ ifeq ($(ENABLE_GLOB),1)
CXXFLAGS += -DYOSYS_ENABLE_GLOB
endif
+ifeq ($(ENABLE_ZLIB),1)
+CXXFLAGS += -DYOSYS_ENABLE_ZLIB
+LDLIBS += -lz
+endif
+
+
ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
ifeq ($(OS), FreeBSD)
@@ -394,7 +404,7 @@ endif
ifeq ($(CONFIG),mxe)
CXXFLAGS += -DYOSYS_ENABLE_TCL
-LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz
+LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv
else
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
ifeq ($(OS), FreeBSD)
@@ -479,6 +489,11 @@ define add_include_file
$(eval $(call add_share_file,$(dir share/include/$(1)),$(1)))
endef
+define add_extra_objs
+EXTRA_OBJS += $(1)
+.SECONDARY: $(1)
+endef
+
ifeq ($(PRETTY), 1)
P_STATUS = 0
P_OFFSET = 0
@@ -666,21 +681,31 @@ else
SEEDOPT=""
endif
+ifneq ($(ABCEXTERNAL),)
+ABCOPT="-A $(ABCEXTERNAL)"
+else
+ABCOPT=""
+endif
+
test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && bash run-test.sh $(SEEDOPT)
+ +cd tests/simple_abc9 && bash run-test.sh $(SEEDOPT)
+cd tests/hana && bash run-test.sh $(SEEDOPT)
+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
+cd tests/share && bash run-test.sh $(SEEDOPT)
+ +cd tests/opt_share && bash run-test.sh $(SEEDOPT)
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
+cd tests/techmap && bash run-test.sh
- +cd tests/memories && bash run-test.sh $(SEEDOPT)
+ +cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT)
+cd tests/bram && bash run-test.sh $(SEEDOPT)
+cd tests/various && bash run-test.sh
+cd tests/sat && bash run-test.sh
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
+ +cd tests/proc && bash run-test.sh
+cd tests/opt && bash run-test.sh
- +cd tests/aiger && bash run-test.sh
+ +cd tests/aiger && bash run-test.sh $(ABCOPT)
+ +cd tests/arch && bash run-test.sh
@echo ""
@echo " Passed \"make test\"."
@echo ""
@@ -765,7 +790,7 @@ clean:
rm -rf kernel/*.pyh
if test -d manual; then cd manual && sh clean.sh; fi
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc
- rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a
+ rm -f kernel/version_*.o kernel/version_*.cc
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
rm -rf tests/asicworld/*.out tests/asicworld/*.log
rm -rf tests/hana/*.out tests/hana/*.log
@@ -854,9 +879,11 @@ config-mxe: clean
config-msys2: clean
echo 'CONFIG := msys2' > Makefile.conf
+ echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
config-msys2-64: clean
echo 'CONFIG := msys2-64' > Makefile.conf
+ echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
config-cygwin: clean
echo 'CONFIG := cygwin' > Makefile.conf
diff --git a/README.md b/README.md
index 42f972c8e..606c4942e 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
```
yosys -- Yosys Open SYnthesis Suite
-Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at>
+Copyright (C) 2012 - 2019 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
@@ -67,25 +67,28 @@ prerequisites for building yosys:
$ sudo apt-get install build-essential clang bison flex \
libreadline-dev gawk tcl-dev libffi-dev git \
graphviz xdot pkg-config python3 libboost-system-dev \
- libboost-python-dev libboost-filesystem-dev
+ libboost-python-dev libboost-filesystem-dev zlib1g-dev
-Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies:
+Similarily, on Mac OS X Homebrew can be used to install dependencies:
$ brew tap Homebrew/bundle && brew bundle
+
+or MacPorts:
+
$ sudo port install bison flex readline gawk libffi \
- git graphviz pkgconfig python36 boost
+ git graphviz pkgconfig python36 boost zlib tcl
On FreeBSD use the following command to install all prerequisites:
# pkg install bison flex readline gawk libffi\
- git graphviz pkgconfig python3 python36 tcl-wrapper boost-libs
+ git graphviz pkgconf python3 python36 tcl-wrapper boost-libs
On FreeBSD system use gmake instead of make. To run tests use:
% MAKE=gmake CC=cc gmake test
For Cygwin use the following command to install all prerequisites, or select these additional packages:
- setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build
+ setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel
There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well
as a source distribution for Visual Studio. Visit the Yosys download page for
@@ -130,18 +133,15 @@ commands and ``help <command>`` to print details on the specified command:
yosys> help help
-reading the design using the Verilog frontend:
+reading and elaborating the design using the Verilog frontend:
- yosys> read_verilog tests/simple/fiedler-cooley.v
+ yosys> read -sv tests/simple/fiedler-cooley.v
+ yosys> hierarchy -top up3down5
writing the design to the console in Yosys's internal format:
yosys> write_ilang
-elaborate design hierarchy:
-
- yosys> hierarchy
-
convert processes (``always`` blocks) to netlist elements and perform
some simple optimizations:
@@ -163,51 +163,26 @@ write design netlist to a new Verilog file:
yosys> write_verilog synth.v
-a similar synthesis can be performed using yosys command line options only:
-
- $ ./yosys -o synth.v -p hierarchy -p proc -p opt \
- -p techmap -p opt tests/simple/fiedler-cooley.v
-
or using a simple synthesis script:
$ cat synth.ys
- read_verilog tests/simple/fiedler-cooley.v
- hierarchy; proc; opt; techmap; opt
+ read -sv tests/simple/fiedler-cooley.v
+ hierarchy -top up3down5
+ proc; opt; techmap; opt
write_verilog synth.v
$ ./yosys synth.ys
-It is also possible to only have the synthesis commands but not the read/write
-commands in the synthesis script:
-
- $ cat synth.ys
- hierarchy; proc; opt; techmap; opt
-
- $ ./yosys -o synth.v tests/simple/fiedler-cooley.v synth.ys
-
-The following very basic synthesis script should work well with all designs:
-
- # check design hierarchy
- hierarchy
-
- # translate processes (always blocks)
- proc; opt
-
- # detect and optimize FSM encodings
- fsm; opt
-
- # implement memories (arrays)
- memory; opt
-
- # convert to gate logic
- techmap; opt
-
If ABC is enabled in the Yosys build configuration and a cell library is given
in the liberty file ``mycells.lib``, the following synthesis script will
synthesize for the given cell library:
+ # read design
+ read -sv tests/simple/fiedler-cooley.v
+ hierarchy -top up3down5
+
# the high-level stuff
- hierarchy; proc; fsm; opt; memory; opt
+ proc; fsm; opt; memory; opt
# mapping to internal cell library
techmap; opt
@@ -222,7 +197,8 @@ synthesize 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 ``examples/cmos/cmos_cells.lib`` from the yosys sources.
+you can use the file ``examples/cmos/cmos_cells.lib`` from the yosys sources
+as simple example.
Liberty file downloads for and information about free and open ASIC standard
cell libraries can be found here:
@@ -231,20 +207,18 @@ cell libraries can be found here:
- 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:
+``help synth``):
- # the high-level stuff
- hierarchy
- synth -run coarse
+ read -sv tests/simple/fiedler-cooley.v
+ synth -top up3down5
- # mapping to internal cells
- techmap; opt -fast
+ # mapping to target cells
dfflibmap -liberty mycells.lib
abc -liberty mycells.lib
clean
-Yosys is under construction. A more detailed documentation will follow.
+The command ``prep`` provides a good default word-level synthesis script, as
+used in SMT-based formal verification.
Unsupported Verilog-2005 Features
@@ -434,6 +408,23 @@ Verilog Attributes and non-standard features
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
functionality. (By default specify .. endspecify blocks are ignored.)
+- The module attribute ``abc_box_id`` specifies a positive integer linking a
+ blackbox or whitebox definition to a corresponding entry in a `abc9`
+ box-file.
+
+- The port attribute ``abc_scc_break`` indicates a module input port that will
+ be treated as a primary output during `abc9` techmapping. Doing so eliminates
+ the possibility of a strongly-connected component (i.e. a combinatorial loop)
+ existing. Typically, this is specified for sequential inputs on otherwise
+ combinatorial boxes -- for example, applying ``abc_scc_break`` onto the `D`
+ port of a LUTRAM cell prevents `abc9` from interpreting any `Q` -> `D` paths
+ as a combinatorial loop.
+
+- The port attribute ``abc_carry`` marks the carry-in (if an input port) and
+ carry-out (if output port) ports of a box. This information is necessary for
+ `abc9` to preserve the integrity of carry-chains. Specifying this attribute
+ onto a bus port will affect only its most significant bit.
+
Non-standard or SystemVerilog features for formal verification
==============================================================
diff --git a/backends/aiger/Makefile.inc b/backends/aiger/Makefile.inc
index 0fc37e95c..4a4cf30bd 100644
--- a/backends/aiger/Makefile.inc
+++ b/backends/aiger/Makefile.inc
@@ -1,3 +1,4 @@
OBJS += backends/aiger/aiger.o
+OBJS += backends/aiger/xaiger.o
diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc
index d685c5638..7c851bb91 100644
--- a/backends/aiger/aiger.cc
+++ b/backends/aiger/aiger.cc
@@ -70,34 +70,35 @@ struct AigerWriter
int bit2aig(SigBit bit)
{
- if (aig_map.count(bit) == 0)
- {
- aig_map[bit] = -1;
-
- if (initstate_bits.count(bit)) {
- log_assert(initstate_ff > 0);
- aig_map[bit] = initstate_ff;
- } else
- if (not_map.count(bit)) {
- int a = bit2aig(not_map.at(bit)) ^ 1;
- aig_map[bit] = a;
- } else
- if (and_map.count(bit)) {
- auto args = and_map.at(bit);
- int a0 = bit2aig(args.first);
- int a1 = bit2aig(args.second);
- aig_map[bit] = mkgate(a0, a1);
- } else
- if (alias_map.count(bit)) {
- aig_map[bit] = bit2aig(alias_map.at(bit));
- }
+ auto it = aig_map.find(bit);
+ if (it != aig_map.end()) {
+ log_assert(it->second >= 0);
+ return it->second;
+ }
- if (bit == State::Sx || bit == State::Sz)
- log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n");
+ // NB: Cannot use iterator returned from aig_map.insert()
+ // since this function is called recursively
+
+ int a = -1;
+ if (not_map.count(bit)) {
+ a = bit2aig(not_map.at(bit)) ^ 1;
+ } else
+ if (and_map.count(bit)) {
+ auto args = and_map.at(bit);
+ int a0 = bit2aig(args.first);
+ int a1 = bit2aig(args.second);
+ a = mkgate(a0, a1);
+ } else
+ if (alias_map.count(bit)) {
+ a = bit2aig(alias_map.at(bit));
}
- log_assert(aig_map.at(bit) >= 0);
- return aig_map.at(bit);
+ if (bit == State::Sx || bit == State::Sz)
+ log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n");
+
+ log_assert(a >= 0);
+ aig_map[bit] = a;
+ return a;
}
AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
@@ -685,7 +686,7 @@ struct AigerBackend : public Backend {
log("invariant constraints.\n");
log("\n");
log(" -ascii\n");
- log(" write ASCII version of AGIER format\n");
+ log(" write ASCII version of AIGER format\n");
log("\n");
log(" -zinit\n");
log(" convert FFs to zero-initialized FFs, adding additional inputs for\n");
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
new file mode 100644
index 000000000..77d0e94c2
--- /dev/null
+++ b/backends/aiger/xaiger.cc
@@ -0,0 +1,841 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// https://stackoverflow.com/a/46137633
+#ifdef _MSC_VER
+#include <stdlib.h>
+#define bswap32 _byteswap_ulong
+#elif defined(__APPLE__)
+#include <libkern/OSByteOrder.h>
+#define bswap32 OSSwapInt32
+#elif defined(__GNUC__)
+#define bswap32 __builtin_bswap32
+#else
+#include <cstdint>
+inline static uint32_t bswap32(uint32_t x)
+{
+ // https://stackoverflow.com/a/27796212
+ register uint32_t value = number_to_be_reversed;
+ uint8_t lolo = (value >> 0) & 0xFF;
+ uint8_t lohi = (value >> 8) & 0xFF;
+ uint8_t hilo = (value >> 16) & 0xFF;
+ uint8_t hihi = (value >> 24) & 0xFF;
+ return (hihi << 24)
+ | (hilo << 16)
+ | (lohi << 8)
+ | (lolo << 0);
+}
+#endif
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/utils.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+inline int32_t to_big_endian(int32_t i32) {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ return bswap32(i32);
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ return i32;
+#else
+#error "Unknown endianness"
+#endif
+}
+
+void aiger_encode(std::ostream &f, int x)
+{
+ log_assert(x >= 0);
+
+ while (x & ~0x7f) {
+ f.put((x & 0x7f) | 0x80);
+ x = x >> 7;
+ }
+
+ f.put(x);
+}
+
+struct XAigerWriter
+{
+ Module *module;
+ SigMap sigmap;
+
+ pool<SigBit> input_bits, output_bits;
+ dict<SigBit, SigBit> not_map, alias_map;
+ dict<SigBit, pair<SigBit, SigBit>> and_map;
+ vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits;
+ vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits;
+
+ vector<pair<int, int>> aig_gates;
+ vector<int> aig_outputs;
+ int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0;
+
+ dict<SigBit, int> aig_map;
+ dict<SigBit, int> ordered_outputs;
+
+ vector<Cell*> box_list;
+ bool omode = false;
+
+ int mkgate(int a0, int a1)
+ {
+ aig_m++, aig_a++;
+ aig_gates.push_back(a0 > a1 ? make_pair(a0, a1) : make_pair(a1, a0));
+ return 2*aig_m;
+ }
+
+ int bit2aig(SigBit bit)
+ {
+ auto it = aig_map.find(bit);
+ if (it != aig_map.end()) {
+ log_assert(it->second >= 0);
+ return it->second;
+ }
+
+ // NB: Cannot use iterator returned from aig_map.insert()
+ // since this function is called recursively
+
+ int a = -1;
+ if (not_map.count(bit)) {
+ a = bit2aig(not_map.at(bit)) ^ 1;
+ } else
+ if (and_map.count(bit)) {
+ auto args = and_map.at(bit);
+ int a0 = bit2aig(args.first);
+ int a1 = bit2aig(args.second);
+ a = mkgate(a0, a1);
+ } else
+ if (alias_map.count(bit)) {
+ a = bit2aig(alias_map.at(bit));
+ }
+
+ if (bit == State::Sx || bit == State::Sz) {
+ log_debug("Design contains 'x' or 'z' bits. Treating as 1'b0.\n");
+ a = aig_map.at(State::S0);
+ }
+
+ log_assert(a >= 0);
+ aig_map[bit] = a;
+ return a;
+ }
+
+ XAigerWriter(Module *module, bool holes_mode=false) : module(module), sigmap(module)
+ {
+ pool<SigBit> undriven_bits;
+ pool<SigBit> unused_bits;
+ pool<SigBit> keep_bits;
+
+ // promote public wires
+ for (auto wire : module->wires())
+ if (wire->name[0] == '\\')
+ sigmap.add(wire);
+
+ // promote input wires
+ for (auto wire : module->wires())
+ if (wire->port_input)
+ sigmap.add(wire);
+
+ // promote output wires
+ for (auto wire : module->wires())
+ if (wire->port_output)
+ sigmap.add(wire);
+
+ for (auto wire : module->wires())
+ {
+ bool keep = wire->attributes.count("\\keep");
+
+ for (int i = 0; i < GetSize(wire); i++)
+ {
+ SigBit wirebit(wire, i);
+ SigBit bit = sigmap(wirebit);
+
+ if (bit.wire) {
+ undriven_bits.insert(bit);
+ unused_bits.insert(bit);
+ }
+
+ if (keep)
+ keep_bits.insert(bit);
+
+ if (wire->port_input || keep) {
+ if (bit != wirebit)
+ alias_map[bit] = wirebit;
+ input_bits.insert(wirebit);
+ }
+
+ if (wire->port_output || keep) {
+ if (bit != RTLIL::Sx) {
+ if (bit != wirebit)
+ alias_map[wirebit] = bit;
+ output_bits.insert(wirebit);
+ }
+ else
+ log_debug("Skipping PO '%s' driven by 1'bx\n", log_signal(wirebit));
+ }
+ }
+ }
+
+ for (auto bit : input_bits)
+ undriven_bits.erase(sigmap(bit));
+ for (auto bit : output_bits)
+ if (!bit.wire->port_input)
+ unused_bits.erase(bit);
+
+ // TODO: Speed up toposort -- ultimately we care about
+ // box ordering, but not individual AIG cells
+ dict<SigBit, pool<IdString>> bit_drivers, bit_users;
+ TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
+ bool abc_box_seen = false;
+
+ for (auto cell : module->selected_cells()) {
+ if (cell->type == "$_NOT_")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
+ unused_bits.erase(A);
+ undriven_bits.erase(Y);
+ not_map[Y] = A;
+ if (!holes_mode) {
+ toposort.node(cell->name);
+ bit_users[A].insert(cell->name);
+ bit_drivers[Y].insert(cell->name);
+ }
+ continue;
+ }
+
+ if (cell->type == "$_AND_")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit B = sigmap(cell->getPort("\\B").as_bit());
+ SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
+ unused_bits.erase(A);
+ unused_bits.erase(B);
+ undriven_bits.erase(Y);
+ and_map[Y] = make_pair(A, B);
+ if (!holes_mode) {
+ toposort.node(cell->name);
+ bit_users[A].insert(cell->name);
+ bit_users[B].insert(cell->name);
+ bit_drivers[Y].insert(cell->name);
+ }
+ continue;
+ }
+
+ log_assert(!holes_mode);
+
+ RTLIL::Module* inst_module = module->design->module(cell->type);
+ if (inst_module && inst_module->attributes.count("\\abc_box_id")) {
+ abc_box_seen = true;
+
+ if (!holes_mode) {
+ toposort.node(cell->name);
+ for (const auto &conn : cell->connections()) {
+ if (cell->input(conn.first)) {
+ // Ignore inout for the sake of topographical ordering
+ if (cell->output(conn.first)) continue;
+ 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);
+ }
+ }
+ }
+ else {
+ bool cell_known = cell->known();
+ for (const auto &c : cell->connections()) {
+ if (c.second.is_fully_const()) continue;
+ auto is_input = !cell_known || cell->input(c.first);
+ auto is_output = !cell_known || cell->output(c.first);
+ if (!is_input && !is_output)
+ log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
+
+ if (is_input) {
+ for (auto b : c.second.bits()) {
+ Wire *w = b.wire;
+ if (!w) continue;
+ if (!w->port_output || !cell_known) {
+ SigBit I = sigmap(b);
+ if (I != b)
+ alias_map[b] = I;
+ output_bits.insert(b);
+ unused_bits.erase(b);
+
+ if (!cell_known)
+ keep_bits.insert(b);
+ }
+ }
+ }
+ if (is_output) {
+ for (auto b : c.second.bits()) {
+ Wire *w = b.wire;
+ if (!w) continue;
+ input_bits.insert(b);
+ SigBit O = sigmap(b);
+ if (O != b)
+ alias_map[O] = b;
+ undriven_bits.erase(O);
+ }
+ }
+ }
+ }
+
+ //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
+ }
+
+ if (abc_box_seen) {
+ 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);
+
+#if 0
+ toposort.analyze_loops = true;
+#endif
+ bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
+#if 0
+ unsigned i = 0;
+ for (auto &it : toposort.loops) {
+ log(" loop %d\n", i++);
+ for (auto cell_name : it) {
+ auto cell = module->cell(cell_name);
+ log_assert(cell);
+ log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str());
+ }
+ }
+#endif
+ log_assert(no_loops);
+
+ for (auto cell_name : toposort.sorted) {
+ RTLIL::Cell *cell = module->cell(cell_name);
+ log_assert(cell);
+
+ RTLIL::Module* box_module = module->design->module(cell->type);
+ if (!box_module || !box_module->attributes.count("\\abc_box_id"))
+ continue;
+
+ // Fully pad all unused input connections of this box cell with S0
+ // Fully pad all undriven output connections of this box cell with anonymous wires
+ // NB: Assume box_module->ports are sorted alphabetically
+ // (as RTLIL::Module::fixup_ports() would do)
+ for (const auto &port_name : box_module->ports) {
+ RTLIL::Wire* w = box_module->wire(port_name);
+ log_assert(w);
+ auto it = cell->connections_.find(port_name);
+ if (w->port_input) {
+ RTLIL::SigSpec rhs;
+ if (it != cell->connections_.end()) {
+ if (GetSize(it->second) < GetSize(w))
+ it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second)));
+ rhs = it->second;
+ }
+ else {
+ rhs = RTLIL::SigSpec(State::S0, GetSize(w));
+ cell->setPort(port_name, rhs);
+ }
+
+ int offset = 0;
+ for (auto b : rhs.bits()) {
+ SigBit I = sigmap(b);
+ if (b == RTLIL::Sx)
+ b = State::S0;
+ else if (I != b) {
+ if (I == RTLIL::Sx)
+ alias_map[b] = State::S0;
+ else
+ alias_map[b] = I;
+ }
+ co_bits.emplace_back(b, cell, port_name, offset++, 0);
+ unused_bits.erase(b);
+ }
+ }
+ if (w->port_output) {
+ RTLIL::SigSpec rhs;
+ auto it = cell->connections_.find(w->name);
+ if (it != cell->connections_.end()) {
+ if (GetSize(it->second) < GetSize(w))
+ it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second)));
+ rhs = it->second;
+ }
+ else {
+ rhs = module->addWire(NEW_ID, GetSize(w));
+ cell->setPort(port_name, rhs);
+ }
+
+ int offset = 0;
+ for (const auto &b : rhs.bits()) {
+ ci_bits.emplace_back(b, cell, port_name, offset++);
+ SigBit O = sigmap(b);
+ if (O != b)
+ alias_map[O] = b;
+ undriven_bits.erase(O);
+
+ auto jt = input_bits.find(b);
+ if (jt != input_bits.end()) {
+ log_assert(keep_bits.count(O));
+ input_bits.erase(b);
+ }
+ }
+ }
+ }
+ box_list.emplace_back(cell);
+ }
+
+ // TODO: Free memory from toposort, bit_drivers, bit_users
+ }
+
+ for (auto bit : input_bits) {
+ if (!output_bits.count(bit))
+ continue;
+ RTLIL::Wire *wire = bit.wire;
+ // If encountering an inout port, or a keep-ed wire, then create a new wire
+ // with $inout.out suffix, make it a PO driven by the existing inout, and
+ // inherit existing inout's drivers
+ if ((wire->port_input && wire->port_output && !undriven_bits.count(bit))
+ || keep_bits.count(bit)) {
+ RTLIL::IdString wire_name = wire->name.str() + "$inout.out";
+ RTLIL::Wire *new_wire = module->wire(wire_name);
+ if (!new_wire)
+ new_wire = module->addWire(wire_name, GetSize(wire));
+ SigBit new_bit(new_wire, bit.offset);
+ module->connect(new_bit, bit);
+ if (not_map.count(bit)) {
+ auto a = not_map.at(bit);
+ not_map[new_bit] = a;
+ }
+ else if (and_map.count(bit)) {
+ auto a = and_map.at(bit);
+ and_map[new_bit] = a;
+ }
+ else if (alias_map.count(bit)) {
+ auto a = alias_map.at(bit);
+ alias_map[new_bit] = a;
+ }
+ else
+ alias_map[new_bit] = bit;
+ output_bits.erase(bit);
+ output_bits.insert(new_bit);
+ }
+ }
+
+ for (auto bit : unused_bits)
+ undriven_bits.erase(bit);
+
+ if (!undriven_bits.empty() && !holes_mode) {
+ undriven_bits.sort();
+ for (auto bit : undriven_bits) {
+ log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit));
+ input_bits.insert(bit);
+ }
+ log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module));
+ }
+
+ if (holes_mode) {
+ struct sort_by_port_id {
+ bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const {
+ return a.wire->port_id < b.wire->port_id;
+ }
+ };
+ input_bits.sort(sort_by_port_id());
+ output_bits.sort(sort_by_port_id());
+ }
+ else {
+ input_bits.sort();
+ output_bits.sort();
+ }
+
+ not_map.sort();
+ and_map.sort();
+
+ aig_map[State::S0] = 0;
+ aig_map[State::S1] = 1;
+
+ for (auto bit : input_bits) {
+ aig_m++, aig_i++;
+ log_assert(!aig_map.count(bit));
+ aig_map[bit] = 2*aig_m;
+ }
+
+ for (auto &c : ci_bits) {
+ RTLIL::SigBit bit = std::get<0>(c);
+ aig_m++, aig_i++;
+ aig_map[bit] = 2*aig_m;
+ }
+
+ for (auto &c : co_bits) {
+ RTLIL::SigBit bit = std::get<0>(c);
+ std::get<4>(c) = ordered_outputs[bit] = aig_o++;
+ aig_outputs.push_back(bit2aig(bit));
+ }
+
+ for (auto bit : output_bits) {
+ ordered_outputs[bit] = aig_o++;
+ aig_outputs.push_back(bit2aig(bit));
+ }
+
+ if (output_bits.empty()) {
+ aig_o++;
+ aig_outputs.push_back(0);
+ omode = true;
+ }
+ }
+
+ void write_aiger(std::ostream &f, bool ascii_mode)
+ {
+ int aig_obc = aig_o;
+ int aig_obcj = aig_obc;
+ int aig_obcjf = aig_obcj;
+
+ log_assert(aig_m == aig_i + aig_l + aig_a);
+ log_assert(aig_obcjf == GetSize(aig_outputs));
+
+ f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a);
+ f << stringf("\n");
+
+ if (ascii_mode)
+ {
+ for (int i = 0; i < aig_i; i++)
+ f << stringf("%d\n", 2*i+2);
+
+ for (int i = 0; i < aig_obc; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = aig_obc; i < aig_obcj; i++)
+ f << stringf("1\n");
+
+ for (int i = aig_obc; i < aig_obcj; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = aig_obcj; i < aig_obcjf; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = 0; i < aig_a; i++)
+ f << stringf("%d %d %d\n", 2*(aig_i+aig_l+i)+2, aig_gates.at(i).first, aig_gates.at(i).second);
+ }
+ else
+ {
+ for (int i = 0; i < aig_obc; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = aig_obc; i < aig_obcj; i++)
+ f << stringf("1\n");
+
+ for (int i = aig_obc; i < aig_obcj; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = aig_obcj; i < aig_obcjf; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = 0; i < aig_a; i++) {
+ int lhs = 2*(aig_i+aig_l+i)+2;
+ int rhs0 = aig_gates.at(i).first;
+ int rhs1 = aig_gates.at(i).second;
+ int delta0 = lhs - rhs0;
+ int delta1 = rhs0 - rhs1;
+ aiger_encode(f, delta0);
+ aiger_encode(f, delta1);
+ }
+ }
+
+ f << "c";
+
+ if (!box_list.empty()) {
+ auto write_buffer = [](std::stringstream &buffer, int i32) {
+ int32_t i32_be = to_big_endian(i32);
+ buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
+ };
+
+ std::stringstream h_buffer;
+ auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
+ write_h_buffer(1);
+ log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits));
+ write_h_buffer(input_bits.size() + ci_bits.size());
+ log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits));
+ write_h_buffer(output_bits.size() + co_bits.size());
+ log_debug("piNum = %d\n", GetSize(input_bits));
+ write_h_buffer(input_bits.size());
+ log_debug("poNum = %d\n", GetSize(output_bits));
+ write_h_buffer(output_bits.size());
+ log_debug("boxNum = %d\n", GetSize(box_list));
+ write_h_buffer(box_list.size());
+
+ RTLIL::Module *holes_module = module->design->addModule("$__holes__");
+ log_assert(holes_module);
+
+ int port_id = 1;
+ int box_count = 0;
+ for (auto cell : box_list) {
+ RTLIL::Module* box_module = module->design->module(cell->type);
+ int box_inputs = 0, box_outputs = 0;
+ Cell *holes_cell = nullptr;
+ if (box_module->get_bool_attribute("\\whitebox")) {
+ holes_cell = holes_module->addCell(cell->name, cell->type);
+ holes_cell->parameters = cell->parameters;
+ }
+
+ // NB: Assume box_module->ports are sorted alphabetically
+ // (as RTLIL::Module::fixup_ports() would do)
+ for (const auto &port_name : box_module->ports) {
+ RTLIL::Wire *w = box_module->wire(port_name);
+ log_assert(w);
+ RTLIL::Wire *holes_wire;
+ RTLIL::SigSpec port_wire;
+ if (w->port_input) {
+ for (int i = 0; i < GetSize(w); i++) {
+ box_inputs++;
+ holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
+ if (!holes_wire) {
+ holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
+ holes_wire->port_input = true;
+ holes_wire->port_id = port_id++;
+ holes_module->ports.push_back(holes_wire->name);
+ }
+ if (holes_cell)
+ port_wire.append(holes_wire);
+ }
+ if (!port_wire.empty())
+ holes_cell->setPort(w->name, port_wire);
+ }
+ if (w->port_output) {
+ box_outputs += GetSize(w);
+ for (int i = 0; i < GetSize(w); i++) {
+ if (GetSize(w) == 1)
+ holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), w->name.c_str()));
+ else
+ holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), w->name.c_str(), i));
+ holes_wire->port_output = true;
+ holes_wire->port_id = port_id++;
+ holes_module->ports.push_back(holes_wire->name);
+ if (holes_cell)
+ port_wire.append(holes_wire);
+ else
+ holes_module->connect(holes_wire, State::S0);
+ }
+ if (!port_wire.empty())
+ holes_cell->setPort(w->name, port_wire);
+ }
+ }
+
+ write_h_buffer(box_inputs);
+ write_h_buffer(box_outputs);
+ write_h_buffer(box_module->attributes.at("\\abc_box_id").as_int());
+ write_h_buffer(box_count++);
+ }
+
+ f << "h";
+ std::string buffer_str = h_buffer.str();
+ int32_t buffer_size_be = to_big_endian(buffer_str.size());
+ f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
+ f.write(buffer_str.data(), buffer_str.size());
+
+ std::stringstream r_buffer;
+ auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1);
+ write_r_buffer(0);
+
+ f << "r";
+ buffer_str = r_buffer.str();
+ buffer_size_be = to_big_endian(buffer_str.size());
+ f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
+ f.write(buffer_str.data(), buffer_str.size());
+
+ if (holes_module) {
+ log_push();
+
+ // NB: fixup_ports() will sort ports by name
+ //holes_module->fixup_ports();
+ holes_module->check();
+
+ holes_module->design->selection_stack.emplace_back(false);
+ RTLIL::Selection& sel = holes_module->design->selection_stack.back();
+ sel.select(holes_module);
+
+ // TODO: Should not need to opt_merge if we only instantiate
+ // each box type once...
+ Pass::call(holes_module->design, "opt_merge -share_all");
+
+ Pass::call(holes_module->design, "flatten -wb");
+
+ // TODO: Should techmap/aigmap/check all lib_whitebox-es just once,
+ // instead of per write_xaiger call
+ Pass::call(holes_module->design, "techmap");
+ Pass::call(holes_module->design, "aigmap");
+ for (auto cell : holes_module->cells())
+ if (!cell->type.in("$_NOT_", "$_AND_"))
+ log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
+
+ holes_module->design->selection_stack.pop_back();
+
+ // Move into a new (temporary) design so that "clean" will only
+ // operate (and run checks on) this one module
+ RTLIL::Design *holes_design = new RTLIL::Design;
+ holes_module->design->modules_.erase(holes_module->name);
+ holes_design->add(holes_module);
+ Pass::call(holes_design, "clean -purge");
+
+ std::stringstream a_buffer;
+ XAigerWriter writer(holes_module, true /* holes_mode */);
+ writer.write_aiger(a_buffer, false /*ascii_mode*/);
+
+ delete holes_design;
+
+ f << "a";
+ std::string buffer_str = a_buffer.str();
+ int32_t buffer_size_be = to_big_endian(buffer_str.size());
+ f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
+ f.write(buffer_str.data(), buffer_str.size());
+
+ log_pop();
+ }
+ }
+
+ f << stringf("Generated by %s\n", yosys_version_str);
+ }
+
+ void write_map(std::ostream &f, bool verbose_map)
+ {
+ dict<int, string> input_lines;
+ dict<int, string> output_lines;
+ dict<int, string> wire_lines;
+
+ for (auto wire : module->wires())
+ {
+ //if (!verbose_map && wire->name[0] == '$')
+ // continue;
+
+ SigSpec sig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(wire); i++)
+ {
+ RTLIL::SigBit b(wire, i);
+ if (input_bits.count(b)) {
+ int a = aig_map.at(b);
+ log_assert((a & 1) == 0);
+ input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire));
+ }
+
+ if (output_bits.count(b)) {
+ int o = ordered_outputs.at(b);
+ output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), i, log_id(wire));
+ continue;
+ }
+
+ if (verbose_map) {
+ if (aig_map.count(sig[i]) == 0)
+ continue;
+
+ int a = aig_map.at(sig[i]);
+ wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire));
+ }
+ }
+ }
+
+ input_lines.sort();
+ for (auto &it : input_lines)
+ f << it.second;
+ log_assert(input_lines.size() == input_bits.size());
+
+ int box_count = 0;
+ for (auto cell : box_list)
+ f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name));
+
+ output_lines.sort();
+ for (auto &it : output_lines)
+ f << it.second;
+ log_assert(output_lines.size() == output_bits.size());
+ if (omode && output_bits.empty())
+ f << "output " << output_lines.size() << " 0 $__dummy__\n";
+
+ wire_lines.sort();
+ for (auto &it : wire_lines)
+ f << it.second;
+ }
+};
+
+struct XAigerBackend : public Backend {
+ XAigerBackend() : Backend("xaiger", "write design to XAIGER file") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_xaiger [options] [filename]\n");
+ log("\n");
+ log("Write the current design to an XAIGER file. The design must be flattened and\n");
+ log("all unsupported cells will be converted into psuedo-inputs and pseudo-outputs.\n");
+ log("\n");
+ log(" -ascii\n");
+ log(" write ASCII version of AIGER format\n");
+ log("\n");
+ log(" -map <filename>\n");
+ log(" write an extra file with port and latch symbols\n");
+ log("\n");
+ log(" -vmap <filename>\n");
+ log(" like -map, but more verbose\n");
+ log("\n");
+ }
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool ascii_mode = false;
+ bool verbose_map = false;
+ std::string map_filename;
+
+ log_header(design, "Executing XAIGER backend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-ascii") {
+ ascii_mode = true;
+ continue;
+ }
+ if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
+ map_filename = args[++argidx];
+ continue;
+ }
+ if (map_filename.empty() && args[argidx] == "-vmap" && argidx+1 < args.size()) {
+ map_filename = args[++argidx];
+ verbose_map = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ Module *top_module = design->top_module();
+
+ if (top_module == nullptr)
+ log_error("Can't find top module in current design!\n");
+
+ XAigerWriter writer(top_module);
+ writer.write_aiger(*f, ascii_mode);
+
+ if (!map_filename.empty()) {
+ std::ofstream mapf;
+ mapf.open(map_filename.c_str(), std::ofstream::trunc);
+ if (mapf.fail())
+ log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno));
+ writer.write_map(mapf, verbose_map);
+ }
+ }
+} XAigerBackend;
+
+PRIVATE_NAMESPACE_END
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index a1761b662..b6e38c16c 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -327,6 +327,13 @@ struct BlifDumper
goto internal_cell;
}
+ if (!config->icells_mode && cell->type == "$_NMUX_") {
+ f << stringf(".names %s %s %s %s\n0-0 1\n-01 1\n",
+ cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
+ cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y")));
+ goto internal_cell;
+ }
+
if (!config->icells_mode && cell->type == "$_FF_") {
f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr_init(cell->getPort("\\Q")));
@@ -370,7 +377,7 @@ struct BlifDumper
f << stringf("\n");
RTLIL::SigSpec mask = cell->parameters.at("\\LUT");
for (int i = 0; i < (1 << width); i++)
- if (mask[i] == RTLIL::S1) {
+ if (mask[i] == State::S1) {
for (int j = width-1; j >= 0; j--) {
f << ((i>>j)&1 ? '1' : '0');
}
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 511a11942..7c054d655 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -17,6 +17,11 @@
*
*/
+// [[CITE]] Btor2 , BtorMC and Boolector 3.0
+// Aina Niemetz, Mathias Preiner, Clifford Wolf, Armin Biere
+// Computer Aided Verification - 30th International Conference, CAV 2018
+// https://cs.stanford.edu/people/niemetz/publication/2018/niemetzpreinerwolfbiere-cav18/
+
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@@ -491,7 +496,7 @@ struct BtorWorker
goto okay;
}
- if (cell->type.in("$mux", "$_MUX_"))
+ if (cell->type.in("$mux", "$_MUX_", "$_NMUX_"))
{
SigSpec sig_a = sigmap(cell->getPort("\\A"));
SigSpec sig_b = sigmap(cell->getPort("\\B"));
@@ -506,6 +511,12 @@ struct BtorWorker
int nid = next_nid++;
btorf("%d ite %d %d %d %d\n", nid, sid, nid_s, nid_b, nid_a);
+ if (cell->type == "$_NMUX_") {
+ int tmp = nid;
+ nid = next_nid++;
+ btorf("%d not %d %d\n", nid, sid, tmp);
+ }
+
add_nid_sig(nid, sig_y);
goto okay;
}
@@ -605,8 +616,8 @@ struct BtorWorker
if (initstate_nid < 0)
{
int sid = get_bv_sid(1);
- int one_nid = get_sig_nid(Const(1, 1));
- int zero_nid = get_sig_nid(Const(0, 1));
+ int one_nid = get_sig_nid(State::S1);
+ int zero_nid = get_sig_nid(State::S0);
initstate_nid = next_nid++;
btorf("%d state %d\n", initstate_nid, sid);
btorf("%d init %d %d %d\n", next_nid++, sid, initstate_nid, one_nid);
@@ -875,9 +886,28 @@ struct BtorWorker
else
{
if (bit_cell.count(bit) == 0)
- log_error("No driver for signal bit %s.\n", log_signal(bit));
- export_cell(bit_cell.at(bit));
- log_assert(bit_nid.count(bit));
+ {
+ SigSpec s = bit;
+
+ while (i+GetSize(s) < GetSize(sig) && sig[i+GetSize(s)].wire != nullptr &&
+ bit_cell.count(sig[i+GetSize(s)]) == 0)
+ s.append(sig[i+GetSize(s)]);
+
+ log_warning("No driver for signal %s.\n", log_signal(s));
+
+ int sid = get_bv_sid(GetSize(s));
+ int nid = next_nid++;
+ btorf("%d input %d %s\n", nid, sid);
+ nid_width[nid] = GetSize(s);
+
+ i += GetSize(s)-1;
+ continue;
+ }
+ else
+ {
+ export_cell(bit_cell.at(bit));
+ log_assert(bit_nid.count(bit));
+ }
}
}
diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index 1c7a7351f..87db0edf7 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -122,9 +122,9 @@ struct FirrtlWorker
// Current (3/13/2019) conventions:
// generate a constant 0 for clock and a constant 1 for enable if they are undefined.
if (!clk.is_fully_def())
- this->clk = SigSpec(RTLIL::Const(0, 1));
+ this->clk = SigSpec(State::S0);
if (!ena.is_fully_def())
- this->ena = SigSpec(RTLIL::Const(1, 1));
+ this->ena = SigSpec(State::S1);
}
string gen_read(const char * indent) {
string addr_expr = make_expr(addr);
@@ -297,7 +297,7 @@ struct FirrtlWorker
std::string cell_type = fid(cell->type);
std::string instanceOf;
// If this is a parameterized module, its parent module is encoded in the cell type
- if (cell->type.substr(0, 8) == "$paramod")
+ if (cell->type.begins_with("$paramod"))
{
std::string::iterator it;
for (it = cell_type.begin(); it < cell_type.end(); it++)
@@ -363,7 +363,7 @@ struct FirrtlWorker
}
// Check for subfield assignment.
std::string bitsString = "bits(";
- if (sinkExpr.substr(0, bitsString.length()) == bitsString ) {
+ if (sinkExpr.compare(0, bitsString.length(), bitsString) == 0) {
if (sinkSig == nullptr)
log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str());
// Don't generate the assignment here.
@@ -381,10 +381,10 @@ struct FirrtlWorker
// Given an expression for a shift amount, and a maximum width,
// generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics.
- std::string gen_dshl(const string b_expr, const int b_padded_width)
+ std::string gen_dshl(const string b_expr, const int b_width)
{
string result = b_expr;
- if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) {
+ if (b_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) {
int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
// Deal with the difference in semantics between FIRRTL and verilog
@@ -422,22 +422,33 @@ struct FirrtlWorker
for (auto cell : module->cells())
{
- bool extract_y_bits = false; // Assume no extraction of final bits will be required.
+ static Const ndef(0, 0);
+
// Is this cell is a module instance?
if (cell->type[0] != '$')
{
process_instance(cell, wire_exprs);
continue;
}
+ // Not a module instance. Set up cell properties
+ bool extract_y_bits = false; // Assume no extraction of final bits will be required.
+ int a_width = cell->parameters.at("\\A_WIDTH", ndef).as_int(); // The width of "A"
+ int b_width = cell->parameters.at("\\B_WIDTH", ndef).as_int(); // The width of "A"
+ const int y_width = cell->parameters.at("\\Y_WIDTH", ndef).as_int(); // The width of the result
+ const bool a_signed = cell->parameters.at("\\A_SIGNED", ndef).as_bool();
+ const bool b_signed = cell->parameters.at("\\B_SIGNED", ndef).as_bool();
+ bool firrtl_is_signed = a_signed; // The result is signed (subsequent code may change this).
+ int firrtl_width = 0;
+ string primop;
+ bool always_uint = false;
+ string y_id = make_id(cell->name);
+
if (cell->type.in("$not", "$logic_not", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_bool", "$reduce_xnor"))
{
- string y_id = make_id(cell->name);
- bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
- int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
- if (cell->parameters.at("\\A_SIGNED").as_bool()) {
+ if (a_signed) {
a_expr = "asSInt(" + a_expr + ")";
}
@@ -446,12 +457,13 @@ struct FirrtlWorker
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
}
- string primop;
- bool always_uint = false;
+ // Assume the FIRRTL width is a single bit.
+ firrtl_width = 1;
if (cell->type == "$not") primop = "not";
else if (cell->type == "$neg") {
primop = "neg";
- is_signed = true; // Result of "neg" is signed (an SInt).
+ firrtl_is_signed = true; // Result of "neg" is signed (an SInt).
+ firrtl_width = a_width;
} else if (cell->type == "$logic_not") {
primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
@@ -466,14 +478,12 @@ struct FirrtlWorker
else if (cell->type == "$reduce_bool") {
primop = "neq";
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
- bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
- int a_width = cell->parameters.at("\\A_WIDTH").as_int();
a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width);
}
string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str());
- if ((is_signed && !always_uint))
+ if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str());
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
@@ -481,81 +491,121 @@ struct FirrtlWorker
continue;
}
- if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx",
+ if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or", "$eq", "$eqx",
"$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
- "$logic_and", "$logic_or"))
+ "$logic_and", "$logic_or", "$pow"))
{
- string y_id = make_id(cell->name);
- bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
- int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B"));
- int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
- if (cell->parameters.at("\\A_SIGNED").as_bool()) {
+ if (a_signed) {
a_expr = "asSInt(" + a_expr + ")";
- }
- // Shift amount is always unsigned, and needn't be padded to result width.
- if (!cell->type.in("$shr", "$sshr", "$shl", "$sshl")) {
- if (cell->parameters.at("\\B_SIGNED").as_bool()) {
- b_expr = "asSInt(" + b_expr + ")";
+ // Expand the "A" operand to the result width
+ if (a_width < y_width) {
+ a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+ a_width = y_width;
}
- if (b_padded_width < y_width) {
- auto b_sig = cell->getPort("\\B");
- b_padded_width = y_width;
+ }
+ // Shift amount is always unsigned, and needn't be padded to result width,
+ // otherwise, we need to cast the b_expr appropriately
+ if (b_signed && !cell->type.in("$shr", "$sshr", "$shl", "$sshl", "$pow")) {
+ b_expr = "asSInt(" + b_expr + ")";
+ // Expand the "B" operand to the result width
+ if (b_width < y_width) {
+ b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
+ b_width = y_width;
}
}
+ // For the arithmetic ops, expand operand widths to result widths befor performing the operation.
+ // This corresponds (according to iverilog) to what verilog compilers implement.
+ if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or"))
+ {
+ if (a_width < y_width) {
+ a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+ a_width = y_width;
+ }
+ if (b_width < y_width) {
+ b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
+ b_width = y_width;
+ }
+ }
+ // Assume the FIRRTL width is the width of "A"
+ firrtl_width = a_width;
auto a_sig = cell->getPort("\\A");
- if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) {
- a_expr = "asUInt(" + a_expr + ")";
+ if (cell->type == "$add") {
+ primop = "add";
+ firrtl_is_signed = a_signed | b_signed;
+ firrtl_width = max(a_width, b_width);
+ } else if (cell->type == "$sub") {
+ primop = "sub";
+ firrtl_is_signed = true;
+ int a_widthInc = (!a_signed && b_signed) ? 2 : (a_signed && !b_signed) ? 1 : 0;
+ int b_widthInc = (a_signed && !b_signed) ? 2 : (!a_signed && b_signed) ? 1 : 0;
+ firrtl_width = max(a_width + a_widthInc, b_width + b_widthInc);
+ } else if (cell->type == "$mul") {
+ primop = "mul";
+ firrtl_is_signed = a_signed | b_signed;
+ firrtl_width = a_width + b_width;
+ } else if (cell->type == "$div") {
+ primop = "div";
+ firrtl_is_signed = a_signed | b_signed;
+ firrtl_width = a_width;
+ } else if (cell->type == "$mod") {
+ primop = "rem";
+ firrtl_width = min(a_width, b_width);
+ } else if (cell->type == "$and") {
+ primop = "and";
+ always_uint = true;
+ firrtl_width = max(a_width, b_width);
}
-
- string primop;
- bool always_uint = false;
- if (cell->type == "$add") primop = "add";
- else if (cell->type == "$sub") primop = "sub";
- else if (cell->type == "$mul") primop = "mul";
- else if (cell->type == "$div") primop = "div";
- else if (cell->type == "$mod") primop = "rem";
- else if (cell->type == "$and") {
- primop = "and";
- always_uint = true;
- }
else if (cell->type == "$or" ) {
- primop = "or";
- always_uint = true;
- }
+ primop = "or";
+ always_uint = true;
+ firrtl_width = max(a_width, b_width);
+ }
else if (cell->type == "$xor") {
- primop = "xor";
- always_uint = true;
- }
+ primop = "xor";
+ always_uint = true;
+ firrtl_width = max(a_width, b_width);
+ }
+ else if (cell->type == "$xnor") {
+ primop = "xnor";
+ always_uint = true;
+ firrtl_width = max(a_width, b_width);
+ }
else if ((cell->type == "$eq") | (cell->type == "$eqx")) {
- primop = "eq";
- always_uint = true;
- }
+ primop = "eq";
+ always_uint = true;
+ firrtl_width = 1;
+ }
else if ((cell->type == "$ne") | (cell->type == "$nex")) {
- primop = "neq";
- always_uint = true;
- }
+ primop = "neq";
+ always_uint = true;
+ firrtl_width = 1;
+ }
else if (cell->type == "$gt") {
- primop = "gt";
- always_uint = true;
- }
+ primop = "gt";
+ always_uint = true;
+ firrtl_width = 1;
+ }
else if (cell->type == "$ge") {
- primop = "geq";
- always_uint = true;
- }
+ primop = "geq";
+ always_uint = true;
+ firrtl_width = 1;
+ }
else if (cell->type == "$lt") {
- primop = "lt";
- always_uint = true;
- }
+ primop = "lt";
+ always_uint = true;
+ firrtl_width = 1;
+ }
else if (cell->type == "$le") {
- primop = "leq";
- always_uint = true;
- }
+ primop = "leq";
+ always_uint = true;
+ firrtl_width = 1;
+ }
else if ((cell->type == "$shl") | (cell->type == "$sshl")) {
// FIRRTL will widen the result (y) by the amount of the shift.
// We'll need to offset this by extracting the un-widened portion as Verilog would do.
@@ -564,11 +614,14 @@ struct FirrtlWorker
auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) {
primop = "shl";
- b_expr = std::to_string(b_sig.as_int());
+ int shift_amount = b_sig.as_int();
+ b_expr = std::to_string(shift_amount);
+ firrtl_width = a_width + shift_amount;
} else {
primop = "dshl";
// Convert from FIRRTL left shift semantics.
- b_expr = gen_dshl(b_expr, b_padded_width);
+ b_expr = gen_dshl(b_expr, b_width);
+ firrtl_width = a_width + (1 << b_width) - 1;
}
}
else if ((cell->type == "$shr") | (cell->type == "$sshr")) {
@@ -578,36 +631,86 @@ struct FirrtlWorker
auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) {
primop = "shr";
- b_expr = std::to_string(b_sig.as_int());
+ int shift_amount = b_sig.as_int();
+ b_expr = std::to_string(shift_amount);
+ firrtl_width = max(1, a_width - shift_amount);
} else {
primop = "dshr";
+ firrtl_width = a_width;
+ }
+ // We'll need to do some special fixups if the source (and thus result) is signed.
+ if (firrtl_is_signed) {
+ // If this is a "logical" shift right, pretend the source is unsigned.
+ if (cell->type == "$shr") {
+ a_expr = "asUInt(" + a_expr + ")";
+ }
}
}
else if ((cell->type == "$logic_and")) {
- primop = "and";
- a_expr = "neq(" + a_expr + ", UInt(0))";
- b_expr = "neq(" + b_expr + ", UInt(0))";
- always_uint = true;
- }
+ primop = "and";
+ a_expr = "neq(" + a_expr + ", UInt(0))";
+ b_expr = "neq(" + b_expr + ", UInt(0))";
+ always_uint = true;
+ firrtl_width = 1;
+ }
else if ((cell->type == "$logic_or")) {
- primop = "or";
- a_expr = "neq(" + a_expr + ", UInt(0))";
- b_expr = "neq(" + b_expr + ", UInt(0))";
- always_uint = true;
- }
+ primop = "or";
+ a_expr = "neq(" + a_expr + ", UInt(0))";
+ b_expr = "neq(" + b_expr + ", UInt(0))";
+ always_uint = true;
+ firrtl_width = 1;
+ }
+ else if ((cell->type == "$pow")) {
+ if (a_sig.is_fully_const() && a_sig.as_int() == 2) {
+ // We'll convert this to a shift. To simplify things, change the a_expr to "1"
+ // so we can use b_expr directly as a shift amount.
+ // Only support 2 ** N (i.e., shift left)
+ // FIRRTL will widen the result (y) by the amount of the shift.
+ // We'll need to offset this by extracting the un-widened portion as Verilog would do.
+ a_expr = firrtl_is_signed ? "SInt(1)" : "UInt(1)";
+ extract_y_bits = true;
+ // Is the shift amount constant?
+ auto b_sig = cell->getPort("\\B");
+ if (b_sig.is_fully_const()) {
+ primop = "shl";
+ int shiftAmount = b_sig.as_int();
+ if (shiftAmount < 0) {
+ log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, log_id(module), log_id(cell));
+ }
+ b_expr = std::to_string(shiftAmount);
+ firrtl_width = a_width + shiftAmount;
+ } else {
+ primop = "dshl";
+ // Convert from FIRRTL left shift semantics.
+ b_expr = gen_dshl(b_expr, b_width);
+ firrtl_width = a_width + (1 << b_width) - 1;
+ }
+ } else {
+ log_error("Non power 2: %s.%s\n", log_id(module), log_id(cell));
+ }
+ }
if (!cell->parameters.at("\\B_SIGNED").as_bool()) {
b_expr = "asUInt(" + b_expr + ")";
}
- string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
+ string expr;
+ // Deal with $xnor == ~^ (not xor)
+ if (primop == "xnor") {
+ expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str());
+ } else {
+ expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
+ }
- // Deal with FIRRTL's "shift widens" semantics
+ // Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result.
+ // If the operation is signed, the FIRRTL width will be 1 one bit larger.
if (extract_y_bits) {
expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
+ } else if (firrtl_is_signed && (firrtl_width + 1) < y_width) {
+ expr = stringf("pad(%s, %d)", expr.c_str(), y_width);
}
- if ((is_signed && !always_uint) || cell->type.in("$sub"))
+ if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str());
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
@@ -618,7 +721,6 @@ struct FirrtlWorker
if (cell->type.in("$mux"))
{
- string y_id = make_id(cell->name);
int width = cell->parameters.at("\\WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B"));
@@ -762,21 +864,20 @@ struct FirrtlWorker
if (clkpol == false)
log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell));
- string q_id = make_id(cell->name);
int width = cell->parameters.at("\\WIDTH").as_int();
string expr = make_expr(cell->getPort("\\D"));
string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")";
- wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", q_id.c_str(), width, clk_expr.c_str()));
+ wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", y_id.c_str(), width, clk_expr.c_str()));
- cell_exprs.push_back(stringf(" %s <= %s\n", q_id.c_str(), expr.c_str()));
- register_reverse_wire_map(q_id, cell->getPort("\\Q"));
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ register_reverse_wire_map(y_id, cell->getPort("\\Q"));
continue;
}
// This may be a parameterized module - paramod.
- if (cell->type.substr(0, 8) == "$paramod")
+ if (cell->type.begins_with("$paramod"))
{
process_instance(cell, wire_exprs);
continue;
@@ -785,8 +886,6 @@ struct FirrtlWorker
// assign y = a[b +: y_width];
// We'll extract the correct bits as part of the primop.
- string y_id = make_id(cell->name);
- int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
// Get the initial bit selector
string b_expr = make_expr(cell->getPort("\\B"));
@@ -808,18 +907,15 @@ struct FirrtlWorker
// assign y = a >> b;
// where b may be negative
- string y_id = make_id(cell->name);
- int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B"));
auto b_string = b_expr.c_str();
- int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
string expr;
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
if (cell->getParam("\\B_SIGNED").as_bool()) {
// We generate a left or right shift based on the sign of b.
- std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width);
+ std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_width).c_str(), y_width);
std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
expr = stringf("mux(%s < 0, %s, %s)",
b_string,
@@ -833,7 +929,21 @@ struct FirrtlWorker
register_reverse_wire_map(y_id, cell->getPort("\\Y"));
continue;
}
- log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
+ if (cell->type == "$pos") {
+ // assign y = a;
+// printCell(cell);
+ string a_expr = make_expr(cell->getPort("\\A"));
+ // Verilog appears to treat the result as signed, so if the result is wider than "A",
+ // we need to pad.
+ if (a_width < y_width) {
+ a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+ }
+ wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), a_expr.c_str()));
+ register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+ continue;
+ }
+ log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
}
for (auto conn : module->connections())
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
index b4ba2b03f..e06786220 100644
--- a/backends/ilang/ilang_backend.cc
+++ b/backends/ilang/ilang_backend.cc
@@ -40,8 +40,8 @@ void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi
for (int i = 0; i < width; i++) {
log_assert(offset+i < (int)data.bits.size());
switch (data.bits[offset+i]) {
- case RTLIL::S0: break;
- case RTLIL::S1: val |= 1 << i; break;
+ case State::S0: break;
+ case State::S1: val |= 1 << i; break;
default: val = -1; break;
}
}
@@ -54,8 +54,8 @@ void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi
for (int i = offset+width-1; i >= offset; i--) {
log_assert(i < (int)data.bits.size());
switch (data.bits[i]) {
- case RTLIL::S0: f << stringf("0"); break;
- case RTLIL::S1: f << stringf("1"); break;
+ case State::S0: f << stringf("0"); break;
+ case State::S1: f << stringf("1"); break;
case RTLIL::Sx: f << stringf("x"); break;
case RTLIL::Sz: f << stringf("z"); break;
case RTLIL::Sa: f << stringf("-"); break;
@@ -204,6 +204,11 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it)
{
+ for (auto ait = (*it)->attributes.begin(); ait != (*it)->attributes.end(); ++ait) {
+ f << stringf("%s attribute %s ", indent.c_str(), ait->first.c_str());
+ dump_const(f, ait->second);
+ f << stringf("\n");
+ }
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0)
diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc
index b0e3cd252..809a0fa09 100644
--- a/backends/intersynth/intersynth.cc
+++ b/backends/intersynth/intersynth.cc
@@ -108,7 +108,7 @@ struct IntersynthBackend : public Backend {
if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str());
RTLIL::Design *lib = new RTLIL::Design;
- Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
+ Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog"));
libs.push_back(lib);
}
@@ -183,7 +183,7 @@ struct IntersynthBackend : public Backend {
if (param.second.bits.size() != 32) {
node_code += stringf(" %s '", RTLIL::id2cstr(param.first));
for (int i = param.second.bits.size()-1; i >= 0; i--)
- node_code += param.second.bits[i] == RTLIL::S1 ? "1" : "0";
+ node_code += param.second.bits[i] == State::S1 ? "1" : "0";
} else
node_code += stringf(" %s 0x%x", RTLIL::id2cstr(param.first), param.second.as_int());
}
diff --git a/backends/json/json.cc b/backends/json/json.cc
index 5022d5da1..107009ee4 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -83,20 +83,43 @@ struct JsonWriter
return str + " ]";
}
+ void write_parameter_value(const Const &value)
+ {
+ if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) {
+ string str = value.decode_string();
+ int state = 0;
+ for (char c : str) {
+ if (state == 0) {
+ if (c == '0' || c == '1' || c == 'x' || c == 'z')
+ state = 0;
+ else if (c == ' ')
+ state = 1;
+ else
+ state = 2;
+ } else if (state == 1 && c != ' ')
+ state = 2;
+ }
+ if (state < 2)
+ str += " ";
+ f << get_string(str);
+ } else
+ if (GetSize(value) == 32 && value.is_fully_def()) {
+ if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
+ f << stringf("%d", value.as_int());
+ else
+ f << stringf("%u", value.as_int());
+ } else {
+ f << get_string(value.as_string());
+ }
+ }
+
void write_parameters(const dict<IdString, Const> &parameters, bool for_module=false)
{
bool first = true;
for (auto &param : parameters) {
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str());
- if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
- f << get_string(param.second.decode_string());
- else if (GetSize(param.second.bits) > 32)
- f << get_string(param.second.as_string());
- else if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
- f << stringf("%d", param.second.as_int());
- else
- f << stringf("%u", param.second.as_int());
+ write_parameter_value(param.second);
first = false;
}
}
@@ -126,6 +149,10 @@ struct JsonWriter
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(n).c_str());
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
+ if (w->start_offset)
+ f << stringf(" \"offset\": %d,\n", w->start_offset);
+ if (w->upto)
+ f << stringf(" \"upto\": 1,\n");
f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
f << stringf(" }");
first = false;
@@ -189,6 +216,10 @@ struct JsonWriter
f << stringf(" %s: {\n", get_name(w->name).c_str());
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
+ if (w->start_offset)
+ f << stringf(" \"offset\": %d,\n", w->start_offset);
+ if (w->upto)
+ f << stringf(" \"upto\": 1,\n");
f << stringf(" \"attributes\": {");
write_parameters(w->attributes);
f << stringf("\n }\n");
@@ -334,12 +365,13 @@ struct JsonBackend : public Backend {
log("Module and cell ports and nets can be single bit wide or vectors of multiple\n");
log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n");
log("values referenced above are vectors of this integers. Signal bits that are\n");
- log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
- log("a number.\n");
+ log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n");
+ log("\"z\" instead of a number.\n");
log("\n");
- log("Numeric parameter and attribute values up to 32 bits are written as decimal\n");
- log("values. Numbers larger than that are written as string holding the binary\n");
- log("representation of the value.\n");
+ log("Numeric 32-bit parameter and attribute values are written as decimal values.\n");
+ log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n");
+ log("as string holding the binary representation of the value. Strings are written\n");
+ log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n");
log("\n");
log("For example the following Verilog code:\n");
log("\n");
diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc
index 6f2ccbe20..54dbb84af 100644
--- a/backends/simplec/simplec.cc
+++ b/backends/simplec/simplec.cc
@@ -472,7 +472,7 @@ struct SimplecWorker
return;
}
- if (cell->type == "$_MUX_")
+ if (cell->type.in("$_MUX_", "$_NMUX_"))
{
SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
@@ -484,7 +484,9 @@ struct SimplecWorker
string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0";
// casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933)
- string expr = stringf("%s ? (bool)%s : (bool)%s", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
+ string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(),
+ cell->type == "$_NMUX_" ? "!" : "", b_expr.c_str(),
+ cell->type == "$_NMUX_" ? "!" : "", a_expr.c_str());
log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index e318a4051..081dcda99 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -510,6 +510,7 @@ struct Smt2Worker
if (cell->type == "$_ANDNOT_") return export_gate(cell, "(and A (not B))");
if (cell->type == "$_ORNOT_") return export_gate(cell, "(or A (not B))");
if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)");
+ if (cell->type == "$_NMUX_") return export_gate(cell, "(not (ite S B A))");
if (cell->type == "$_AOI3_") return export_gate(cell, "(not (or (and A B) C))");
if (cell->type == "$_OAI3_") return export_gate(cell, "(not (and (or A B) C))");
if (cell->type == "$_AOI4_") return export_gate(cell, "(not (or (and A B) (and C D)))");
@@ -600,7 +601,7 @@ struct Smt2Worker
if (cell->type == "$logic_and") return export_reduce(cell, "(and (or A) (or B))", false);
if (cell->type == "$logic_or") return export_reduce(cell, "(or A B)", false);
- if (cell->type == "$mux" || cell->type == "$pmux")
+ if (cell->type.in("$mux", "$pmux"))
{
int width = GetSize(cell->getPort("\\Y"));
std::string processed_expr = get_bv(cell->getPort("\\A"));
@@ -1475,7 +1476,7 @@ struct Smt2Backend : public Backend {
int indent = 0;
while (indent < GetSize(line) && (line[indent] == ' ' || line[indent] == '\t'))
indent++;
- if (line.substr(indent, 2) == "%%")
+ if (line.compare(indent, 2, "%%") == 0)
break;
*f << line << std::endl;
}
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
index cea0fc56c..bac68ac70 100644
--- a/backends/smt2/smtio.py
+++ b/backends/smt2/smtio.py
@@ -43,7 +43,11 @@ if os.name == "posix":
if current_rlimit_stack[1] != resource.RLIM_INFINITY:
smtio_stacksize = min(smtio_stacksize, current_rlimit_stack[1])
if current_rlimit_stack[0] < smtio_stacksize:
- resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, current_rlimit_stack[1]))
+ try:
+ resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, current_rlimit_stack[1]))
+ except ValueError:
+ # couldn't get more stack, just run with what we have
+ pass
# currently running solvers (so we can kill them)
@@ -1043,7 +1047,10 @@ class MkVcd:
scope = scope[:-1]
while uipath[:-1] != scope:
- print("$scope module %s $end" % uipath[len(scope)], file=self.f)
+ scopename = uipath[len(scope)]
+ if scopename.startswith("$"):
+ scopename = "\\" + scopename
+ print("$scope module %s $end" % scopename, file=self.f)
scope.append(uipath[len(scope)])
if path in self.clocks and self.clocks[path][1] == "event":
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index d75456c1b..f755307bf 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -61,7 +61,7 @@ struct SmvWorker
{
string name = stringf("_%s", id.c_str());
- if (name.substr(0, 2) == "_\\")
+ if (name.compare(0, 2, "_\\") == 0)
name = "_" + name.substr(2);
for (auto &c : name) {
@@ -537,6 +537,13 @@ struct SmvWorker
continue;
}
+ if (cell->type == "$_NMUX_")
+ {
+ definitions.push_back(stringf("%s := !(bool(%s) ? %s : %s);", lvalue(cell->getPort("\\Y")),
+ rvalue(cell->getPort("\\S")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\A"))));
+ continue;
+ }
+
if (cell->type == "$_AOI3_")
{
definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 827af5d85..7b1db4776 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -189,7 +189,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
if (width < 0)
width = data.bits.size() - offset;
if (width == 0) {
- f << "\"\"";
+ // See IEEE 1364-2005 Clause 5.1.14.
+ f << "{0{1'b0}}";
return;
}
if (nostr)
@@ -199,9 +200,9 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
int32_t val = 0;
for (int i = offset+width-1; i >= offset; i--) {
log_assert(i < (int)data.bits.size());
- if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
+ if (data.bits[i] != State::S0 && data.bits[i] != State::S1)
goto dump_hex;
- if (data.bits[i] == RTLIL::S1)
+ if (data.bits[i] == State::S1)
val |= 1 << (i - offset);
}
if (decimal)
@@ -218,11 +219,11 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
for (int i = offset; i < offset+width; i++) {
log_assert(i < (int)data.bits.size());
switch (data.bits[i]) {
- case RTLIL::S0: bin_digits.push_back('0'); break;
- case RTLIL::S1: bin_digits.push_back('1'); break;
+ case State::S0: bin_digits.push_back('0'); break;
+ case State::S1: bin_digits.push_back('1'); break;
case RTLIL::Sx: bin_digits.push_back('x'); break;
case RTLIL::Sz: bin_digits.push_back('z'); break;
- case RTLIL::Sa: bin_digits.push_back('z'); break;
+ case RTLIL::Sa: bin_digits.push_back('?'); break;
case RTLIL::Sm: log_error("Found marker state in final netlist.");
}
}
@@ -251,6 +252,12 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
hex_digits.push_back('z');
continue;
}
+ if (bit_3 == '?' || bit_2 == '?' || bit_1 == '?' || bit_0 == '?') {
+ if (bit_3 != '?' || bit_2 != '?' || bit_1 != '?' || bit_0 != '?')
+ goto dump_bin;
+ hex_digits.push_back('?');
+ continue;
+ }
int val = 8*(bit_3 - '0') + 4*(bit_2 - '0') + 2*(bit_1 - '0') + (bit_0 - '0');
hex_digits.push_back(val < 10 ? '0' + val : 'a' + val - 10);
}
@@ -266,11 +273,11 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
for (int i = offset+width-1; i >= offset; i--) {
log_assert(i < (int)data.bits.size());
switch (data.bits[i]) {
- case RTLIL::S0: f << stringf("0"); break;
- case RTLIL::S1: f << stringf("1"); break;
+ case State::S0: f << stringf("0"); break;
+ case State::S1: f << stringf("1"); break;
case RTLIL::Sx: f << stringf("x"); break;
case RTLIL::Sz: f << stringf("z"); break;
- case RTLIL::Sa: f << stringf("z"); break;
+ case RTLIL::Sa: f << stringf("?"); break;
case RTLIL::Sm: log_error("Found marker state in final netlist.");
}
}
@@ -364,20 +371,22 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
}
}
-void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false)
+void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false, bool as_comment = false)
{
if (noattr)
return;
+ if (attr2comment)
+ as_comment = true;
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
- f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
+ f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str());
f << stringf(" = ");
- if (modattr && (it->second == Const(0, 1) || it->second == Const(0)))
+ if (modattr && (it->second == State::S0 || it->second == Const(0)))
f << stringf(" 0 ");
- else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
+ else if (modattr && (it->second == State::S1 || it->second == Const(1)))
f << stringf(" 1 ");
else
- dump_const(f, it->second, -1, 0, false, attr2comment);
- f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
+ dump_const(f, it->second, -1, 0, false, as_comment);
+ f << stringf(" %s%c", as_comment ? "*/" : "*)", term);
}
}
@@ -549,6 +558,20 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
+ if (cell->type == "$_NMUX_") {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = !(");
+ dump_cell_expr_port(f, cell, "S", false);
+ f << stringf(" ? ");
+ dump_attributes(f, "", cell->attributes, ' ');
+ dump_cell_expr_port(f, cell, "B", false);
+ f << stringf(" : ");
+ dump_cell_expr_port(f, cell, "A", false);
+ f << stringf(");\n");
+ return true;
+ }
+
if (cell->type.in("$_AOI3_", "$_OAI3_")) {
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort("\\Y"));
@@ -581,7 +604,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
- if (cell->type.substr(0, 6) == "$_DFF_")
+ if (cell->type.begins_with("$_DFF_"))
{
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
@@ -622,7 +645,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
- if (cell->type.substr(0, 8) == "$_DFFSR_")
+ if (cell->type.begins_with("$_DFFSR_"))
{
char pol_c = cell->type[8], pol_s = cell->type[9], pol_r = cell->type[10];
@@ -780,7 +803,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
- if (cell->type == "$pmux" || cell->type == "$pmux_safe")
+ if (cell->type == "$pmux")
{
int width = cell->parameters["\\WIDTH"].as_int();
int s_width = cell->getPort("\\S").size();
@@ -792,18 +815,17 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
dump_attributes(f, indent + " ", cell->attributes);
- if (cell->type != "$pmux_safe" && !noattr)
+ if (!noattr)
f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
f << stringf("%s" " casez (s)", indent.c_str());
- if (cell->type != "$pmux_safe")
- f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
+ f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
for (int i = 0; i < s_width; i++)
{
f << stringf("%s" " %d'b", indent.c_str(), s_width);
for (int j = s_width-1; j >= 0; j--)
- f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
+ f << stringf("%c", j == i ? '1' : '?');
f << stringf(":\n");
f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
@@ -927,7 +949,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
- if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
+ if (cell->type.in("$dff", "$adff", "$dffe"))
{
RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
bool pol_clk, pol_arst = false, pol_en = false;
@@ -1492,12 +1514,14 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
return;
}
+ dump_attributes(f, indent, sw->attributes);
f << stringf("%s" "casez (", indent.c_str());
dump_sigspec(f, sw->signal);
f << stringf(")\n");
bool got_default = false;
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
+ dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*as_comment=*/true);
if ((*it)->compare.size() == 0) {
if (got_default)
continue;
@@ -1662,7 +1686,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
}
}
- dump_attributes(f, indent, module->attributes, '\n', true);
+ dump_attributes(f, indent, module->attributes, '\n', /*attr2comment=*/true);
f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
bool keep_running = true;
for (int port_id = 1; keep_running; port_id++) {
diff --git a/examples/mimas2/README b/examples/mimas2/README
new file mode 100644
index 000000000..b12875cbc
--- /dev/null
+++ b/examples/mimas2/README
@@ -0,0 +1,8 @@
+A simple example design, based on the Numato Labs Mimas V2 board
+================================================================
+
+This example uses Yosys for synthesis and Xilinx ISE
+for place&route and bit-stream creation.
+
+To synthesize:
+ bash run.sh
diff --git a/examples/mimas2/example.ucf b/examples/mimas2/example.ucf
new file mode 100644
index 000000000..4e31b74ab
--- /dev/null
+++ b/examples/mimas2/example.ucf
@@ -0,0 +1,13 @@
+CONFIG VCCAUX = "3.3" ;
+
+
+NET "CLK" LOC = D9 | IOSTANDARD = LVCMOS33 | PERIOD = 12MHz ;
+
+NET "LED[7]" LOC = P15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[6]" LOC = P16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[5]" LOC = N15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[4]" LOC = N16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[3]" LOC = U17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[2]" LOC = U18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[1]" LOC = T17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[0]" LOC = T18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
diff --git a/examples/mimas2/example.v b/examples/mimas2/example.v
new file mode 100644
index 000000000..2a9117393
--- /dev/null
+++ b/examples/mimas2/example.v
@@ -0,0 +1,14 @@
+module example(
+ input wire CLK,
+ output wire [7:0] LED
+);
+
+reg [27:0] ctr;
+initial ctr = 0;
+
+always @(posedge CLK)
+ ctr <= ctr + 1;
+
+assign LED = ctr[27:20];
+
+endmodule
diff --git a/examples/mimas2/run.sh b/examples/mimas2/run.sh
new file mode 100644
index 000000000..aafde78ed
--- /dev/null
+++ b/examples/mimas2/run.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+set -e
+yosys run_yosys.ys
+edif2ngd example.edif
+ngdbuild example -uc example.ucf -p xc6slx9csg324-3
+map -w example
+par -w example.ncd example_par.ncd
+bitgen -w example_par.ncd -g StartupClk:JTAGClk
diff --git a/examples/mimas2/run_yosys.ys b/examples/mimas2/run_yosys.ys
new file mode 100644
index 000000000..b3204b1ca
--- /dev/null
+++ b/examples/mimas2/run_yosys.ys
@@ -0,0 +1,4 @@
+read_verilog example.v
+synth_xilinx -top example -family xc6s
+iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I
+write_edif -pvector bra example.edif
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index 68552fd06..06522939f 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -2,7 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Eddie Hung <eddie@fpgeh.com>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -22,19 +22,191 @@
// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
-#ifndef _WIN32
-#include <libgen.h>
+// https://stackoverflow.com/a/46137633
+#ifdef _MSC_VER
+#include <stdlib.h>
+#define __builtin_bswap32 _byteswap_ulong
+#elif defined(__APPLE__)
+#include <libkern/OSByteOrder.h>
+#define __builtin_bswap32 OSSwapInt32
#endif
-#include <array>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
#include "aigerparse.h"
YOSYS_NAMESPACE_BEGIN
-AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
- : design(design), f(f), clk_name(clk_name)
+inline int32_t from_big_endian(int32_t i32) {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ return __builtin_bswap32(i32);
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ return i32;
+#else
+#error "Unknown endianness"
+#endif
+}
+
+#define log_debug2(...) ;
+//#define log_debug2(...) log_debug(__VA_ARGS__)
+
+struct ConstEvalAig
+{
+ RTLIL::Module *module;
+ dict<RTLIL::SigBit, RTLIL::State> values_map;
+ dict<RTLIL::SigBit, RTLIL::Cell*> sig2driver;
+ dict<SigBit, pool<RTLIL::SigBit>> sig2deps;
+
+ ConstEvalAig(RTLIL::Module *module) : module(module)
+ {
+ for (auto &it : module->cells_) {
+ if (!yosys_celltypes.cell_known(it.second->type))
+ continue;
+ for (auto &it2 : it.second->connections())
+ if (yosys_celltypes.cell_output(it.second->type, it2.first)) {
+ auto r YS_ATTRIBUTE(unused) = sig2driver.insert(std::make_pair(it2.second, it.second));
+ log_assert(r.second);
+ }
+ }
+ }
+
+ void clear()
+ {
+ values_map.clear();
+ sig2deps.clear();
+ }
+
+ void set(RTLIL::SigBit sig, RTLIL::State value)
+ {
+ auto it = values_map.find(sig);
+#ifndef NDEBUG
+ if (it != values_map.end()) {
+ RTLIL::State current_val = it->second;
+ log_assert(current_val == value);
+ }
+#endif
+ if (it != values_map.end())
+ it->second = value;
+ else
+ values_map[sig] = value;
+ }
+
+ void set_incremental(RTLIL::SigSpec sig, RTLIL::Const value)
+ {
+ log_assert(GetSize(sig) == GetSize(value));
+
+ for (int i = 0; i < GetSize(sig); i++) {
+ auto it = values_map.find(sig[i]);
+ if (it != values_map.end()) {
+ RTLIL::State current_val = it->second;
+ if (current_val != value[i])
+ for (auto dep : sig2deps[sig[i]])
+ values_map.erase(dep);
+ it->second = value[i];
+ }
+ else
+ values_map[sig[i]] = value[i];
+ }
+ }
+
+ void compute_deps(RTLIL::SigBit output, const pool<RTLIL::SigBit> &inputs)
+ {
+ sig2deps[output].insert(output);
+
+ RTLIL::Cell *cell = sig2driver.at(output);
+ RTLIL::SigBit sig_a = cell->getPort("\\A");
+ sig2deps[sig_a].reserve(sig2deps[sig_a].size() + sig2deps[output].size()); // Reserve so that any invalidation
+ // that may occur does so here, and
+ // not mid insertion (below)
+ sig2deps[sig_a].insert(sig2deps[output].begin(), sig2deps[output].end());
+ if (!inputs.count(sig_a))
+ compute_deps(sig_a, inputs);
+
+ if (cell->type == "$_AND_") {
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ sig2deps[sig_b].reserve(sig2deps[sig_b].size() + sig2deps[output].size()); // Reserve so that any invalidation
+ // that may occur does so here, and
+ // not mid insertion (below)
+ sig2deps[sig_b].insert(sig2deps[output].begin(), sig2deps[output].end());
+
+ if (!inputs.count(sig_b))
+ compute_deps(sig_b, inputs);
+ }
+ else if (cell->type == "$_NOT_") {
+ }
+ else log_abort();
+ }
+
+ bool eval(RTLIL::Cell *cell)
+ {
+ RTLIL::SigBit sig_y = cell->getPort("\\Y");
+ if (values_map.count(sig_y))
+ return true;
+
+ RTLIL::SigBit sig_a = cell->getPort("\\A");
+ if (!eval(sig_a))
+ return false;
+
+ RTLIL::State eval_ret = RTLIL::Sx;
+ if (cell->type == "$_NOT_") {
+ if (sig_a == State::S0) eval_ret = State::S1;
+ else if (sig_a == State::S1) eval_ret = State::S0;
+ }
+ else if (cell->type == "$_AND_") {
+ if (sig_a == State::S0) {
+ eval_ret = State::S0;
+ goto eval_end;
+ }
+
+ {
+ RTLIL::SigBit sig_b = cell->getPort("\\B");
+ if (!eval(sig_b))
+ return false;
+ if (sig_b == State::S0) {
+ eval_ret = State::S0;
+ goto eval_end;
+ }
+
+ if (sig_a != State::S1 || sig_b != State::S1)
+ goto eval_end;
+
+ eval_ret = State::S1;
+ }
+ }
+ else log_abort();
+
+eval_end:
+ set(sig_y, eval_ret);
+ return true;
+ }
+
+ bool eval(RTLIL::SigBit &sig)
+ {
+ auto it = values_map.find(sig);
+ if (it != values_map.end()) {
+ sig = it->second;
+ return true;
+ }
+
+ RTLIL::Cell *cell = sig2driver.at(sig);
+ if (!eval(cell))
+ return false;
+
+ it = values_map.find(sig);
+ if (it != values_map.end()) {
+ sig = it->second;
+ return true;
+ }
+
+ return false;
+ }
+};
+
+AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports)
+ : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports)
{
module = new RTLIL::Module;
module->name = module_name;
@@ -73,6 +245,8 @@ end_of_header:
log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
line_count = 1;
+ piNum = 0;
+ flopNum = 0;
if (header == "aag")
parse_aiger_ascii();
@@ -81,20 +255,9 @@ end_of_header:
else
log_abort();
- RTLIL::Wire* n0 = module->wire("\\n0");
+ RTLIL::Wire* n0 = module->wire("\\__0__");
if (n0)
- module->connect(n0, RTLIL::S0);
-
- for (unsigned i = 0; i < outputs.size(); ++i) {
- RTLIL::Wire *wire = outputs[i];
- if (wire->port_input) {
- RTLIL::Wire *o_wire = module->addWire(wire->name.str() + "_o");
- o_wire->port_output = true;
- wire->port_output = false;
- module->connect(o_wire, wire);
- outputs[i] = o_wire;
- }
- }
+ module->connect(n0, State::S0);
// Parse footer (symbol table, comments, etc.)
unsigned l1;
@@ -131,36 +294,188 @@ end_of_header:
std::getline(f, line); // Ignore up to start of next line
}
- module->fixup_ports();
- design->add(module);
+ post_process();
+}
+
+static uint32_t parse_xaiger_literal(std::istream &f)
+{
+ uint32_t l;
+ f.read(reinterpret_cast<char*>(&l), sizeof(l));
+ if (f.gcount() != sizeof(l))
+#if defined(_WIN32) && defined(__MINGW32__)
+ log_error("Offset %I64d: unable to read literal!\n", static_cast<int64_t>(f.tellg()));
+#else
+ log_error("Offset %" PRId64 ": unable to read literal!\n", static_cast<int64_t>(f.tellg()));
+#endif
+ return from_big_endian(l);
}
static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
{
const unsigned variable = literal >> 1;
const bool invert = literal & 1;
- RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix?
+ RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : ""));
RTLIL::Wire *wire = module->wire(wire_name);
if (wire) return wire;
- log_debug("Creating %s\n", wire_name.c_str());
+ log_debug2("Creating %s\n", wire_name.c_str());
wire = module->addWire(wire_name);
+ wire->port_input = wire->port_output = false;
if (!invert) return wire;
- RTLIL::IdString wire_inv_name(stringf("\\n%d", variable));
+ RTLIL::IdString wire_inv_name(stringf("\\__%d__", variable));
RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
if (wire_inv) {
if (module->cell(wire_inv_name)) return wire;
}
else {
- log_debug("Creating %s\n", wire_inv_name.c_str());
+ log_debug2("Creating %s\n", wire_inv_name.c_str());
wire_inv = module->addWire(wire_inv_name);
+ wire_inv->port_input = wire_inv->port_output = false;
}
- log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
- module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix?
+ log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
+ module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire);
return wire;
}
+void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
+{
+ std::string header;
+ f >> header;
+ if (header != "aag" && header != "aig")
+ log_error("Unsupported AIGER file!\n");
+
+ // Parse rest of header
+ if (!(f >> M >> I >> L >> O >> A))
+ log_error("Invalid AIGER header\n");
+
+ // Optional values
+ B = C = J = F = 0;
+
+ std::string line;
+ std::getline(f, line); // Ignore up to start of next line, as standard
+ // says anything that follows could be used for
+ // optional sections
+
+ log_debug("M=%u I=%u L=%u O=%u A=%u\n", M, I, L, O, A);
+
+ line_count = 1;
+ piNum = 0;
+ flopNum = 0;
+
+ if (header == "aag")
+ parse_aiger_ascii();
+ else if (header == "aig")
+ parse_aiger_binary();
+ else
+ log_abort();
+
+ RTLIL::Wire* n0 = module->wire("\\__0__");
+ if (n0)
+ module->connect(n0, State::S0);
+
+ // Parse footer (symbol table, comments, etc.)
+ std::string s;
+ bool comment_seen = false;
+ for (int c = f.peek(); c != EOF; c = f.peek()) {
+ if (comment_seen || c == 'c') {
+ if (!comment_seen) {
+ f.ignore(1);
+ c = f.peek();
+ comment_seen = true;
+ }
+ if (c == '\n')
+ break;
+ f.ignore(1);
+ // XAIGER extensions
+ if (c == 'm') {
+ uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+ uint32_t lutNum = parse_xaiger_literal(f);
+ uint32_t lutSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+ log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize);
+ ConstEvalAig ce(module);
+ for (unsigned i = 0; i < lutNum; ++i) {
+ uint32_t rootNodeID = parse_xaiger_literal(f);
+ uint32_t cutLeavesM = parse_xaiger_literal(f);
+ log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM);
+ RTLIL::Wire *output_sig = module->wire(stringf("\\__%d__", rootNodeID));
+ uint32_t nodeID;
+ RTLIL::SigSpec input_sig;
+ for (unsigned j = 0; j < cutLeavesM; ++j) {
+ nodeID = parse_xaiger_literal(f);
+ log_debug2("\t%u\n", nodeID);
+ RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID));
+ log_assert(wire);
+ input_sig.append(wire);
+ }
+ // TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size())
+ ce.clear();
+ ce.compute_deps(output_sig, input_sig.to_sigbit_pool());
+ RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size());
+ for (int j = 0; j < (1 << cutLeavesM); ++j) {
+ int gray = j ^ (j >> 1);
+ ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast<int>(cutLeavesM)});
+ RTLIL::SigBit o(output_sig);
+ bool success YS_ATTRIBUTE(unused) = ce.eval(o);
+ log_assert(success);
+ log_assert(o.wire == nullptr);
+ lut_mask[gray] = o.data;
+ }
+ RTLIL::Cell *output_cell = module->cell(stringf("\\__%d__$and", rootNodeID));
+ log_assert(output_cell);
+ module->remove(output_cell);
+ module->addLut(stringf("\\__%d__$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask));
+ }
+ }
+ else if (c == 'r') {
+ uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+ flopNum = parse_xaiger_literal(f);
+ log_assert(dataSize == (flopNum+1) * sizeof(uint32_t));
+ f.ignore(flopNum * sizeof(uint32_t));
+ }
+ else if (c == 'n') {
+ parse_xaiger_literal(f);
+ f >> s;
+ log_debug("n: '%s'\n", s.c_str());
+ }
+ else if (c == 'h') {
+ f.ignore(sizeof(uint32_t));
+ uint32_t version YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+ log_assert(version == 1);
+ uint32_t ciNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+ log_debug("ciNum = %u\n", ciNum);
+ uint32_t coNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+ log_debug("coNum = %u\n", coNum);
+ piNum = parse_xaiger_literal(f);
+ log_debug("piNum = %u\n", piNum);
+ uint32_t poNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+ log_debug("poNum = %u\n", poNum);
+ uint32_t boxNum = parse_xaiger_literal(f);
+ log_debug("boxNum = %u\n", boxNum);
+ for (unsigned i = 0; i < boxNum; i++) {
+ f.ignore(2*sizeof(uint32_t));
+ uint32_t boxUniqueId = parse_xaiger_literal(f);
+ log_assert(boxUniqueId > 0);
+ uint32_t oldBoxNum = parse_xaiger_literal(f);
+ RTLIL::Cell* cell = module->addCell(stringf("$__box%u__", oldBoxNum), box_lookup.at(boxUniqueId));
+ boxes.emplace_back(cell);
+ }
+ }
+ else if (c == 'a' || c == 'i' || c == 'o') {
+ uint32_t dataSize = parse_xaiger_literal(f);
+ f.ignore(dataSize);
+ }
+ else {
+ break;
+ }
+ }
+ else
+ log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
+ }
+
+ post_process();
+}
+
void AigerReader::parse_aiger_ascii()
{
std::string line;
@@ -172,8 +487,8 @@ void AigerReader::parse_aiger_ascii()
for (unsigned i = 1; i <= I; ++i, ++line_count) {
if (!(f >> l1))
log_error("Line %u cannot be interpreted as an input!\n", line_count);
- log_debug("%d is an input\n", l1);
- log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted?
+ log_debug2("%d is an input\n", l1);
+ log_assert(!(l1 & 1)); // Inputs can't be inverted
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_input = true;
inputs.push_back(wire);
@@ -182,17 +497,19 @@ void AigerReader::parse_aiger_ascii()
// Parse latches
RTLIL::Wire *clk_wire = nullptr;
if (L > 0) {
+ log_assert(clk_name != "");
clk_wire = module->wire(clk_name);
log_assert(!clk_wire);
- log_debug("Creating %s\n", clk_name.c_str());
+ log_debug2("Creating %s\n", clk_name.c_str());
clk_wire = module->addWire(clk_name);
clk_wire->port_input = true;
+ clk_wire->port_output = false;
}
for (unsigned i = 0; i < L; ++i, ++line_count) {
if (!(f >> l1 >> l2))
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
- log_debug("%d %d is a latch\n", l1, l2);
- log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted?
+ log_debug2("%d %d is a latch\n", l1, l2);
+ log_assert(!(l1 & 1));
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
@@ -204,18 +521,18 @@ void AigerReader::parse_aiger_ascii()
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
if (l3 == 0)
- q_wire->attributes["\\init"] = RTLIL::S0;
+ q_wire->attributes["\\init"] = State::S0;
else if (l3 == 1)
- q_wire->attributes["\\init"] = RTLIL::S1;
+ q_wire->attributes["\\init"] = State::S1;
else if (l3 == l1) {
- //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
+ //q_wire->attributes["\\init"] = RTLIL::Sx;
}
else
log_error("Line %u has invalid reset literal for latch!\n", line_count);
}
else {
// AIGER latches are assumed to be initialized to zero
- q_wire->attributes["\\init"] = RTLIL::S0;
+ q_wire->attributes["\\init"] = State::S0;
}
latches.push_back(q_wire);
}
@@ -225,8 +542,18 @@ void AigerReader::parse_aiger_ascii()
if (!(f >> l1))
log_error("Line %u cannot be interpreted as an output!\n", line_count);
- log_debug("%d is an output\n", l1);
- RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+ log_debug2("%d is an output\n", l1);
+ const unsigned variable = l1 >> 1;
+ const bool invert = l1 & 1;
+ RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
+ RTLIL::Wire *wire = module->wire(wire_name);
+ if (!wire)
+ wire = createWireIfNotExists(module, l1);
+ else if (wire->port_input || wire->port_output) {
+ RTLIL::Wire *new_wire = module->addWire(NEW_ID);
+ module->connect(new_wire, wire);
+ wire = new_wire;
+ }
wire->port_output = true;
outputs.push_back(wire);
}
@@ -236,7 +563,7 @@ void AigerReader::parse_aiger_ascii()
if (!(f >> l1))
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
- log_debug("%d is a bad state property\n", l1);
+ log_debug2("%d is a bad state property\n", l1);
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_output = true;
bad_properties.push_back(wire);
@@ -259,12 +586,12 @@ void AigerReader::parse_aiger_ascii()
if (!(f >> l1 >> l2 >> l3))
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
- log_debug("%d %d %d is an AND\n", l1, l2, l3);
- log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
+ log_debug2("%d %d %d is an AND\n", l1, l2, l3);
+ log_assert(!(l1 & 1));
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
- module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire);
+ module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire);
}
std::getline(f, line); // Ignore up to start of next line
}
@@ -285,19 +612,23 @@ void AigerReader::parse_aiger_binary()
// Parse inputs
for (unsigned i = 1; i <= I; ++i) {
+ log_debug2("%d is an input\n", i);
RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
wire->port_input = true;
+ log_assert(!wire->port_output);
inputs.push_back(wire);
}
// Parse latches
RTLIL::Wire *clk_wire = nullptr;
if (L > 0) {
+ log_assert(clk_name != "");
clk_wire = module->wire(clk_name);
log_assert(!clk_wire);
- log_debug("Creating %s\n", clk_name.c_str());
+ log_debug2("Creating %s\n", clk_name.c_str());
clk_wire = module->addWire(clk_name);
clk_wire->port_input = true;
+ clk_wire->port_output = false;
}
l1 = (I+1) * 2;
for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
@@ -315,18 +646,18 @@ void AigerReader::parse_aiger_binary()
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
if (l3 == 0)
- q_wire->attributes["\\init"] = RTLIL::S0;
+ q_wire->attributes["\\init"] = State::S0;
else if (l3 == 1)
- q_wire->attributes["\\init"] = RTLIL::S1;
+ q_wire->attributes["\\init"] = State::S1;
else if (l3 == l1) {
- //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
+ //q_wire->attributes["\\init"] = RTLIL::Sx;
}
else
log_error("Line %u has invalid reset literal for latch!\n", line_count);
}
else {
// AIGER latches are assumed to be initialized to zero
- q_wire->attributes["\\init"] = RTLIL::S0;
+ q_wire->attributes["\\init"] = State::S0;
}
latches.push_back(q_wire);
}
@@ -336,8 +667,18 @@ void AigerReader::parse_aiger_binary()
if (!(f >> l1))
log_error("Line %u cannot be interpreted as an output!\n", line_count);
- log_debug("%d is an output\n", l1);
- RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+ log_debug2("%d is an output\n", l1);
+ const unsigned variable = l1 >> 1;
+ const bool invert = l1 & 1;
+ RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix?
+ RTLIL::Wire *wire = module->wire(wire_name);
+ if (!wire)
+ wire = createWireIfNotExists(module, l1);
+ else if (wire->port_input || wire->port_output) {
+ RTLIL::Wire *new_wire = module->addWire(NEW_ID);
+ module->connect(new_wire, wire);
+ wire = new_wire;
+ }
wire->port_output = true;
outputs.push_back(wire);
}
@@ -348,7 +689,7 @@ void AigerReader::parse_aiger_binary()
if (!(f >> l1))
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
- log_debug("%d is a bad state property\n", l1);
+ log_debug2("%d is a bad state property\n", l1);
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_output = true;
bad_properties.push_back(wire);
@@ -374,16 +715,278 @@ void AigerReader::parse_aiger_binary()
l2 = parse_next_delta_literal(f, l1);
l3 = parse_next_delta_literal(f, l2);
- log_debug("%d %d %d is an AND\n", l1, l2, l3);
- log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
+ log_debug2("%d %d %d is an AND\n", l1, l2, l3);
+ log_assert(!(l1 & 1));
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
+ module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire);
+ }
+}
+
+void AigerReader::post_process()
+{
+ pool<IdString> seen_boxes;
+ unsigned ci_count = 0, co_count = 0;
+ for (auto cell : boxes) {
+ RTLIL::Module* box_module = design->module(cell->type);
+ log_assert(box_module);
+
+ if (seen_boxes.insert(cell->type).second) {
+ auto it = box_module->attributes.find("\\abc_carry");
+ if (it != box_module->attributes.end()) {
+ RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
+ auto carry_in_out = it->second.decode_string();
+ auto pos = carry_in_out.find(',');
+ if (pos == std::string::npos)
+ log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type));
+ auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos));
+ carry_in = box_module->wire(carry_in_name);
+ if (!carry_in || !carry_in->port_input)
+ log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str());
+
+ auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1));
+ carry_out = box_module->wire(carry_out_name);
+ if (!carry_out || !carry_out->port_output)
+ log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str());
- RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_");
- and_cell->setPort("\\A", i1_wire);
- and_cell->setPort("\\B", i2_wire);
- and_cell->setPort("\\Y", o_wire);
+ auto &ports = box_module->ports;
+ for (auto jt = ports.begin(); jt != ports.end(); ) {
+ RTLIL::Wire* w = box_module->wire(*jt);
+ log_assert(w);
+ if (w == carry_in || w == carry_out) {
+ jt = ports.erase(jt);
+ continue;
+ }
+ if (w->port_id > carry_in->port_id)
+ --w->port_id;
+ if (w->port_id > carry_out->port_id)
+ --w->port_id;
+ log_assert(w->port_input || w->port_output);
+ log_assert(ports[w->port_id-1] == w->name);
+ ++jt;
+ }
+ ports.push_back(carry_in->name);
+ carry_in->port_id = ports.size();
+ ports.push_back(carry_out->name);
+ carry_out->port_id = ports.size();
+ }
+ }
+
+ // NB: Assume box_module->ports are sorted alphabetically
+ // (as RTLIL::Module::fixup_ports() would do)
+ for (auto port_name : box_module->ports) {
+ RTLIL::Wire* w = box_module->wire(port_name);
+ log_assert(w);
+ RTLIL::SigSpec rhs;
+ RTLIL::Wire* wire = nullptr;
+ for (int i = 0; i < GetSize(w); i++) {
+ if (w->port_input) {
+ log_assert(co_count < outputs.size());
+ wire = outputs[co_count++];
+ log_assert(wire);
+ log_assert(wire->port_output);
+ wire->port_output = false;
+ }
+ if (w->port_output) {
+ log_assert((piNum + ci_count) < inputs.size());
+ wire = inputs[piNum + ci_count++];
+ log_assert(wire);
+ log_assert(wire->port_input);
+ wire->port_input = false;
+ }
+ rhs.append(wire);
+ }
+ cell->setPort(port_name, rhs);
+ }
+ }
+
+ dict<RTLIL::IdString, int> wideports_cache;
+
+ if (!map_filename.empty()) {
+ std::ifstream mf(map_filename);
+ std::string type, symbol;
+ int variable, index;
+ while (mf >> type >> variable >> index >> symbol) {
+ RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
+ if (type == "input") {
+ log_assert(static_cast<unsigned>(variable) < inputs.size());
+ RTLIL::Wire* wire = inputs[variable];
+ log_assert(wire);
+ log_assert(wire->port_input);
+
+ if (index == 0) {
+ // Cope with the fact that a CI might be identical
+ // to a PI (necessary due to ABC); in those cases
+ // simply connect the latter to the former
+ RTLIL::Wire* existing = module->wire(escaped_s);
+ if (!existing)
+ module->rename(wire, escaped_s);
+ else {
+ wire->port_input = false;
+ module->connect(wire, existing);
+ }
+ }
+ else if (index > 0) {
+ std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
+ RTLIL::Wire* existing = module->wire(indexed_name);
+ if (!existing) {
+ module->rename(wire, indexed_name);
+ if (wideports)
+ wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
+ }
+ else {
+ module->connect(wire, existing);
+ wire->port_input = false;
+ }
+ }
+ }
+ else if (type == "output") {
+ log_assert(static_cast<unsigned>(variable + co_count) < outputs.size());
+ RTLIL::Wire* wire = outputs[variable + co_count];
+ log_assert(wire);
+ log_assert(wire->port_output);
+ if (escaped_s == "$__dummy__") {
+ wire->port_output = false;
+ continue;
+ }
+
+ if (index == 0) {
+ // Cope with the fact that a CO might be identical
+ // to a PO (necessary due to ABC); in those cases
+ // simply connect the latter to the former
+ RTLIL::Wire* existing = module->wire(escaped_s);
+ if (!existing) {
+ if (escaped_s.ends_with("$inout.out")) {
+ wire->port_output = false;
+ RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10));
+ log_assert(in_wire);
+ log_assert(in_wire->port_input && !in_wire->port_output);
+ in_wire->port_output = true;
+ module->connect(in_wire, wire);
+ }
+ else
+ module->rename(wire, escaped_s);
+ }
+ else {
+ wire->port_output = false;
+ module->connect(wire, existing);
+ }
+ }
+ else if (index > 0) {
+ std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
+ RTLIL::Wire* existing = module->wire(indexed_name);
+ if (!existing) {
+ if (escaped_s.ends_with("$inout.out")) {
+ wire->port_output = false;
+ RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index));
+ log_assert(in_wire);
+ log_assert(in_wire->port_input && !in_wire->port_output);
+ in_wire->port_output = true;
+ module->connect(in_wire, wire);
+ }
+ else {
+ module->rename(wire, indexed_name);
+ if (wideports)
+ wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
+ }
+ }
+ else {
+ module->connect(wire, existing);
+ wire->port_output = false;
+ }
+ }
+ }
+ else if (type == "box") {
+ RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable));
+ if (cell) { // ABC could have optimised this box away
+ module->rename(cell, escaped_s);
+ for (const auto &i : cell->connections()) {
+ RTLIL::IdString port_name = i.first;
+ RTLIL::SigSpec rhs = i.second;
+ int index = 0;
+ for (auto bit : rhs.bits()) {
+ RTLIL::Wire* wire = bit.wire;
+ RTLIL::IdString escaped_s = RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name)));
+ if (index == 0)
+ module->rename(wire, escaped_s);
+ else if (index > 0) {
+ module->rename(wire, stringf("%s[%d]", escaped_s.c_str(), index));
+ if (wideports)
+ wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
+ }
+ index++;
+ }
+ }
+ }
+ }
+ else
+ log_error("Symbol type '%s' not recognised.\n", type.c_str());
+ }
+ }
+
+ for (auto &wp : wideports_cache) {
+ auto name = wp.first;
+ int width = wp.second + 1;
+
+ RTLIL::Wire *wire = module->wire(name);
+ if (wire)
+ module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0)));
+
+ // Do not make ports with a mix of input/output into
+ // wide ports
+ bool port_input = false, port_output = false;
+ for (int i = 0; i < width; i++) {
+ RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
+ RTLIL::Wire *other_wire = module->wire(other_name);
+ if (other_wire) {
+ port_input = port_input || other_wire->port_input;
+ port_output = port_output || other_wire->port_output;
+ }
+ }
+
+ wire = module->addWire(name, width);
+ wire->port_input = port_input;
+ wire->port_output = port_output;
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
+ RTLIL::Wire *other_wire = module->wire(other_name);
+ if (other_wire) {
+ other_wire->port_input = false;
+ other_wire->port_output = false;
+ }
+ if (wire->port_input) {
+ if (other_wire)
+ module->connect(other_wire, SigSpec(wire, i));
+ }
+ else {
+ // Since we skip POs that are connected to Sx,
+ // re-connect them here
+ module->connect(SigSpec(wire, i), other_wire ? other_wire : SigSpec(RTLIL::Sx));
+ }
+ }
+ }
+
+ module->fixup_ports();
+
+ // Insert into a new (temporary) design so that "clean" will only
+ // operate (and run checks on) this one module
+ RTLIL::Design *mapped_design = new RTLIL::Design;
+ mapped_design->add(module);
+ Pass::call(mapped_design, "clean");
+ mapped_design->modules_.erase(module->name);
+ delete mapped_design;
+
+ design->add(module);
+
+ for (auto cell : module->cells().to_vector()) {
+ if (cell->type != "$lut") continue;
+ auto y_port = cell->getPort("\\Y").as_bit();
+ if (y_port.wire->width == 1)
+ module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str()));
+ else
+ module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset));
}
}
@@ -398,18 +1001,19 @@ struct AigerFrontend : public Frontend {
log("Load module from an AIGER file into the current design.\n");
log("\n");
log(" -module_name <module_name>\n");
- log(" Name of module to be created (default: "
-#ifdef _WIN32
- "top" // FIXME
-#else
- "<filename>"
-#endif
- ")\n");
+ log(" Name of module to be created (default: <filename>)\n");
log("\n");
log(" -clk_name <wire_name>\n");
log(" AIGER latches to be transformed into posedge DFFs clocked by wire of");
log(" this name (default: clk)\n");
log("\n");
+ log(" -map <filename>\n");
+ log(" read file with port and latch symbols\n");
+ log("\n");
+ log(" -wideports\n");
+ log(" Merge ports that match the pattern 'name[int]' into a single\n");
+ log(" multi-bit port 'name'.\n");
+ log("\n");
}
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -417,6 +1021,8 @@ struct AigerFrontend : public Frontend {
RTLIL::IdString clk_name = "\\clk";
RTLIL::IdString module_name;
+ std::string map_filename;
+ bool wideports = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -429,13 +1035,23 @@ struct AigerFrontend : public Frontend {
clk_name = RTLIL::escape_id(args[++argidx]);
continue;
}
+ if (map_filename.empty() && arg == "-map" && argidx+1 < args.size()) {
+ map_filename = args[++argidx];
+ continue;
+ }
+ if (arg == "-wideports") {
+ wideports = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
if (module_name.empty()) {
#ifdef _WIN32
- module_name = "top"; // FIXME: basename equivalent on Win32?
+ char fname[_MAX_FNAME];
+ _splitpath(filename.c_str(), NULL /* drive */, NULL /* dir */, fname, NULL /* ext */);
+ module_name = fname;
#else
char* bn = strdup(filename.c_str());
module_name = RTLIL::escape_id(bn);
@@ -443,7 +1059,7 @@ struct AigerFrontend : public Frontend {
#endif
}
- AigerReader reader(design, *f, module_name, clk_name);
+ AigerReader reader(design, *f, module_name, clk_name, map_filename, wideports);
reader.parse_aiger();
}
} AigerFrontend;
diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h
index 0e3719cc4..583c9d0f9 100644
--- a/frontends/aiger/aigerparse.h
+++ b/frontends/aiger/aigerparse.h
@@ -2,7 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Eddie Hung <eddie@fpgeh.com>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -31,20 +31,26 @@ struct AigerReader
std::istream &f;
RTLIL::IdString clk_name;
RTLIL::Module *module;
+ std::string map_filename;
+ bool wideports;
unsigned M, I, L, O, A;
unsigned B, C, J, F; // Optional in AIGER 1.9
unsigned line_count;
+ uint32_t piNum, flopNum;
std::vector<RTLIL::Wire*> inputs;
std::vector<RTLIL::Wire*> latches;
std::vector<RTLIL::Wire*> outputs;
std::vector<RTLIL::Wire*> bad_properties;
+ std::vector<RTLIL::Cell*> boxes;
- AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name);
+ AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports);
void parse_aiger();
+ void parse_xaiger(const dict<int,IdString> &box_lookup);
void parse_aiger_ascii();
void parse_aiger_binary();
+ void post_process();
};
YOSYS_NAMESPACE_END
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 3d066af53..82283fb5b 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -283,8 +283,8 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
if (!bits.empty()) {
fprintf(f, " bits='");
for (size_t i = bits.size(); i > 0; i--)
- fprintf(f, "%c", bits[i-1] == RTLIL::S0 ? '0' :
- bits[i-1] == RTLIL::S1 ? '1' :
+ fprintf(f, "%c", bits[i-1] == State::S0 ? '0' :
+ bits[i-1] == State::S1 ? '1' :
bits[i-1] == RTLIL::Sx ? 'x' :
bits[i-1] == RTLIL::Sz ? 'z' : '?');
fprintf(f, "'(%d)", GetSize(bits));
@@ -716,7 +716,7 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width)
node->integer = v;
node->is_signed = is_signed;
for (int i = 0; i < width; i++) {
- node->bits.push_back((v & 1) ? RTLIL::S1 : RTLIL::S0);
+ node->bits.push_back((v & 1) ? State::S1 : State::S0);
v = v >> 1;
}
node->range_valid = true;
@@ -733,9 +733,9 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
node->bits = v;
for (size_t i = 0; i < 32; i++) {
if (i < node->bits.size())
- node->integer |= (node->bits[i] == RTLIL::S1) << i;
+ node->integer |= (node->bits[i] == State::S1) << i;
else if (is_signed && !node->bits.empty())
- node->integer |= (node->bits.back() == RTLIL::S1) << i;
+ node->integer |= (node->bits.back() == State::S1) << i;
}
node->range_valid = true;
node->range_left = node->bits.size()-1;
@@ -767,7 +767,7 @@ AstNode *AstNode::mkconst_str(const std::string &str)
for (size_t i = 0; i < str.size(); i++) {
unsigned char ch = str[str.size() - i - 1];
for (int j = 0; j < 8; j++) {
- data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0);
+ data.push_back((ch & 1) ? State::S1 : State::S0);
ch = ch >> 1;
}
}
@@ -780,7 +780,7 @@ AstNode *AstNode::mkconst_str(const std::string &str)
bool AstNode::bits_only_01() const
{
for (auto bit : bits)
- if (bit != RTLIL::S0 && bit != RTLIL::S1)
+ if (bit != State::S0 && bit != State::S1)
return false;
return true;
}
@@ -1164,7 +1164,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
}
}
- if (flag_icells && (*it)->str.substr(0, 2) == "\\$")
+ if (flag_icells && (*it)->str.compare(0, 2, "\\$") == 0)
(*it)->str = (*it)->str.substr(1);
if (defer)
@@ -1172,7 +1172,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
if (design->has((*it)->str)) {
RTLIL::Module *existing_mod = design->module((*it)->str);
- if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
+ if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) {
log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", (*it)->str.c_str());
} else if (nooverwrite) {
log("Ignoring re-definition of module `%s' at %s:%d.\n",
@@ -1463,7 +1463,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
{
std::string stripped_name = name.str();
- if (stripped_name.substr(0, 9) == "$abstract")
+ if (stripped_name.compare(0, 9, "$abstract") == 0)
stripped_name = stripped_name.substr(9);
log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
@@ -1502,7 +1502,10 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
rewrite_parameter:
para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
delete child->children.at(0);
- if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0)
+ if ((parameters[para_id].flags & RTLIL::CONST_FLAG_REAL) != 0) {
+ child->children[0] = new AstNode(AST_REALVALUE);
+ child->children[0]->realvalue = std::stod(parameters[para_id].decode_string());
+ } else if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0)
child->children[0] = AstNode::mkconst_str(parameters[para_id].decode_string());
else
child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0);
@@ -1551,7 +1554,9 @@ RTLIL::Module *AstModule::clone() const
new_mod->nomeminit = nomeminit;
new_mod->nomem2reg = nomem2reg;
new_mod->mem2reg = mem2reg;
+ new_mod->noblackbox = noblackbox;
new_mod->lib = lib;
+ new_mod->nowb = nowb;
new_mod->noopt = noopt;
new_mod->icells = icells;
new_mod->pwires = pwires;
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 079fc11e5..407a34472 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -504,6 +504,7 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::CaseRule *backup_case = current_case;
current_case = new RTLIL::CaseRule;
+ current_case->attributes["\\src"] = stringf("%s:%d", child->filename.c_str(), child->linenum);
last_generated_case = current_case;
addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
for (auto node : child->children) {
@@ -1515,7 +1516,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
AstNode *child = *it;
if (child->type == AST_CELLTYPE) {
cell->type = child->str;
- if (flag_icells && cell->type.substr(0, 2) == "\\$")
+ if (flag_icells && cell->type.begins_with("\\$"))
cell->type = cell->type.substr(1);
continue;
}
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index e947125bf..86dd80c65 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -150,6 +150,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
reg->str = stringf("%s[%d]", node->str.c_str(), i);
reg->is_reg = true;
reg->is_signed = node->is_signed;
+ for (auto &it : node->attributes)
+ if (it.first != ID(mem2reg))
+ reg->attributes.emplace(it.first, it.second->clone());
+ reg->filename = node->filename;
+ reg->linenum = node->linenum;
children.push_back(reg);
while (reg->simplify(true, false, false, 1, -1, false, false)) { }
}
@@ -2319,7 +2324,7 @@ skip_dynamic_range_lvalue_expansion:;
if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0)
{
AstNode *cell_arg = new AstNode(AST_PARASET, attr.second->clone());
- cell_arg->str = RTLIL::escape_id(attr.first.str().substr(strlen("\\via_celltype_defparam_")));
+ cell_arg->str = RTLIL::escape_id(attr.first.substr(strlen("\\via_celltype_defparam_")));
cell->children.push_back(cell_arg);
}
@@ -2793,13 +2798,13 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
std::getline(f, line);
for (int i = 0; i < GetSize(line); i++) {
- if (in_comment && line.substr(i, 2) == "*/") {
+ if (in_comment && line.compare(i, 2, "*/") == 0) {
line[i] = ' ';
line[i+1] = ' ';
in_comment = false;
continue;
}
- if (!in_comment && line.substr(i, 2) == "/*")
+ if (!in_comment && line.compare(i, 2, "/*") == 0)
in_comment = true;
if (in_comment)
line[i] = ' ';
@@ -2808,7 +2813,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
while (1)
{
token = next_token(line, " \t\r\n");
- if (token.empty() || token.substr(0, 2) == "//")
+ if (token.empty() || token.compare(0, 2, "//") == 0)
break;
if (token[0] == '@') {
@@ -3439,19 +3444,11 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
{
std::map<std::string, AstNode*> backup_scope;
std::map<std::string, AstNode::varinfo_t> variables;
- bool delete_temp_block = false;
- AstNode *block = NULL;
+ AstNode *block = new AstNode(AST_BLOCK);
size_t argidx = 0;
for (auto child : children)
{
- if (child->type == AST_BLOCK)
- {
- log_assert(block == NULL);
- block = child;
- continue;
- }
-
if (child->type == AST_WIRE)
{
while (child->simplify(true, false, false, 1, -1, false, true)) { }
@@ -3468,13 +3465,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
continue;
}
- log_assert(block == NULL);
- delete_temp_block = true;
- block = new AstNode(AST_BLOCK);
block->children.push_back(child->clone());
}
- log_assert(block != NULL);
log_assert(variables.count(str) != 0);
while (!block->children.empty())
@@ -3642,8 +3635,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
log_abort();
}
- if (delete_temp_block)
- delete block;
+ delete block;
for (auto &it : backup_scope)
if (it.second == NULL)
diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc
index a6a07863f..d17cacf29 100644
--- a/frontends/blif/blifparse.cc
+++ b/frontends/blif/blifparse.cc
@@ -78,7 +78,7 @@ failed:
return std::pair<RTLIL::IdString, int>("\\" + name, 0);
}
-void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode, bool wideports)
+void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool run_clean, bool sop_mode, bool wideports)
{
RTLIL::Module *module = nullptr;
RTLIL::Const *lutptr = NULL;
diff --git a/frontends/blif/blifparse.h b/frontends/blif/blifparse.h
index 955b6aacf..2b84cb795 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, IdString dff_name,
bool run_clean = false, bool sop_mode = false, bool wideports = false);
YOSYS_NAMESPACE_END
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index 44c99906a..b4b9693da 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -282,14 +282,14 @@ proc_stmt:
} case_body sync_list TOK_END EOL;
switch_stmt:
- attr_list TOK_SWITCH sigspec EOL {
+ TOK_SWITCH sigspec EOL {
RTLIL::SwitchRule *rule = new RTLIL::SwitchRule;
- rule->signal = *$3;
+ rule->signal = *$2;
rule->attributes = attrbuf;
switch_stack.back()->push_back(rule);
attrbuf.clear();
- delete $3;
- } switch_body TOK_END EOL;
+ delete $2;
+ } attr_list switch_body TOK_END EOL;
attr_list:
/* empty */ |
@@ -298,9 +298,11 @@ attr_list:
switch_body:
switch_body TOK_CASE {
RTLIL::CaseRule *rule = new RTLIL::CaseRule;
+ rule->attributes = attrbuf;
switch_stack.back()->back()->cases.push_back(rule);
switch_stack.push_back(&rule->switches);
case_stack.push_back(rule);
+ attrbuf.clear();
} compare_list EOL case_body {
switch_stack.pop_back();
case_stack.pop_back();
@@ -319,12 +321,15 @@ compare_list:
/* empty */;
case_body:
+ case_body attr_stmt |
case_body switch_stmt |
case_body assign_stmt |
/* empty */;
assign_stmt:
TOK_ASSIGN sigspec sigspec EOL {
+ if (attrbuf.size() != 0)
+ rtlil_frontend_ilang_yyerror("dangling attribute");
case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
delete $2;
delete $3;
diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc
index 82361ea9b..7aceffbfc 100644
--- a/frontends/json/jsonparse.cc
+++ b/frontends/json/jsonparse.cc
@@ -25,7 +25,7 @@ struct JsonNode
{
char type; // S=String, N=Number, A=Array, D=Dict
string data_string;
- int data_number;
+ int64_t data_number;
vector<JsonNode*> data_array;
dict<string, JsonNode*> data_dict;
vector<string> data_dict_keys;
@@ -206,6 +206,38 @@ struct JsonNode
}
};
+Const json_parse_attr_param_value(JsonNode *node)
+{
+ Const value;
+
+ if (node->type == 'S') {
+ string &s = node->data_string;
+ size_t cursor = s.find_first_not_of("01xz");
+ if (cursor == string::npos) {
+ value = Const::from_string(s);
+ } else if (s.find_first_not_of(' ', cursor) == string::npos) {
+ value = Const(s.substr(0, GetSize(s)-1));
+ } else {
+ value = Const(s);
+ }
+ } else
+ if (node->type == 'N') {
+ value = Const(node->data_number, 32);
+ if (node->data_number < 0)
+ value.flags |= RTLIL::CONST_FLAG_SIGNED;
+ } else
+ if (node->type == 'A') {
+ log_error("JSON attribute or parameter value is an array.\n");
+ } else
+ if (node->type == 'D') {
+ log_error("JSON attribute or parameter value is a dict.\n");
+ } else {
+ log_abort();
+ }
+
+ return value;
+}
+
void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
{
if (node->type != 'D')
@@ -214,28 +246,7 @@ void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
for (auto it : node->data_dict)
{
IdString key = RTLIL::escape_id(it.first.c_str());
- JsonNode *value_node = it.second;
- Const value;
-
- if (value_node->type == 'S') {
- string &s = value_node->data_string;
- if (s.find_first_not_of("01xz") == string::npos)
- value = Const::from_string(s);
- else
- value = Const(s);
- } else
- if (value_node->type == 'N') {
- value = Const(value_node->data_number, 32);
- } else
- if (value_node->type == 'A') {
- log_error("JSON attribute or parameter value is an array.\n");
- } else
- if (value_node->type == 'D') {
- log_error("JSON attribute or parameter value is a dict.\n");
- } else {
- log_abort();
- }
-
+ Const value = json_parse_attr_param_value(it.second);
results[key] = value;
}
}
@@ -292,6 +303,18 @@ void json_import(Design *design, string &modname, JsonNode *node)
if (port_wire == nullptr)
port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array));
+ if (port_node->data_dict.count("upto") != 0) {
+ JsonNode *val = port_node->data_dict.at("upto");
+ if (val->type == 'N')
+ port_wire->upto = val->data_number != 0;
+ }
+
+ if (port_node->data_dict.count("offset") != 0) {
+ JsonNode *val = port_node->data_dict.at("offset");
+ if (val->type == 'N')
+ port_wire->start_offset = val->data_number;
+ }
+
if (port_direction_node->data_string == "input") {
port_wire->port_input = true;
} else
@@ -372,6 +395,18 @@ void json_import(Design *design, string &modname, JsonNode *node)
if (wire == nullptr)
wire = module->addWire(net_name, GetSize(bits_node->data_array));
+ if (net_node->data_dict.count("upto") != 0) {
+ JsonNode *val = net_node->data_dict.at("upto");
+ if (val->type == 'N')
+ wire->upto = val->data_number != 0;
+ }
+
+ if (net_node->data_dict.count("offset") != 0) {
+ JsonNode *val = net_node->data_dict.at("offset");
+ if (val->type == 'N')
+ wire->start_offset = val->data_number;
+ }
+
for (int i = 0; i < GetSize(bits_node->data_array); i++)
{
JsonNode *bitval_node = bits_node->data_array.at(i);
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index 6e3cffaca..14de95e07 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -551,7 +551,7 @@ struct LibertyFrontend : public Frontend {
if (design->has(cell_name)) {
Module *existing_mod = design->module(cell_name);
if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
- log_error("Re-definition of of cell/module %s!\n", log_id(cell_name));
+ log_error("Re-definition of cell/module %s!\n", log_id(cell_name));
} else if (flag_nooverwrite) {
log("Ignoring re-definition of module %s.\n", log_id(cell_name));
continue;
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 2bf99e58e..c5eef4b55 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
@@ -111,9 +112,10 @@ string get_full_netlist_name(Netlist *nl)
// ==================================================================
-VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover) :
+VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover, bool mode_fullinit) :
mode_gates(mode_gates), mode_keep(mode_keep), mode_nosva(mode_nosva),
- mode_names(mode_names), mode_verific(mode_verific), mode_autocover(mode_autocover)
+ mode_names(mode_names), mode_verific(mode_verific), mode_autocover(mode_autocover),
+ mode_fullinit(mode_fullinit)
{
}
@@ -1454,6 +1456,50 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
merge_past_ffs(past_ffs);
}
+
+ if (!mode_fullinit)
+ {
+ pool<SigBit> non_ff_bits;
+ CellTypes ff_types;
+
+ ff_types.setup_internals_ff();
+ ff_types.setup_stdcells_mem();
+
+ for (auto cell : module->cells())
+ {
+ if (ff_types.cell_known(cell->type))
+ continue;
+
+ for (auto conn : cell->connections())
+ {
+ if (!cell->output(conn.first))
+ continue;
+
+ for (auto bit : conn.second)
+ if (bit.wire != nullptr)
+ non_ff_bits.insert(bit);
+ }
+ }
+
+ for (auto wire : module->wires())
+ {
+ if (!wire->attributes.count("\\init"))
+ continue;
+
+ Const &initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initval); i++)
+ {
+ if (initval[i] != State::S0 && initval[i] != State::S1)
+ continue;
+
+ if (non_ff_bits.count(SigBit(wire, i)))
+ initval[i] = State::Sx;
+ }
+
+ if (initval.is_fully_undef())
+ wire->attributes.erase("\\init");
+ }
+ }
}
// ==================================================================
@@ -1743,7 +1789,7 @@ struct VerificExtNets
new_net = new Net(name.c_str());
nl->Add(new_net);
- Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
+ Net *n YS_ATTRIBUTE(unused) = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
log_assert(n == ca_net);
}
@@ -1829,7 +1875,7 @@ void verific_import(Design *design, const std::map<std::string,std::string> &par
while (!nl_todo.empty()) {
Netlist *nl = *nl_todo.begin();
if (nl_done.count(nl) == 0) {
- VerificImporter importer(false, false, false, false, false, false);
+ VerificImporter importer(false, false, false, false, false, false, false);
importer.import_netlist(design, nl, nl_todo);
}
nl_todo.erase(nl);
@@ -1952,6 +1998,9 @@ struct VerificPass : public Pass {
log(" -autocover\n");
log(" Generate automatic cover statements for all asserts\n");
log("\n");
+ log(" -fullinit\n");
+ log(" Keep all register initializations, even those for non-FF registers.\n");
+ log("\n");
log(" -chparam name value \n");
log(" Elaborate the specified top modules (all modules when -all given) using\n");
log(" this parameter value. Modules on which this parameter does not exist will\n");
@@ -2140,7 +2189,7 @@ struct VerificPass : public Pass {
veri_file::DefineMacro("VERIFIC");
veri_file::DefineMacro(args[argidx] == "-formal" ? "FORMAL" : "SYNTHESIS");
- for (argidx++; argidx < GetSize(args) && GetSize(args[argidx]) >= 2 && args[argidx].substr(0, 2) == "-D"; argidx++) {
+ for (argidx++; argidx < GetSize(args) && GetSize(args[argidx]) >= 2 && args[argidx].compare(0, 2, "-D") == 0; argidx++) {
std::string name = args[argidx].substr(2);
if (args[argidx] == "-D") {
if (++argidx >= GetSize(args))
@@ -2213,7 +2262,7 @@ struct VerificPass : public Pass {
std::set<Netlist*> nl_todo, nl_done;
bool mode_all = false, mode_gates = false, mode_keep = false;
bool mode_nosva = false, mode_names = false, mode_verific = false;
- bool mode_autocover = false;
+ bool mode_autocover = false, mode_fullinit = false;
bool flatten = false, extnets = false;
string dumpfile;
Map parameters(STRING_HASH);
@@ -2255,6 +2304,10 @@ struct VerificPass : public Pass {
mode_autocover = true;
continue;
}
+ if (args[argidx] == "-fullinit") {
+ mode_fullinit = true;
+ continue;
+ }
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
@@ -2283,7 +2336,7 @@ struct VerificPass : public Pass {
break;
}
- if (argidx > GetSize(args) && args[argidx].substr(0, 1) == "-")
+ if (argidx > GetSize(args) && args[argidx].compare(0, 1, "-") == 0)
cmd_error(args, argidx, "unknown option");
if (mode_all)
@@ -2378,7 +2431,7 @@ struct VerificPass : public Pass {
Netlist *nl = *nl_todo.begin();
if (nl_done.count(nl) == 0) {
VerificImporter importer(mode_gates, mode_keep, mode_nosva,
- mode_names, mode_verific, mode_autocover);
+ mode_names, mode_verific, mode_autocover, mode_fullinit);
importer.import_netlist(design, nl, nl_todo);
}
nl_todo.erase(nl);
@@ -2484,7 +2537,7 @@ struct ReadPass : public Pass {
args[0] = "verific";
} else {
args[0] = "read_verilog";
- args.erase(args.begin()+1, args.begin()+2);
+ args[1] = "-defer";
}
Pass::call(design, args);
return;
@@ -2498,6 +2551,7 @@ struct ReadPass : public Pass {
if (args[1] == "-formal")
args.insert(args.begin()+1, std::string());
args[1] = "-sv";
+ args.insert(args.begin()+1, "-defer");
}
Pass::call(design, args);
return;
diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h
index 88a6cc0ba..5cbd78f7b 100644
--- a/frontends/verific/verific.h
+++ b/frontends/verific/verific.h
@@ -72,9 +72,9 @@ struct VerificImporter
pool<Verific::Net*, hash_ptr_ops> any_all_nets;
bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific;
- bool mode_autocover;
+ bool mode_autocover, mode_fullinit;
- VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover);
+ VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover, bool mode_fullinit);
RTLIL::SigBit net_map_at(Verific::Net *net);
diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc
index 8ea8372d3..909e9b4f1 100644
--- a/frontends/verific/verificsva.cc
+++ b/frontends/verific/verificsva.cc
@@ -357,7 +357,7 @@ struct SvaFsm
for (int i = 0; i < GetSize(nodes); i++)
{
if (next_state_sig[i] != State::S0) {
- clocking.addDff(NEW_ID, next_state_sig[i], state_wire[i], Const(0, 1));
+ clocking.addDff(NEW_ID, next_state_sig[i], state_wire[i], State::S0);
} else {
module->connect(state_wire[i], State::S0);
}
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index 57d366dbf..4bf5b1cf5 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -99,7 +99,7 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
if (base == 10) {
while (!digits.empty())
- data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
+ data.push_back(my_decimal_div_by_two(digits) ? State::S1 : State::S0);
} else {
int bits_per_digit = my_ilog2(base-1);
for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
@@ -115,17 +115,17 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
else if (*it == 0xf2)
data.push_back(RTLIL::Sa);
else
- data.push_back((*it & bitmask) ? RTLIL::S1 : RTLIL::S0);
+ data.push_back((*it & bitmask) ? State::S1 : State::S0);
}
}
}
int len = GetSize(data);
- RTLIL::State msb = data.empty() ? RTLIL::S0 : data.back();
+ RTLIL::State msb = data.empty() ? State::S0 : data.back();
if (len_in_bits < 0) {
if (len < 32)
- data.resize(32, msb == RTLIL::S0 || msb == RTLIL::S1 ? RTLIL::S0 : msb);
+ data.resize(32, msb == State::S0 || msb == State::S1 ? RTLIL::S0 : msb);
return;
}
@@ -133,11 +133,11 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len);
for (len = len - 1; len >= 0; len--)
- if (data[len] == RTLIL::S1)
+ if (data[len] == State::S1)
break;
- if (msb == RTLIL::S0 || msb == RTLIL::S1) {
+ if (msb == State::S0 || msb == State::S1) {
len += 1;
- data.resize(len_in_bits, RTLIL::S0);
+ data.resize(len_in_bits, State::S0);
} else {
len += 2;
data.resize(len_in_bits, msb);
@@ -153,7 +153,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
if (warn_z) {
AstNode *ret = const2ast(code, case_type);
- if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
+ if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
current_filename.c_str(), get_line_num());
return ret;
@@ -169,7 +169,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
for (int i = 0; i < len; i++) {
unsigned char ch = str[len - i];
for (int j = 0; j < 8; j++) {
- data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0);
+ data.push_back((ch & 1) ? State::S1 : State::S0);
ch = ch >> 1;
}
}
@@ -190,8 +190,8 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
if (*endptr == 0) {
std::vector<RTLIL::State> data;
my_strtobin(data, str, -1, 10, case_type, false);
- if (data.back() == RTLIL::S1)
- data.push_back(RTLIL::S0);
+ if (data.back() == State::S1)
+ data.push_back(State::S0);
return AstNode::mkconst_bits(data, true);
}
@@ -204,7 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
std::vector<RTLIL::State> data;
bool is_signed = false;
- bool is_unsized = false;
+ bool is_unsized = len_in_bits < 0;
if (*(endptr+1) == 's') {
is_signed = true;
endptr++;
@@ -213,32 +213,32 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
case 'b':
case 'B':
- my_strtobin(data, endptr+2, len_in_bits, 2, case_type, false);
+ my_strtobin(data, endptr+2, len_in_bits, 2, case_type, is_unsized);
break;
case 'o':
case 'O':
- my_strtobin(data, endptr+2, len_in_bits, 8, case_type, false);
+ my_strtobin(data, endptr+2, len_in_bits, 8, case_type, is_unsized);
break;
case 'd':
case 'D':
- my_strtobin(data, endptr+2, len_in_bits, 10, case_type, false);
+ my_strtobin(data, endptr+2, len_in_bits, 10, case_type, is_unsized);
break;
case 'h':
case 'H':
- my_strtobin(data, endptr+2, len_in_bits, 16, case_type, false);
+ my_strtobin(data, endptr+2, len_in_bits, 16, case_type, is_unsized);
break;
default:
char next_char = char(tolower(*(endptr+1)));
if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') {
- my_strtobin(data, endptr+1, 1, 2, case_type, true);
is_unsized = true;
+ my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized);
} else {
return NULL;
}
}
if (len_in_bits < 0) {
- if (is_signed && data.back() == RTLIL::S1)
- data.push_back(RTLIL::S0);
+ if (is_signed && data.back() == State::S1)
+ data.push_back(State::S0);
}
return AstNode::mkconst_bits(data, is_signed, is_unsized);
}
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index d3fd91473..57e55b1f4 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -70,6 +70,9 @@ YOSYS_NAMESPACE_END
#define YY_INPUT(buf,result,max_size) \
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
+#undef YY_BUF_SIZE
+#define YY_BUF_SIZE 65536
+
%}
%option yylineno
@@ -193,6 +196,8 @@ YOSYS_NAMESPACE_END
to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
global state.. its a mess) */
[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
+ if (!strcmp(yytext, "default"))
+ return TOK_DEFAULT;
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
return TOK_SVA_LABEL;
}
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 8234479cc..4afd72b73 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -274,7 +274,7 @@ hierarchical_id:
$$ = $1;
} |
hierarchical_id TOK_PACKAGESEP TOK_ID {
- if ($3->substr(0, 1) == "\\")
+ if ($3->compare(0, 1, "\\") == 0)
*$1 += "::" + $3->substr(1);
else
*$1 += "::" + *$3;
@@ -282,7 +282,7 @@ hierarchical_id:
$$ = $1;
} |
hierarchical_id '.' TOK_ID {
- if ($3->substr(0, 1) == "\\")
+ if ($3->compare(0, 1, "\\") == 0)
*$1 += "." + $3->substr(1);
else
*$1 += "." + *$3;
@@ -517,6 +517,7 @@ wire_type_token:
TOK_GENVAR {
astbuf3->type = AST_GENVAR;
astbuf3->is_reg = true;
+ astbuf3->is_signed = true;
astbuf3->range_left = 31;
astbuf3->range_right = 0;
} |
@@ -1020,13 +1021,8 @@ list_of_specparam_assignments:
specparam_assignment:
ignspec_id '=' constant_mintypmax_expression ;
-/*
-pulsestyle_declaration :
- ;
-
-showcancelled_declaration :
- ;
-*/
+ignspec_opt_cond:
+ TOK_IF '(' ignspec_expr ')' | /* empty */;
path_declaration :
simple_path_declaration ';'
@@ -1035,8 +1031,8 @@ path_declaration :
;
simple_path_declaration :
- parallel_path_description '=' path_delay_value |
- full_path_description '=' path_delay_value
+ ignspec_opt_cond parallel_path_description '=' path_delay_value |
+ ignspec_opt_cond full_path_description '=' path_delay_value
;
path_delay_value :
@@ -1046,32 +1042,20 @@ path_delay_value :
;
list_of_path_delay_extra_expressions :
-/*
- t_path_delay_expression
- | trise_path_delay_expression ',' tfall_path_delay_expression
- | trise_path_delay_expression ',' tfall_path_delay_expression ',' tz_path_delay_expression
- | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
- tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression
- | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
- tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression ','
- t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ','
- tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression
-*/
- ',' path_delay_expression
- | ',' path_delay_expression ',' path_delay_expression
- | ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression
- | ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
- path_delay_expression ',' path_delay_expression ',' path_delay_expression
- ;
+ ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions;
+
+specify_edge_identifier :
+ TOK_POSEDGE | TOK_NEGEDGE ;
parallel_path_description :
- '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ;
+ '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' |
+ '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor opt_polarity_operator ':' ignspec_expr ')' ')' |
+ '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr ')' ')' ;
full_path_description :
- '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' ;
+ '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' |
+ '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs opt_polarity_operator ':' ignspec_expr ')' ')' |
+ '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs TOK_POS_INDEXED ignspec_expr ')' ')' ;
// This was broken into 2 rules to solve shift/reduce conflicts
list_of_path_inputs :
@@ -1111,56 +1095,6 @@ system_timing_args :
system_timing_arg |
system_timing_args ',' system_timing_arg ;
-/*
-t_path_delay_expression :
- path_delay_expression;
-
-trise_path_delay_expression :
- path_delay_expression;
-
-tfall_path_delay_expression :
- path_delay_expression;
-
-tz_path_delay_expression :
- path_delay_expression;
-
-t01_path_delay_expression :
- path_delay_expression;
-
-t10_path_delay_expression :
- path_delay_expression;
-
-t0z_path_delay_expression :
- path_delay_expression;
-
-tz1_path_delay_expression :
- path_delay_expression;
-
-t1z_path_delay_expression :
- path_delay_expression;
-
-tz0_path_delay_expression :
- path_delay_expression;
-
-t0x_path_delay_expression :
- path_delay_expression;
-
-tx1_path_delay_expression :
- path_delay_expression;
-
-t1x_path_delay_expression :
- path_delay_expression;
-
-tx0_path_delay_expression :
- path_delay_expression;
-
-txz_path_delay_expression :
- path_delay_expression;
-
-tzx_path_delay_expression :
- path_delay_expression;
-*/
-
path_delay_expression :
ignspec_constant_expression;
@@ -1400,7 +1334,13 @@ wire_name:
node->children.push_back(rng);
}
node->type = AST_MEMORY;
- node->children.push_back($2);
+ auto *rangeNode = $2;
+ if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) {
+ // SV array size [n], rewrite as [n-1:0]
+ rangeNode->children[0] = new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true));
+ rangeNode->children.push_back(AstNode::mkconst_int(0, false));
+ }
+ node->children.push_back(rangeNode);
}
if (current_function_or_task == NULL) {
if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) {
@@ -2244,7 +2184,7 @@ basic_expr:
$$ = $1;
} |
'(' expr ')' TOK_CONSTVAL {
- if ($4->substr(0, 1) != "'")
+ if ($4->compare(0, 1, "'") != 0)
frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str());
AstNode *bits = $2;
AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
@@ -2254,7 +2194,7 @@ basic_expr:
delete $4;
} |
hierarchical_id TOK_CONSTVAL {
- if ($2->substr(0, 1) != "'")
+ if ($2->compare(0, 1, "'") != 0)
frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str());
AstNode *bits = new AstNode(AST_IDENTIFIER);
bits->str = *$1;
diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc
index 26c625f89..02854edb2 100644
--- a/kernel/cellaigs.cc
+++ b/kernel/cellaigs.cc
@@ -268,9 +268,9 @@ Aig::Aig(Cell *cell)
cell->parameters.sort();
for (auto p : cell->parameters)
{
- if (p.first == "\\A_WIDTH" && mkname_a_signed) {
+ if (p.first == ID(A_WIDTH) && mkname_a_signed) {
name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U');
- } else if (p.first == "\\B_WIDTH" && mkname_b_signed) {
+ } else if (p.first == ID(B_WIDTH) && mkname_b_signed) {
name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U');
} else {
mkname_last = name;
@@ -280,181 +280,183 @@ Aig::Aig(Cell *cell)
mkname_a_signed = false;
mkname_b_signed = false;
mkname_is_signed = false;
- if (p.first == "\\A_SIGNED") {
+ if (p.first == ID(A_SIGNED)) {
mkname_a_signed = true;
mkname_is_signed = p.second.as_bool();
}
- if (p.first == "\\B_SIGNED") {
+ if (p.first == ID(B_SIGNED)) {
mkname_b_signed = true;
mkname_is_signed = p.second.as_bool();
}
}
- if (cell->type.in("$not", "$_NOT_", "$pos", "$_BUF_"))
+ if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($_BUF_)))
{
- for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) {
- int A = mk.inport("\\A", i);
- int Y = cell->type.in("$not", "$_NOT_") ? mk.not_gate(A) : A;
- mk.outport(Y, "\\Y", i);
+ for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) {
+ int A = mk.inport(ID::A, i);
+ int Y = cell->type.in(ID($not), ID($_NOT_)) ? mk.not_gate(A) : A;
+ mk.outport(Y, ID::Y, i);
}
goto optimize;
}
- if (cell->type.in("$and", "$_AND_", "$_NAND_", "$or", "$_OR_", "$_NOR_", "$xor", "$xnor", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
- {
- for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) {
- int A = mk.inport("\\A", i);
- int B = mk.inport("\\B", i);
- int Y = cell->type.in("$and", "$_AND_") ? mk.and_gate(A, B) :
- cell->type.in("$_NAND_") ? mk.nand_gate(A, B) :
- cell->type.in("$or", "$_OR_") ? mk.or_gate(A, B) :
- cell->type.in("$_NOR_") ? mk.nor_gate(A, B) :
- cell->type.in("$xor", "$_XOR_") ? mk.xor_gate(A, B) :
- cell->type.in("$xnor", "$_XNOR_") ? mk.xnor_gate(A, B) :
- cell->type.in("$_ANDNOT_") ? mk.andnot_gate(A, B) :
- cell->type.in("$_ORNOT_") ? mk.ornot_gate(A, B) : -1;
- mk.outport(Y, "\\Y", i);
+ if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_), ID($or), ID($_OR_), ID($_NOR_), ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_)))
+ {
+ for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) {
+ int A = mk.inport(ID::A, i);
+ int B = mk.inport(ID::B, i);
+ int Y = cell->type.in(ID($and), ID($_AND_)) ? mk.and_gate(A, B) :
+ cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) :
+ cell->type.in(ID($or), ID($_OR_)) ? mk.or_gate(A, B) :
+ cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) :
+ cell->type.in(ID($xor), ID($_XOR_)) ? mk.xor_gate(A, B) :
+ cell->type.in(ID($xnor), ID($_XNOR_)) ? mk.xnor_gate(A, B) :
+ cell->type.in(ID($_ANDNOT_)) ? mk.andnot_gate(A, B) :
+ cell->type.in(ID($_ORNOT_)) ? mk.ornot_gate(A, B) : -1;
+ mk.outport(Y, ID::Y, i);
}
goto optimize;
}
- if (cell->type.in("$mux", "$_MUX_"))
+ if (cell->type.in(ID($mux), ID($_MUX_)))
{
- int S = mk.inport("\\S");
- for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) {
- int A = mk.inport("\\A", i);
- int B = mk.inport("\\B", i);
+ int S = mk.inport(ID(S));
+ for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) {
+ int A = mk.inport(ID::A, i);
+ int B = mk.inport(ID::B, i);
int Y = mk.mux_gate(A, B, S);
- mk.outport(Y, "\\Y", i);
+ if (cell->type == ID($_NMUX_))
+ Y = mk.not_gate(Y);
+ mk.outport(Y, ID::Y, i);
}
goto optimize;
}
- if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool"))
+ if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool)))
{
- int Y = mk.inport("\\A", 0);
- for (int i = 1; i < GetSize(cell->getPort("\\A")); i++) {
- int A = mk.inport("\\A", i);
- if (cell->type == "$reduce_and") Y = mk.and_gate(A, Y);
- if (cell->type == "$reduce_or") Y = mk.or_gate(A, Y);
- if (cell->type == "$reduce_bool") Y = mk.or_gate(A, Y);
- if (cell->type == "$reduce_xor") Y = mk.xor_gate(A, Y);
- if (cell->type == "$reduce_xnor") Y = mk.xor_gate(A, Y);
+ int Y = mk.inport(ID::A, 0);
+ for (int i = 1; i < GetSize(cell->getPort(ID::A)); i++) {
+ int A = mk.inport(ID::A, i);
+ if (cell->type == ID($reduce_and)) Y = mk.and_gate(A, Y);
+ if (cell->type == ID($reduce_or)) Y = mk.or_gate(A, Y);
+ if (cell->type == ID($reduce_bool)) Y = mk.or_gate(A, Y);
+ if (cell->type == ID($reduce_xor)) Y = mk.xor_gate(A, Y);
+ if (cell->type == ID($reduce_xnor)) Y = mk.xor_gate(A, Y);
}
- if (cell->type == "$reduce_xnor")
+ if (cell->type == ID($reduce_xnor))
Y = mk.not_gate(Y);
- mk.outport(Y, "\\Y", 0);
- for (int i = 1; i < GetSize(cell->getPort("\\Y")); i++)
- mk.outport(mk.bool_node(false), "\\Y", i);
+ mk.outport(Y, ID::Y, 0);
+ for (int i = 1; i < GetSize(cell->getPort(ID::Y)); i++)
+ mk.outport(mk.bool_node(false), ID::Y, i);
goto optimize;
}
- if (cell->type.in("$logic_not", "$logic_and", "$logic_or"))
+ if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or)))
{
- int A = mk.inport("\\A", 0), Y = -1;
- for (int i = 1; i < GetSize(cell->getPort("\\A")); i++)
- A = mk.or_gate(mk.inport("\\A", i), A);
- if (cell->type.in("$logic_and", "$logic_or")) {
- int B = mk.inport("\\B", 0);
- for (int i = 1; i < GetSize(cell->getPort("\\B")); i++)
- B = mk.or_gate(mk.inport("\\B", i), B);
- if (cell->type == "$logic_and") Y = mk.and_gate(A, B);
- if (cell->type == "$logic_or") Y = mk.or_gate(A, B);
+ int A = mk.inport(ID::A, 0), Y = -1;
+ for (int i = 1; i < GetSize(cell->getPort(ID::A)); i++)
+ A = mk.or_gate(mk.inport(ID::A, i), A);
+ if (cell->type.in(ID($logic_and), ID($logic_or))) {
+ int B = mk.inport(ID::B, 0);
+ for (int i = 1; i < GetSize(cell->getPort(ID::B)); i++)
+ B = mk.or_gate(mk.inport(ID::B, i), B);
+ if (cell->type == ID($logic_and)) Y = mk.and_gate(A, B);
+ if (cell->type == ID($logic_or)) Y = mk.or_gate(A, B);
} else {
- if (cell->type == "$logic_not") Y = mk.not_gate(A);
+ if (cell->type == ID($logic_not)) Y = mk.not_gate(A);
}
- mk.outport_bool(Y, "\\Y");
+ mk.outport_bool(Y, ID::Y);
goto optimize;
}
- if (cell->type.in("$add", "$sub"))
+ if (cell->type.in(ID($add), ID($sub)))
{
- int width = GetSize(cell->getPort("\\Y"));
- vector<int> A = mk.inport_vec("\\A", width);
- vector<int> B = mk.inport_vec("\\B", width);
+ int width = GetSize(cell->getPort(ID::Y));
+ vector<int> A = mk.inport_vec(ID::A, width);
+ vector<int> B = mk.inport_vec(ID::B, width);
int carry = mk.bool_node(false);
- if (cell->type == "$sub") {
+ if (cell->type == ID($sub)) {
for (auto &n : B)
n = mk.not_gate(n);
carry = mk.not_gate(carry);
}
vector<int> Y = mk.adder(A, B, carry);
- mk.outport_vec(Y, "\\Y");
+ mk.outport_vec(Y, ID::Y);
goto optimize;
}
- if (cell->type == "$alu")
+ if (cell->type == ID($alu))
{
- int width = GetSize(cell->getPort("\\Y"));
- vector<int> A = mk.inport_vec("\\A", width);
- vector<int> B = mk.inport_vec("\\B", width);
- int carry = mk.inport("\\CI");
- int binv = mk.inport("\\BI");
+ int width = GetSize(cell->getPort(ID::Y));
+ vector<int> A = mk.inport_vec(ID::A, width);
+ vector<int> B = mk.inport_vec(ID::B, width);
+ int carry = mk.inport(ID(CI));
+ int binv = mk.inport(ID(BI));
for (auto &n : B)
n = mk.xor_gate(n, binv);
vector<int> X(width), CO(width);
vector<int> Y = mk.adder(A, B, carry, &X, &CO);
for (int i = 0; i < width; i++)
X[i] = mk.xor_gate(A[i], B[i]);
- mk.outport_vec(Y, "\\Y");
- mk.outport_vec(X, "\\X");
- mk.outport_vec(CO, "\\CO");
+ mk.outport_vec(Y, ID::Y);
+ mk.outport_vec(X, ID(X));
+ mk.outport_vec(CO, ID(CO));
goto optimize;
}
- if (cell->type.in("$eq", "$ne"))
+ if (cell->type.in(ID($eq), ID($ne)))
{
- 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 width = max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::B)));
+ vector<int> A = mk.inport_vec(ID::A, width);
+ vector<int> B = mk.inport_vec(ID::B, width);
int Y = mk.bool_node(false);
for (int i = 0; i < width; i++)
Y = mk.or_gate(Y, mk.xor_gate(A[i], B[i]));
- if (cell->type == "$eq")
+ if (cell->type == ID($eq))
Y = mk.not_gate(Y);
- mk.outport_bool(Y, "\\Y");
+ mk.outport_bool(Y, ID::Y);
goto optimize;
}
- if (cell->type == "$_AOI3_")
+ if (cell->type == ID($_AOI3_))
{
- int A = mk.inport("\\A");
- int B = mk.inport("\\B");
- int C = mk.inport("\\C");
+ int A = mk.inport(ID::A);
+ int B = mk.inport(ID::B);
+ int C = mk.inport(ID(C));
int Y = mk.nor_gate(mk.and_gate(A, B), C);
- mk.outport(Y, "\\Y");
+ mk.outport(Y, ID::Y);
goto optimize;
}
- if (cell->type == "$_OAI3_")
+ if (cell->type == ID($_OAI3_))
{
- int A = mk.inport("\\A");
- int B = mk.inport("\\B");
- int C = mk.inport("\\C");
+ int A = mk.inport(ID::A);
+ int B = mk.inport(ID::B);
+ int C = mk.inport(ID(C));
int Y = mk.nand_gate(mk.or_gate(A, B), C);
- mk.outport(Y, "\\Y");
+ mk.outport(Y, ID::Y);
goto optimize;
}
- if (cell->type == "$_AOI4_")
+ if (cell->type == ID($_AOI4_))
{
- int A = mk.inport("\\A");
- int B = mk.inport("\\B");
- int C = mk.inport("\\C");
- int D = mk.inport("\\D");
+ int A = mk.inport(ID::A);
+ int B = mk.inport(ID::B);
+ int C = mk.inport(ID(C));
+ int D = mk.inport(ID(D));
int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D));
- mk.outport(Y, "\\Y");
+ mk.outport(Y, ID::Y);
goto optimize;
}
- if (cell->type == "$_OAI4_")
+ if (cell->type == ID($_OAI4_))
{
- int A = mk.inport("\\A");
- int B = mk.inport("\\B");
- int C = mk.inport("\\C");
- int D = mk.inport("\\D");
+ int A = mk.inport(ID::A);
+ int B = mk.inport(ID::B);
+ int C = mk.inport(ID(C));
+ int D = mk.inport(ID(D));
int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D));
- mk.outport(Y, "\\Y");
+ mk.outport(Y, ID::Y);
goto optimize;
}
diff --git a/kernel/celledges.cc b/kernel/celledges.cc
index 556e8b826..d0bb99e83 100644
--- a/kernel/celledges.cc
+++ b/kernel/celledges.cc
@@ -24,9 +24,9 @@ PRIVATE_NAMESPACE_BEGIN
void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
{
- IdString A = "\\A", Y = "\\Y";
+ IdString A = ID::A, Y = ID::Y;
- bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
int a_width = GetSize(cell->getPort(A));
int y_width = GetSize(cell->getPort(Y));
@@ -41,14 +41,14 @@ void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
{
- IdString A = "\\A", B = "\\B", Y = "\\Y";
+ IdString A = ID::A, B = ID::B, Y = ID::Y;
- bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
int a_width = GetSize(cell->getPort(A));
int b_width = GetSize(cell->getPort(B));
int y_width = GetSize(cell->getPort(Y));
- if (cell->type == "$and" && !is_signed) {
+ if (cell->type == ID($and) && !is_signed) {
if (a_width > b_width)
a_width = b_width;
else
@@ -71,9 +71,9 @@ void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
{
- IdString A = "\\A", Y = "\\Y";
+ IdString A = ID::A, Y = ID::Y;
- bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
int a_width = GetSize(cell->getPort(A));
int y_width = GetSize(cell->getPort(Y));
@@ -87,14 +87,14 @@ void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
{
- IdString A = "\\A", B = "\\B", Y = "\\Y";
+ IdString A = ID::A, B = ID::B, Y = ID::Y;
- bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
int a_width = GetSize(cell->getPort(A));
int b_width = GetSize(cell->getPort(B));
int y_width = GetSize(cell->getPort(Y));
- if (!is_signed && cell->type != "$sub") {
+ if (!is_signed && cell->type != ID($sub)) {
int ab_width = std::max(a_width, b_width);
y_width = std::min(y_width, ab_width+1);
}
@@ -114,7 +114,7 @@ void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
{
- IdString A = "\\A", Y = "\\Y";
+ IdString A = ID::A, Y = ID::Y;
int a_width = GetSize(cell->getPort(A));
@@ -124,7 +124,7 @@ void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
{
- IdString A = "\\A", B = "\\B", Y = "\\Y";
+ IdString A = ID::A, B = ID::B, Y = ID::Y;
int a_width = GetSize(cell->getPort(A));
int b_width = GetSize(cell->getPort(B));
@@ -138,7 +138,7 @@ void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
{
- IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y";
+ IdString A = ID::A, B = ID::B, S = ID(S), Y = ID::Y;
int a_width = GetSize(cell->getPort(A));
int b_width = GetSize(cell->getPort(B));
@@ -160,43 +160,43 @@ PRIVATE_NAMESPACE_END
bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
{
- if (cell->type.in("$not", "$pos")) {
+ if (cell->type.in(ID($not), ID($pos))) {
bitwise_unary_op(this, cell);
return true;
}
- if (cell->type.in("$and", "$or", "$xor", "$xnor")) {
+ if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) {
bitwise_binary_op(this, cell);
return true;
}
- if (cell->type == "$neg") {
+ if (cell->type == ID($neg)) {
arith_neg_op(this, cell);
return true;
}
- if (cell->type.in("$add", "$sub")) {
+ if (cell->type.in(ID($add), ID($sub))) {
arith_binary_op(this, cell);
return true;
}
- if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", "$logic_not")) {
+ if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) {
reduce_op(this, cell);
return true;
}
// FIXME:
- // if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) {
+ // if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) {
// shift_op(this, cell);
// return true;
// }
- if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) {
+ if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) {
compare_op(this, cell);
return true;
}
- if (cell->type.in("$mux", "$pmux")) {
+ if (cell->type.in(ID($mux), ID($pmux))) {
mux_op(this, cell);
return true;
}
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 4e91eddda..bc96fd602 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -84,46 +84,46 @@ struct CellTypes
{
setup_internals_eval();
- IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
- IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT";
- IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST";
-
- setup_type("$tribuf", {A, EN}, {Y}, true);
-
- setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
- setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
- setup_type("$equiv", {A, B}, {Y}, true);
- setup_type("$specify2", {EN, SRC, DST}, pool<RTLIL::IdString>(), true);
- setup_type("$specify3", {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true);
- setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true);
+ IdString A = ID::A, B = ID::B, EN = ID(EN), Y = ID::Y;
+ IdString SRC = ID(SRC), DST = ID(DST), DAT = ID(DAT);
+ IdString EN_SRC = ID(EN_SRC), EN_DST = ID(EN_DST);
+
+ setup_type(ID($tribuf), {A, EN}, {Y}, true);
+
+ setup_type(ID($assert), {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type(ID($assume), {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type(ID($live), {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type(ID($fair), {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type(ID($cover), {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type(ID($initstate), pool<RTLIL::IdString>(), {Y}, true);
+ setup_type(ID($anyconst), pool<RTLIL::IdString>(), {Y}, true);
+ setup_type(ID($anyseq), pool<RTLIL::IdString>(), {Y}, true);
+ setup_type(ID($allconst), pool<RTLIL::IdString>(), {Y}, true);
+ setup_type(ID($allseq), pool<RTLIL::IdString>(), {Y}, true);
+ setup_type(ID($equiv), {A, B}, {Y}, true);
+ setup_type(ID($specify2), {EN, SRC, DST}, pool<RTLIL::IdString>(), true);
+ setup_type(ID($specify3), {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true);
+ setup_type(ID($specrule), {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true);
}
void setup_internals_eval()
{
std::vector<RTLIL::IdString> unary_ops = {
- "$not", "$pos", "$neg",
- "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
- "$logic_not", "$slice", "$lut", "$sop"
+ ID($not), ID($pos), ID($neg),
+ ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool),
+ ID($logic_not), ID($slice), ID($lut), ID($sop)
};
std::vector<RTLIL::IdString> binary_ops = {
- "$and", "$or", "$xor", "$xnor",
- "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
- "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
- "$add", "$sub", "$mul", "$div", "$mod", "$pow",
- "$logic_and", "$logic_or", "$concat", "$macc"
+ ID($and), ID($or), ID($xor), ID($xnor),
+ ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
+ ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
+ ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow),
+ ID($logic_and), ID($logic_or), ID($concat), ID($macc)
};
- IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y";
- IdString P = "\\P", G = "\\G", C = "\\C", X = "\\X";
- IdString BI = "\\BI", CI = "\\CI", CO = "\\CO", EN = "\\EN";
+ IdString A = ID::A, B = ID::B, S = ID(S), Y = ID::Y;
+ IdString P = ID(P), G = ID(G), C = ID(C), X = ID(X);
+ IdString BI = ID(BI), CI = ID(CI), CO = ID(CO), EN = ID(EN);
for (auto type : unary_ops)
setup_type(type, {A}, {Y}, true);
@@ -131,81 +131,91 @@ struct CellTypes
for (auto type : binary_ops)
setup_type(type, {A, B}, {Y}, true);
- for (auto type : std::vector<RTLIL::IdString>({"$mux", "$pmux"}))
+ for (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux)}))
setup_type(type, {A, B, S}, {Y}, true);
- setup_type("$lcu", {P, G, CI}, {CO}, true);
- setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
- setup_type("$fa", {A, B, C}, {X, Y}, true);
+ setup_type(ID($lcu), {P, G, CI}, {CO}, true);
+ setup_type(ID($alu), {A, B, CI, BI}, {X, Y, CO}, true);
+ setup_type(ID($fa), {A, B, C}, {X, Y}, true);
+ }
+
+ void setup_internals_ff()
+ {
+ IdString SET = ID(SET), CLR = ID(CLR), CLK = ID(CLK), ARST = ID(ARST), EN = ID(EN);
+ IdString Q = ID(Q), D = ID(D);
+
+ setup_type(ID($sr), {SET, CLR}, {Q});
+ setup_type(ID($ff), {D}, {Q});
+ setup_type(ID($dff), {CLK, D}, {Q});
+ setup_type(ID($dffe), {CLK, EN, D}, {Q});
+ setup_type(ID($dffsr), {CLK, SET, CLR, D}, {Q});
+ setup_type(ID($adff), {CLK, ARST, D}, {Q});
+ setup_type(ID($dlatch), {EN, D}, {Q});
+ setup_type(ID($dlatchsr), {EN, SET, CLR, D}, {Q});
+
}
void setup_internals_mem()
{
- IdString SET = "\\SET", CLR = "\\CLR", CLK = "\\CLK", ARST = "\\ARST", EN = "\\EN";
- IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA", RD_EN = "\\RD_EN";
- IdString RD_CLK = "\\RD_CLK", RD_ADDR = "\\RD_ADDR", WR_CLK = "\\WR_CLK", WR_EN = "\\WR_EN";
- IdString WR_ADDR = "\\WR_ADDR", WR_DATA = "\\WR_DATA", RD_DATA = "\\RD_DATA";
- IdString CTRL_IN = "\\CTRL_IN", CTRL_OUT = "\\CTRL_OUT";
-
- setup_type("$sr", {SET, CLR}, {Q});
- setup_type("$ff", {D}, {Q});
- setup_type("$dff", {CLK, D}, {Q});
- setup_type("$dffe", {CLK, EN, D}, {Q});
- setup_type("$dffsr", {CLK, SET, CLR, D}, {Q});
- setup_type("$adff", {CLK, ARST, D}, {Q});
- setup_type("$dlatch", {EN, D}, {Q});
- setup_type("$dlatchsr", {EN, SET, CLR, D}, {Q});
-
- setup_type("$memrd", {CLK, EN, ADDR}, {DATA});
- setup_type("$memwr", {CLK, EN, ADDR, DATA}, pool<RTLIL::IdString>());
- setup_type("$meminit", {ADDR, DATA}, pool<RTLIL::IdString>());
- setup_type("$mem", {RD_CLK, RD_EN, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA});
-
- setup_type("$fsm", {CLK, ARST, CTRL_IN}, {CTRL_OUT});
+ setup_internals_ff();
+
+ IdString CLK = ID(CLK), ARST = ID(ARST), EN = ID(EN);
+ IdString ADDR = ID(ADDR), DATA = ID(DATA), RD_EN = ID(RD_EN);
+ IdString RD_CLK = ID(RD_CLK), RD_ADDR = ID(RD_ADDR), WR_CLK = ID(WR_CLK), WR_EN = ID(WR_EN);
+ IdString WR_ADDR = ID(WR_ADDR), WR_DATA = ID(WR_DATA), RD_DATA = ID(RD_DATA);
+ IdString CTRL_IN = ID(CTRL_IN), CTRL_OUT = ID(CTRL_OUT);
+
+ setup_type(ID($memrd), {CLK, EN, ADDR}, {DATA});
+ setup_type(ID($memwr), {CLK, EN, ADDR, DATA}, pool<RTLIL::IdString>());
+ setup_type(ID($meminit), {ADDR, DATA}, pool<RTLIL::IdString>());
+ setup_type(ID($mem), {RD_CLK, RD_EN, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA});
+
+ setup_type(ID($fsm), {CLK, ARST, CTRL_IN}, {CTRL_OUT});
}
void setup_stdcells()
{
setup_stdcells_eval();
- IdString A = "\\A", E = "\\E", Y = "\\Y";
+ IdString A = ID::A, E = ID(E), Y = ID::Y;
- setup_type("$_TBUF_", {A, E}, {Y}, true);
+ setup_type(ID($_TBUF_), {A, E}, {Y}, true);
}
void setup_stdcells_eval()
{
- IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
- IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
- IdString I = "\\I", J = "\\J", K = "\\K", L = "\\L";
- IdString M = "\\M", N = "\\N", O = "\\O", P = "\\P";
- IdString S = "\\S", T = "\\T", U = "\\U", V = "\\V";
- IdString Y = "\\Y";
-
- setup_type("$_BUF_", {A}, {Y}, true);
- setup_type("$_NOT_", {A}, {Y}, true);
- setup_type("$_AND_", {A, B}, {Y}, true);
- setup_type("$_NAND_", {A, B}, {Y}, true);
- setup_type("$_OR_", {A, B}, {Y}, true);
- setup_type("$_NOR_", {A, B}, {Y}, true);
- setup_type("$_XOR_", {A, B}, {Y}, true);
- setup_type("$_XNOR_", {A, B}, {Y}, true);
- setup_type("$_ANDNOT_", {A, B}, {Y}, true);
- setup_type("$_ORNOT_", {A, B}, {Y}, true);
- setup_type("$_MUX_", {A, B, S}, {Y}, true);
- setup_type("$_MUX4_", {A, B, C, D, S, T}, {Y}, true);
- setup_type("$_MUX8_", {A, B, C, D, E, F, G, H, S, T, U}, {Y}, true);
- setup_type("$_MUX16_", {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V}, {Y}, true);
- setup_type("$_AOI3_", {A, B, C}, {Y}, true);
- setup_type("$_OAI3_", {A, B, C}, {Y}, true);
- setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
- setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
+ IdString A = ID::A, B = ID::B, C = ID(C), D = ID(D);
+ IdString E = ID(E), F = ID(F), G = ID(G), H = ID(H);
+ IdString I = ID(I), J = ID(J), K = ID(K), L = ID(L);
+ IdString M = ID(M), N = ID(N), O = ID(O), P = ID(P);
+ IdString S = ID(S), T = ID(T), U = ID(U), V = ID(V);
+ IdString Y = ID::Y;
+
+ setup_type(ID($_BUF_), {A}, {Y}, true);
+ setup_type(ID($_NOT_), {A}, {Y}, true);
+ setup_type(ID($_AND_), {A, B}, {Y}, true);
+ setup_type(ID($_NAND_), {A, B}, {Y}, true);
+ setup_type(ID($_OR_), {A, B}, {Y}, true);
+ setup_type(ID($_NOR_), {A, B}, {Y}, true);
+ setup_type(ID($_XOR_), {A, B}, {Y}, true);
+ setup_type(ID($_XNOR_), {A, B}, {Y}, true);
+ setup_type(ID($_ANDNOT_), {A, B}, {Y}, true);
+ setup_type(ID($_ORNOT_), {A, B}, {Y}, true);
+ setup_type(ID($_MUX_), {A, B, S}, {Y}, true);
+ setup_type(ID($_NMUX_), {A, B, S}, {Y}, true);
+ setup_type(ID($_MUX4_), {A, B, C, D, S, T}, {Y}, true);
+ setup_type(ID($_MUX8_), {A, B, C, D, E, F, G, H, S, T, U}, {Y}, true);
+ setup_type(ID($_MUX16_), {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V}, {Y}, true);
+ setup_type(ID($_AOI3_), {A, B, C}, {Y}, true);
+ setup_type(ID($_OAI3_), {A, B, C}, {Y}, true);
+ setup_type(ID($_AOI4_), {A, B, C, D}, {Y}, true);
+ setup_type(ID($_OAI4_), {A, B, C, D}, {Y}, true);
}
void setup_stdcells_mem()
{
- IdString S = "\\S", R = "\\R", C = "\\C";
- IdString D = "\\D", Q = "\\Q", E = "\\E";
+ IdString S = ID(S), R = ID(R), C = ID(C);
+ IdString D = ID(D), Q = ID(Q), E = ID(E);
std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};
@@ -213,7 +223,7 @@ struct CellTypes
for (auto c2 : list_np)
setup_type(stringf("$_SR_%c%c_", c1, c2), {S, R}, {Q});
- setup_type("$_FF_", {D}, {Q});
+ setup_type(ID($_FF_), {D}, {Q});
for (auto c1 : list_np)
setup_type(stringf("$_DFF_%c_", c1), {C, D}, {Q});
@@ -246,24 +256,24 @@ struct CellTypes
cell_types.clear();
}
- bool cell_known(RTLIL::IdString type)
+ bool cell_known(RTLIL::IdString type) const
{
return cell_types.count(type) != 0;
}
- bool cell_output(RTLIL::IdString type, RTLIL::IdString port)
+ bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const
{
auto it = cell_types.find(type);
return it != cell_types.end() && it->second.outputs.count(port) != 0;
}
- bool cell_input(RTLIL::IdString type, RTLIL::IdString port)
+ bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const
{
auto it = cell_types.find(type);
return it != cell_types.end() && it->second.inputs.count(port) != 0;
}
- bool cell_evaluable(RTLIL::IdString type)
+ bool cell_evaluable(RTLIL::IdString type) const
{
auto it = cell_types.find(type);
return it != cell_types.end() && it->second.is_evaluable;
@@ -272,20 +282,20 @@ struct CellTypes
static RTLIL::Const eval_not(RTLIL::Const v)
{
for (auto &bit : v.bits)
- if (bit == RTLIL::S0) bit = RTLIL::S1;
- else if (bit == RTLIL::S1) bit = RTLIL::S0;
+ if (bit == State::S0) bit = State::S1;
+ else if (bit == State::S1) bit = State::S0;
return v;
}
static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr)
{
- if (type == "$sshr" && !signed1)
- type = "$shr";
- if (type == "$sshl" && !signed1)
- type = "$shl";
+ if (type == ID($sshr) && !signed1)
+ type = ID($shr);
+ if (type == ID($sshl) && !signed1)
+ type = ID($shl);
- if (type != "$sshr" && type != "$sshl" && type != "$shr" && type != "$shl" && type != "$shift" && type != "$shiftx" &&
- type != "$pos" && type != "$neg" && type != "$not") {
+ if (type != ID($sshr) && type != ID($sshl) && type != ID($shr) && type != ID($shl) && type != ID($shift) && type != ID($shiftx) &&
+ type != ID($pos) && type != ID($neg) && type != ID($not)) {
if (!signed1 || !signed2)
signed1 = false, signed2 = false;
}
@@ -328,25 +338,25 @@ struct CellTypes
HANDLE_CELL_TYPE(neg)
#undef HANDLE_CELL_TYPE
- if (type == "$_BUF_")
+ if (type == ID($_BUF_))
return arg1;
- if (type == "$_NOT_")
+ if (type == ID($_NOT_))
return eval_not(arg1);
- if (type == "$_AND_")
+ if (type == ID($_AND_))
return const_and(arg1, arg2, false, false, 1);
- if (type == "$_NAND_")
+ if (type == ID($_NAND_))
return eval_not(const_and(arg1, arg2, false, false, 1));
- if (type == "$_OR_")
+ if (type == ID($_OR_))
return const_or(arg1, arg2, false, false, 1);
- if (type == "$_NOR_")
+ if (type == ID($_NOR_))
return eval_not(const_or(arg1, arg2, false, false, 1));
- if (type == "$_XOR_")
+ if (type == ID($_XOR_))
return const_xor(arg1, arg2, false, false, 1);
- if (type == "$_XNOR_")
+ if (type == ID($_XNOR_))
return const_xnor(arg1, arg2, false, false, 1);
- if (type == "$_ANDNOT_")
+ if (type == ID($_ANDNOT_))
return const_and(arg1, eval_not(arg2), false, false, 1);
- if (type == "$_ORNOT_")
+ if (type == ID($_ORNOT_))
return const_or(arg1, eval_not(arg2), false, false, 1);
if (errp != nullptr) {
@@ -359,35 +369,35 @@ struct CellTypes
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)
{
- if (cell->type == "$slice") {
+ if (cell->type == ID($slice)) {
RTLIL::Const ret;
- int width = cell->parameters.at("\\Y_WIDTH").as_int();
- int offset = cell->parameters.at("\\OFFSET").as_int();
+ int width = cell->parameters.at(ID(Y_WIDTH)).as_int();
+ int offset = cell->parameters.at(ID(OFFSET)).as_int();
ret.bits.insert(ret.bits.end(), arg1.bits.begin()+offset, arg1.bits.begin()+offset+width);
return ret;
}
- if (cell->type == "$concat") {
+ if (cell->type == ID($concat)) {
RTLIL::Const ret = arg1;
ret.bits.insert(ret.bits.end(), arg2.bits.begin(), arg2.bits.end());
return ret;
}
- if (cell->type == "$lut")
+ if (cell->type == ID($lut))
{
- int width = cell->parameters.at("\\WIDTH").as_int();
+ int width = cell->parameters.at(ID(WIDTH)).as_int();
- std::vector<RTLIL::State> t = cell->parameters.at("\\LUT").bits;
+ std::vector<RTLIL::State> t = cell->parameters.at(ID(LUT)).bits;
while (GetSize(t) < (1 << width))
- t.push_back(RTLIL::S0);
+ t.push_back(State::S0);
t.resize(1 << width);
for (int i = width-1; i >= 0; i--) {
RTLIL::State sel = arg1.bits.at(i);
std::vector<RTLIL::State> new_t;
- if (sel == RTLIL::S0)
+ if (sel == State::S0)
new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
- else if (sel == RTLIL::S1)
+ else if (sel == State::S1)
new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
else
for (int j = 0; j < GetSize(t)/2; j++)
@@ -399,14 +409,14 @@ struct CellTypes
return t;
}
- if (cell->type == "$sop")
+ if (cell->type == ID($sop))
{
- int width = cell->parameters.at("\\WIDTH").as_int();
- int depth = cell->parameters.at("\\DEPTH").as_int();
- std::vector<RTLIL::State> t = cell->parameters.at("\\TABLE").bits;
+ int width = cell->parameters.at(ID(WIDTH)).as_int();
+ int depth = cell->parameters.at(ID(DEPTH)).as_int();
+ std::vector<RTLIL::State> t = cell->parameters.at(ID(TABLE)).bits;
while (GetSize(t) < width*depth*2)
- t.push_back(RTLIL::S0);
+ t.push_back(State::S0);
RTLIL::State default_ret = State::S0;
@@ -437,15 +447,15 @@ struct CellTypes
return default_ret;
}
- bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
- bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
- int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1;
+ bool signed_a = cell->parameters.count(ID(A_SIGNED)) > 0 && cell->parameters[ID(A_SIGNED)].as_bool();
+ bool signed_b = cell->parameters.count(ID(B_SIGNED)) > 0 && cell->parameters[ID(B_SIGNED)].as_bool();
+ int result_len = cell->parameters.count(ID(Y_WIDTH)) > 0 ? cell->parameters[ID(Y_WIDTH)].as_int() : -1;
return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp);
}
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)
{
- if (cell->type.in("$mux", "$pmux", "$_MUX_")) {
+ if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
RTLIL::Const ret = arg1;
for (size_t i = 0; i < arg3.bits.size(); i++)
if (arg3.bits[i] == RTLIL::State::S1) {
@@ -455,9 +465,9 @@ struct CellTypes
return ret;
}
- if (cell->type == "$_AOI3_")
+ if (cell->type == ID($_AOI3_))
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1));
- if (cell->type == "$_OAI3_")
+ if (cell->type == ID($_OAI3_))
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1));
log_assert(arg3.bits.size() == 0);
@@ -466,9 +476,9 @@ struct CellTypes
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr)
{
- if (cell->type == "$_AOI4_")
+ if (cell->type == ID($_AOI4_))
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
- if (cell->type == "$_OAI4_")
+ if (cell->type == ID($_OAI4_))
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1));
log_assert(arg4.bits.size() == 0);
@@ -482,4 +492,3 @@ extern CellTypes yosys_celltypes;
YOSYS_NAMESPACE_END
#endif
-
diff --git a/kernel/consteval.h b/kernel/consteval.h
index 154373a8d..7a83d28e7 100644
--- a/kernel/consteval.h
+++ b/kernel/consteval.h
@@ -89,12 +89,12 @@ struct ConstEval
bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef)
{
- if (cell->type == "$lcu")
+ if (cell->type == ID($lcu))
{
- RTLIL::SigSpec sig_p = cell->getPort("\\P");
- RTLIL::SigSpec sig_g = cell->getPort("\\G");
- RTLIL::SigSpec sig_ci = cell->getPort("\\CI");
- RTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort("\\CO")));
+ RTLIL::SigSpec sig_p = cell->getPort(ID(P));
+ RTLIL::SigSpec sig_g = cell->getPort(ID(G));
+ RTLIL::SigSpec sig_ci = cell->getPort(ID(CI));
+ RTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort(ID(CO))));
if (sig_co.is_fully_const())
return true;
@@ -114,8 +114,8 @@ struct ConstEval
bool carry = sig_ci.as_bool();
for (int i = 0; i < GetSize(coval); i++) {
- carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry);
- coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0;
+ carry = (sig_g[i] == State::S1) || (sig_p[i] == RTLIL::S1 && carry);
+ coval.bits[i] = carry ? State::S1 : State::S0;
}
set(sig_co, coval);
@@ -128,24 +128,24 @@ struct ConstEval
RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y;
- log_assert(cell->hasPort("\\Y"));
- sig_y = values_map(assign_map(cell->getPort("\\Y")));
+ log_assert(cell->hasPort(ID::Y));
+ sig_y = values_map(assign_map(cell->getPort(ID::Y)));
if (sig_y.is_fully_const())
return true;
- if (cell->hasPort("\\S")) {
- sig_s = cell->getPort("\\S");
+ if (cell->hasPort(ID(S))) {
+ sig_s = cell->getPort(ID(S));
if (!eval(sig_s, undef, cell))
return false;
}
- if (cell->hasPort("\\A"))
- sig_a = cell->getPort("\\A");
+ if (cell->hasPort(ID::A))
+ sig_a = cell->getPort(ID::A);
- if (cell->hasPort("\\B"))
- sig_b = cell->getPort("\\B");
+ if (cell->hasPort(ID::B))
+ sig_b = cell->getPort(ID::B);
- if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_")
+ if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_NMUX_)))
{
std::vector<RTLIL::SigSpec> y_candidates;
int count_maybe_set_s_bits = 0;
@@ -175,7 +175,10 @@ struct ConstEval
for (auto &yc : y_candidates) {
if (!eval(yc, undef, cell))
return false;
- y_values.push_back(yc.as_const());
+ if (cell->type == ID($_NMUX_))
+ y_values.push_back(RTLIL::const_not(yc.as_const(), Const(), false, false, GetSize(yc)));
+ else
+ y_values.push_back(yc.as_const());
}
if (y_values.size() > 1)
@@ -195,10 +198,10 @@ struct ConstEval
else
set(sig_y, y_values.front());
}
- else if (cell->type == "$fa")
+ else if (cell->type == ID($fa))
{
- RTLIL::SigSpec sig_c = cell->getPort("\\C");
- RTLIL::SigSpec sig_x = cell->getPort("\\X");
+ RTLIL::SigSpec sig_c = cell->getPort(ID(C));
+ RTLIL::SigSpec sig_x = cell->getPort(ID(X));
int width = GetSize(sig_c);
if (!eval(sig_a, undef, cell))
@@ -224,13 +227,13 @@ struct ConstEval
set(sig_y, val_y);
set(sig_x, val_x);
}
- else if (cell->type == "$alu")
+ else if (cell->type == ID($alu))
{
- bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
- bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
+ bool signed_a = cell->parameters.count(ID(A_SIGNED)) > 0 && cell->parameters[ID(A_SIGNED)].as_bool();
+ bool signed_b = cell->parameters.count(ID(B_SIGNED)) > 0 && cell->parameters[ID(B_SIGNED)].as_bool();
- RTLIL::SigSpec sig_ci = cell->getPort("\\CI");
- RTLIL::SigSpec sig_bi = cell->getPort("\\BI");
+ RTLIL::SigSpec sig_ci = cell->getPort(ID(CI));
+ RTLIL::SigSpec sig_bi = cell->getPort(ID(BI));
if (!eval(sig_a, undef, cell))
return false;
@@ -244,15 +247,15 @@ struct ConstEval
if (!eval(sig_bi, undef, cell))
return false;
- RTLIL::SigSpec sig_x = cell->getPort("\\X");
- RTLIL::SigSpec sig_co = cell->getPort("\\CO");
+ RTLIL::SigSpec sig_x = cell->getPort(ID(X));
+ RTLIL::SigSpec sig_co = cell->getPort(ID(CO));
bool any_input_undef = !(sig_a.is_fully_def() && sig_b.is_fully_def() && sig_ci.is_fully_def() && sig_bi.is_fully_def());
sig_a.extend_u0(GetSize(sig_y), signed_a);
sig_b.extend_u0(GetSize(sig_y), signed_b);
- bool carry = sig_ci[0] == RTLIL::S1;
- bool b_inv = sig_bi[0] == RTLIL::S1;
+ bool carry = sig_ci[0] == State::S1;
+ bool b_inv = sig_bi[0] == State::S1;
for (int i = 0; i < GetSize(sig_y); i++)
{
@@ -261,26 +264,26 @@ struct ConstEval
if (!x_inputs.is_fully_def()) {
set(sig_x[i], RTLIL::Sx);
} else {
- bool bit_a = sig_a[i] == RTLIL::S1;
- bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv;
+ bool bit_a = sig_a[i] == State::S1;
+ bool bit_b = (sig_b[i] == State::S1) != b_inv;
bool bit_x = bit_a != bit_b;
- set(sig_x[i], bit_x ? RTLIL::S1 : RTLIL::S0);
+ set(sig_x[i], bit_x ? State::S1 : State::S0);
}
if (any_input_undef) {
set(sig_y[i], RTLIL::Sx);
set(sig_co[i], RTLIL::Sx);
} else {
- bool bit_a = sig_a[i] == RTLIL::S1;
- bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv;
+ bool bit_a = sig_a[i] == State::S1;
+ bool bit_b = (sig_b[i] == State::S1) != b_inv;
bool bit_y = (bit_a != bit_b) != carry;
carry = (bit_a && bit_b) || (bit_a && carry) || (bit_b && carry);
- set(sig_y[i], bit_y ? RTLIL::S1 : RTLIL::S0);
- set(sig_co[i], carry ? RTLIL::S1 : RTLIL::S0);
+ set(sig_y[i], bit_y ? State::S1 : State::S0);
+ set(sig_co[i], carry ? State::S1 : State::S0);
}
}
}
- else if (cell->type == "$macc")
+ else if (cell->type == ID($macc))
{
Macc macc;
macc.from_cell(cell);
@@ -295,21 +298,21 @@ struct ConstEval
return false;
}
- RTLIL::Const result(0, GetSize(cell->getPort("\\Y")));
+ RTLIL::Const result(0, GetSize(cell->getPort(ID::Y)));
if (!macc.eval(result))
log_abort();
- set(cell->getPort("\\Y"), result);
+ set(cell->getPort(ID::Y), result);
}
else
{
RTLIL::SigSpec sig_c, sig_d;
- if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) {
- if (cell->hasPort("\\C"))
- sig_c = cell->getPort("\\C");
- if (cell->hasPort("\\D"))
- sig_d = cell->getPort("\\D");
+ if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) {
+ if (cell->hasPort(ID(C)))
+ sig_c = cell->getPort(ID(C));
+ if (cell->hasPort(ID(D)))
+ sig_d = cell->getPort(ID(D));
}
if (sig_a.size() > 0 && !eval(sig_a, undef, cell))
diff --git a/kernel/cost.h b/kernel/cost.h
index 41a09eb63..ea2a4c1f0 100644
--- a/kernel/cost.h
+++ b/kernel/cost.h
@@ -24,62 +24,92 @@
YOSYS_NAMESPACE_BEGIN
-int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr);
-
-inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
- RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr)
+struct CellCosts
{
- static dict<RTLIL::IdString, int> gate_cost = {
- { "$_BUF_", 1 },
- { "$_NOT_", 2 },
- { "$_AND_", 4 },
- { "$_NAND_", 4 },
- { "$_OR_", 4 },
- { "$_NOR_", 4 },
- { "$_ANDNOT_", 4 },
- { "$_ORNOT_", 4 },
- { "$_XOR_", 8 },
- { "$_XNOR_", 8 },
- { "$_AOI3_", 6 },
- { "$_OAI3_", 6 },
- { "$_AOI4_", 8 },
- { "$_OAI4_", 8 },
- { "$_MUX_", 4 }
- };
-
- if (gate_cost.count(type))
- return gate_cost.at(type);
-
- if (parameters.empty() && design && design->module(type))
+ static const dict<RTLIL::IdString, int>& default_gate_cost() {
+ static const dict<RTLIL::IdString, int> db = {
+ { ID($_BUF_), 1 },
+ { ID($_NOT_), 2 },
+ { ID($_AND_), 4 },
+ { ID($_NAND_), 4 },
+ { ID($_OR_), 4 },
+ { ID($_NOR_), 4 },
+ { ID($_ANDNOT_), 4 },
+ { ID($_ORNOT_), 4 },
+ { ID($_XOR_), 5 },
+ { ID($_XNOR_), 5 },
+ { ID($_AOI3_), 6 },
+ { ID($_OAI3_), 6 },
+ { ID($_AOI4_), 7 },
+ { ID($_OAI4_), 7 },
+ { ID($_MUX_), 4 },
+ { ID($_NMUX_), 4 }
+ };
+ return db;
+ }
+
+ static const dict<RTLIL::IdString, int>& cmos_gate_cost() {
+ static const dict<RTLIL::IdString, int> db = {
+ { ID($_BUF_), 1 },
+ { ID($_NOT_), 2 },
+ { ID($_AND_), 6 },
+ { ID($_NAND_), 4 },
+ { ID($_OR_), 6 },
+ { ID($_NOR_), 4 },
+ { ID($_ANDNOT_), 6 },
+ { ID($_ORNOT_), 6 },
+ { ID($_XOR_), 12 },
+ { ID($_XNOR_), 12 },
+ { ID($_AOI3_), 6 },
+ { ID($_OAI3_), 6 },
+ { ID($_AOI4_), 8 },
+ { ID($_OAI4_), 8 },
+ { ID($_MUX_), 12 },
+ { ID($_NMUX_), 10 }
+ };
+ return db;
+ }
+
+ dict<RTLIL::IdString, int> mod_cost_cache;
+ const dict<RTLIL::IdString, int> *gate_cost = nullptr;
+ Design *design = nullptr;
+
+ int get(RTLIL::IdString type) const
{
- RTLIL::Module *mod = design->module(type);
+ if (gate_cost && gate_cost->count(type))
+ return gate_cost->at(type);
- if (mod->attributes.count("\\cost"))
- return mod->attributes.at("\\cost").as_int();
+ log_warning("Can't determine cost of %s cell.\n", log_id(type));
+ return 1;
+ }
- dict<RTLIL::IdString, int> local_mod_cost_cache;
- if (mod_cost_cache == nullptr)
- mod_cost_cache = &local_mod_cost_cache;
+ int get(RTLIL::Cell *cell)
+ {
+ if (gate_cost && gate_cost->count(cell->type))
+ return gate_cost->at(cell->type);
- if (mod_cost_cache->count(mod->name))
- return mod_cost_cache->at(mod->name);
+ if (design && design->module(cell->type) && cell->parameters.empty())
+ {
+ RTLIL::Module *mod = design->module(cell->type);
- int module_cost = 1;
- for (auto c : mod->cells())
- module_cost += get_cell_cost(c, mod_cost_cache);
+ if (mod->attributes.count(ID(cost)))
+ return mod->attributes.at(ID(cost)).as_int();
- (*mod_cost_cache)[mod->name] = module_cost;
- return module_cost;
- }
+ if (mod_cost_cache.count(mod->name))
+ return mod_cost_cache.at(mod->name);
- log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters));
- return 1;
-}
+ int module_cost = 1;
+ for (auto c : mod->cells())
+ module_cost += get(c);
-inline int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache)
-{
- return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache);
-}
+ mod_cost_cache[mod->name] = module_cost;
+ return module_cost;
+ }
+
+ log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters));
+ return 1;
+ }
+};
YOSYS_NAMESPACE_END
diff --git a/kernel/driver.cc b/kernel/driver.cc
index f273057dd..70a97c4b9 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -522,6 +522,12 @@ int main(int argc, char **argv)
if (!backend_command.empty())
run_backend(output_filename, backend_command);
+ yosys_design->check();
+ for (auto it : saved_designs)
+ it.second->check();
+ for (auto it : pushed_designs)
+ it->check();
+
if (!depsfile.empty())
{
FILE *f = fopen(depsfile.c_str(), "wt");
diff --git a/kernel/log.cc b/kernel/log.cc
index a7820950c..e0a60ca12 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -61,7 +61,7 @@ int log_force_debug = 0;
int log_debug_suppressed = 0;
vector<int> header_count;
-pool<RTLIL::IdString> log_id_cache;
+vector<char*> log_id_cache;
vector<shared_str> string_buf;
int string_buf_index = -1;
@@ -69,6 +69,13 @@ static struct timeval initial_tv = { 0, 0 };
static bool next_print_log = false;
static int log_newline_count = 0;
+static void log_id_cache_clear()
+{
+ for (auto p : log_id_cache)
+ free(p);
+ log_id_cache.clear();
+}
+
#if defined(_WIN32) && !defined(__MINGW32__)
// this will get time information and return it in timeval, simulating gettimeofday()
int gettimeofday(struct timeval *tv, struct timezone *tz)
@@ -414,7 +421,7 @@ void log_push()
void log_pop()
{
header_count.pop_back();
- log_id_cache.clear();
+ log_id_cache_clear();
string_buf.clear();
string_buf_index = -1;
log_flush();
@@ -521,7 +528,7 @@ void log_reset_stack()
{
while (header_count.size() > 1)
header_count.pop_back();
- log_id_cache.clear();
+ log_id_cache_clear();
string_buf.clear();
string_buf_index = -1;
log_flush();
@@ -580,8 +587,8 @@ const char *log_const(const RTLIL::Const &value, bool autoint)
const char *log_id(RTLIL::IdString str)
{
- log_id_cache.insert(str);
- const char *p = str.c_str();
+ log_id_cache.push_back(strdup(str.c_str()));
+ const char *p = log_id_cache.back();
if (p[0] != '\\')
return p;
if (p[1] == '$' || p[1] == '\\' || p[1] == 0)
diff --git a/kernel/log.h b/kernel/log.h
index 3e1facae8..5f53f533a 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -91,7 +91,7 @@ YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(prin
static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; }
# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
#else
-static inline bool ys_debug(int n = 0) { return false; }
+static inline bool ys_debug(int = 0) { return false; }
# define log_debug(_fmt, ...) do { } while (0)
#endif
diff --git a/kernel/macc.h b/kernel/macc.h
index 286ce567f..371f6737d 100644
--- a/kernel/macc.h
+++ b/kernel/macc.h
@@ -70,9 +70,9 @@ struct Macc
while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == port.in_b[GetSize(port.in_b)-2])
port.in_b.remove(GetSize(port.in_b)-1);
} else {
- while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == RTLIL::S0)
+ while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == State::S0)
port.in_a.remove(GetSize(port.in_a)-1);
- while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == RTLIL::S0)
+ while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == State::S0)
port.in_b.remove(GetSize(port.in_b)-1);
}
@@ -80,9 +80,9 @@ struct Macc
}
for (auto &bit : bit_ports)
- if (bit == RTLIL::S1)
+ if (bit == State::S1)
off = const_add(off, RTLIL::Const(1, width), false, false, width);
- else if (bit != RTLIL::S0)
+ else if (bit != State::S0)
new_bit_ports.append(bit);
if (off.as_bool()) {
@@ -99,24 +99,24 @@ struct Macc
void from_cell(RTLIL::Cell *cell)
{
- RTLIL::SigSpec port_a = cell->getPort("\\A");
+ RTLIL::SigSpec port_a = cell->getPort(ID::A);
ports.clear();
- bit_ports = cell->getPort("\\B");
+ bit_ports = cell->getPort(ID::B);
- std::vector<RTLIL::State> config_bits = cell->getParam("\\CONFIG").bits;
+ std::vector<RTLIL::State> config_bits = cell->getParam(ID(CONFIG)).bits;
int config_cursor = 0;
#ifndef NDEBUG
- int config_width = cell->getParam("\\CONFIG_WIDTH").as_int();
+ int config_width = cell->getParam(ID(CONFIG_WIDTH)).as_int();
log_assert(GetSize(config_bits) >= config_width);
#endif
int num_bits = 0;
- if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 1;
- if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 2;
- if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 4;
- if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 8;
+ if (config_bits[config_cursor++] == State::S1) num_bits |= 1;
+ if (config_bits[config_cursor++] == State::S1) num_bits |= 2;
+ if (config_bits[config_cursor++] == State::S1) num_bits |= 4;
+ if (config_bits[config_cursor++] == State::S1) num_bits |= 8;
int port_a_cursor = 0;
while (port_a_cursor < GetSize(port_a))
@@ -124,12 +124,12 @@ struct Macc
log_assert(config_cursor + 2 + 2*num_bits <= config_width);
port_t this_port;
- this_port.is_signed = config_bits[config_cursor++] == RTLIL::S1;
- this_port.do_subtract = config_bits[config_cursor++] == RTLIL::S1;
+ this_port.is_signed = config_bits[config_cursor++] == State::S1;
+ this_port.do_subtract = config_bits[config_cursor++] == State::S1;
int size_a = 0;
for (int i = 0; i < num_bits; i++)
- if (config_bits[config_cursor++] == RTLIL::S1)
+ if (config_bits[config_cursor++] == State::S1)
size_a |= 1 << i;
this_port.in_a = port_a.extract(port_a_cursor, size_a);
@@ -137,7 +137,7 @@ struct Macc
int size_b = 0;
for (int i = 0; i < num_bits; i++)
- if (config_bits[config_cursor++] == RTLIL::S1)
+ if (config_bits[config_cursor++] == State::S1)
size_b |= 1 << i;
this_port.in_b = port_a.extract(port_a_cursor, size_b);
@@ -166,43 +166,43 @@ struct Macc
num_bits++, max_size /= 2;
log_assert(num_bits < 16);
- config_bits.push_back(num_bits & 1 ? RTLIL::S1 : RTLIL::S0);
- config_bits.push_back(num_bits & 2 ? RTLIL::S1 : RTLIL::S0);
- config_bits.push_back(num_bits & 4 ? RTLIL::S1 : RTLIL::S0);
- config_bits.push_back(num_bits & 8 ? RTLIL::S1 : RTLIL::S0);
+ config_bits.push_back(num_bits & 1 ? State::S1 : State::S0);
+ config_bits.push_back(num_bits & 2 ? State::S1 : State::S0);
+ config_bits.push_back(num_bits & 4 ? State::S1 : State::S0);
+ config_bits.push_back(num_bits & 8 ? State::S1 : State::S0);
for (auto &port : ports)
{
if (GetSize(port.in_a) == 0)
continue;
- config_bits.push_back(port.is_signed ? RTLIL::S1 : RTLIL::S0);
- config_bits.push_back(port.do_subtract ? RTLIL::S1 : RTLIL::S0);
+ config_bits.push_back(port.is_signed ? State::S1 : State::S0);
+ config_bits.push_back(port.do_subtract ? State::S1 : State::S0);
int size_a = GetSize(port.in_a);
for (int i = 0; i < num_bits; i++)
- config_bits.push_back(size_a & (1 << i) ? RTLIL::S1 : RTLIL::S0);
+ config_bits.push_back(size_a & (1 << i) ? State::S1 : State::S0);
int size_b = GetSize(port.in_b);
for (int i = 0; i < num_bits; i++)
- config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::S0);
+ config_bits.push_back(size_b & (1 << i) ? State::S1 : State::S0);
port_a.append(port.in_a);
port_a.append(port.in_b);
}
- cell->setPort("\\A", port_a);
- cell->setPort("\\B", bit_ports);
- cell->setParam("\\CONFIG", config_bits);
- cell->setParam("\\CONFIG_WIDTH", GetSize(config_bits));
- cell->setParam("\\A_WIDTH", GetSize(port_a));
- cell->setParam("\\B_WIDTH", GetSize(bit_ports));
+ cell->setPort(ID::A, port_a);
+ cell->setPort(ID::B, bit_ports);
+ cell->setParam(ID(CONFIG), config_bits);
+ cell->setParam(ID(CONFIG_WIDTH), GetSize(config_bits));
+ cell->setParam(ID(A_WIDTH), GetSize(port_a));
+ cell->setParam(ID(B_WIDTH), GetSize(bit_ports));
}
bool eval(RTLIL::Const &result) const
{
for (auto &bit : result.bits)
- bit = RTLIL::S0;
+ bit = State::S0;
for (auto &port : ports)
{
diff --git a/kernel/register.cc b/kernel/register.cc
index 71eb6b187..1fd1bad1d 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -25,6 +25,65 @@
#include <stdio.h>
#include <errno.h>
+#ifdef YOSYS_ENABLE_ZLIB
+#include <zlib.h>
+
+PRIVATE_NAMESPACE_BEGIN
+#define GZ_BUFFER_SIZE 8192
+void decompress_gzip(const std::string &filename, std::stringstream &out)
+{
+ char buffer[GZ_BUFFER_SIZE];
+ int bytes_read;
+ gzFile gzf = gzopen(filename.c_str(), "rb");
+ while(!gzeof(gzf)) {
+ bytes_read = gzread(gzf, reinterpret_cast<void *>(buffer), GZ_BUFFER_SIZE);
+ out.write(buffer, bytes_read);
+ }
+ gzclose(gzf);
+}
+
+/*
+An output stream that uses a stringbuf to buffer data internally,
+using zlib to write gzip-compressed data every time the stream is flushed.
+*/
+class gzip_ostream : public std::ostream {
+public:
+ gzip_ostream()
+ {
+ rdbuf(&outbuf);
+ }
+ bool open(const std::string &filename)
+ {
+ return outbuf.open(filename);
+ }
+private:
+ class gzip_streambuf : public std::stringbuf {
+ public:
+ gzip_streambuf() { };
+ bool open(const std::string &filename)
+ {
+ gzf = gzopen(filename.c_str(), "wb");
+ return gzf != nullptr;
+ }
+ virtual int sync() override
+ {
+ gzwrite(gzf, reinterpret_cast<const void *>(str().c_str()), unsigned(str().size()));
+ str("");
+ return 0;
+ }
+ ~gzip_streambuf()
+ {
+ sync();
+ gzclose(gzf);
+ }
+ private:
+ gzFile gzf = nullptr;
+ } outbuf;
+};
+PRIVATE_NAMESPACE_END
+
+#endif
+
YOSYS_NAMESPACE_BEGIN
#define MAX_REG_COUNT 1000
@@ -141,7 +200,7 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig
{
std::string arg = args[argidx];
- if (arg.substr(0, 1) == "-")
+ if (arg.compare(0, 1, "-") == 0)
cmd_error(args, argidx, "Unknown option or option in arguments.");
if (!select)
@@ -236,8 +295,6 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
pass_register[args[0]]->post_execute(state);
while (design->selection_stack.size() > orig_sel_stack_pos)
design->selection_stack.pop_back();
-
- design->check();
}
void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command)
@@ -319,8 +376,10 @@ void ScriptPass::run(std::string command, std::string info)
log(" %s\n", command.c_str());
else
log(" %s %s\n", command.c_str(), info.c_str());
- } else
+ } else {
Pass::call(active_design, command);
+ active_design->check();
+ }
}
void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to)
@@ -390,7 +449,7 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
{
std::string arg = args[argidx];
- if (arg.substr(0, 1) == "-")
+ if (arg.compare(0, 1, "-") == 0)
cmd_error(args, argidx, "Unknown option or option in arguments.");
if (f != NULL)
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
@@ -398,7 +457,7 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
filename = arg;
if (filename == "<<" && argidx+1 < args.size())
filename += args[++argidx];
- if (filename.substr(0, 2) == "<<") {
+ if (filename.compare(0, 2, "<<") == 0) {
if (Frontend::current_script_file == NULL)
log_error("Unexpected here document '%s' outside of script!\n", filename.c_str());
if (filename.size() <= 2)
@@ -416,7 +475,7 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
break;
}
size_t indent = buffer.find_first_not_of(" \t\r\n");
- if (indent != std::string::npos && buffer.substr(indent, eot_marker.size()) == eot_marker)
+ if (indent != std::string::npos && buffer.compare(indent, eot_marker.size(), eot_marker) == 0)
break;
last_here_document += buffer;
}
@@ -436,12 +495,34 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
delete ff;
else
f = ff;
+ if (f != NULL) {
+ // Check for gzip magic
+ unsigned char magic[3];
+ int n = readsome(*ff, reinterpret_cast<char*>(magic), 3);
+ if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) {
+ #ifdef YOSYS_ENABLE_ZLIB
+ log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str());
+ if (magic[2] != 8)
+ log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n",
+ filename.c_str(), unsigned(magic[2]));
+ delete ff;
+ std::stringstream *df = new std::stringstream();
+ decompress_gzip(filename, *df);
+ f = df;
+ #else
+ log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str());
+ #endif
+ } else {
+ ff->clear();
+ ff->seekg(0, std::ios::beg);
+ }
+ }
}
if (f == NULL)
log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
for (size_t i = argidx+1; i < args.size(); i++)
- if (args[i].substr(0, 1) == "-")
+ if (args[i].compare(0, 1, "-") == 0)
cmd_error(args, i, "Found option, expected arguments.");
if (argidx+1 < args.size()) {
@@ -492,8 +573,6 @@ void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string
args.push_back(filename);
frontend_register[args[0]]->execute(args, design);
}
-
- design->check();
}
Backend::Backend(std::string name, std::string short_help) :
@@ -533,7 +612,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
{
std::string arg = args[argidx];
- if (arg.substr(0, 1) == "-" && arg != "-")
+ if (arg.compare(0, 1, "-") == 0 && arg != "-")
cmd_error(args, argidx, "Unknown option or option in arguments.");
if (f != NULL)
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
@@ -545,14 +624,29 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
}
filename = arg;
- std::ofstream *ff = new std::ofstream;
- ff->open(filename.c_str(), std::ofstream::trunc);
- yosys_output_files.insert(filename);
- if (ff->fail()) {
- delete ff;
- log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ rewrite_filename(filename);
+ if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".gz") == 0) {
+#ifdef YOSYS_ENABLE_ZLIB
+ gzip_ostream *gf = new gzip_ostream;
+ if (!gf->open(filename)) {
+ delete gf;
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ }
+ yosys_output_files.insert(filename);
+ f = gf;
+#else
+ log_cmd_error("Yosys is compiled without zlib support, unable to write gzip output.\n");
+#endif
+ } else {
+ std::ofstream *ff = new std::ofstream;
+ ff->open(filename.c_str(), std::ofstream::trunc);
+ yosys_output_files.insert(filename);
+ if (ff->fail()) {
+ delete ff;
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ }
+ f = ff;
}
- f = ff;
}
if (called_with_fp)
@@ -602,8 +696,6 @@ void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string f
while (design->selection_stack.size() > orig_sel_stack_pos)
design->selection_stack.pop_back();
-
- design->check();
}
static struct CellHelpMessages {
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index a09f4a0d1..1d380135b 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -29,12 +29,23 @@
YOSYS_NAMESPACE_BEGIN
RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard;
-std::vector<int> RTLIL::IdString::global_refcount_storage_;
std::vector<char*> RTLIL::IdString::global_id_storage_;
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
+#ifndef YOSYS_NO_IDS_REFCNT
+std::vector<int> RTLIL::IdString::global_refcount_storage_;
std::vector<int> RTLIL::IdString::global_free_idx_list_;
+#endif
+#ifdef YOSYS_USE_STICKY_IDS
int RTLIL::IdString::last_created_idx_[8];
int RTLIL::IdString::last_created_idx_ptr_;
+#endif
+
+IdString RTLIL::ID::A;
+IdString RTLIL::ID::B;
+IdString RTLIL::ID::Y;
+IdString RTLIL::ID::keep;
+IdString RTLIL::ID::whitebox;
+IdString RTLIL::ID::blackbox;
RTLIL::Const::Const()
{
@@ -47,7 +58,7 @@ RTLIL::Const::Const(std::string str)
for (int i = str.size()-1; i >= 0; i--) {
unsigned char ch = str[i];
for (int j = 0; j < 8; j++) {
- bits.push_back((ch & 1) != 0 ? RTLIL::S1 : RTLIL::S0);
+ bits.push_back((ch & 1) != 0 ? State::S1 : State::S0);
ch = ch >> 1;
}
}
@@ -57,7 +68,7 @@ RTLIL::Const::Const(int val, int width)
{
flags = RTLIL::CONST_FLAG_NONE;
for (int i = 0; i < width; i++) {
- bits.push_back((val & 1) != 0 ? RTLIL::S1 : RTLIL::S0);
+ bits.push_back((val & 1) != 0 ? State::S1 : State::S0);
val = val >> 1;
}
}
@@ -73,7 +84,7 @@ RTLIL::Const::Const(const std::vector<bool> &bits)
{
flags = RTLIL::CONST_FLAG_NONE;
for (auto b : bits)
- this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0);
+ this->bits.push_back(b ? State::S1 : State::S0);
}
RTLIL::Const::Const(const RTLIL::Const &c)
@@ -106,7 +117,7 @@ bool RTLIL::Const::operator !=(const RTLIL::Const &other) const
bool RTLIL::Const::as_bool() const
{
for (size_t i = 0; i < bits.size(); i++)
- if (bits[i] == RTLIL::S1)
+ if (bits[i] == State::S1)
return true;
return false;
}
@@ -115,9 +126,9 @@ int RTLIL::Const::as_int(bool is_signed) const
{
int32_t ret = 0;
for (size_t i = 0; i < bits.size() && i < 32; i++)
- if (bits[i] == RTLIL::S1)
+ if (bits[i] == State::S1)
ret |= 1 << i;
- if (is_signed && bits.back() == RTLIL::S1)
+ if (is_signed && bits.back() == State::S1)
for (size_t i = bits.size(); i < 32; i++)
ret |= 1 << i;
return ret;
@@ -264,16 +275,16 @@ pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const
void RTLIL::AttrObject::set_src_attribute(const std::string &src)
{
if (src.empty())
- attributes.erase("\\src");
+ attributes.erase(ID(src));
else
- attributes["\\src"] = src;
+ attributes[ID(src)] = src;
}
std::string RTLIL::AttrObject::get_src_attribute() const
{
std::string src;
- if (attributes.count("\\src"))
- src = attributes.at("\\src").decode_string();
+ if (attributes.count(ID(src)))
+ src = attributes.at(ID(src)).decode_string();
return src;
}
@@ -417,7 +428,7 @@ RTLIL::Module *RTLIL::Design::top_module()
int module_count = 0;
for (auto mod : selected_modules()) {
- if (mod->get_bool_attribute("\\top"))
+ if (mod->get_bool_attribute(ID(top)))
return mod;
module_count++;
module = mod;
@@ -706,7 +717,7 @@ void RTLIL::Module::makeblackbox()
processes.clear();
remove(delwires);
- set_bool_attribute("\\blackbox");
+ set_bool_attribute(ID::blackbox);
}
void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>)
@@ -754,7 +765,7 @@ namespace {
cell->name.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str());
}
- int param(const char *name)
+ int param(RTLIL::IdString name)
{
if (cell->parameters.count(name) == 0)
error(__LINE__);
@@ -762,7 +773,7 @@ namespace {
return cell->parameters.at(name).as_int();
}
- int param_bool(const char *name)
+ int param_bool(RTLIL::IdString name)
{
int v = param(name);
if (cell->parameters.at(name).bits.size() > 32)
@@ -772,14 +783,14 @@ namespace {
return v;
}
- void param_bits(const char *name, int width)
+ void param_bits(RTLIL::IdString name, int width)
{
param(name);
if (int(cell->parameters.at(name).bits.size()) != width)
error(__LINE__);
}
- void port(const char *name, int width)
+ void port(RTLIL::IdString name, int width)
{
if (!cell->hasPort(name))
error(__LINE__);
@@ -797,9 +808,9 @@ namespace {
if (expected_ports.count(conn.first) == 0)
error(__LINE__);
- if (expected_params.count("\\A_SIGNED") != 0 && expected_params.count("\\B_SIGNED") && check_matched_sign) {
- bool a_is_signed = param("\\A_SIGNED") != 0;
- bool b_is_signed = param("\\B_SIGNED") != 0;
+ if (expected_params.count(ID(A_SIGNED)) != 0 && expected_params.count(ID(B_SIGNED)) && check_matched_sign) {
+ bool a_is_signed = param(ID(A_SIGNED)) != 0;
+ bool b_is_signed = param(ID(B_SIGNED)) != 0;
if (a_is_signed != b_is_signed)
error(__LINE__);
}
@@ -828,481 +839,482 @@ namespace {
void check()
{
- if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || cell->type.substr(0,10) == "$fmcombine" ||
- cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
+ if (!cell->type.begins_with("$") || cell->type.begins_with("$__") || cell->type.begins_with("$paramod") || cell->type.begins_with("$fmcombine") ||
+ cell->type.begins_with("$verific$") || cell->type.begins_with("$array:") || cell->type.begins_with("$extern:"))
return;
- if (cell->type.in("$not", "$pos", "$neg")) {
- param_bool("\\A_SIGNED");
- port("\\A", param("\\A_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
+ if (cell->type.in(ID($not), ID($pos), ID($neg))) {
+ param_bool(ID(A_SIGNED));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
check_expected();
return;
}
- if (cell->type.in("$and", "$or", "$xor", "$xnor")) {
- param_bool("\\A_SIGNED");
- param_bool("\\B_SIGNED");
- port("\\A", param("\\A_WIDTH"));
- port("\\B", param("\\B_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
+ if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) {
+ param_bool(ID(A_SIGNED));
+ param_bool(ID(B_SIGNED));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::B, param(ID(B_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
check_expected();
return;
}
- if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) {
- param_bool("\\A_SIGNED");
- port("\\A", param("\\A_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
+ if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool))) {
+ param_bool(ID(A_SIGNED));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
check_expected();
return;
}
- if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) {
- param_bool("\\A_SIGNED");
- param_bool("\\B_SIGNED");
- port("\\A", param("\\A_WIDTH"));
- port("\\B", param("\\B_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
+ if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) {
+ param_bool(ID(A_SIGNED));
+ param_bool(ID(B_SIGNED));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::B, param(ID(B_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
check_expected(false);
return;
}
- if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) {
- param_bool("\\A_SIGNED");
- param_bool("\\B_SIGNED");
- port("\\A", param("\\A_WIDTH"));
- port("\\B", param("\\B_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
+ if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) {
+ param_bool(ID(A_SIGNED));
+ param_bool(ID(B_SIGNED));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::B, param(ID(B_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
check_expected();
return;
}
- if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
- param_bool("\\A_SIGNED");
- param_bool("\\B_SIGNED");
- port("\\A", param("\\A_WIDTH"));
- port("\\B", param("\\B_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
- check_expected(cell->type != "$pow");
+ if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) {
+ param_bool(ID(A_SIGNED));
+ param_bool(ID(B_SIGNED));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::B, param(ID(B_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
+ check_expected(cell->type != ID($pow));
return;
}
- if (cell->type == "$fa") {
- port("\\A", param("\\WIDTH"));
- port("\\B", param("\\WIDTH"));
- port("\\C", param("\\WIDTH"));
- port("\\X", param("\\WIDTH"));
- port("\\Y", param("\\WIDTH"));
+ if (cell->type == ID($fa)) {
+ port(ID::A, param(ID(WIDTH)));
+ port(ID::B, param(ID(WIDTH)));
+ port(ID(C), param(ID(WIDTH)));
+ port(ID(X), param(ID(WIDTH)));
+ port(ID::Y, param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$lcu") {
- port("\\P", param("\\WIDTH"));
- port("\\G", param("\\WIDTH"));
- port("\\CI", 1);
- port("\\CO", param("\\WIDTH"));
+ if (cell->type == ID($lcu)) {
+ port(ID(P), param(ID(WIDTH)));
+ port(ID(G), param(ID(WIDTH)));
+ port(ID(CI), 1);
+ port(ID(CO), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$alu") {
- param_bool("\\A_SIGNED");
- param_bool("\\B_SIGNED");
- port("\\A", param("\\A_WIDTH"));
- port("\\B", param("\\B_WIDTH"));
- port("\\CI", 1);
- port("\\BI", 1);
- port("\\X", param("\\Y_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
- port("\\CO", param("\\Y_WIDTH"));
+ if (cell->type == ID($alu)) {
+ param_bool(ID(A_SIGNED));
+ param_bool(ID(B_SIGNED));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::B, param(ID(B_WIDTH)));
+ port(ID(CI), 1);
+ port(ID(BI), 1);
+ port(ID(X), param(ID(Y_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
+ port(ID(CO), param(ID(Y_WIDTH)));
check_expected();
return;
}
- if (cell->type == "$macc") {
- param("\\CONFIG");
- param("\\CONFIG_WIDTH");
- port("\\A", param("\\A_WIDTH"));
- port("\\B", param("\\B_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
+ if (cell->type == ID($macc)) {
+ param(ID(CONFIG));
+ param(ID(CONFIG_WIDTH));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::B, param(ID(B_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
check_expected();
Macc().from_cell(cell);
return;
}
- if (cell->type == "$logic_not") {
- param_bool("\\A_SIGNED");
- port("\\A", param("\\A_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
+ if (cell->type == ID($logic_not)) {
+ param_bool(ID(A_SIGNED));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
check_expected();
return;
}
- if (cell->type == "$logic_and" || cell->type == "$logic_or") {
- param_bool("\\A_SIGNED");
- param_bool("\\B_SIGNED");
- port("\\A", param("\\A_WIDTH"));
- port("\\B", param("\\B_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
+ if (cell->type.in(ID($logic_and), ID($logic_or))) {
+ param_bool(ID(A_SIGNED));
+ param_bool(ID(B_SIGNED));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::B, param(ID(B_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
check_expected(false);
return;
}
- if (cell->type == "$slice") {
- param("\\OFFSET");
- port("\\A", param("\\A_WIDTH"));
- port("\\Y", param("\\Y_WIDTH"));
- if (param("\\OFFSET") + param("\\Y_WIDTH") > param("\\A_WIDTH"))
+ if (cell->type == ID($slice)) {
+ param(ID(OFFSET));
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::Y, param(ID(Y_WIDTH)));
+ if (param(ID(OFFSET)) + param(ID(Y_WIDTH)) > param(ID(A_WIDTH)))
error(__LINE__);
check_expected();
return;
}
- if (cell->type == "$concat") {
- port("\\A", param("\\A_WIDTH"));
- port("\\B", param("\\B_WIDTH"));
- port("\\Y", param("\\A_WIDTH") + param("\\B_WIDTH"));
+ if (cell->type == ID($concat)) {
+ port(ID::A, param(ID(A_WIDTH)));
+ port(ID::B, param(ID(B_WIDTH)));
+ port(ID::Y, param(ID(A_WIDTH)) + param(ID(B_WIDTH)));
check_expected();
return;
}
- if (cell->type == "$mux") {
- port("\\A", param("\\WIDTH"));
- port("\\B", param("\\WIDTH"));
- port("\\S", 1);
- port("\\Y", param("\\WIDTH"));
+ if (cell->type == ID($mux)) {
+ port(ID::A, param(ID(WIDTH)));
+ port(ID::B, param(ID(WIDTH)));
+ port(ID(S), 1);
+ port(ID::Y, param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$pmux") {
- port("\\A", param("\\WIDTH"));
- port("\\B", param("\\WIDTH") * param("\\S_WIDTH"));
- port("\\S", param("\\S_WIDTH"));
- port("\\Y", param("\\WIDTH"));
+ if (cell->type == ID($pmux)) {
+ port(ID::A, param(ID(WIDTH)));
+ port(ID::B, param(ID(WIDTH)) * param(ID(S_WIDTH)));
+ port(ID(S), param(ID(S_WIDTH)));
+ port(ID::Y, param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$lut") {
- param("\\LUT");
- port("\\A", param("\\WIDTH"));
- port("\\Y", 1);
+ if (cell->type == ID($lut)) {
+ param(ID(LUT));
+ port(ID::A, param(ID(WIDTH)));
+ port(ID::Y, 1);
check_expected();
return;
}
- if (cell->type == "$sop") {
- param("\\DEPTH");
- param("\\TABLE");
- port("\\A", param("\\WIDTH"));
- port("\\Y", 1);
+ if (cell->type == ID($sop)) {
+ param(ID(DEPTH));
+ param(ID(TABLE));
+ port(ID::A, param(ID(WIDTH)));
+ port(ID::Y, 1);
check_expected();
return;
}
- if (cell->type == "$sr") {
- param_bool("\\SET_POLARITY");
- param_bool("\\CLR_POLARITY");
- port("\\SET", param("\\WIDTH"));
- port("\\CLR", param("\\WIDTH"));
- port("\\Q", param("\\WIDTH"));
+ if (cell->type == ID($sr)) {
+ param_bool(ID(SET_POLARITY));
+ param_bool(ID(CLR_POLARITY));
+ port(ID(SET), param(ID(WIDTH)));
+ port(ID(CLR), param(ID(WIDTH)));
+ port(ID(Q), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$ff") {
- port("\\D", param("\\WIDTH"));
- port("\\Q", param("\\WIDTH"));
+ if (cell->type == ID($ff)) {
+ port(ID(D), param(ID(WIDTH)));
+ port(ID(Q), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$dff") {
- param_bool("\\CLK_POLARITY");
- port("\\CLK", 1);
- port("\\D", param("\\WIDTH"));
- port("\\Q", param("\\WIDTH"));
+ if (cell->type == ID($dff)) {
+ param_bool(ID(CLK_POLARITY));
+ port(ID(CLK), 1);
+ port(ID(D), param(ID(WIDTH)));
+ port(ID(Q), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$dffe") {
- param_bool("\\CLK_POLARITY");
- param_bool("\\EN_POLARITY");
- port("\\CLK", 1);
- port("\\EN", 1);
- port("\\D", param("\\WIDTH"));
- port("\\Q", param("\\WIDTH"));
+ if (cell->type == ID($dffe)) {
+ param_bool(ID(CLK_POLARITY));
+ param_bool(ID(EN_POLARITY));
+ port(ID(CLK), 1);
+ port(ID(EN), 1);
+ port(ID(D), param(ID(WIDTH)));
+ port(ID(Q), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$dffsr") {
- param_bool("\\CLK_POLARITY");
- param_bool("\\SET_POLARITY");
- param_bool("\\CLR_POLARITY");
- port("\\CLK", 1);
- port("\\SET", param("\\WIDTH"));
- port("\\CLR", param("\\WIDTH"));
- port("\\D", param("\\WIDTH"));
- port("\\Q", param("\\WIDTH"));
+ if (cell->type == ID($dffsr)) {
+ param_bool(ID(CLK_POLARITY));
+ param_bool(ID(SET_POLARITY));
+ param_bool(ID(CLR_POLARITY));
+ port(ID(CLK), 1);
+ port(ID(SET), param(ID(WIDTH)));
+ port(ID(CLR), param(ID(WIDTH)));
+ port(ID(D), param(ID(WIDTH)));
+ port(ID(Q), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$adff") {
- param_bool("\\CLK_POLARITY");
- param_bool("\\ARST_POLARITY");
- param_bits("\\ARST_VALUE", param("\\WIDTH"));
- port("\\CLK", 1);
- port("\\ARST", 1);
- port("\\D", param("\\WIDTH"));
- port("\\Q", param("\\WIDTH"));
+ if (cell->type == ID($adff)) {
+ param_bool(ID(CLK_POLARITY));
+ param_bool(ID(ARST_POLARITY));
+ param_bits(ID(ARST_VALUE), param(ID(WIDTH)));
+ port(ID(CLK), 1);
+ port(ID(ARST), 1);
+ port(ID(D), param(ID(WIDTH)));
+ port(ID(Q), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$dlatch") {
- param_bool("\\EN_POLARITY");
- port("\\EN", 1);
- port("\\D", param("\\WIDTH"));
- port("\\Q", param("\\WIDTH"));
+ if (cell->type == ID($dlatch)) {
+ param_bool(ID(EN_POLARITY));
+ port(ID(EN), 1);
+ port(ID(D), param(ID(WIDTH)));
+ port(ID(Q), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$dlatchsr") {
- param_bool("\\EN_POLARITY");
- param_bool("\\SET_POLARITY");
- param_bool("\\CLR_POLARITY");
- port("\\EN", 1);
- port("\\SET", param("\\WIDTH"));
- port("\\CLR", param("\\WIDTH"));
- port("\\D", param("\\WIDTH"));
- port("\\Q", param("\\WIDTH"));
+ if (cell->type == ID($dlatchsr)) {
+ param_bool(ID(EN_POLARITY));
+ param_bool(ID(SET_POLARITY));
+ param_bool(ID(CLR_POLARITY));
+ port(ID(EN), 1);
+ port(ID(SET), param(ID(WIDTH)));
+ port(ID(CLR), param(ID(WIDTH)));
+ port(ID(D), param(ID(WIDTH)));
+ port(ID(Q), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$fsm") {
- param("\\NAME");
- param_bool("\\CLK_POLARITY");
- param_bool("\\ARST_POLARITY");
- param("\\STATE_BITS");
- param("\\STATE_NUM");
- param("\\STATE_NUM_LOG2");
- param("\\STATE_RST");
- param_bits("\\STATE_TABLE", param("\\STATE_BITS") * param("\\STATE_NUM"));
- param("\\TRANS_NUM");
- param_bits("\\TRANS_TABLE", param("\\TRANS_NUM") * (2*param("\\STATE_NUM_LOG2") + param("\\CTRL_IN_WIDTH") + param("\\CTRL_OUT_WIDTH")));
- port("\\CLK", 1);
- port("\\ARST", 1);
- port("\\CTRL_IN", param("\\CTRL_IN_WIDTH"));
- port("\\CTRL_OUT", param("\\CTRL_OUT_WIDTH"));
+ if (cell->type == ID($fsm)) {
+ param(ID(NAME));
+ param_bool(ID(CLK_POLARITY));
+ param_bool(ID(ARST_POLARITY));
+ param(ID(STATE_BITS));
+ param(ID(STATE_NUM));
+ param(ID(STATE_NUM_LOG2));
+ param(ID(STATE_RST));
+ param_bits(ID(STATE_TABLE), param(ID(STATE_BITS)) * param(ID(STATE_NUM)));
+ param(ID(TRANS_NUM));
+ param_bits(ID(TRANS_TABLE), param(ID(TRANS_NUM)) * (2*param(ID(STATE_NUM_LOG2)) + param(ID(CTRL_IN_WIDTH)) + param(ID(CTRL_OUT_WIDTH))));
+ port(ID(CLK), 1);
+ port(ID(ARST), 1);
+ port(ID(CTRL_IN), param(ID(CTRL_IN_WIDTH)));
+ port(ID(CTRL_OUT), param(ID(CTRL_OUT_WIDTH)));
check_expected();
return;
}
- if (cell->type == "$memrd") {
- param("\\MEMID");
- param_bool("\\CLK_ENABLE");
- param_bool("\\CLK_POLARITY");
- param_bool("\\TRANSPARENT");
- port("\\CLK", 1);
- port("\\EN", 1);
- port("\\ADDR", param("\\ABITS"));
- port("\\DATA", param("\\WIDTH"));
+ if (cell->type == ID($memrd)) {
+ param(ID(MEMID));
+ param_bool(ID(CLK_ENABLE));
+ param_bool(ID(CLK_POLARITY));
+ param_bool(ID(TRANSPARENT));
+ port(ID(CLK), 1);
+ port(ID(EN), 1);
+ port(ID(ADDR), param(ID(ABITS)));
+ port(ID(DATA), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$memwr") {
- param("\\MEMID");
- param_bool("\\CLK_ENABLE");
- param_bool("\\CLK_POLARITY");
- param("\\PRIORITY");
- port("\\CLK", 1);
- port("\\EN", param("\\WIDTH"));
- port("\\ADDR", param("\\ABITS"));
- port("\\DATA", param("\\WIDTH"));
+ if (cell->type == ID($memwr)) {
+ param(ID(MEMID));
+ param_bool(ID(CLK_ENABLE));
+ param_bool(ID(CLK_POLARITY));
+ param(ID(PRIORITY));
+ port(ID(CLK), 1);
+ port(ID(EN), param(ID(WIDTH)));
+ port(ID(ADDR), param(ID(ABITS)));
+ port(ID(DATA), param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$meminit") {
- param("\\MEMID");
- param("\\PRIORITY");
- port("\\ADDR", param("\\ABITS"));
- port("\\DATA", param("\\WIDTH") * param("\\WORDS"));
+ if (cell->type == ID($meminit)) {
+ param(ID(MEMID));
+ param(ID(PRIORITY));
+ port(ID(ADDR), param(ID(ABITS)));
+ port(ID(DATA), param(ID(WIDTH)) * param(ID(WORDS)));
check_expected();
return;
}
- if (cell->type == "$mem") {
- param("\\MEMID");
- param("\\SIZE");
- param("\\OFFSET");
- param("\\INIT");
- 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"));
- port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH"));
- port("\\WR_CLK", param("\\WR_PORTS"));
- port("\\WR_EN", param("\\WR_PORTS") * param("\\WIDTH"));
- port("\\WR_ADDR", param("\\WR_PORTS") * param("\\ABITS"));
- port("\\WR_DATA", param("\\WR_PORTS") * param("\\WIDTH"));
+ if (cell->type == ID($mem)) {
+ param(ID(MEMID));
+ param(ID(SIZE));
+ param(ID(OFFSET));
+ param(ID(INIT));
+ param_bits(ID(RD_CLK_ENABLE), max(1, param(ID(RD_PORTS))));
+ param_bits(ID(RD_CLK_POLARITY), max(1, param(ID(RD_PORTS))));
+ param_bits(ID(RD_TRANSPARENT), max(1, param(ID(RD_PORTS))));
+ param_bits(ID(WR_CLK_ENABLE), max(1, param(ID(WR_PORTS))));
+ param_bits(ID(WR_CLK_POLARITY), max(1, param(ID(WR_PORTS))));
+ port(ID(RD_CLK), param(ID(RD_PORTS)));
+ port(ID(RD_EN), param(ID(RD_PORTS)));
+ port(ID(RD_ADDR), param(ID(RD_PORTS)) * param(ID(ABITS)));
+ port(ID(RD_DATA), param(ID(RD_PORTS)) * param(ID(WIDTH)));
+ port(ID(WR_CLK), param(ID(WR_PORTS)));
+ port(ID(WR_EN), param(ID(WR_PORTS)) * param(ID(WIDTH)));
+ port(ID(WR_ADDR), param(ID(WR_PORTS)) * param(ID(ABITS)));
+ port(ID(WR_DATA), param(ID(WR_PORTS)) * param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$tribuf") {
- port("\\A", param("\\WIDTH"));
- port("\\Y", param("\\WIDTH"));
- port("\\EN", 1);
+ if (cell->type == ID($tribuf)) {
+ port(ID::A, param(ID(WIDTH)));
+ port(ID::Y, param(ID(WIDTH)));
+ port(ID(EN), 1);
check_expected();
return;
}
- if (cell->type.in("$assert", "$assume", "$live", "$fair", "$cover")) {
- port("\\A", 1);
- port("\\EN", 1);
+ if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) {
+ port(ID::A, 1);
+ port(ID(EN), 1);
check_expected();
return;
}
- if (cell->type == "$initstate") {
- port("\\Y", 1);
+ if (cell->type == ID($initstate)) {
+ port(ID::Y, 1);
check_expected();
return;
}
- if (cell->type.in("$anyconst", "$anyseq", "$allconst", "$allseq")) {
- port("\\Y", param("\\WIDTH"));
+ if (cell->type.in(ID($anyconst), ID($anyseq), ID($allconst), ID($allseq))) {
+ port(ID::Y, param(ID(WIDTH)));
check_expected();
return;
}
- if (cell->type == "$equiv") {
- port("\\A", 1);
- port("\\B", 1);
- port("\\Y", 1);
+ if (cell->type == ID($equiv)) {
+ port(ID::A, 1);
+ port(ID::B, 1);
+ port(ID::Y, 1);
check_expected();
return;
}
- if (cell->type.in("$specify2", "$specify3")) {
- param_bool("\\FULL");
- param_bool("\\SRC_DST_PEN");
- param_bool("\\SRC_DST_POL");
- param("\\T_RISE_MIN");
- param("\\T_RISE_TYP");
- param("\\T_RISE_MAX");
- param("\\T_FALL_MIN");
- param("\\T_FALL_TYP");
- param("\\T_FALL_MAX");
- port("\\EN", 1);
- port("\\SRC", param("\\SRC_WIDTH"));
- port("\\DST", param("\\DST_WIDTH"));
- if (cell->type == "$specify3") {
- param_bool("\\EDGE_EN");
- param_bool("\\EDGE_POL");
- param_bool("\\DAT_DST_PEN");
- param_bool("\\DAT_DST_POL");
- port("\\DAT", param("\\DST_WIDTH"));
+ if (cell->type.in(ID($specify2), ID($specify3))) {
+ param_bool(ID(FULL));
+ param_bool(ID(SRC_DST_PEN));
+ param_bool(ID(SRC_DST_POL));
+ param(ID(T_RISE_MIN));
+ param(ID(T_RISE_TYP));
+ param(ID(T_RISE_MAX));
+ param(ID(T_FALL_MIN));
+ param(ID(T_FALL_TYP));
+ param(ID(T_FALL_MAX));
+ port(ID(EN), 1);
+ port(ID(SRC), param(ID(SRC_WIDTH)));
+ port(ID(DST), param(ID(DST_WIDTH)));
+ if (cell->type == ID($specify3)) {
+ param_bool(ID(EDGE_EN));
+ param_bool(ID(EDGE_POL));
+ param_bool(ID(DAT_DST_PEN));
+ param_bool(ID(DAT_DST_POL));
+ port(ID(DAT), param(ID(DST_WIDTH)));
}
check_expected();
return;
}
- if (cell->type == "$specrule") {
- param("\\TYPE");
- param_bool("\\SRC_PEN");
- param_bool("\\SRC_POL");
- param_bool("\\DST_PEN");
- param_bool("\\DST_POL");
- param("\\T_LIMIT");
- param("\\T_LIMIT2");
- port("\\SRC_EN", 1);
- port("\\DST_EN", 1);
- port("\\SRC", param("\\SRC_WIDTH"));
- port("\\DST", param("\\DST_WIDTH"));
+ if (cell->type == ID($specrule)) {
+ param(ID(TYPE));
+ param_bool(ID(SRC_PEN));
+ param_bool(ID(SRC_POL));
+ param_bool(ID(DST_PEN));
+ param_bool(ID(DST_POL));
+ param(ID(T_LIMIT));
+ param(ID(T_LIMIT2));
+ port(ID(SRC_EN), 1);
+ port(ID(DST_EN), 1);
+ port(ID(SRC), param(ID(SRC_WIDTH)));
+ port(ID(DST), param(ID(DST_WIDTH)));
check_expected();
return;
}
- if (cell->type == "$_BUF_") { check_gate("AY"); return; }
- if (cell->type == "$_NOT_") { check_gate("AY"); return; }
- if (cell->type == "$_AND_") { check_gate("ABY"); return; }
- if (cell->type == "$_NAND_") { check_gate("ABY"); return; }
- if (cell->type == "$_OR_") { check_gate("ABY"); return; }
- if (cell->type == "$_NOR_") { check_gate("ABY"); return; }
- if (cell->type == "$_XOR_") { check_gate("ABY"); return; }
- if (cell->type == "$_XNOR_") { check_gate("ABY"); return; }
- if (cell->type == "$_ANDNOT_") { check_gate("ABY"); return; }
- if (cell->type == "$_ORNOT_") { check_gate("ABY"); return; }
- if (cell->type == "$_MUX_") { check_gate("ABSY"); return; }
- if (cell->type == "$_AOI3_") { check_gate("ABCY"); return; }
- if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; }
- if (cell->type == "$_AOI4_") { check_gate("ABCDY"); return; }
- if (cell->type == "$_OAI4_") { check_gate("ABCDY"); return; }
-
- if (cell->type == "$_TBUF_") { check_gate("AYE"); return; }
-
- if (cell->type == "$_MUX4_") { check_gate("ABCDSTY"); return; }
- if (cell->type == "$_MUX8_") { check_gate("ABCDEFGHSTUY"); return; }
- if (cell->type == "$_MUX16_") { check_gate("ABCDEFGHIJKLMNOPSTUVY"); return; }
-
- if (cell->type == "$_SR_NN_") { check_gate("SRQ"); return; }
- if (cell->type == "$_SR_NP_") { check_gate("SRQ"); return; }
- if (cell->type == "$_SR_PN_") { check_gate("SRQ"); return; }
- if (cell->type == "$_SR_PP_") { check_gate("SRQ"); return; }
-
- if (cell->type == "$_FF_") { check_gate("DQ"); return; }
- if (cell->type == "$_DFF_N_") { check_gate("DQC"); return; }
- if (cell->type == "$_DFF_P_") { check_gate("DQC"); return; }
-
- if (cell->type == "$_DFFE_NN_") { check_gate("DQCE"); return; }
- if (cell->type == "$_DFFE_NP_") { check_gate("DQCE"); return; }
- if (cell->type == "$_DFFE_PN_") { check_gate("DQCE"); return; }
- if (cell->type == "$_DFFE_PP_") { check_gate("DQCE"); return; }
-
- if (cell->type == "$_DFF_NN0_") { check_gate("DQCR"); return; }
- if (cell->type == "$_DFF_NN1_") { check_gate("DQCR"); return; }
- if (cell->type == "$_DFF_NP0_") { check_gate("DQCR"); return; }
- if (cell->type == "$_DFF_NP1_") { check_gate("DQCR"); return; }
- if (cell->type == "$_DFF_PN0_") { check_gate("DQCR"); return; }
- if (cell->type == "$_DFF_PN1_") { check_gate("DQCR"); return; }
- if (cell->type == "$_DFF_PP0_") { check_gate("DQCR"); return; }
- if (cell->type == "$_DFF_PP1_") { check_gate("DQCR"); return; }
-
- if (cell->type == "$_DFFSR_NNN_") { check_gate("CSRDQ"); return; }
- if (cell->type == "$_DFFSR_NNP_") { check_gate("CSRDQ"); return; }
- if (cell->type == "$_DFFSR_NPN_") { check_gate("CSRDQ"); return; }
- if (cell->type == "$_DFFSR_NPP_") { check_gate("CSRDQ"); return; }
- if (cell->type == "$_DFFSR_PNN_") { check_gate("CSRDQ"); return; }
- if (cell->type == "$_DFFSR_PNP_") { check_gate("CSRDQ"); return; }
- if (cell->type == "$_DFFSR_PPN_") { check_gate("CSRDQ"); return; }
- if (cell->type == "$_DFFSR_PPP_") { check_gate("CSRDQ"); return; }
-
- if (cell->type == "$_DLATCH_N_") { check_gate("EDQ"); return; }
- if (cell->type == "$_DLATCH_P_") { check_gate("EDQ"); return; }
-
- if (cell->type == "$_DLATCHSR_NNN_") { check_gate("ESRDQ"); return; }
- if (cell->type == "$_DLATCHSR_NNP_") { check_gate("ESRDQ"); return; }
- if (cell->type == "$_DLATCHSR_NPN_") { check_gate("ESRDQ"); return; }
- if (cell->type == "$_DLATCHSR_NPP_") { check_gate("ESRDQ"); return; }
- if (cell->type == "$_DLATCHSR_PNN_") { check_gate("ESRDQ"); return; }
- if (cell->type == "$_DLATCHSR_PNP_") { check_gate("ESRDQ"); return; }
- if (cell->type == "$_DLATCHSR_PPN_") { check_gate("ESRDQ"); return; }
- if (cell->type == "$_DLATCHSR_PPP_") { check_gate("ESRDQ"); return; }
+ if (cell->type == ID($_BUF_)) { check_gate("AY"); return; }
+ if (cell->type == ID($_NOT_)) { check_gate("AY"); return; }
+ if (cell->type == ID($_AND_)) { check_gate("ABY"); return; }
+ if (cell->type == ID($_NAND_)) { check_gate("ABY"); return; }
+ if (cell->type == ID($_OR_)) { check_gate("ABY"); return; }
+ if (cell->type == ID($_NOR_)) { check_gate("ABY"); return; }
+ if (cell->type == ID($_XOR_)) { check_gate("ABY"); return; }
+ if (cell->type == ID($_XNOR_)) { check_gate("ABY"); return; }
+ if (cell->type == ID($_ANDNOT_)) { check_gate("ABY"); return; }
+ if (cell->type == ID($_ORNOT_)) { check_gate("ABY"); return; }
+ if (cell->type == ID($_MUX_)) { check_gate("ABSY"); return; }
+ if (cell->type == ID($_NMUX_)) { check_gate("ABSY"); return; }
+ if (cell->type == ID($_AOI3_)) { check_gate("ABCY"); return; }
+ if (cell->type == ID($_OAI3_)) { check_gate("ABCY"); return; }
+ if (cell->type == ID($_AOI4_)) { check_gate("ABCDY"); return; }
+ if (cell->type == ID($_OAI4_)) { check_gate("ABCDY"); return; }
+
+ if (cell->type == ID($_TBUF_)) { check_gate("AYE"); return; }
+
+ if (cell->type == ID($_MUX4_)) { check_gate("ABCDSTY"); return; }
+ if (cell->type == ID($_MUX8_)) { check_gate("ABCDEFGHSTUY"); return; }
+ if (cell->type == ID($_MUX16_)) { check_gate("ABCDEFGHIJKLMNOPSTUVY"); return; }
+
+ if (cell->type == ID($_SR_NN_)) { check_gate("SRQ"); return; }
+ if (cell->type == ID($_SR_NP_)) { check_gate("SRQ"); return; }
+ if (cell->type == ID($_SR_PN_)) { check_gate("SRQ"); return; }
+ if (cell->type == ID($_SR_PP_)) { check_gate("SRQ"); return; }
+
+ if (cell->type == ID($_FF_)) { check_gate("DQ"); return; }
+ if (cell->type == ID($_DFF_N_)) { check_gate("DQC"); return; }
+ if (cell->type == ID($_DFF_P_)) { check_gate("DQC"); return; }
+
+ if (cell->type == ID($_DFFE_NN_)) { check_gate("DQCE"); return; }
+ if (cell->type == ID($_DFFE_NP_)) { check_gate("DQCE"); return; }
+ if (cell->type == ID($_DFFE_PN_)) { check_gate("DQCE"); return; }
+ if (cell->type == ID($_DFFE_PP_)) { check_gate("DQCE"); return; }
+
+ if (cell->type == ID($_DFF_NN0_)) { check_gate("DQCR"); return; }
+ if (cell->type == ID($_DFF_NN1_)) { check_gate("DQCR"); return; }
+ if (cell->type == ID($_DFF_NP0_)) { check_gate("DQCR"); return; }
+ if (cell->type == ID($_DFF_NP1_)) { check_gate("DQCR"); return; }
+ if (cell->type == ID($_DFF_PN0_)) { check_gate("DQCR"); return; }
+ if (cell->type == ID($_DFF_PN1_)) { check_gate("DQCR"); return; }
+ if (cell->type == ID($_DFF_PP0_)) { check_gate("DQCR"); return; }
+ if (cell->type == ID($_DFF_PP1_)) { check_gate("DQCR"); return; }
+
+ if (cell->type == ID($_DFFSR_NNN_)) { check_gate("CSRDQ"); return; }
+ if (cell->type == ID($_DFFSR_NNP_)) { check_gate("CSRDQ"); return; }
+ if (cell->type == ID($_DFFSR_NPN_)) { check_gate("CSRDQ"); return; }
+ if (cell->type == ID($_DFFSR_NPP_)) { check_gate("CSRDQ"); return; }
+ if (cell->type == ID($_DFFSR_PNN_)) { check_gate("CSRDQ"); return; }
+ if (cell->type == ID($_DFFSR_PNP_)) { check_gate("CSRDQ"); return; }
+ if (cell->type == ID($_DFFSR_PPN_)) { check_gate("CSRDQ"); return; }
+ if (cell->type == ID($_DFFSR_PPP_)) { check_gate("CSRDQ"); return; }
+
+ if (cell->type == ID($_DLATCH_N_)) { check_gate("EDQ"); return; }
+ if (cell->type == ID($_DLATCH_P_)) { check_gate("EDQ"); return; }
+
+ if (cell->type == ID($_DLATCHSR_NNN_)) { check_gate("ESRDQ"); return; }
+ if (cell->type == ID($_DLATCHSR_NNP_)) { check_gate("ESRDQ"); return; }
+ if (cell->type == ID($_DLATCHSR_NPN_)) { check_gate("ESRDQ"); return; }
+ if (cell->type == ID($_DLATCHSR_NPP_)) { check_gate("ESRDQ"); return; }
+ if (cell->type == ID($_DLATCHSR_PNN_)) { check_gate("ESRDQ"); return; }
+ if (cell->type == ID($_DLATCHSR_PNP_)) { check_gate("ESRDQ"); return; }
+ if (cell->type == ID($_DLATCHSR_PPN_)) { check_gate("ESRDQ"); return; }
+ if (cell->type == ID($_DLATCHSR_PPP_)) { check_gate("ESRDQ"); return; }
error(__LINE__);
}
@@ -1816,11 +1828,11 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth
#define DEF_METHOD(_func, _y_size, _type) \
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
- cell->parameters["\\A_SIGNED"] = is_signed; \
- cell->parameters["\\A_WIDTH"] = sig_a.size(); \
- cell->parameters["\\Y_WIDTH"] = sig_y.size(); \
- cell->setPort("\\A", sig_a); \
- cell->setPort("\\Y", sig_y); \
+ cell->parameters[ID(A_SIGNED)] = is_signed; \
+ cell->parameters[ID(A_WIDTH)] = sig_a.size(); \
+ cell->parameters[ID(Y_WIDTH)] = sig_y.size(); \
+ cell->setPort(ID::A, sig_a); \
+ cell->setPort(ID::Y, sig_y); \
cell->set_src_attribute(src); \
return cell; \
} \
@@ -1829,28 +1841,28 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth
add ## _func(name, sig_a, sig_y, is_signed, src); \
return sig_y; \
}
-DEF_METHOD(Not, sig_a.size(), "$not")
-DEF_METHOD(Pos, sig_a.size(), "$pos")
-DEF_METHOD(Neg, sig_a.size(), "$neg")
-DEF_METHOD(ReduceAnd, 1, "$reduce_and")
-DEF_METHOD(ReduceOr, 1, "$reduce_or")
-DEF_METHOD(ReduceXor, 1, "$reduce_xor")
-DEF_METHOD(ReduceXnor, 1, "$reduce_xnor")
-DEF_METHOD(ReduceBool, 1, "$reduce_bool")
-DEF_METHOD(LogicNot, 1, "$logic_not")
+DEF_METHOD(Not, sig_a.size(), ID($not))
+DEF_METHOD(Pos, sig_a.size(), ID($pos))
+DEF_METHOD(Neg, sig_a.size(), ID($neg))
+DEF_METHOD(ReduceAnd, 1, ID($reduce_and))
+DEF_METHOD(ReduceOr, 1, ID($reduce_or))
+DEF_METHOD(ReduceXor, 1, ID($reduce_xor))
+DEF_METHOD(ReduceXnor, 1, ID($reduce_xnor))
+DEF_METHOD(ReduceBool, 1, ID($reduce_bool))
+DEF_METHOD(LogicNot, 1, ID($logic_not))
#undef DEF_METHOD
#define DEF_METHOD(_func, _y_size, _type) \
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
- cell->parameters["\\A_SIGNED"] = is_signed; \
- cell->parameters["\\B_SIGNED"] = is_signed; \
- cell->parameters["\\A_WIDTH"] = sig_a.size(); \
- cell->parameters["\\B_WIDTH"] = sig_b.size(); \
- cell->parameters["\\Y_WIDTH"] = sig_y.size(); \
- cell->setPort("\\A", sig_a); \
- cell->setPort("\\B", sig_b); \
- cell->setPort("\\Y", sig_y); \
+ cell->parameters[ID(A_SIGNED)] = is_signed; \
+ cell->parameters[ID(B_SIGNED)] = is_signed; \
+ cell->parameters[ID(A_WIDTH)] = sig_a.size(); \
+ cell->parameters[ID(B_WIDTH)] = sig_b.size(); \
+ cell->parameters[ID(Y_WIDTH)] = sig_y.size(); \
+ cell->setPort(ID::A, sig_a); \
+ cell->setPort(ID::B, sig_b); \
+ cell->setPort(ID::Y, sig_y); \
cell->set_src_attribute(src); \
return cell; \
} \
@@ -1859,42 +1871,42 @@ DEF_METHOD(LogicNot, 1, "$logic_not")
add ## _func(name, sig_a, sig_b, sig_y, is_signed, src); \
return sig_y; \
}
-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")
-DEF_METHOD(Sshr, sig_a.size(), "$sshr")
-DEF_METHOD(Shift, sig_a.size(), "$shift")
-DEF_METHOD(Shiftx, sig_a.size(), "$shiftx")
-DEF_METHOD(Lt, 1, "$lt")
-DEF_METHOD(Le, 1, "$le")
-DEF_METHOD(Eq, 1, "$eq")
-DEF_METHOD(Ne, 1, "$ne")
-DEF_METHOD(Eqx, 1, "$eqx")
-DEF_METHOD(Nex, 1, "$nex")
-DEF_METHOD(Ge, 1, "$ge")
-DEF_METHOD(Gt, 1, "$gt")
-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")
+DEF_METHOD(And, max(sig_a.size(), sig_b.size()), ID($and))
+DEF_METHOD(Or, max(sig_a.size(), sig_b.size()), ID($or))
+DEF_METHOD(Xor, max(sig_a.size(), sig_b.size()), ID($xor))
+DEF_METHOD(Xnor, max(sig_a.size(), sig_b.size()), ID($xnor))
+DEF_METHOD(Shl, sig_a.size(), ID($shl))
+DEF_METHOD(Shr, sig_a.size(), ID($shr))
+DEF_METHOD(Sshl, sig_a.size(), ID($sshl))
+DEF_METHOD(Sshr, sig_a.size(), ID($sshr))
+DEF_METHOD(Shift, sig_a.size(), ID($shift))
+DEF_METHOD(Shiftx, sig_a.size(), ID($shiftx))
+DEF_METHOD(Lt, 1, ID($lt))
+DEF_METHOD(Le, 1, ID($le))
+DEF_METHOD(Eq, 1, ID($eq))
+DEF_METHOD(Ne, 1, ID($ne))
+DEF_METHOD(Eqx, 1, ID($eqx))
+DEF_METHOD(Nex, 1, ID($nex))
+DEF_METHOD(Ge, 1, ID($ge))
+DEF_METHOD(Gt, 1, ID($gt))
+DEF_METHOD(Add, max(sig_a.size(), sig_b.size()), ID($add))
+DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), ID($sub))
+DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), ID($mul))
+DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), ID($div))
+DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), ID($mod))
+DEF_METHOD(LogicAnd, 1, ID($logic_and))
+DEF_METHOD(LogicOr, 1, ID($logic_or))
#undef DEF_METHOD
#define DEF_METHOD(_func, _type, _pmux) \
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
- cell->parameters["\\WIDTH"] = sig_a.size(); \
- if (_pmux) cell->parameters["\\S_WIDTH"] = sig_s.size(); \
- cell->setPort("\\A", sig_a); \
- cell->setPort("\\B", sig_b); \
- cell->setPort("\\S", sig_s); \
- cell->setPort("\\Y", sig_y); \
+ cell->parameters[ID(WIDTH)] = sig_a.size(); \
+ if (_pmux) cell->parameters[ID(S_WIDTH)] = sig_s.size(); \
+ cell->setPort(ID::A, sig_a); \
+ cell->setPort(ID::B, sig_b); \
+ cell->setPort(ID(S), sig_s); \
+ cell->setPort(ID::Y, sig_y); \
cell->set_src_attribute(src); \
return cell; \
} \
@@ -1903,8 +1915,8 @@ DEF_METHOD(LogicOr, 1, "$logic_or")
add ## _func(name, sig_a, sig_b, sig_s, sig_y, src); \
return sig_y; \
}
-DEF_METHOD(Mux, "$mux", 0)
-DEF_METHOD(Pmux, "$pmux", 1)
+DEF_METHOD(Mux, ID($mux), 0)
+DEF_METHOD(Pmux, ID($pmux), 1)
#undef DEF_METHOD
#define DEF_METHOD_2(_func, _type, _P1, _P2) \
@@ -1965,21 +1977,22 @@ DEF_METHOD(Pmux, "$pmux", 1)
add ## _func(name, sig1, sig2, sig3, sig4, sig5, src); \
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)
-DEF_METHOD_3(OrGate, "$_OR_", A, B, Y)
-DEF_METHOD_3(NorGate, "$_NOR_", A, B, Y)
-DEF_METHOD_3(XorGate, "$_XOR_", A, B, Y)
-DEF_METHOD_3(XnorGate, "$_XNOR_", A, B, Y)
-DEF_METHOD_3(AndnotGate, "$_ANDNOT_", A, B, Y)
-DEF_METHOD_3(OrnotGate, "$_ORNOT_", A, B, Y)
-DEF_METHOD_4(MuxGate, "$_MUX_", A, B, S, Y)
-DEF_METHOD_4(Aoi3Gate, "$_AOI3_", A, B, C, Y)
-DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y)
-DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y)
-DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y)
+DEF_METHOD_2(BufGate, ID($_BUF_), A, Y)
+DEF_METHOD_2(NotGate, ID($_NOT_), A, Y)
+DEF_METHOD_3(AndGate, ID($_AND_), A, B, Y)
+DEF_METHOD_3(NandGate, ID($_NAND_), A, B, Y)
+DEF_METHOD_3(OrGate, ID($_OR_), A, B, Y)
+DEF_METHOD_3(NorGate, ID($_NOR_), A, B, Y)
+DEF_METHOD_3(XorGate, ID($_XOR_), A, B, Y)
+DEF_METHOD_3(XnorGate, ID($_XNOR_), A, B, Y)
+DEF_METHOD_3(AndnotGate, ID($_ANDNOT_), A, B, Y)
+DEF_METHOD_3(OrnotGate, ID($_ORNOT_), A, B, Y)
+DEF_METHOD_4(MuxGate, ID($_MUX_), A, B, S, Y)
+DEF_METHOD_4(NmuxGate, ID($_NMUX_), A, B, S, Y)
+DEF_METHOD_4(Aoi3Gate, ID($_AOI3_), A, B, C, Y)
+DEF_METHOD_4(Oai3Gate, ID($_OAI3_), A, B, C, Y)
+DEF_METHOD_5(Aoi4Gate, ID($_AOI4_), A, B, C, D, Y)
+DEF_METHOD_5(Oai4Gate, ID($_OAI4_), A, B, C, D, Y)
#undef DEF_METHOD_2
#undef DEF_METHOD_3
#undef DEF_METHOD_4
@@ -1987,165 +2000,165 @@ DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y)
RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed, bool b_signed, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$pow");
- cell->parameters["\\A_SIGNED"] = a_signed;
- cell->parameters["\\B_SIGNED"] = b_signed;
- cell->parameters["\\A_WIDTH"] = sig_a.size();
- cell->parameters["\\B_WIDTH"] = sig_b.size();
- cell->parameters["\\Y_WIDTH"] = sig_y.size();
- cell->setPort("\\A", sig_a);
- cell->setPort("\\B", sig_b);
- cell->setPort("\\Y", sig_y);
+ RTLIL::Cell *cell = addCell(name, ID($pow));
+ cell->parameters[ID(A_SIGNED)] = a_signed;
+ cell->parameters[ID(B_SIGNED)] = b_signed;
+ cell->parameters[ID(A_WIDTH)] = sig_a.size();
+ cell->parameters[ID(B_WIDTH)] = sig_b.size();
+ cell->parameters[ID(Y_WIDTH)] = sig_y.size();
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID::B, sig_b);
+ cell->setPort(ID::Y, sig_y);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$slice");
- cell->parameters["\\A_WIDTH"] = sig_a.size();
- cell->parameters["\\Y_WIDTH"] = sig_y.size();
- cell->parameters["\\OFFSET"] = offset;
- cell->setPort("\\A", sig_a);
- cell->setPort("\\Y", sig_y);
+ RTLIL::Cell *cell = addCell(name, ID($slice));
+ cell->parameters[ID(A_WIDTH)] = sig_a.size();
+ cell->parameters[ID(Y_WIDTH)] = sig_y.size();
+ cell->parameters[ID(OFFSET)] = offset;
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID::Y, sig_y);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$concat");
- cell->parameters["\\A_WIDTH"] = sig_a.size();
- cell->parameters["\\B_WIDTH"] = sig_b.size();
- cell->setPort("\\A", sig_a);
- cell->setPort("\\B", sig_b);
- cell->setPort("\\Y", sig_y);
+ RTLIL::Cell *cell = addCell(name, ID($concat));
+ cell->parameters[ID(A_WIDTH)] = sig_a.size();
+ cell->parameters[ID(B_WIDTH)] = sig_b.size();
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID::B, sig_b);
+ cell->setPort(ID::Y, sig_y);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$lut");
- cell->parameters["\\LUT"] = lut;
- cell->parameters["\\WIDTH"] = sig_a.size();
- cell->setPort("\\A", sig_a);
- cell->setPort("\\Y", sig_y);
+ RTLIL::Cell *cell = addCell(name, ID($lut));
+ cell->parameters[ID(LUT)] = lut;
+ cell->parameters[ID(WIDTH)] = sig_a.size();
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID::Y, sig_y);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addTribuf(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$tribuf");
- cell->parameters["\\WIDTH"] = sig_a.size();
- cell->setPort("\\A", sig_a);
- cell->setPort("\\EN", sig_en);
- cell->setPort("\\Y", sig_y);
+ RTLIL::Cell *cell = addCell(name, ID($tribuf));
+ cell->parameters[ID(WIDTH)] = sig_a.size();
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID(EN), sig_en);
+ cell->setPort(ID::Y, sig_y);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$assert");
- cell->setPort("\\A", sig_a);
- cell->setPort("\\EN", sig_en);
+ RTLIL::Cell *cell = addCell(name, ID($assert));
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID(EN), sig_en);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$assume");
- cell->setPort("\\A", sig_a);
- cell->setPort("\\EN", sig_en);
+ RTLIL::Cell *cell = addCell(name, ID($assume));
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID(EN), sig_en);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addLive(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$live");
- cell->setPort("\\A", sig_a);
- cell->setPort("\\EN", sig_en);
+ RTLIL::Cell *cell = addCell(name, ID($live));
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID(EN), sig_en);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addFair(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$fair");
- cell->setPort("\\A", sig_a);
- cell->setPort("\\EN", sig_en);
+ RTLIL::Cell *cell = addCell(name, ID($fair));
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID(EN), sig_en);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addCover(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$cover");
- cell->setPort("\\A", sig_a);
- cell->setPort("\\EN", sig_en);
+ RTLIL::Cell *cell = addCell(name, ID($cover));
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID(EN), sig_en);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$equiv");
- cell->setPort("\\A", sig_a);
- cell->setPort("\\B", sig_b);
- cell->setPort("\\Y", sig_y);
+ RTLIL::Cell *cell = addCell(name, ID($equiv));
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID::B, sig_b);
+ cell->setPort(ID::Y, sig_y);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity, bool clr_polarity, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$sr");
- cell->parameters["\\SET_POLARITY"] = set_polarity;
- cell->parameters["\\CLR_POLARITY"] = clr_polarity;
- cell->parameters["\\WIDTH"] = sig_q.size();
- cell->setPort("\\SET", sig_set);
- cell->setPort("\\CLR", sig_clr);
- cell->setPort("\\Q", sig_q);
+ RTLIL::Cell *cell = addCell(name, ID($sr));
+ cell->parameters[ID(SET_POLARITY)] = set_polarity;
+ cell->parameters[ID(CLR_POLARITY)] = clr_polarity;
+ cell->parameters[ID(WIDTH)] = sig_q.size();
+ cell->setPort(ID(SET), sig_set);
+ cell->setPort(ID(CLR), sig_clr);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addFf(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$ff");
- cell->parameters["\\WIDTH"] = sig_q.size();
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ RTLIL::Cell *cell = addCell(name, ID($ff));
+ cell->parameters[ID(WIDTH)] = sig_q.size();
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$dff");
- cell->parameters["\\CLK_POLARITY"] = clk_polarity;
- cell->parameters["\\WIDTH"] = sig_q.size();
- cell->setPort("\\CLK", sig_clk);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ RTLIL::Cell *cell = addCell(name, ID($dff));
+ cell->parameters[ID(CLK_POLARITY)] = clk_polarity;
+ cell->parameters[ID(WIDTH)] = sig_q.size();
+ cell->setPort(ID(CLK), sig_clk);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$dffe");
- cell->parameters["\\CLK_POLARITY"] = clk_polarity;
- cell->parameters["\\EN_POLARITY"] = en_polarity;
- cell->parameters["\\WIDTH"] = sig_q.size();
- cell->setPort("\\CLK", sig_clk);
- cell->setPort("\\EN", sig_en);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ RTLIL::Cell *cell = addCell(name, ID($dffe));
+ cell->parameters[ID(CLK_POLARITY)] = clk_polarity;
+ cell->parameters[ID(EN_POLARITY)] = en_polarity;
+ cell->parameters[ID(WIDTH)] = sig_q.size();
+ cell->setPort(ID(CLK), sig_clk);
+ cell->setPort(ID(EN), sig_en);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2153,16 +2166,16 @@ RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk
RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$dffsr");
- cell->parameters["\\CLK_POLARITY"] = clk_polarity;
- cell->parameters["\\SET_POLARITY"] = set_polarity;
- cell->parameters["\\CLR_POLARITY"] = clr_polarity;
- cell->parameters["\\WIDTH"] = sig_q.size();
- cell->setPort("\\CLK", sig_clk);
- cell->setPort("\\SET", sig_set);
- cell->setPort("\\CLR", sig_clr);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ RTLIL::Cell *cell = addCell(name, ID($dffsr));
+ cell->parameters[ID(CLK_POLARITY)] = clk_polarity;
+ cell->parameters[ID(SET_POLARITY)] = set_polarity;
+ cell->parameters[ID(CLR_POLARITY)] = clr_polarity;
+ cell->parameters[ID(WIDTH)] = sig_q.size();
+ cell->setPort(ID(CLK), sig_clk);
+ cell->setPort(ID(SET), sig_set);
+ cell->setPort(ID(CLR), sig_clr);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2170,27 +2183,27 @@ RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, RTLIL::SigSpec sig_cl
RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$adff");
- cell->parameters["\\CLK_POLARITY"] = clk_polarity;
- cell->parameters["\\ARST_POLARITY"] = arst_polarity;
- cell->parameters["\\ARST_VALUE"] = arst_value;
- cell->parameters["\\WIDTH"] = sig_q.size();
- cell->setPort("\\CLK", sig_clk);
- cell->setPort("\\ARST", sig_arst);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ RTLIL::Cell *cell = addCell(name, ID($adff));
+ cell->parameters[ID(CLK_POLARITY)] = clk_polarity;
+ cell->parameters[ID(ARST_POLARITY)] = arst_polarity;
+ cell->parameters[ID(ARST_VALUE)] = arst_value;
+ cell->parameters[ID(WIDTH)] = sig_q.size();
+ cell->setPort(ID(CLK), sig_clk);
+ cell->setPort(ID(ARST), sig_arst);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$dlatch");
- cell->parameters["\\EN_POLARITY"] = en_polarity;
- cell->parameters["\\WIDTH"] = sig_q.size();
- cell->setPort("\\EN", sig_en);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ RTLIL::Cell *cell = addCell(name, ID($dlatch));
+ cell->parameters[ID(EN_POLARITY)] = en_polarity;
+ cell->parameters[ID(WIDTH)] = sig_q.size();
+ cell->setPort(ID(EN), sig_en);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2198,25 +2211,25 @@ RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_e
RTLIL::Cell* RTLIL::Module::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, bool set_polarity, bool clr_polarity, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$dlatchsr");
- cell->parameters["\\EN_POLARITY"] = en_polarity;
- cell->parameters["\\SET_POLARITY"] = set_polarity;
- cell->parameters["\\CLR_POLARITY"] = clr_polarity;
- cell->parameters["\\WIDTH"] = sig_q.size();
- cell->setPort("\\EN", sig_en);
- cell->setPort("\\SET", sig_set);
- cell->setPort("\\CLR", sig_clr);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ RTLIL::Cell *cell = addCell(name, ID($dlatchsr));
+ cell->parameters[ID(EN_POLARITY)] = en_polarity;
+ cell->parameters[ID(SET_POLARITY)] = set_polarity;
+ cell->parameters[ID(CLR_POLARITY)] = clr_polarity;
+ cell->parameters[ID(WIDTH)] = sig_q.size();
+ cell->setPort(ID(EN), sig_en);
+ cell->setPort(ID(SET), sig_set);
+ cell->setPort(ID(CLR), sig_clr);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addFfGate(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src)
{
- RTLIL::Cell *cell = addCell(name, "$_FF_");
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ RTLIL::Cell *cell = addCell(name, ID($_FF_));
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2224,9 +2237,9 @@ RTLIL::Cell* RTLIL::Module::addFfGate(RTLIL::IdString name, RTLIL::SigSpec sig_d
RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N'));
- cell->setPort("\\C", sig_clk);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ cell->setPort(ID(C), sig_clk);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2234,10 +2247,10 @@ RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_
RTLIL::Cell* RTLIL::Module::addDffeGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
- cell->setPort("\\C", sig_clk);
- cell->setPort("\\E", sig_en);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ cell->setPort(ID(C), sig_clk);
+ cell->setPort(ID(E), sig_en);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2246,11 +2259,11 @@ RTLIL::Cell* RTLIL::Module::addDffsrGate(RTLIL::IdString name, RTLIL::SigSpec si
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N'));
- cell->setPort("\\C", sig_clk);
- cell->setPort("\\S", sig_set);
- cell->setPort("\\R", sig_clr);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ cell->setPort(ID(C), sig_clk);
+ cell->setPort(ID(S), sig_set);
+ cell->setPort(ID(R), sig_clr);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2259,10 +2272,10 @@ RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, RTLIL::SigSpec sig
bool arst_value, bool clk_polarity, bool arst_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0'));
- cell->setPort("\\C", sig_clk);
- cell->setPort("\\R", sig_arst);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ cell->setPort(ID(C), sig_clk);
+ cell->setPort(ID(R), sig_arst);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2270,9 +2283,9 @@ RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, RTLIL::SigSpec sig
RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DLATCH_%c_", en_polarity ? 'P' : 'N'));
- cell->setPort("\\E", sig_en);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ cell->setPort(ID(E), sig_en);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2281,11 +2294,11 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DLATCHSR_%c%c%c_", en_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N'));
- cell->setPort("\\E", sig_en);
- cell->setPort("\\S", sig_set);
- cell->setPort("\\R", sig_clr);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ cell->setPort(ID(E), sig_en);
+ cell->setPort(ID(S), sig_set);
+ cell->setPort(ID(R), sig_clr);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->set_src_attribute(src);
return cell;
}
@@ -2293,9 +2306,9 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec
RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID, width);
- Cell *cell = addCell(name, "$anyconst");
- cell->setParam("\\WIDTH", width);
- cell->setPort("\\Y", sig);
+ Cell *cell = addCell(name, ID($anyconst));
+ cell->setParam(ID(WIDTH), width);
+ cell->setPort(ID::Y, sig);
cell->set_src_attribute(src);
return sig;
}
@@ -2303,9 +2316,9 @@ RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const st
RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID, width);
- Cell *cell = addCell(name, "$anyseq");
- cell->setParam("\\WIDTH", width);
- cell->setPort("\\Y", sig);
+ Cell *cell = addCell(name, ID($anyseq));
+ cell->setParam(ID(WIDTH), width);
+ cell->setPort(ID::Y, sig);
cell->set_src_attribute(src);
return sig;
}
@@ -2313,9 +2326,9 @@ RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const std:
RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID, width);
- Cell *cell = addCell(name, "$allconst");
- cell->setParam("\\WIDTH", width);
- cell->setPort("\\Y", sig);
+ Cell *cell = addCell(name, ID($allconst));
+ cell->setParam(ID(WIDTH), width);
+ cell->setPort(ID::Y, sig);
cell->set_src_attribute(src);
return sig;
}
@@ -2323,9 +2336,9 @@ RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const st
RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID, width);
- Cell *cell = addCell(name, "$allseq");
- cell->setParam("\\WIDTH", width);
- cell->setPort("\\Y", sig);
+ Cell *cell = addCell(name, ID($allseq));
+ cell->setParam(ID(WIDTH), width);
+ cell->setPort(ID::Y, sig);
cell->set_src_attribute(src);
return sig;
}
@@ -2333,8 +2346,8 @@ RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const std:
RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID);
- Cell *cell = addCell(name, "$initstate");
- cell->setPort("\\Y", sig);
+ Cell *cell = addCell(name, ID($initstate));
+ cell->setPort(ID::Y, sig);
cell->set_src_attribute(src);
return sig;
}
@@ -2551,60 +2564,60 @@ void RTLIL::Cell::check()
void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
{
- if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || type.substr(0,10) == "$fmcombine" ||
- type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
+ if (!type.begins_with("$") || type.begins_with("$_") || type.begins_with("$paramod") || type.begins_with("$fmcombine") ||
+ type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
return;
- if (type == "$mux" || type == "$pmux") {
- parameters["\\WIDTH"] = GetSize(connections_["\\Y"]);
- if (type == "$pmux")
- parameters["\\S_WIDTH"] = GetSize(connections_["\\S"]);
+ if (type == ID($mux) || type == ID($pmux)) {
+ parameters[ID(WIDTH)] = GetSize(connections_[ID::Y]);
+ if (type == ID($pmux))
+ parameters[ID(S_WIDTH)] = GetSize(connections_[ID(S)]);
check();
return;
}
- if (type == "$lut" || type == "$sop") {
- parameters["\\WIDTH"] = GetSize(connections_["\\A"]);
+ if (type == ID($lut) || type == ID($sop)) {
+ parameters[ID(WIDTH)] = GetSize(connections_[ID::A]);
return;
}
- if (type == "$fa") {
- parameters["\\WIDTH"] = GetSize(connections_["\\Y"]);
+ if (type == ID($fa)) {
+ parameters[ID(WIDTH)] = GetSize(connections_[ID::Y]);
return;
}
- if (type == "$lcu") {
- parameters["\\WIDTH"] = GetSize(connections_["\\CO"]);
+ if (type == ID($lcu)) {
+ parameters[ID(WIDTH)] = GetSize(connections_[ID(CO)]);
return;
}
- bool signedness_ab = !type.in("$slice", "$concat", "$macc");
+ bool signedness_ab = !type.in(ID($slice), ID($concat), ID($macc));
- if (connections_.count("\\A")) {
+ if (connections_.count(ID::A)) {
if (signedness_ab) {
if (set_a_signed)
- parameters["\\A_SIGNED"] = true;
- else if (parameters.count("\\A_SIGNED") == 0)
- parameters["\\A_SIGNED"] = false;
+ parameters[ID(A_SIGNED)] = true;
+ else if (parameters.count(ID(A_SIGNED)) == 0)
+ parameters[ID(A_SIGNED)] = false;
}
- parameters["\\A_WIDTH"] = GetSize(connections_["\\A"]);
+ parameters[ID(A_WIDTH)] = GetSize(connections_[ID::A]);
}
- if (connections_.count("\\B")) {
+ if (connections_.count(ID::B)) {
if (signedness_ab) {
if (set_b_signed)
- parameters["\\B_SIGNED"] = true;
- else if (parameters.count("\\B_SIGNED") == 0)
- parameters["\\B_SIGNED"] = false;
+ parameters[ID(B_SIGNED)] = true;
+ else if (parameters.count(ID(B_SIGNED)) == 0)
+ parameters[ID(B_SIGNED)] = false;
}
- parameters["\\B_WIDTH"] = GetSize(connections_["\\B"]);
+ parameters[ID(B_WIDTH)] = GetSize(connections_[ID::B]);
}
- if (connections_.count("\\Y"))
- parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]);
+ if (connections_.count(ID::Y))
+ parameters[ID(Y_WIDTH)] = GetSize(connections_[ID::Y]);
- if (connections_.count("\\Q"))
- parameters["\\WIDTH"] = GetSize(connections_["\\Q"]);
+ if (connections_.count(ID(Q)))
+ parameters[ID(WIDTH)] = GetSize(connections_[ID(Q)]);
check();
}
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 8509670ff..c08653b65 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -78,6 +78,8 @@ namespace RTLIL
{
#undef YOSYS_XTRACE_GET_PUT
#undef YOSYS_SORT_ID_FREE_LIST
+ #undef YOSYS_USE_STICKY_IDS
+ #undef YOSYS_NO_IDS_REFCNT
// the global id string cache
@@ -87,13 +89,17 @@ namespace RTLIL
~destruct_guard_t() { ok = false; }
} destruct_guard;
- static std::vector<int> global_refcount_storage_;
static std::vector<char*> global_id_storage_;
static dict<char*, int, hash_cstr_ops> global_id_index_;
+ #ifndef YOSYS_NO_IDS_REFCNT
+ static std::vector<int> global_refcount_storage_;
static std::vector<int> global_free_idx_list_;
+ #endif
+ #ifdef YOSYS_USE_STICKY_IDS
static int last_created_idx_ptr_;
static int last_created_idx_[8];
+ #endif
static inline void xtrace_db_dump()
{
@@ -110,12 +116,14 @@ namespace RTLIL
static inline void checkpoint()
{
+ #ifdef YOSYS_USE_STICKY_IDS
last_created_idx_ptr_ = 0;
for (int i = 0; i < 8; i++) {
if (last_created_idx_[i])
put_reference(last_created_idx_[i]);
last_created_idx_[i] = 0;
}
+ #endif
#ifdef YOSYS_SORT_ID_FREE_LIST
std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
#endif
@@ -123,36 +131,47 @@ namespace RTLIL
static inline int get_reference(int idx)
{
- global_refcount_storage_.at(idx)++;
+ if (idx) {
+ #ifndef YOSYS_NO_IDS_REFCNT
+ global_refcount_storage_[idx]++;
+ #endif
#ifdef YOSYS_XTRACE_GET_PUT
- if (yosys_xtrace) {
- log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
- }
+ if (yosys_xtrace)
+ log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
#endif
+ }
return idx;
}
- static inline int get_reference(const char *p)
+ static int get_reference(const char *p)
{
log_assert(destruct_guard.ok);
- if (p[0]) {
- log_assert(p[1] != 0);
- log_assert(p[0] == '$' || p[0] == '\\');
- }
+ if (!p[0])
+ return 0;
+
+ log_assert(p[0] == '$' || p[0] == '\\');
+ log_assert(p[1] != 0);
auto it = global_id_index_.find((char*)p);
if (it != global_id_index_.end()) {
+ #ifndef YOSYS_NO_IDS_REFCNT
global_refcount_storage_.at(it->second)++;
+ #endif
#ifdef YOSYS_XTRACE_GET_PUT
- if (yosys_xtrace) {
+ if (yosys_xtrace)
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
- }
#endif
return it->second;
}
+ #ifndef YOSYS_NO_IDS_REFCNT
if (global_free_idx_list_.empty()) {
+ if (global_id_storage_.empty()) {
+ global_refcount_storage_.push_back(0);
+ global_id_storage_.push_back((char*)"");
+ global_id_index_[global_id_storage_.back()] = 0;
+ }
log_assert(global_id_storage_.size() < 0x40000000);
global_free_idx_list_.push_back(global_id_storage_.size());
global_id_storage_.push_back(nullptr);
@@ -164,13 +183,15 @@ namespace RTLIL
global_id_storage_.at(idx) = strdup(p);
global_id_index_[global_id_storage_.at(idx)] = idx;
global_refcount_storage_.at(idx)++;
-
- // Avoid Create->Delete->Create pattern
- if (last_created_idx_[last_created_idx_ptr_])
- put_reference(last_created_idx_[last_created_idx_ptr_]);
- last_created_idx_[last_created_idx_ptr_] = idx;
- get_reference(last_created_idx_[last_created_idx_ptr_]);
- last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
+ #else
+ if (global_id_storage_.empty()) {
+ global_id_storage_.push_back((char*)"");
+ global_id_index_[global_id_storage_.back()] = 0;
+ }
+ int idx = global_id_storage_.size();
+ global_id_storage_.push_back(strdup(p));
+ global_id_index_[global_id_storage_.back()] = idx;
+ #endif
if (yosys_xtrace) {
log("#X# New IdString '%s' with index %d.\n", p, idx);
@@ -178,18 +199,28 @@ namespace RTLIL
}
#ifdef YOSYS_XTRACE_GET_PUT
- if (yosys_xtrace) {
+ if (yosys_xtrace)
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
- }
#endif
+
+ #ifdef YOSYS_USE_STICKY_IDS
+ // Avoid Create->Delete->Create pattern
+ if (last_created_idx_[last_created_idx_ptr_])
+ put_reference(last_created_idx_[last_created_idx_ptr_]);
+ last_created_idx_[last_created_idx_ptr_] = idx;
+ get_reference(last_created_idx_[last_created_idx_ptr_]);
+ last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
+ #endif
+
return idx;
}
+ #ifndef YOSYS_NO_IDS_REFCNT
static inline void put_reference(int idx)
{
// put_reference() may be called from destructors after the destructor of
// global_refcount_storage_ has been run. in this case we simply do nothing.
- if (!destruct_guard.ok)
+ if (!destruct_guard.ok || !idx)
return;
#ifdef YOSYS_XTRACE_GET_PUT
@@ -198,11 +229,13 @@ namespace RTLIL
}
#endif
- log_assert(global_refcount_storage_.at(idx) > 0);
+ int &refcount = global_refcount_storage_[idx];
- if (--global_refcount_storage_.at(idx) != 0)
+ if (--refcount > 0)
return;
+ log_assert(refcount == 0);
+
if (yosys_xtrace) {
log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx);
log_backtrace("-X- ", yosys_xtrace-1);
@@ -213,46 +246,50 @@ namespace RTLIL
global_id_storage_.at(idx) = nullptr;
global_free_idx_list_.push_back(idx);
}
+ #else
+ static inline void put_reference(int) { }
+ #endif
// the actual IdString object is just is a single int
int index_;
- IdString() : index_(get_reference("")) { }
- IdString(const char *str) : index_(get_reference(str)) { }
- IdString(const IdString &str) : index_(get_reference(str.index_)) { }
- IdString(const std::string &str) : index_(get_reference(str.c_str())) { }
- ~IdString() { put_reference(index_); }
+ inline IdString() : index_(0) { }
+ inline IdString(const char *str) : index_(get_reference(str)) { }
+ inline IdString(const IdString &str) : index_(get_reference(str.index_)) { }
+ inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; }
+ inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { }
+ inline ~IdString() { put_reference(index_); }
- void operator=(const IdString &rhs) {
+ inline void operator=(const IdString &rhs) {
put_reference(index_);
index_ = get_reference(rhs.index_);
}
- void operator=(const char *rhs) {
+ inline void operator=(const char *rhs) {
IdString id(rhs);
*this = id;
}
- void operator=(const std::string &rhs) {
+ inline void operator=(const std::string &rhs) {
IdString id(rhs);
*this = id;
}
- const char *c_str() const {
+ inline const char *c_str() const {
return global_id_storage_.at(index_);
}
- std::string str() const {
+ inline std::string str() const {
return std::string(global_id_storage_.at(index_));
}
- bool operator<(const IdString &rhs) const {
+ inline bool operator<(const 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_; }
+ inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; }
+ inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; }
// The methods below are just convenience functions for better compatibility with std::string.
@@ -276,8 +313,24 @@ namespace RTLIL
return std::string(c_str() + pos, len);
}
+ int compare(size_t pos, size_t len, const char* s) const {
+ return strncmp(c_str()+pos, s, len);
+ }
+
+ bool begins_with(const char* prefix) const {
+ size_t len = strlen(prefix);
+ if (size() < len) return false;
+ return compare(0, len, prefix) == 0;
+ }
+
+ bool ends_with(const char* suffix) const {
+ size_t len = strlen(suffix);
+ if (size() < len) return false;
+ return compare(size()-len, len, suffix) == 0;
+ }
+
size_t size() const {
- return str().size();
+ return strlen(c_str());
}
bool empty() const {
@@ -316,6 +369,14 @@ namespace RTLIL
bool in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }
};
+ namespace ID {
+ // defined in rtlil.cc, initialized in yosys.cc
+ extern IdString A, B, Y;
+ extern IdString keep;
+ extern IdString whitebox;
+ extern IdString blackbox;
+ };
+
static inline std::string escape_id(std::string str) {
if (str.size() > 0 && str[0] != '\\' && str[0] != '$')
return "\\" + str;
@@ -408,8 +469,12 @@ namespace RTLIL
// It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.
template<typename T>
- struct ObjIterator
- {
+ struct ObjIterator {
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = T;
+ using difference_type = ptrdiff_t;
+ using pointer = T*;
+ using reference = T&;
typename dict<RTLIL::IdString, T>::iterator it;
dict<RTLIL::IdString, T> *list_p;
int *refcount_p;
@@ -462,13 +527,25 @@ namespace RTLIL
return it != other.it;
}
- inline void operator++() {
+
+ inline bool operator==(const RTLIL::ObjIterator<T> &other) const {
+ return !(*this != other);
+ }
+
+ inline ObjIterator<T>& operator++() {
log_assert(list_p != nullptr);
if (++it == list_p->end()) {
(*refcount_p)--;
list_p = nullptr;
refcount_p = nullptr;
}
+ return *this;
+ }
+
+ inline const ObjIterator<T> operator++(int) {
+ ObjIterator<T> result(*this);
+ ++(*this);
+ return result;
}
};
@@ -572,7 +649,7 @@ struct RTLIL::AttrObject
bool get_bool_attribute(RTLIL::IdString id) const;
bool get_blackbox_attribute(bool ignore_wb=false) const {
- return get_bool_attribute("\\blackbox") || (!ignore_wb && get_bool_attribute("\\whitebox"));
+ return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
}
void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
@@ -760,6 +837,7 @@ public:
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(int offset, int length = 1) const;
+ RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); }
void append(const RTLIL::SigSpec &signal);
void append_bit(const RTLIL::SigBit &bit);
@@ -806,6 +884,7 @@ public:
operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
operator std::vector<RTLIL::SigBit>() const { return bits(); }
+ RTLIL::SigBit at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; }
unsigned int hash() const { if (!hash_) updhash(); return hash_; };
@@ -1126,6 +1205,7 @@ public:
RTLIL::Cell* addAndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
RTLIL::Cell* addOrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
RTLIL::Cell* addMuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addNmuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = "");
RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = "");
RTLIL::Cell* addOai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = "");
RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y, const std::string &src = "");
@@ -1201,6 +1281,7 @@ public:
RTLIL::SigBit AndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
RTLIL::SigBit OrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
RTLIL::SigBit MuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = "");
+ RTLIL::SigBit NmuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = "");
RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = "");
RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = "");
RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, const std::string &src = "");
@@ -1303,8 +1384,8 @@ public:
void fixup_parameters(bool set_a_signed = false, bool set_b_signed = false);
bool has_keep_attr() const {
- return get_bool_attribute("\\keep") || (module && module->design && module->design->module(type) &&
- module->design->module(type)->get_bool_attribute("\\keep"));
+ return get_bool_attribute(ID::keep) || (module && module->design && module->design->module(type) &&
+ module->design->module(type)->get_bool_attribute(ID::keep));
}
template<typename T> void rewrite_sigspecs(T &functor);
@@ -1315,7 +1396,7 @@ public:
#endif
};
-struct RTLIL::CaseRule
+struct RTLIL::CaseRule : public RTLIL::AttrObject
{
std::vector<RTLIL::SigSpec> compare;
std::vector<RTLIL::SigSig> actions;
@@ -1372,7 +1453,7 @@ struct RTLIL::Process : public RTLIL::AttrObject
inline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { }
inline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }
-inline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? RTLIL::S1 : RTLIL::S0) { }
+inline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? State::S1 : State::S0) { }
inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }
inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); }
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
diff --git a/kernel/satgen.h b/kernel/satgen.h
index 210cca3f3..133389eee 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -224,8 +224,8 @@ struct SatGen
void extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, RTLIL::Cell *cell, size_t y_width = 0, bool forced_signed = false)
{
bool is_signed = forced_signed;
- if (!forced_signed && cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters.count("\\B_SIGNED") > 0)
- is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool();
+ if (!forced_signed && cell->parameters.count(ID(A_SIGNED)) > 0 && cell->parameters.count(ID(B_SIGNED)) > 0)
+ is_signed = cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool();
while (vec_a.size() < vec_b.size() || vec_a.size() < y_width)
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);
while (vec_b.size() < vec_a.size() || vec_b.size() < y_width)
@@ -241,7 +241,7 @@ struct SatGen
void extendSignalWidthUnary(std::vector<int> &vec_a, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false)
{
- bool is_signed = forced_signed || (cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool());
+ bool is_signed = forced_signed || (cell->parameters.count(ID(A_SIGNED)) > 0 && cell->parameters[ID(A_SIGNED)].as_bool());
while (vec_a.size() < vec_y.size())
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);
while (vec_y.size() < vec_a.size())
@@ -277,13 +277,13 @@ struct SatGen
bool importCell(RTLIL::Cell *cell, int timestep = -1)
{
bool arith_undef_handled = false;
- bool is_arith_compare = cell->type.in("$lt", "$le", "$ge", "$gt");
+ bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt));
- if (model_undef && (cell->type.in("$add", "$sub", "$mul", "$div", "$mod") || is_arith_compare))
+ if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod)) || is_arith_compare))
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
if (is_arith_compare)
extendSignalWidth(undef_a, undef_b, cell, true);
else
@@ -293,8 +293,8 @@ struct SatGen
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
int undef_y_bit = ez->OR(undef_any_a, undef_any_b);
- if (cell->type == "$div" || cell->type == "$mod") {
- std::vector<int> b = importSigSpec(cell->getPort("\\B"), timestep);
+ if (cell->type.in(ID($div), ID($mod))) {
+ std::vector<int> b = importSigSpec(cell->getPort(ID::B), timestep);
undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b)));
}
@@ -310,68 +310,68 @@ struct SatGen
arith_undef_handled = true;
}
- if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_",
- "$and", "$or", "$xor", "$xnor", "$add", "$sub"))
+ if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_),
+ ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($sub)))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidth(a, b, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
- if (cell->type == "$and" || cell->type == "$_AND_")
+ if (cell->type.in(ID($and), ID($_AND_)))
ez->assume(ez->vec_eq(ez->vec_and(a, b), yy));
- if (cell->type == "$_NAND_")
+ if (cell->type == ID($_NAND_))
ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy));
- if (cell->type == "$or" || cell->type == "$_OR_")
+ if (cell->type.in(ID($or), ID($_OR_)))
ez->assume(ez->vec_eq(ez->vec_or(a, b), yy));
- if (cell->type == "$_NOR_")
+ if (cell->type == ID($_NOR_))
ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy));
- if (cell->type == "$xor" || cell->type == "$_XOR_")
+ if (cell->type.in(ID($xor), ID($_XOR_)))
ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy));
- if (cell->type == "$xnor" || cell->type == "$_XNOR_")
+ if (cell->type.in(ID($xnor), ID($_XNOR_)))
ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy));
- if (cell->type == "$_ANDNOT_")
+ if (cell->type == ID($_ANDNOT_))
ez->assume(ez->vec_eq(ez->vec_and(a, ez->vec_not(b)), yy));
- if (cell->type == "$_ORNOT_")
+ if (cell->type == ID($_ORNOT_))
ez->assume(ez->vec_eq(ez->vec_or(a, ez->vec_not(b)), yy));
- if (cell->type == "$add")
+ if (cell->type == ID($add))
ez->assume(ez->vec_eq(ez->vec_add(a, b), yy));
- if (cell->type == "$sub")
+ if (cell->type == ID($sub))
ez->assume(ez->vec_eq(ez->vec_sub(a, b), yy));
if (model_undef && !arith_undef_handled)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidth(undef_a, undef_b, undef_y, cell, false);
- if (cell->type.in("$and", "$_AND_", "$_NAND_")) {
+ if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_))) {
std::vector<int> a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a));
std::vector<int> b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b));
std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b0)));
ez->assume(ez->vec_eq(yX, undef_y));
}
- else if (cell->type.in("$or", "$_OR_", "$_NOR_")) {
+ else if (cell->type.in(ID($or), ID($_OR_), ID($_NOR_))) {
std::vector<int> a1 = ez->vec_and(a, ez->vec_not(undef_a));
std::vector<int> b1 = ez->vec_and(b, ez->vec_not(undef_b));
std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b1)));
ez->assume(ez->vec_eq(yX, undef_y));
}
- else if (cell->type.in("$xor", "$xnor", "$_XOR_", "$_XNOR_")) {
+ else if (cell->type.in(ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_))) {
std::vector<int> yX = ez->vec_or(undef_a, undef_b);
ez->assume(ez->vec_eq(yX, undef_y));
}
- else if (cell->type == "$_ANDNOT_") {
+ else if (cell->type == ID($_ANDNOT_)) {
std::vector<int> a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a));
std::vector<int> b1 = ez->vec_and(b, ez->vec_not(undef_b));
std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b1)));
ez->assume(ez->vec_eq(yX, undef_y));
}
- else if (cell->type == "$_ORNOT_") {
+ else if (cell->type == ID($_ORNOT_)) {
std::vector<int> a1 = ez->vec_and(a, ez->vec_not(undef_a));
std::vector<int> b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b));
std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b0)));
@@ -384,36 +384,36 @@ struct SatGen
}
else if (model_undef)
{
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
undefGating(y, yy, undef_y);
}
return true;
}
- if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
+ if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_)))
{
- bool aoi_mode = cell->type.in("$_AOI3_", "$_AOI4_");
- bool three_mode = cell->type.in("$_AOI3_", "$_OAI3_");
-
- int a = importDefSigSpec(cell->getPort("\\A"), timestep).at(0);
- int b = importDefSigSpec(cell->getPort("\\B"), timestep).at(0);
- int c = importDefSigSpec(cell->getPort("\\C"), timestep).at(0);
- int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0);
- int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0);
+ bool aoi_mode = cell->type.in(ID($_AOI3_), ID($_AOI4_));
+ bool three_mode = cell->type.in(ID($_AOI3_), ID($_OAI3_));
+
+ int a = importDefSigSpec(cell->getPort(ID::A), timestep).at(0);
+ int b = importDefSigSpec(cell->getPort(ID::B), timestep).at(0);
+ int c = importDefSigSpec(cell->getPort(ID(C)), timestep).at(0);
+ int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort(ID(D)), timestep).at(0);
+ int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0);
int yy = model_undef ? ez->literal() : y;
- if (cell->type.in("$_AOI3_", "$_AOI4_"))
+ if (cell->type.in(ID($_AOI3_), ID($_AOI4_)))
ez->assume(ez->IFF(ez->NOT(ez->OR(ez->AND(a, b), ez->AND(c, d))), yy));
else
ez->assume(ez->IFF(ez->NOT(ez->AND(ez->OR(a, b), ez->OR(c, d))), yy));
if (model_undef)
{
- int undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep).at(0);
- int undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep).at(0);
- int undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep).at(0);
- int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0);
- int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0);
+ int undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep).at(0);
+ int undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep).at(0);
+ int undef_c = importUndefSigSpec(cell->getPort(ID(C)), timestep).at(0);
+ int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort(ID(D)), timestep).at(0);
+ int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0);
if (aoi_mode)
{
@@ -456,18 +456,18 @@ struct SatGen
return true;
}
- if (cell->type == "$_NOT_" || cell->type == "$not")
+ if (cell->type.in(ID($_NOT_), ID($not)))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidthUnary(a, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
ez->assume(ez->vec_eq(ez->vec_not(a), yy));
if (model_undef) {
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidthUnary(undef_a, undef_y, cell, false);
ez->assume(ez->vec_eq(undef_a, undef_y));
undefGating(y, yy, undef_y);
@@ -475,22 +475,25 @@ struct SatGen
return true;
}
- if (cell->type == "$_MUX_" || cell->type == "$mux")
+ if (cell->type.in(ID($_MUX_), ID($mux), ID($_NMUX_)))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> s = importDefSigSpec(cell->getPort(ID(S)), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
- ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy));
+ if (cell->type == ID($_NMUX_))
+ ez->assume(ez->vec_eq(ez->vec_not(ez->vec_ite(s.at(0), b, a)), yy));
+ else
+ ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy));
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_s = importUndefSigSpec(cell->getPort(ID(S)), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b));
std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b));
@@ -501,12 +504,12 @@ struct SatGen
return true;
}
- if (cell->type == "$pmux")
+ if (cell->type == ID($pmux))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> s = importDefSigSpec(cell->getPort(ID(S)), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -519,10 +522,10 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_s = importUndefSigSpec(cell->getPort(ID(S)), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
int maybe_a = ez->CONST_TRUE;
@@ -552,15 +555,15 @@ struct SatGen
return true;
}
- if (cell->type == "$pos" || cell->type == "$neg")
+ if (cell->type.in(ID($pos), ID($neg)))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidthUnary(a, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
- if (cell->type == "$pos") {
+ if (cell->type == ID($pos)) {
ez->assume(ez->vec_eq(a, yy));
} else {
std::vector<int> zero(a.size(), ez->CONST_FALSE);
@@ -569,11 +572,11 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidthUnary(undef_a, undef_y, cell);
- if (cell->type == "$pos") {
+ if (cell->type == ID($pos)) {
ez->assume(ez->vec_eq(undef_a, undef_y));
} else {
int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
@@ -586,42 +589,41 @@ struct SatGen
return true;
}
- if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_xor" ||
- cell->type == "$reduce_xnor" || cell->type == "$reduce_bool" || cell->type == "$logic_not")
+ if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not)))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
- if (cell->type == "$reduce_and")
+ if (cell->type == ID($reduce_and))
ez->SET(ez->expression(ez->OpAnd, a), yy.at(0));
- if (cell->type == "$reduce_or" || cell->type == "$reduce_bool")
+ if (cell->type.in(ID($reduce_or), ID($reduce_bool)))
ez->SET(ez->expression(ez->OpOr, a), yy.at(0));
- if (cell->type == "$reduce_xor")
+ if (cell->type == ID($reduce_xor))
ez->SET(ez->expression(ez->OpXor, a), yy.at(0));
- if (cell->type == "$reduce_xnor")
+ if (cell->type == ID($reduce_xnor))
ez->SET(ez->NOT(ez->expression(ez->OpXor, a)), yy.at(0));
- if (cell->type == "$logic_not")
+ if (cell->type == ID($logic_not))
ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0));
for (size_t i = 1; i < y.size(); i++)
ez->SET(ez->CONST_FALSE, yy.at(i));
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
int aX = ez->expression(ezSAT::OpOr, undef_a);
- if (cell->type == "$reduce_and") {
+ if (cell->type == ID($reduce_and)) {
int a0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)));
ez->assume(ez->IFF(ez->AND(ez->NOT(a0), aX), undef_y.at(0)));
}
- else if (cell->type == "$reduce_or" || cell->type == "$reduce_bool" || cell->type == "$logic_not") {
+ else if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) {
int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(a, ez->vec_not(undef_a)));
ez->assume(ez->IFF(ez->AND(ez->NOT(a1), aX), undef_y.at(0)));
}
- else if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor") {
+ else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) {
ez->assume(ez->IFF(aX, undef_y.at(0)));
} else
log_abort();
@@ -634,18 +636,18 @@ struct SatGen
return true;
}
- if (cell->type == "$logic_and" || cell->type == "$logic_or")
+ if (cell->type.in(ID($logic_and), ID($logic_or)))
{
- std::vector<int> vec_a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> vec_b = importDefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> vec_a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> vec_b = importDefSigSpec(cell->getPort(ID::B), timestep);
int a = ez->expression(ez->OpOr, vec_a);
int b = ez->expression(ez->OpOr, vec_b);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
- if (cell->type == "$logic_and")
+ if (cell->type == ID($logic_and))
ez->SET(ez->expression(ez->OpAnd, a, b), yy.at(0));
else
ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0));
@@ -654,9 +656,9 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
int a0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_a), ez->expression(ezSAT::OpOr, undef_a)));
int b0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_b), ez->expression(ezSAT::OpOr, undef_b)));
@@ -665,9 +667,9 @@ struct SatGen
int aX = ez->expression(ezSAT::OpOr, undef_a);
int bX = ez->expression(ezSAT::OpOr, undef_b);
- if (cell->type == "$logic_and")
+ if (cell->type == ID($logic_and))
ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a1, b1)), ez->NOT(a0), ez->NOT(b0)), undef_y.at(0));
- else if (cell->type == "$logic_or")
+ else if (cell->type == ID($logic_or))
ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a0, b0)), ez->NOT(a1), ez->NOT(b1)), undef_y.at(0));
else
log_abort();
@@ -680,47 +682,47 @@ struct SatGen
return true;
}
- if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt")
+ if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt)))
{
- bool is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool();
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ bool is_signed = cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool();
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidth(a, b, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
- if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) {
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ if (model_undef && cell->type.in(ID($eqx), ID($nex))) {
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
extendSignalWidth(undef_a, undef_b, cell, true);
a = ez->vec_or(a, undef_a);
b = ez->vec_or(b, undef_b);
}
- if (cell->type == "$lt")
+ if (cell->type == ID($lt))
ez->SET(is_signed ? ez->vec_lt_signed(a, b) : ez->vec_lt_unsigned(a, b), yy.at(0));
- if (cell->type == "$le")
+ if (cell->type == ID($le))
ez->SET(is_signed ? ez->vec_le_signed(a, b) : ez->vec_le_unsigned(a, b), yy.at(0));
- if (cell->type == "$eq" || cell->type == "$eqx")
+ if (cell->type.in(ID($eq), ID($eqx)))
ez->SET(ez->vec_eq(a, b), yy.at(0));
- if (cell->type == "$ne" || cell->type == "$nex")
+ if (cell->type.in(ID($ne), ID($nex)))
ez->SET(ez->vec_ne(a, b), yy.at(0));
- if (cell->type == "$ge")
+ if (cell->type == ID($ge))
ez->SET(is_signed ? ez->vec_ge_signed(a, b) : ez->vec_ge_unsigned(a, b), yy.at(0));
- if (cell->type == "$gt")
+ if (cell->type == ID($gt))
ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0));
for (size_t i = 1; i < y.size(); i++)
ez->SET(ez->CONST_FALSE, yy.at(i));
- if (model_undef && (cell->type == "$eqx" || cell->type == "$nex"))
+ if (model_undef && cell->type.in(ID($eqx), ID($nex)))
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidth(undef_a, undef_b, cell, true);
- if (cell->type == "$eqx")
+ if (cell->type == ID($eqx))
yy.at(0) = ez->AND(yy.at(0), ez->vec_eq(undef_a, undef_b));
else
yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b));
@@ -730,11 +732,11 @@ struct SatGen
ez->assume(ez->vec_eq(y, yy));
}
- else if (model_undef && (cell->type == "$eq" || cell->type == "$ne"))
+ else if (model_undef && cell->type.in(ID($eq), ID($ne)))
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidth(undef_a, undef_b, cell, true);
int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
@@ -756,7 +758,7 @@ struct SatGen
else
{
if (model_undef) {
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
undefGating(y, yy, undef_y);
}
log_assert(!model_undef || arith_undef_handled);
@@ -764,15 +766,15 @@ struct SatGen
return true;
}
- if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
+ if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
int extend_bit = ez->CONST_FALSE;
- if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
+ if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID(A_SIGNED)].as_bool())
extend_bit = a.back();
while (y.size() < a.size())
@@ -783,29 +785,29 @@ struct SatGen
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
std::vector<int> shifted_a;
- if (cell->type == "$shl" || cell->type == "$sshl")
+ if (cell->type.in( ID($shl), ID($sshl)))
shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
- if (cell->type == "$shr")
+ if (cell->type == ID($shr))
shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
- if (cell->type == "$sshr")
- shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
+ if (cell->type == ID($sshr))
+ shifted_a = ez->vec_shift_right(a, b, false, cell->parameters[ID(A_SIGNED)].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
- if (cell->type == "$shift" || cell->type == "$shiftx")
- shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
+ if (cell->type.in(ID($shift), ID($shiftx)))
+ shifted_a = ez->vec_shift_right(a, b, cell->parameters[ID(B_SIGNED)].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
ez->assume(ez->vec_eq(shifted_a, yy));
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> undef_a_shifted;
- extend_bit = cell->type == "$shiftx" ? ez->CONST_TRUE : ez->CONST_FALSE;
- if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
+ extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE;
+ if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID(A_SIGNED)].as_bool())
extend_bit = undef_a.back();
while (undef_y.size() < undef_a.size())
@@ -813,20 +815,20 @@ struct SatGen
while (undef_y.size() > undef_a.size())
undef_a.push_back(extend_bit);
- if (cell->type == "$shl" || cell->type == "$sshl")
+ if (cell->type.in(ID($shl), ID($sshl)))
undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
- if (cell->type == "$shr")
+ if (cell->type == ID($shr))
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
- if (cell->type == "$sshr")
- undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
+ if (cell->type == ID($sshr))
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters[ID(A_SIGNED)].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
- if (cell->type == "$shift")
- undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
+ if (cell->type == ID($shift))
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID(B_SIGNED)].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
- if (cell->type == "$shiftx")
- undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE);
+ if (cell->type == ID($shiftx))
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID(B_SIGNED)].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE);
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
std::vector<int> undef_all_y_bits(undef_y.size(), undef_any_b);
@@ -836,11 +838,11 @@ struct SatGen
return true;
}
- if (cell->type == "$mul")
+ if (cell->type == ID($mul))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidth(a, b, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@@ -857,17 +859,17 @@ struct SatGen
if (model_undef) {
log_assert(arith_undef_handled);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
undefGating(y, yy, undef_y);
}
return true;
}
- if (cell->type == "$macc")
+ if (cell->type == ID($macc))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
Macc macc;
macc.from_cell(cell);
@@ -916,13 +918,13 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
ez->assume(ez->vec_eq(undef_y, std::vector<int>(GetSize(y), ez->OR(undef_any_a, undef_any_b))));
undefGating(y, tmp, undef_y);
@@ -933,17 +935,17 @@ struct SatGen
return true;
}
- if (cell->type == "$div" || cell->type == "$mod")
+ if (cell->type.in(ID($div), ID($mod)))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidth(a, b, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
std::vector<int> a_u, b_u;
- if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) {
+ if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool()) {
a_u = ez->vec_ite(a.back(), ez->vec_neg(a), a);
b_u = ez->vec_ite(b.back(), ez->vec_neg(b), b);
} else {
@@ -968,13 +970,13 @@ struct SatGen
}
std::vector<int> y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size());
- if (cell->type == "$div") {
- if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool())
+ if (cell->type == ID($div)) {
+ if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool())
ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u)));
else
ez->assume(ez->vec_eq(y_tmp, y_u));
} else {
- if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool())
+ if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool())
ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf)));
else
ez->assume(ez->vec_eq(y_tmp, chain_buf));
@@ -984,20 +986,20 @@ struct SatGen
ez->assume(ez->expression(ezSAT::OpOr, b));
} else {
std::vector<int> div_zero_result;
- if (cell->type == "$div") {
- if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) {
+ if (cell->type == ID($div)) {
+ if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool()) {
std::vector<int> all_ones(y.size(), ez->CONST_TRUE);
std::vector<int> only_first_one(y.size(), ez->CONST_FALSE);
only_first_one.at(0) = ez->CONST_TRUE;
div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones);
} else {
- div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->CONST_TRUE);
+ div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE);
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
}
} else {
- int copy_a_bits = min(cell->getPort("\\A").size(), cell->getPort("\\B").size());
+ int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::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())
+ if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool())
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back());
else
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
@@ -1007,27 +1009,27 @@ struct SatGen
if (model_undef) {
log_assert(arith_undef_handled);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
undefGating(y, yy, undef_y);
}
return true;
}
- if (cell->type == "$lut")
+ if (cell->type == ID($lut))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> lut;
- for (auto bit : cell->getParam("\\LUT").bits)
- lut.push_back(bit == RTLIL::S1 ? ez->CONST_TRUE : ez->CONST_FALSE);
+ for (auto bit : cell->getParam(ID(LUT)).bits)
+ lut.push_back(bit == State::S1 ? ez->CONST_TRUE : ez->CONST_FALSE);
while (GetSize(lut) < (1 << GetSize(a)))
lut.push_back(ez->CONST_FALSE);
lut.resize(1 << GetSize(a));
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
std::vector<int> t(lut), u(GetSize(t), ez->CONST_FALSE);
for (int i = GetSize(a)-1; i >= 0; i--)
@@ -1045,7 +1047,7 @@ struct SatGen
log_assert(GetSize(t) == 1);
log_assert(GetSize(u) == 1);
undefGating(y, t, u);
- ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort("\\Y"), timestep), u));
+ ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort(ID::Y), timestep), u));
}
else
{
@@ -1063,15 +1065,15 @@ struct SatGen
return true;
}
- if (cell->type == "$sop")
+ if (cell->type == ID($sop))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0);
- int width = cell->getParam("\\WIDTH").as_int();
- int depth = cell->getParam("\\DEPTH").as_int();
+ int width = cell->getParam(ID(WIDTH)).as_int();
+ int depth = cell->getParam(ID(DEPTH)).as_int();
- vector<State> table_raw = cell->getParam("\\TABLE").bits;
+ vector<State> table_raw = cell->getParam(ID(TABLE)).bits;
while (GetSize(table_raw) < 2*width*depth)
table_raw.push_back(State::S0);
@@ -1094,8 +1096,8 @@ struct SatGen
if (model_undef)
{
std::vector<int> products, undef_products;
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0);
for (int i = 0; i < depth; i++)
{
@@ -1145,13 +1147,13 @@ struct SatGen
return true;
}
- if (cell->type == "$fa")
+ if (cell->type == ID($fa))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> c = importDefSigSpec(cell->getPort("\\C"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
- std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> c = importDefSigSpec(cell->getPort(ID(C)), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
+ std::vector<int> x = importDefSigSpec(cell->getPort(ID(X)), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
std::vector<int> xx = model_undef ? ez->vec_var(x.size()) : x;
@@ -1165,12 +1167,12 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_c = importUndefSigSpec(cell->getPort(ID(C)), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
- std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+ std::vector<int> undef_x = importUndefSigSpec(cell->getPort(ID(X)), timestep);
ez->assume(ez->vec_eq(undef_y, ez->vec_or(ez->vec_or(undef_a, undef_b), undef_c)));
ez->assume(ez->vec_eq(undef_x, undef_y));
@@ -1181,12 +1183,12 @@ struct SatGen
return true;
}
- if (cell->type == "$lcu")
+ if (cell->type == ID($lcu))
{
- std::vector<int> p = importDefSigSpec(cell->getPort("\\P"), timestep);
- std::vector<int> g = importDefSigSpec(cell->getPort("\\G"), timestep);
- std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep);
- std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep);
+ std::vector<int> p = importDefSigSpec(cell->getPort(ID(P)), timestep);
+ std::vector<int> g = importDefSigSpec(cell->getPort(ID(G)), timestep);
+ std::vector<int> ci = importDefSigSpec(cell->getPort(ID(CI)), timestep);
+ std::vector<int> co = importDefSigSpec(cell->getPort(ID(CO)), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(co.size()) : co;
@@ -1195,10 +1197,10 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_p = importUndefSigSpec(cell->getPort("\\P"), timestep);
- std::vector<int> undef_g = importUndefSigSpec(cell->getPort("\\G"), timestep);
- std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep);
- std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep);
+ std::vector<int> undef_p = importUndefSigSpec(cell->getPort(ID(P)), timestep);
+ std::vector<int> undef_g = importUndefSigSpec(cell->getPort(ID(G)), timestep);
+ std::vector<int> undef_ci = importUndefSigSpec(cell->getPort(ID(CI)), timestep);
+ std::vector<int> undef_co = importUndefSigSpec(cell->getPort(ID(CO)), timestep);
int undef_any_p = ez->expression(ezSAT::OpOr, undef_p);
int undef_any_g = ez->expression(ezSAT::OpOr, undef_g);
@@ -1213,15 +1215,15 @@ struct SatGen
return true;
}
- if (cell->type == "$alu")
+ if (cell->type == ID($alu))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
- std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep);
- std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep);
- std::vector<int> bi = importDefSigSpec(cell->getPort("\\BI"), timestep);
- std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
+ std::vector<int> x = importDefSigSpec(cell->getPort(ID(X)), timestep);
+ std::vector<int> ci = importDefSigSpec(cell->getPort(ID(CI)), timestep);
+ std::vector<int> bi = importDefSigSpec(cell->getPort(ID(BI)), timestep);
+ std::vector<int> co = importDefSigSpec(cell->getPort(ID(CO)), timestep);
extendSignalWidth(a, b, y, cell);
extendSignalWidth(a, b, x, cell);
@@ -1246,14 +1248,14 @@ struct SatGen
if (model_undef)
{
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
- std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep);
- std::vector<int> undef_bi = importUndefSigSpec(cell->getPort("\\BI"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_ci = importUndefSigSpec(cell->getPort(ID(CI)), timestep);
+ std::vector<int> undef_bi = importUndefSigSpec(cell->getPort(ID(BI)), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
- std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep);
- std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+ std::vector<int> undef_x = importUndefSigSpec(cell->getPort(ID(X)), timestep);
+ std::vector<int> undef_co = importUndefSigSpec(cell->getPort(ID(CO)), timestep);
extendSignalWidth(undef_a, undef_b, undef_y, cell);
extendSignalWidth(undef_a, undef_b, undef_x, cell);
@@ -1279,19 +1281,19 @@ struct SatGen
return true;
}
- if (cell->type == "$slice")
+ if (cell->type == ID($slice))
{
- RTLIL::SigSpec a = cell->getPort("\\A");
- RTLIL::SigSpec y = cell->getPort("\\Y");
- ez->assume(signals_eq(a.extract(cell->parameters.at("\\OFFSET").as_int(), y.size()), y, timestep));
+ RTLIL::SigSpec a = cell->getPort(ID::A);
+ RTLIL::SigSpec y = cell->getPort(ID::Y);
+ ez->assume(signals_eq(a.extract(cell->parameters.at(ID(OFFSET)).as_int(), y.size()), y, timestep));
return true;
}
- if (cell->type == "$concat")
+ if (cell->type == ID($concat))
{
- RTLIL::SigSpec a = cell->getPort("\\A");
- RTLIL::SigSpec b = cell->getPort("\\B");
- RTLIL::SigSpec y = cell->getPort("\\Y");
+ RTLIL::SigSpec a = cell->getPort(ID::A);
+ RTLIL::SigSpec b = cell->getPort(ID::B);
+ RTLIL::SigSpec y = cell->getPort(ID::Y);
RTLIL::SigSpec ab = a;
ab.append(b);
@@ -1300,24 +1302,24 @@ struct SatGen
return true;
}
- if (timestep > 0 && cell->type.in("$ff", "$dff", "$_FF_", "$_DFF_N_", "$_DFF_P_"))
+ if (timestep > 0 && cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_N_), ID($_DFF_P_)))
{
if (timestep == 1)
{
- initial_state.add((*sigmap)(cell->getPort("\\Q")));
+ initial_state.add((*sigmap)(cell->getPort(ID(Q))));
}
else
{
- std::vector<int> d = importDefSigSpec(cell->getPort("\\D"), timestep-1);
- std::vector<int> q = importDefSigSpec(cell->getPort("\\Q"), timestep);
+ std::vector<int> d = importDefSigSpec(cell->getPort(ID(D)), timestep-1);
+ std::vector<int> q = importDefSigSpec(cell->getPort(ID(Q)), timestep);
std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q;
ez->assume(ez->vec_eq(d, qq));
if (model_undef)
{
- std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1);
- std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Q"), timestep);
+ std::vector<int> undef_d = importUndefSigSpec(cell->getPort(ID(D)), timestep-1);
+ std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID(Q)), timestep);
ez->assume(ez->vec_eq(undef_d, undef_q));
undefGating(q, qq, undef_q);
@@ -1326,21 +1328,21 @@ struct SatGen
return true;
}
- if (cell->type == "$anyconst")
+ if (cell->type == ID($anyconst))
{
if (timestep < 2)
return true;
- std::vector<int> d = importDefSigSpec(cell->getPort("\\Y"), timestep-1);
- std::vector<int> q = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> d = importDefSigSpec(cell->getPort(ID::Y), timestep-1);
+ std::vector<int> q = importDefSigSpec(cell->getPort(ID::Y), timestep);
std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q;
ez->assume(ez->vec_eq(d, qq));
if (model_undef)
{
- std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\Y"), timestep-1);
- std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_d = importUndefSigSpec(cell->getPort(ID::Y), timestep-1);
+ std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep);
ez->assume(ez->vec_eq(undef_d, undef_q));
undefGating(q, qq, undef_q);
@@ -1348,23 +1350,23 @@ struct SatGen
return true;
}
- if (cell->type == "$anyseq")
+ if (cell->type == ID($anyseq))
{
return true;
}
- if (cell->type == "$_BUF_" || cell->type == "$equiv")
+ if (cell->type.in(ID($_BUF_), ID($equiv)))
{
- std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidthUnary(a, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
ez->assume(ez->vec_eq(a, yy));
if (model_undef) {
- std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
extendSignalWidthUnary(undef_a, undef_y, cell, false);
ez->assume(ez->vec_eq(undef_a, undef_y));
undefGating(y, yy, undef_y);
@@ -1372,18 +1374,18 @@ struct SatGen
return true;
}
- if (cell->type == "$initstate")
+ if (cell->type == ID($initstate))
{
auto key = make_pair(prefix, timestep);
if (initstates.count(key) == 0)
initstates[key] = false;
- std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
log_assert(GetSize(y) == 1);
ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE);
if (model_undef) {
- std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
log_assert(GetSize(undef_y) == 1);
ez->SET(undef_y[0], ez->CONST_FALSE);
}
@@ -1391,19 +1393,19 @@ struct SatGen
return true;
}
- if (cell->type == "$assert")
+ if (cell->type == ID($assert))
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
- asserts_a[pf].append((*sigmap)(cell->getPort("\\A")));
- asserts_en[pf].append((*sigmap)(cell->getPort("\\EN")));
+ asserts_a[pf].append((*sigmap)(cell->getPort(ID::A)));
+ asserts_en[pf].append((*sigmap)(cell->getPort(ID(EN))));
return true;
}
- if (cell->type == "$assume")
+ if (cell->type == ID($assume))
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
- assumes_a[pf].append((*sigmap)(cell->getPort("\\A")));
- assumes_en[pf].append((*sigmap)(cell->getPort("\\EN")));
+ assumes_a[pf].append((*sigmap)(cell->getPort(ID::A)));
+ assumes_en[pf].append((*sigmap)(cell->getPort(ID(EN))));
return true;
}
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 94d6d675f..5018a4888 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -129,7 +129,7 @@ void yosys_banner()
log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n");
- log(" | Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> |\n");
+ log(" | Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> |\n");
log(" | |\n");
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
@@ -510,10 +510,13 @@ void yosys_setup()
if(already_setup)
return;
already_setup = true;
- // if there are already IdString objects then we have a global initialization order bug
- IdString empty_id;
- log_assert(empty_id.index_ == 0);
- IdString::get_reference(empty_id.index_);
+
+ RTLIL::ID::A = "\\A";
+ RTLIL::ID::B = "\\B";
+ RTLIL::ID::Y = "\\Y";
+ RTLIL::ID::keep = "\\keep";
+ RTLIL::ID::whitebox = "\\whitebox";
+ RTLIL::ID::blackbox = "\\blackbox";
#ifdef WITH_PYTHON
PyImport_AppendInittab((char*)"libyosys", INIT_MODULE);
@@ -575,9 +578,6 @@ void yosys_shutdown()
#ifdef WITH_PYTHON
Py_Finalize();
#endif
-
- IdString empty_id;
- IdString::put_reference(empty_id.index_);
}
RTLIL::IdString new_id(std::string file, int line, std::string func)
@@ -647,12 +647,12 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern)
void rewrite_filename(std::string &filename)
{
- if (filename.substr(0, 1) == "\"" && filename.substr(GetSize(filename)-1) == "\"")
+ if (filename.compare(0, 1, "\"") == 0 && filename.compare(GetSize(filename)-1, std::string::npos, "\"") == 0)
filename = filename.substr(1, GetSize(filename)-2);
- if (filename.substr(0, 2) == "+/")
+ if (filename.compare(0, 2, "+/") == 0)
filename = proc_share_dirname() + filename.substr(2);
#ifndef _WIN32
- if (filename.substr(0, 2) == "~/")
+ if (filename.compare(0, 2, "~/") == 0)
filename = filename.replace(0, 1, getenv("HOME"));
#endif
}
@@ -894,23 +894,26 @@ void run_frontend(std::string filename, std::string command, std::string *backen
design = yosys_design;
if (command == "auto") {
- if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
+ std::string filename_trim = filename;
+ if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".gz") == 0)
+ filename_trim.erase(filename_trim.size()-3);
+ if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-2, std::string::npos, ".v") == 0)
command = "verilog";
- else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
+ else if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".sv") == 0)
command = "verilog -sv";
- else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".vhd")
+ else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vhd") == 0)
command = "vhdl";
- else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif")
+ else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".blif") == 0)
command = "blif";
- else if (filename.size() > 5 && filename.substr(filename.size()-6) == ".eblif")
+ else if (filename_trim.size() > 5 && filename_trim.compare(filename_trim.size()-6, std::string::npos, ".eblif") == 0)
command = "blif";
- else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".json")
+ else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".json") == 0)
command = "json";
- else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
+ else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".il") == 0)
command = "ilang";
- else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
+ else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".ys") == 0)
command = "script";
- else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".tcl")
+ else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".tcl") == 0)
command = "tcl";
else if (filename == "-")
command = "script";
@@ -961,14 +964,18 @@ void run_frontend(std::string filename, std::string command, std::string *backen
command += next_line;
}
handle_label(command, from_to_active, run_from, run_to);
- if (from_to_active)
+ if (from_to_active) {
Pass::call(design, command);
+ design->check();
+ }
}
if (!command.empty()) {
handle_label(command, from_to_active, run_from, run_to);
- if (from_to_active)
+ if (from_to_active) {
Pass::call(design, command);
+ design->check();
+ }
}
}
catch (...) {
@@ -997,6 +1004,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen
Pass::call(design, vector<string>({command, filename}));
else
Frontend::frontend_call(design, NULL, filename, command);
+ design->check();
}
void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
@@ -1020,17 +1028,17 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig
design = yosys_design;
if (command == "auto") {
- if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
+ if (filename.size() > 2 && filename.compare(filename.size()-2, std::string::npos, ".v") == 0)
command = "verilog";
- else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
+ else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0)
command = "ilang";
- else if (filename.size() > 4 && filename.substr(filename.size()-4) == ".aig")
+ else if (filename.size() > 4 && filename.compare(filename.size()-4, std::string::npos, ".aig") == 0)
command = "aiger";
- else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
+ else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".blif") == 0)
command = "blif";
- else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".edif")
+ else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".edif") == 0)
command = "edif";
- else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".json")
+ else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".json") == 0)
command = "json";
else if (filename == "-")
command = "ilang";
@@ -1064,7 +1072,7 @@ static char *readline_cmd_generator(const char *text, int state)
}
for (; it != pass_register.end(); it++) {
- if (it->first.substr(0, len) == text)
+ if (it->first.compare(0, len, text) == 0)
return strdup((it++)->first.c_str());
}
return NULL;
@@ -1086,7 +1094,7 @@ static char *readline_obj_generator(const char *text, int state)
if (design->selected_active_module.empty())
{
for (auto &it : design->modules_)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
}
else
@@ -1095,19 +1103,19 @@ static char *readline_obj_generator(const char *text, int state)
RTLIL::Module *module = design->modules_.at(design->selected_active_module);
for (auto &it : module->wires_)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
for (auto &it : module->memories)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
for (auto &it : module->cells_)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
for (auto &it : module->processes)
- if (RTLIL::unescape_id(it.first).substr(0, len) == text)
+ if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
}
@@ -1180,6 +1188,7 @@ void shell(RTLIL::Design *design)
design->selection_stack.pop_back();
log_reset_stack();
}
+ design->check();
}
if (command == NULL)
printf("exit\n");
@@ -1254,24 +1263,59 @@ struct HistoryPass : public Pass {
#endif
struct ScriptCmdPass : public Pass {
- ScriptCmdPass() : Pass("script", "execute commands from script file") { }
+ ScriptCmdPass() : Pass("script", "execute commands from file or wire") { }
void help() YS_OVERRIDE {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" script <filename> [<from_label>:<to_label>]\n");
+ log(" script -scriptwire [selection]\n");
log("\n");
- log("This command executes the yosys commands in the specified file.\n");
+ log("This command executes the yosys commands in the specified file (default\n");
+ log("behaviour), or commands embedded in the constant text value connected to the\n");
+ log("selected wires.\n");
log("\n");
- log("The 2nd argument can be used to only execute the section of the\n");
- log("file between the specified labels. An empty from label is synonymous\n");
- log("for the beginning of the file and an empty to label is synonymous\n");
- log("for the end of the file.\n");
+ log("In the default (file) case, the 2nd argument can be used to only execute the\n");
+ log("section of the file between the specified labels. An empty from label is\n");
+ log("synonymous with the beginning of the file and an empty to label is synonymous\n");
+ log("with the end of the file.\n");
log("\n");
log("If only one label is specified (without ':') then only the block\n");
log("marked with that label (until the next label) is executed.\n");
log("\n");
+ log("In \"-scriptwire\" mode, the commands on the selected wire(s) will be executed\n");
+ log("in the scope of (and thus, relative to) the wires' owning module(s). This\n");
+ log("'-module' mode can be exited by using the 'cd' command.\n");
+ log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
- if (args.size() < 2)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool scriptwire = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-scriptwire") {
+ scriptwire = true;
+ continue;
+ }
+ break;
+ }
+ if (scriptwire) {
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules())
+ for (auto &c : mod->connections()) {
+ if (!c.first.is_wire())
+ continue;
+ auto w = c.first.as_wire();
+ if (!mod->selected(w))
+ continue;
+ if (!c.second.is_fully_const())
+ log_error("RHS of selected wire %s.%s is not constant.\n", log_id(mod), log_id(w));
+ auto v = c.second.as_const();
+ Pass::call_on_module(design, mod, v.decode_string());
+ }
+ }
+ else if (args.size() < 2)
log_cmd_error("Missing script file.\n");
else if (args.size() == 2)
run_frontend(args[1], "script", design);
diff --git a/kernel/yosys.h b/kernel/yosys.h
index c7b671724..a80cb00b4 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -52,6 +52,7 @@
#include <stdexcept>
#include <memory>
#include <cmath>
+#include <cstddef>
#include <sstream>
#include <fstream>
@@ -87,6 +88,10 @@ extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
extern void Tcl_Finalize(void);
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
+extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
+extern Tcl_Obj *Tcl_NewIntObj(int intValue);
+extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
+extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
# endif
#endif
@@ -300,8 +305,17 @@ RTLIL::IdString new_id(std::string file, int line, std::string func);
#define NEW_ID \
YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
-#define ID(_str) \
- ([]() { static YOSYS_NAMESPACE_PREFIX RTLIL::IdString _id(_str); return _id; })()
+// Create a statically allocated IdString object, using for example ID(A) or ID($add).
+//
+// Recipe for Converting old code that is using conversion of strings like "\\A" and
+// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for
+// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary.
+//
+// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' <filename>
+//
+#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \
+ static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
+namespace ID = RTLIL::ID;
RTLIL::Design *yosys_get_design();
std::string proc_self_dirname();
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index cb1bcf1be..0106059b6 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -494,6 +494,6 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA
\end{fixme}
\begin{fixme}
-Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
+Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, {\tt \$\_OAI4\_}, and {\tt \$\_NMUX\_} cells.
\end{fixme}
diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex
index 1a25c477f..3009bf2c0 100644
--- a/manual/CHAPTER_Overview.tex
+++ b/manual/CHAPTER_Overview.tex
@@ -331,8 +331,9 @@ to update {\tt \textbackslash{}q}.
An RTLIL::Process is a container for zero or more RTLIL::SyncRule objects and
exactly one RTLIL::CaseRule object, which is called the {\it root case}.
-An RTLIL::SyncRule object contains an (optional) synchronization condition
-(signal and edge-type) and zero or more assignments (RTLIL::SigSig).
+An RTLIL::SyncRule object contains an (optional) synchronization condition (signal and edge-type) and zero or
+more assignments (RTLIL::SigSig). The {\tt always} synchronization condition is used to break combinatorial
+loops when a latch should be inferred instead.
An RTLIL::CaseRule is a container for zero or more assignments (RTLIL::SigSig)
and zero or more RTLIL::SwitchRule objects. An RTLIL::SwitchRule objects is a
diff --git a/misc/launcher.c b/misc/launcher.c
index 157d68cf3..e0d8208f1 100644
--- a/misc/launcher.c
+++ b/misc/launcher.c
@@ -61,6 +61,7 @@ SOFTWARE. */
#include <windows.h>
#include <tchar.h>
#include <fcntl.h>
+#include <unistd.h>
int child_pid=0;
@@ -338,7 +339,7 @@ int run(int argc, char **argv, int is_gui) {
if (is_gui) {
/* Use exec, we don't need to wait for the GUI to finish */
- execv(ptr, (const char * const *)(newargs));
+ execv(ptr, (char * const *)(newargs));
return fail("Could not exec %s", ptr); /* shouldn't get here! */
}
diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py
index 48a54b643..2bf364470 100644
--- a/misc/py_wrap_generator.py
+++ b/misc/py_wrap_generator.py
@@ -773,6 +773,9 @@ class WClass:
#if self.link_type != link_types.pointer:
text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{"
+ text += "\n\t\t\tif(ref == nullptr){"
+ text += "\n\t\t\t\tthrow std::runtime_error(\"" + self.name + " does not exist.\");"
+ text += "\n\t\t\t}"
text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));"
if self.link_type == link_types.pointer:
text += "\n\t\t\tret->ref_obj = ref;"
diff --git a/passes/cmds/blackbox.cc b/passes/cmds/blackbox.cc
index 6094f8f16..d09ed872e 100644
--- a/passes/cmds/blackbox.cc
+++ b/passes/cmds/blackbox.cc
@@ -23,7 +23,7 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct BlackboxPass : public Pass {
- BlackboxPass() : Pass("blackbox", "change type of cells in the design") { }
+ BlackboxPass() : Pass("blackbox", "convert modules into blackbox modules") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
index 038ab7c7c..5a47988ec 100644
--- a/passes/cmds/bugpoint.cc
+++ b/passes/cmds/bugpoint.cc
@@ -51,14 +51,14 @@ struct BugpointPass : public Pass {
log(" only consider crashes that place this string in the log file.\n");
log("\n");
log(" -fast\n");
- log(" run `clean -purge` after each minimization step. converges faster, but\n");
- log(" produces larger testcases, and may fail to produce any testcase at all if\n");
- log(" the crash is related to dangling wires.\n");
+ log(" run `proc_clean; clean -purge` after each minimization step. converges\n");
+ log(" faster, but produces larger testcases, and may fail to produce any\n");
+ log(" testcase at all if the crash is related to dangling wires.\n");
log("\n");
log(" -clean\n");
- log(" run `clean -purge` before checking testcase and after finishing. produces\n");
- log(" smaller and more useful testcases, but may fail to produce any testcase\n");
- log(" at all if the crash is related to dangling wires.\n");
+ log(" run `proc_clean; clean -purge` before checking testcase and after\n");
+ log(" finishing. produces smaller and more useful testcases, but may fail to\n");
+ log(" produce any testcase at all if the crash is related to dangling wires.\n");
log("\n");
log(" -modules\n");
log(" try to remove modules.\n");
@@ -72,6 +72,12 @@ struct BugpointPass : public Pass {
log(" -connections\n");
log(" try to reconnect ports to 'x.\n");
log("\n");
+ log(" -assigns\n");
+ log(" try to remove process assigns from cases.\n");
+ log("\n");
+ log(" -updates\n");
+ log(" try to remove process updates from syncs.\n");
+ log("\n");
}
bool run_yosys(RTLIL::Design *design, string yosys_cmd, string script)
@@ -110,6 +116,7 @@ struct BugpointPass : public Pass {
RTLIL::Design *design_copy = new RTLIL::Design;
for (auto &it : design->modules_)
design_copy->add(it.second->clone());
+ Pass::call(design_copy, "proc_clean -quiet");
Pass::call(design_copy, "clean -purge");
if (do_delete)
@@ -117,7 +124,7 @@ struct BugpointPass : public Pass {
return design_copy;
}
- RTLIL::Design *simplify_something(RTLIL::Design *design, int &seed, bool stage2, bool modules, bool ports, bool cells, bool connections)
+ RTLIL::Design *simplify_something(RTLIL::Design *design, int &seed, bool stage2, bool modules, bool ports, bool cells, bool connections, bool assigns, bool updates)
{
RTLIL::Design *design_copy = new RTLIL::Design;
for (auto &it : design->modules_)
@@ -225,6 +232,59 @@ struct BugpointPass : public Pass {
}
}
}
+ if (assigns)
+ {
+ for (auto mod : design_copy->modules())
+ {
+ if (mod->get_blackbox_attribute())
+ continue;
+
+ for (auto &pr : mod->processes)
+ {
+ vector<RTLIL::CaseRule*> cases = {&pr.second->root_case};
+ while (!cases.empty())
+ {
+ RTLIL::CaseRule *cs = cases[0];
+ cases.erase(cases.begin());
+ for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it)
+ {
+ if (index++ == seed)
+ {
+ log("Trying to remove assign %s %s in %s.%s.\n", log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str());
+ cs->actions.erase(it);
+ return design_copy;
+ }
+ }
+ for (auto &sw : cs->switches)
+ cases.insert(cases.end(), sw->cases.begin(), sw->cases.end());
+ }
+ }
+ }
+ }
+ if (updates)
+ {
+ for (auto mod : design_copy->modules())
+ {
+ if (mod->get_blackbox_attribute())
+ continue;
+
+ for (auto &pr : mod->processes)
+ {
+ for (auto &sy : pr.second->syncs)
+ {
+ for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it)
+ {
+ if (index++ == seed)
+ {
+ log("Trying to remove sync %s update %s %s in %s.%s.\n", log_signal(sy->signal), log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str());
+ sy->actions.erase(it);
+ return design_copy;
+ }
+ }
+ }
+ }
+ }
+ }
return NULL;
}
@@ -232,7 +292,7 @@ struct BugpointPass : public Pass {
{
string yosys_cmd = "yosys", script, grep;
bool fast = false, clean = false;
- bool modules = false, ports = false, cells = false, connections = false, has_part = false;
+ bool modules = false, ports = false, cells = false, connections = false, assigns = false, updates = false, has_part = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -277,6 +337,16 @@ struct BugpointPass : public Pass {
has_part = true;
continue;
}
+ if (args[argidx] == "-assigns") {
+ assigns = true;
+ has_part = true;
+ continue;
+ }
+ if (args[argidx] == "-updates") {
+ updates = true;
+ has_part = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -290,6 +360,8 @@ struct BugpointPass : public Pass {
ports = true;
cells = true;
connections = true;
+ assigns = true;
+ updates = true;
}
if (!design->full_selection())
@@ -305,7 +377,7 @@ struct BugpointPass : public Pass {
bool found_something = false, stage2 = false;
while (true)
{
- if (RTLIL::Design *simplified = simplify_something(crashing_design, seed, stage2, modules, ports, cells, connections))
+ if (RTLIL::Design *simplified = simplify_something(crashing_design, seed, stage2, modules, ports, cells, connections, assigns, updates))
{
simplified = clean_design(simplified, fast, /*do_delete=*/true);
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 1128116b4..628ac4c5e 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -121,7 +121,7 @@ struct CoverPass : public Pass {
}
break;
}
- while (argidx < args.size() && args[argidx].substr(0, 1) != "-")
+ while (argidx < args.size() && args[argidx].compare(0, 1, "-") != 0)
patterns.push_back(args[argidx++]);
extra_args(args, argidx, design);
diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc
index f8d91ea48..5822c09f8 100644
--- a/passes/cmds/delete.cc
+++ b/passes/cmds/delete.cc
@@ -107,7 +107,7 @@ struct DeletePass : public Pass {
for (auto &it : module->cells_) {
if (design->selected(module, it.second))
delete_cells.insert(it.second);
- if ((it.second->type == "$memrd" || it.second->type == "$memwr") &&
+ if (it.second->type.in("$memrd", "$memwr") &&
delete_mems.count(it.second->parameters.at("\\MEMID").decode_string()) != 0)
delete_cells.insert(it.second);
}
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index b5e8ef1af..59d10a1b8 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -34,7 +34,7 @@ static bool match_ids(RTLIL::IdString id, std::string pattern)
{
if (id == pattern)
return true;
- if (id.size() > 0 && id[0] == '\\' && id.substr(1) == pattern)
+ if (id.size() > 0 && id[0] == '\\' && id.compare(1, std::string::npos, pattern.c_str()) == 0)
return true;
if (patmatch(pattern.c_str(), id.c_str()))
return true;
@@ -124,11 +124,11 @@ static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, st
size_t pos = match_expr.find_first_of("<!=>");
if (pos != std::string::npos) {
- if (match_expr.substr(pos, 2) == "!=")
+ if (match_expr.compare(pos, 2, "!=") == 0)
return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), '!');
- if (match_expr.substr(pos, 2) == "<=")
+ if (match_expr.compare(pos, 2, "<=") == 0)
return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), '[');
- if (match_expr.substr(pos, 2) == ">=")
+ if (match_expr.compare(pos, 2, ">=") == 0)
return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), ']');
return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+1), match_expr[pos]);
}
@@ -711,32 +711,32 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
log_cmd_error("Must have at least one element on the stack for operator %%a.\n");
select_op_alias(design, work_stack[work_stack.size()-1]);
} else
- if (arg == "%x" || (arg.size() > 2 && arg.substr(0, 2) == "%x" && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) {
+ if (arg == "%x" || (arg.size() > 2 && arg.compare(0, 2, "%x") == 0 && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%x.\n");
select_op_expand(design, arg, 'x', false);
} else
- if (arg == "%ci" || (arg.size() > 3 && arg.substr(0, 3) == "%ci" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
+ if (arg == "%ci" || (arg.size() > 3 && arg.compare(0, 3, "%ci") == 0 && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%ci.\n");
select_op_expand(design, arg, 'i', false);
} else
- if (arg == "%co" || (arg.size() > 3 && arg.substr(0, 3) == "%co" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
+ if (arg == "%co" || (arg.size() > 3 && arg.compare(0, 3, "%co") == 0 && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%co.\n");
select_op_expand(design, arg, 'o', false);
} else
- if (arg == "%xe" || (arg.size() > 3 && arg.substr(0, 3) == "%xe" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
+ if (arg == "%xe" || (arg.size() > 3 && arg.compare(0, 3, "%xe") == 0 && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%xe.\n");
select_op_expand(design, arg, 'x', true);
} else
- if (arg == "%cie" || (arg.size() > 4 && arg.substr(0, 4) == "%cie" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) {
+ if (arg == "%cie" || (arg.size() > 4 && arg.compare(0, 4, "%cie") == 0 && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%cie.\n");
select_op_expand(design, arg, 'i', true);
} else
- if (arg == "%coe" || (arg.size() > 4 && arg.substr(0, 4) == "%coe" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) {
+ if (arg == "%coe" || (arg.size() > 4 && arg.compare(0, 4, "%coe") == 0 && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%coe.\n");
select_op_expand(design, arg, 'o', true);
@@ -766,7 +766,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
} else {
size_t pos = arg.find('/');
if (pos == std::string::npos) {
- if (arg.find(':') == std::string::npos || arg.substr(0, 1) == "A")
+ if (arg.find(':') == std::string::npos || arg.compare(0, 1, "A") == 0)
arg_mod = arg;
else
arg_mod = "*", arg_memb = arg;
@@ -787,7 +787,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
sel.full_selection = false;
for (auto &mod_it : design->modules_)
{
- if (arg_mod.substr(0, 2) == "A:") {
+ if (arg_mod.compare(0, 2, "A:") == 0) {
if (!match_attr(mod_it.second->attributes, arg_mod.substr(2)))
continue;
} else
@@ -800,27 +800,27 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
}
RTLIL::Module *mod = mod_it.second;
- if (arg_memb.substr(0, 2) == "w:") {
+ if (arg_memb.compare(0, 2, "w:") == 0) {
for (auto &it : mod->wires_)
if (match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.substr(0, 2) == "i:") {
+ if (arg_memb.compare(0, 2, "i:") == 0) {
for (auto &it : mod->wires_)
if (it.second->port_input && match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.substr(0, 2) == "o:") {
+ if (arg_memb.compare(0, 2, "o:") == 0) {
for (auto &it : mod->wires_)
if (it.second->port_output && match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.substr(0, 2) == "x:") {
+ if (arg_memb.compare(0, 2, "x:") == 0) {
for (auto &it : mod->wires_)
if ((it.second->port_input || it.second->port_output) && match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.substr(0, 2) == "s:") {
+ if (arg_memb.compare(0, 2, "s:") == 0) {
size_t delim = arg_memb.substr(2).find(':');
if (delim == std::string::npos) {
int width = atoi(arg_memb.substr(2).c_str());
@@ -837,27 +837,27 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
sel.selected_members[mod->name].insert(it.first);
}
} else
- if (arg_memb.substr(0, 2) == "m:") {
+ if (arg_memb.compare(0, 2, "m:") == 0) {
for (auto &it : mod->memories)
if (match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.substr(0, 2) == "c:") {
+ if (arg_memb.compare(0, 2, "c:") ==0) {
for (auto &it : mod->cells_)
if (match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.substr(0, 2) == "t:") {
+ if (arg_memb.compare(0, 2, "t:") == 0) {
for (auto &it : mod->cells_)
if (match_ids(it.second->type, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.substr(0, 2) == "p:") {
+ if (arg_memb.compare(0, 2, "p:") == 0) {
for (auto &it : mod->processes)
if (match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.substr(0, 2) == "a:") {
+ if (arg_memb.compare(0, 2, "a:") == 0) {
for (auto &it : mod->wires_)
if (match_attr(it.second->attributes, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
@@ -871,12 +871,12 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (match_attr(it.second->attributes, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
- if (arg_memb.substr(0, 2) == "r:") {
+ if (arg_memb.compare(0, 2, "r:") == 0) {
for (auto &it : mod->cells_)
if (match_attr(it.second->parameters, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else {
- if (arg_memb.substr(0, 2) == "n:")
+ if (arg_memb.compare(0, 2, "n:") == 0)
arg_memb = arg_memb.substr(2);
for (auto &it : mod->wires_)
if (match_ids(it.first, arg_memb))
@@ -927,7 +927,7 @@ void handle_extra_select_args(Pass *pass, vector<string> args, size_t argidx, si
{
work_stack.clear();
for (; argidx < args_size; argidx++) {
- if (args[argidx].substr(0, 1) == "-") {
+ if (args[argidx].compare(0, 1, "-") == 0) {
if (pass != NULL)
pass->cmd_error(args, argidx, "Unexpected option in selection arguments.");
else
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index b9fcc3e7a..1ccfc2e86 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -34,7 +34,7 @@ struct setunset_t
setunset_t(std::string set_name, std::string set_value) : name(RTLIL::escape_id(set_name)), value(), unset(false)
{
- if (set_value.substr(0, 1) == "\"" && set_value.substr(GetSize(set_value)-1) == "\"") {
+ if (set_value.compare(0, 1, "\"") == 0 && set_value.compare(GetSize(set_value)-1, std::string::npos, "\"") == 0) {
value = RTLIL::Const(set_value.substr(1, GetSize(set_value)-2));
} else {
RTLIL::SigSpec sig_value;
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index cf729215f..2e9fc72af 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -527,11 +527,11 @@ struct ShowWorker
{
currentColor = xorshift32(currentColor);
if (wires_on_demand.count(it.first) > 0) {
- if (it.second.in.size() == 1 && it.second.out.size() > 1 && it.second.in.begin()->substr(0, 1) == "p")
+ if (it.second.in.size() == 1 && it.second.out.size() > 1 && it.second.in.begin()->compare(0, 1, "p") == 0)
it.second.out.erase(*it.second.in.begin());
if (it.second.in.size() == 1 && it.second.out.size() == 1) {
std::string from = *it.second.in.begin(), to = *it.second.out.begin();
- if (from != to || from.substr(0, 1) != "p")
+ if (from != to || from.compare(0, 1, "p") != 0)
fprintf(f, "%s:e -> %s:w [%s, %s];\n", from.c_str(), to.c_str(), nextColor(it.second.color).c_str(), widthLabel(it.second.bits).c_str());
continue;
}
@@ -808,7 +808,7 @@ struct ShowPass : public Pass {
if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str());
RTLIL::Design *lib = new RTLIL::Design;
- Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
+ Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog"));
libs.push_back(lib);
}
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index d22685b62..c8e4f3981 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -17,11 +17,10 @@
*
*/
-#include "kernel/register.h"
+#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "passes/techmap/libparse.h"
-
-#include "kernel/log.h"
+#include "kernel/cost.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -223,6 +222,28 @@ struct statdata_t
log("\n");
log(" Estimated number of LCs: %10d\n", lc_cnt);
}
+
+ if (tech == "cmos")
+ {
+ int tran_cnt = 0;
+ bool tran_cnt_exact = true;
+ auto &gate_costs = CellCosts::cmos_gate_cost();
+
+ for (auto it : num_cells_by_type) {
+ auto ctype = it.first;
+ auto cnum = it.second;
+
+ if (gate_costs.count(ctype))
+ tran_cnt += cnum * gate_costs.at(ctype);
+ else if (ctype.in("$_DFF_P_", "$_DFF_N_"))
+ tran_cnt += cnum * 16;
+ else
+ tran_cnt_exact = false;
+ }
+
+ log("\n");
+ log(" Estimated number of transistors: %10d%s\n", tran_cnt, tran_cnt_exact ? "" : "+");
+ }
}
};
@@ -285,8 +306,8 @@ struct StatPass : public Pass {
log(" use cell area information from the provided liberty file\n");
log("\n");
log(" -tech <technology>\n");
- log(" print area estemate for the specified technology. Corrently supported\n");
- log(" calues for <technology>: xilinx\n");
+ log(" print area estemate for the specified technology. Currently supported\n");
+ log(" values for <technology>: xilinx, cmos\n");
log("\n");
log(" -width\n");
log(" annotate internal cell types with their word width.\n");
@@ -330,7 +351,7 @@ struct StatPass : public Pass {
}
extra_args(args, argidx, design);
- if (techname != "" && techname != "xilinx")
+ if (techname != "" && techname != "xilinx" && techname != "cmos")
log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
for (auto mod : design->selected_modules())
diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc
index 9613b462b..64a762d7c 100644
--- a/passes/cmds/write_file.cc
+++ b/passes/cmds/write_file.cc
@@ -62,7 +62,7 @@ struct WriteFileFrontend : public Frontend {
if (argidx < args.size() && args[argidx].rfind("-", 0) != 0)
output_filename = args[argidx++];
else
- log_cmd_error("Missing putput filename.\n");
+ log_cmd_error("Missing output filename.\n");
extra_args(f, filename, args, argidx);
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
index dbd8682e6..4855ce29e 100644
--- a/passes/equiv/equiv_make.cc
+++ b/passes/equiv/equiv_make.cc
@@ -532,10 +532,10 @@ struct EquivMakePass : public Pass {
log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str());
if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes())
- log_cmd_error("Gold module contains memories or procresses. Run 'memory' or 'proc' respectively.\n");
+ log_cmd_error("Gold module contains memories or processes. Run 'memory' or 'proc' respectively.\n");
if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes())
- log_cmd_error("Gate module contains memories or procresses. Run 'memory' or 'proc' respectively.\n");
+ log_cmd_error("Gate module contains memories or processes. Run 'memory' or 'proc' respectively.\n");
worker.read_blacklists();
worker.read_encfiles();
diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc
index 3596dfd7b..19d1c25ac 100644
--- a/passes/equiv/equiv_opt.cc
+++ b/passes/equiv/equiv_opt.cc
@@ -97,7 +97,7 @@ struct EquivOptPass:public ScriptPass
for (; argidx < args.size(); argidx++) {
if (command.empty()) {
- if (args[argidx].substr(0, 1) == "-")
+ if (args[argidx].compare(0, 1, "-") == 0)
cmd_error(args, argidx, "Unknown option.");
} else {
command += " ";
diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc
index a7973fd04..6672948b9 100644
--- a/passes/equiv/equiv_struct.cc
+++ b/passes/equiv/equiv_struct.cc
@@ -215,9 +215,9 @@ struct EquivStructWorker
if (c != nullptr) {
string n = cell_name.str();
cells_type = c->type;
- if (GetSize(n) > 5 && n.substr(GetSize(n)-5) == "_gold")
+ if (GetSize(n) > 5 && n.compare(GetSize(n)-5, std::string::npos, "_gold") == 0)
gold_cells.push_back(c);
- else if (GetSize(n) > 5 && n.substr(GetSize(n)-5) == "_gate")
+ else if (GetSize(n) > 5 && n.compare(GetSize(n)-5, std::string::npos, "_gate") == 0)
gate_cells.push_back(c);
else
other_cells.push_back(c);
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index c34d0c15c..1610ec751 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -50,7 +50,7 @@ struct FsmExpand
if (full_mode || cell->type == "$_MUX_")
return true;
- if (cell->type == "$mux" || cell->type == "$pmux")
+ if (cell->type.in("$mux", "$pmux"))
if (cell->getPort("\\A").size() < 2)
return true;
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index 6095eaf30..a85c3bec0 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -168,7 +168,7 @@ undef_bit_in_next_state:
ctrl_in_bit_indices[ctrl_in[i]] = i;
for (auto &it : ctrl_in_bit_indices)
- if (tr.ctrl_in.bits.at(it.second) == RTLIL::S1 && exclusive_ctrls.count(it.first) != 0)
+ if (tr.ctrl_in.bits.at(it.second) == State::S1 && exclusive_ctrls.count(it.first) != 0)
for (auto &dc_bit : exclusive_ctrls.at(it.first))
if (ctrl_in_bit_indices.count(dc_bit))
tr.ctrl_in.bits.at(ctrl_in_bit_indices.at(dc_bit)) = RTLIL::State::Sa;
@@ -216,13 +216,13 @@ undef_bit_in_next_state:
ce.push();
dont_care.append(undef);
ce.set(undef, constval.as_const());
- if (exclusive_ctrls.count(undef) && constval == RTLIL::S1)
+ if (exclusive_ctrls.count(undef) && constval == State::S1)
for (auto &bit : exclusive_ctrls.at(undef)) {
RTLIL::SigSpec bitval = bit;
- if (ce.eval(bitval) && bitval != RTLIL::S0)
+ if (ce.eval(bitval) && bitval != State::S0)
goto found_contradiction_1;
else
- ce.set(bit, RTLIL::S0);
+ ce.set(bit, State::S0);
}
find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
found_contradiction_1:
@@ -231,21 +231,21 @@ undef_bit_in_next_state:
else
{
ce.push(), ce_nostop.push();
- ce.set(undef, RTLIL::S0);
- ce_nostop.set(undef, RTLIL::S0);
+ ce.set(undef, State::S0);
+ ce_nostop.set(undef, State::S0);
find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
ce.pop(), ce_nostop.pop();
ce.push(), ce_nostop.push();
- ce.set(undef, RTLIL::S1);
- ce_nostop.set(undef, RTLIL::S1);
+ ce.set(undef, State::S1);
+ ce_nostop.set(undef, State::S1);
if (exclusive_ctrls.count(undef))
for (auto &bit : exclusive_ctrls.at(undef)) {
RTLIL::SigSpec bitval = bit;
- if ((ce.eval(bitval) || ce_nostop.eval(bitval)) && bitval != RTLIL::S0)
+ if ((ce.eval(bitval) || ce_nostop.eval(bitval)) && bitval != State::S0)
goto found_contradiction_2;
else
- ce.set(bit, RTLIL::S0), ce_nostop.set(bit, RTLIL::S0);
+ ce.set(bit, State::S0), ce_nostop.set(bit, RTLIL::S0);
}
find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
found_contradiction_2:
@@ -263,8 +263,8 @@ static void extract_fsm(RTLIL::Wire *wire)
RTLIL::SigSpec dff_in(RTLIL::State::Sm, wire->width);
RTLIL::Const reset_state(RTLIL::State::Sx, wire->width);
- RTLIL::SigSpec clk = RTLIL::S0;
- RTLIL::SigSpec arst = RTLIL::S0;
+ RTLIL::SigSpec clk = State::S0;
+ RTLIL::SigSpec arst = State::S0;
bool clk_polarity = true;
bool arst_polarity = true;
@@ -371,8 +371,8 @@ static void extract_fsm(RTLIL::Wire *wire)
RTLIL::Cell *fsm_cell = module->addCell(stringf("$fsm$%s$%d", wire->name.c_str(), autoidx++), "$fsm");
fsm_cell->setPort("\\CLK", clk);
fsm_cell->setPort("\\ARST", arst);
- fsm_cell->parameters["\\CLK_POLARITY"] = clk_polarity ? RTLIL::S1 : RTLIL::S0;
- fsm_cell->parameters["\\ARST_POLARITY"] = arst_polarity ? RTLIL::S1 : RTLIL::S0;
+ fsm_cell->parameters["\\CLK_POLARITY"] = clk_polarity ? State::S1 : State::S0;
+ fsm_cell->parameters["\\ARST_POLARITY"] = arst_polarity ? State::S1 : State::S0;
fsm_cell->setPort("\\CTRL_IN", ctrl_in);
fsm_cell->setPort("\\CTRL_OUT", ctrl_out);
fsm_cell->parameters["\\NAME"] = RTLIL::Const(wire->name.str());
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index 90c958912..80913fda8 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -133,7 +133,7 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const
cases_vector.append(and_sig);
break;
case 0:
- cases_vector.append(RTLIL::SigSpec(1, 1));
+ cases_vector.append(State::S1);
break;
default:
log_abort();
@@ -150,7 +150,7 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const
} else if (cases_vector.size() == 1) {
module->connect(RTLIL::SigSig(output, cases_vector));
} else {
- module->connect(RTLIL::SigSig(output, RTLIL::SigSpec(0, 1)));
+ module->connect(RTLIL::SigSig(output, State::S0));
}
}
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 213437c01..fd95b94b2 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -48,7 +48,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
RTLIL::Cell *cell = i2.second;
if (design->has(cell->type))
continue;
- if (cell->type.substr(0, 1) == "$" && cell->type.substr(0, 3) != "$__")
+ if (cell->type.begins_with("$__"))
continue;
for (auto &pattern : celltypes)
if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str()))
@@ -143,7 +143,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
// Return the "basic" type for an array item.
std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) {
std::string basicType = celltype;
- if (celltype.substr(0, 7) == "$array:") {
+ if (celltype.compare(0, strlen("$array:"), "$array:") == 0) {
int pos_idx = celltype.find_first_of(':');
int pos_num = celltype.find_first_of(':', pos_idx + 1);
int pos_type = celltype.find_first_of(':', pos_num + 1);
@@ -194,16 +194,16 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
std::vector<RTLIL::IdString> connections_to_add_name;
std::vector<RTLIL::SigSpec> connections_to_add_signal;
- if (cell->type.substr(0, 7) == "$array:") {
+ if (cell->type.begins_with("$array:")) {
int pos[3];
basic_cell_type(cell->type.str(), pos);
int pos_idx = pos[0];
int pos_num = pos[1];
int pos_type = pos[2];
- int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str());
- int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str());
+ int idx = atoi(cell->type.substr(pos_idx + 1, pos_num).c_str());
+ int num = atoi(cell->type.substr(pos_num + 1, pos_type).c_str());
array_cells[cell] = std::pair<int, int>(idx, num);
- cell->type = cell->type.str().substr(pos_type + 1);
+ cell->type = cell->type.substr(pos_type + 1);
}
dict<RTLIL::IdString, RTLIL::Module*> interfaces_to_add_to_submodule;
dict<RTLIL::IdString, RTLIL::IdString> modports_used_in_submodule;
@@ -422,7 +422,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
for (auto &conn : cell->connections_) {
int conn_size = conn.second.size();
RTLIL::IdString portname = conn.first;
- if (portname.substr(0, 1) == "$") {
+ if (portname.begins_with("$")) {
int port_id = atoi(portname.substr(1).c_str());
for (auto &wire_it : mod->wires_)
if (wire_it.second->port_id == port_id) {
@@ -457,9 +457,8 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::
for (auto cell : mod->cells()) {
std::string celltype = cell->type.str();
- if (celltype.substr(0, 7) == "$array:") {
+ if (celltype.compare(0, strlen("$array:"), "$array:") == 0)
celltype = basic_cell_type(celltype);
- }
if (design->module(celltype))
hierarchy_worker(design, used, design->module(celltype), indent+4);
}
@@ -521,9 +520,8 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
for (auto cell : module->cells()) {
std::string celltype = cell->type.str();
// Is this an array instance
- if (celltype.substr(0, 7) == "$array:") {
+ if (celltype.compare(0, strlen("$array:"), "$array:") == 0)
celltype = basic_cell_type(celltype);
- }
// Is this cell a module instance?
auto instModule = design->module(celltype);
// If there is no instance for this, issue a warning.
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index ddc56d9b5..aa8f94149 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -68,6 +68,10 @@ struct rules_t
if (groups != GetSize(transp)) log_error("Bram %s variant %d has %d groups but only %d entries in 'transp'.\n", log_id(name), variant, groups, GetSize(transp));
if (groups != GetSize(clocks)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clocks'.\n", log_id(name), variant, groups, GetSize(clocks));
if (groups != GetSize(clkpol)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clkpol'.\n", log_id(name), variant, groups, GetSize(clkpol));
+
+ int group = 0;
+ for (auto e : enable)
+ if (e > dbits) log_error("Bram %s variant %d group %d has %d enable bits but only %d dbits.\n", log_id(name), variant, group, e, dbits);
}
vector<portinfo_t> make_portinfos() const
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 369fcc84e..6acbce62f 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -194,8 +194,8 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
log_assert(sig_wr_en.size() == wr_ports * memory->width);
mem->parameters["\\WR_PORTS"] = Const(wr_ports);
- mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.as_const() : Const(0, 1);
- mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.as_const() : Const(0, 1);
+ mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.as_const() : State::S0;
+ mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.as_const() : State::S0;
mem->setPort("\\WR_CLK", sig_wr_clk);
mem->setPort("\\WR_ADDR", sig_wr_addr);
@@ -209,9 +209,9 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
log_assert(sig_rd_data.size() == rd_ports * memory->width);
mem->parameters["\\RD_PORTS"] = Const(rd_ports);
- mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.as_const() : Const(0, 1);
- mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.as_const() : Const(0, 1);
- mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.as_const() : Const(0, 1);
+ mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.as_const() : State::S0;
+ mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.as_const() : State::S0;
+ mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.as_const() : State::S0;
mem->setPort("\\RD_CLK", sig_rd_clk);
mem->setPort("\\RD_ADDR", sig_rd_addr);
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 220d29295..be4b3c100 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -17,6 +17,7 @@
*
*/
+#include <algorithm>
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
@@ -182,20 +183,27 @@ struct MemoryDffWorker
if (mux_cells_a.count(sig_data) || mux_cells_b.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"));
+ RTLIL::SigSpec en;
+ std::vector<RTLIL::SigSpec> check_q;
+
+ do {
+ 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);
+ check_q.push_back(sigmap(mux->getPort(enable_invert ? "\\B" : "\\A")));
+ sig_data = sigmap(mux->getPort("\\Y"));
+ en.append(enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S"));
+ } while (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data));
- sig_data = sigmap(mux->getPort("\\Y"));
for (auto bit : sig_data)
if (sigbit_users_count[bit] > 1)
goto skip_ff_after_read_merging;
- if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) && sig_data == check_q)
+ if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) &&
+ std::all_of(check_q.begin(), check_q.end(), [&](const SigSpec &cq) {return cq == sig_data; }))
{
disconnect_dff(sig_data);
cell->setPort("\\CLK", clk_data);
- cell->setPort("\\EN", enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S"));
+ cell->setPort("\\EN", en.size() > 1 ? module->ReduceAnd(NEW_ID, en) : en);
cell->setPort("\\DATA", sig_data);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
@@ -254,7 +262,7 @@ struct MemoryDffWorker
mux_cells_a[sigmap(cell->getPort("\\A"))] = cell;
mux_cells_b[sigmap(cell->getPort("\\B"))] = cell;
}
- if (cell->type == "$not" || cell->type == "$_NOT_" || (cell->type == "$logic_not" && GetSize(cell->getPort("\\A")) == 1)) {
+ if (cell->type.in("$not", "$_NOT_") || (cell->type == "$logic_not" && GetSize(cell->getPort("\\A")) == 1)) {
SigSpec sig_a = cell->getPort("\\A");
SigSpec sig_y = cell->getPort("\\Y");
if (cell->type == "$not")
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index a0b808e56..65bccb5ef 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -301,7 +301,7 @@ struct MemoryMapWorker
RTLIL::Wire *w = w_seladdr;
- if (wr_bit != RTLIL::SigSpec(1, 1))
+ if (wr_bit != State::S1)
{
RTLIL::Cell *c = module->addCell(genid(cell->name, "$wren", i, "", j, "", wr_offset), "$and");
c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index 172afe0cb..eb912cfd4 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -155,7 +155,7 @@ struct MemoryShareWorker
{
bool ignore_data_port = false;
- if (cell->type == "$mux" || cell->type == "$pmux")
+ if (cell->type.in("$mux", "$pmux"))
{
std::vector<RTLIL::SigBit> sig_a = sigmap(cell->getPort("\\A"));
std::vector<RTLIL::SigBit> sig_b = sigmap(cell->getPort("\\B"));
@@ -173,7 +173,7 @@ struct MemoryShareWorker
continue;
}
- if ((cell->type == "$memwr" || cell->type == "$memrd") &&
+ if (cell->type.in("$memwr", "$memrd") &&
cell->parameters.at("\\MEMID").decode_string() == memid)
ignore_data_port = true;
@@ -690,7 +690,7 @@ struct MemoryShareWorker
sigmap_xmux.add(cell->getPort("\\Y"), sig_a);
}
- if (cell->type == "$mux" || cell->type == "$pmux")
+ if (cell->type.in("$mux", "$pmux"))
{
std::vector<RTLIL::SigBit> sig_y = sigmap(cell->getPort("\\Y"));
for (int i = 0; i < int(sig_y.size()); i++)
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 337fee9e4..eb07e9452 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -4,6 +4,7 @@ OBJS += passes/opt/opt_merge.o
OBJS += passes/opt/opt_muxtree.o
OBJS += passes/opt/opt_reduce.o
OBJS += passes/opt/opt_rmdff.o
+OBJS += passes/opt/opt_share.o
OBJS += passes/opt/opt_clean.o
OBJS += passes/opt/opt_expr.o
@@ -14,5 +15,5 @@ OBJS += passes/opt/opt_demorgan.o
OBJS += passes/opt/rmports.o
OBJS += passes/opt/opt_lut.o
OBJS += passes/opt/pmux2shiftx.o
+OBJS += passes/opt/muxpack.o
endif
-
diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc
new file mode 100644
index 000000000..c40c02acd
--- /dev/null
+++ b/passes/opt/muxpack.cc
@@ -0,0 +1,368 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ExclusiveDatabase
+{
+ Module *module;
+ const SigMap &sigmap;
+
+ dict<SigBit, std::pair<SigSpec,std::vector<Const>>> sig_cmp_prev;
+
+ ExclusiveDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap)
+ {
+ SigSpec const_sig, nonconst_sig;
+ SigBit y_port;
+ pool<Cell*> reduce_or;
+ for (auto cell : module->cells()) {
+ if (cell->type == ID($eq)) {
+ nonconst_sig = sigmap(cell->getPort(ID::A));
+ const_sig = sigmap(cell->getPort(ID::B));
+ if (!const_sig.is_fully_const()) {
+ if (!nonconst_sig.is_fully_const())
+ continue;
+ std::swap(nonconst_sig, const_sig);
+ }
+ y_port = sigmap(cell->getPort(ID::Y));
+ }
+ else if (cell->type == ID($logic_not)) {
+ nonconst_sig = sigmap(cell->getPort(ID::A));
+ const_sig = Const(State::S0, GetSize(nonconst_sig));
+ y_port = sigmap(cell->getPort(ID::Y));
+ }
+ else if (cell->type == ID($reduce_or)) {
+ reduce_or.insert(cell);
+ continue;
+ }
+ else continue;
+
+ log_assert(!nonconst_sig.empty());
+ log_assert(!const_sig.empty());
+ sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,std::vector<Const>{const_sig.as_const()});
+ }
+
+ for (auto cell : reduce_or) {
+ nonconst_sig = SigSpec();
+ std::vector<Const> values;
+ SigSpec a_port = sigmap(cell->getPort(ID::A));
+ for (auto bit : a_port) {
+ auto it = sig_cmp_prev.find(bit);
+ if (it == sig_cmp_prev.end()) {
+ nonconst_sig = SigSpec();
+ break;
+ }
+ if (nonconst_sig.empty())
+ nonconst_sig = it->second.first;
+ else if (nonconst_sig != it->second.first) {
+ nonconst_sig = SigSpec();
+ break;
+ }
+ for (auto value : it->second.second)
+ values.push_back(value);
+ }
+ if (nonconst_sig.empty())
+ continue;
+ y_port = sigmap(cell->getPort(ID::Y));
+ sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,std::move(values));
+ }
+ }
+
+ bool query(const SigSpec &sig) const
+ {
+ SigSpec nonconst_sig;
+ pool<Const> const_values;
+
+ for (auto bit : sig.bits()) {
+ auto it = sig_cmp_prev.find(bit);
+ if (it == sig_cmp_prev.end())
+ return false;
+
+ if (nonconst_sig.empty())
+ nonconst_sig = it->second.first;
+ else if (nonconst_sig != it->second.first)
+ return false;
+
+ for (auto value : it->second.second)
+ if (!const_values.insert(value).second)
+ return false;
+ }
+
+ return true;
+ }
+};
+
+
+struct MuxpackWorker
+{
+ Module *module;
+ SigMap sigmap;
+
+ int mux_count, pmux_count;
+
+ pool<Cell*> remove_cells;
+
+ dict<SigSpec, Cell*> sig_chain_next;
+ dict<SigSpec, Cell*> sig_chain_prev;
+ pool<SigBit> sigbit_with_non_chain_users;
+ pool<Cell*> chain_start_cells;
+ pool<Cell*> candidate_cells;
+
+ ExclusiveDatabase excl_db;
+
+ void make_sig_chain_next_prev()
+ {
+ for (auto wire : module->wires())
+ {
+ if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
+ for (auto bit : sigmap(wire))
+ sigbit_with_non_chain_users.insert(bit);
+ }
+ }
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type.in(ID($mux), ID($pmux)) && !cell->get_bool_attribute(ID::keep))
+ {
+ SigSpec a_sig = sigmap(cell->getPort(ID::A));
+ SigSpec b_sig;
+ if (cell->type == ID($mux))
+ b_sig = sigmap(cell->getPort(ID::B));
+ SigSpec y_sig = sigmap(cell->getPort(ID::Y));
+
+ if (sig_chain_next.count(a_sig))
+ for (auto a_bit : a_sig.bits())
+ sigbit_with_non_chain_users.insert(a_bit);
+ else {
+ sig_chain_next[a_sig] = cell;
+ candidate_cells.insert(cell);
+ }
+
+ if (!b_sig.empty()) {
+ if (sig_chain_next.count(b_sig))
+ for (auto b_bit : b_sig.bits())
+ sigbit_with_non_chain_users.insert(b_bit);
+ else {
+ sig_chain_next[b_sig] = cell;
+ candidate_cells.insert(cell);
+ }
+ }
+
+ sig_chain_prev[y_sig] = cell;
+ continue;
+ }
+
+ for (auto conn : cell->connections())
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sigbit_with_non_chain_users.insert(bit);
+ }
+ }
+
+ void find_chain_start_cells()
+ {
+ for (auto cell : candidate_cells)
+ {
+ log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type));
+
+ SigSpec a_sig = sigmap(cell->getPort(ID::A));
+ if (cell->type == ID($mux)) {
+ SigSpec b_sig = sigmap(cell->getPort(ID::B));
+ if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1)
+ goto start_cell;
+
+ if (!sig_chain_prev.count(a_sig))
+ a_sig = b_sig;
+ }
+ else if (cell->type == ID($pmux)) {
+ if (!sig_chain_prev.count(a_sig))
+ goto start_cell;
+ }
+ else log_abort();
+
+ for (auto bit : a_sig.bits())
+ if (sigbit_with_non_chain_users.count(bit))
+ goto start_cell;
+
+ {
+ Cell *prev_cell = sig_chain_prev.at(a_sig);
+ log_assert(prev_cell);
+ SigSpec s_sig = sigmap(cell->getPort(ID(S)));
+ s_sig.append(sigmap(prev_cell->getPort(ID(S))));
+ if (!excl_db.query(s_sig))
+ goto start_cell;
+ }
+
+ continue;
+
+ start_cell:
+ chain_start_cells.insert(cell);
+ }
+ }
+
+ vector<Cell*> create_chain(Cell *start_cell)
+ {
+ vector<Cell*> chain;
+
+ Cell *c = start_cell;
+ while (c != nullptr)
+ {
+ chain.push_back(c);
+
+ SigSpec y_sig = sigmap(c->getPort(ID::Y));
+
+ if (sig_chain_next.count(y_sig) == 0)
+ break;
+
+ c = sig_chain_next.at(y_sig);
+ if (chain_start_cells.count(c) != 0)
+ break;
+ }
+
+ return chain;
+ }
+
+ void process_chain(vector<Cell*> &chain)
+ {
+ if (GetSize(chain) < 2)
+ return;
+
+ int cursor = 0;
+ while (cursor < GetSize(chain))
+ {
+ int cases = GetSize(chain) - cursor;
+
+ Cell *first_cell = chain[cursor];
+ dict<int, SigBit> taps_dict;
+
+ if (cases < 2) {
+ cursor++;
+ continue;
+ }
+
+ Cell *last_cell = chain[cursor+cases-1];
+
+ log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n",
+ log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), cases);
+
+ mux_count += cases;
+ pmux_count += 1;
+
+ first_cell->type = ID($pmux);
+ SigSpec b_sig = first_cell->getPort(ID::B);
+ SigSpec s_sig = first_cell->getPort(ID(S));
+
+ for (int i = 1; i < cases; i++) {
+ Cell* prev_cell = chain[cursor+i-1];
+ Cell* cursor_cell = chain[cursor+i];
+ if (sigmap(prev_cell->getPort(ID::Y)) == sigmap(cursor_cell->getPort(ID::A))) {
+ b_sig.append(cursor_cell->getPort(ID::B));
+ s_sig.append(cursor_cell->getPort(ID(S)));
+ }
+ else {
+ log_assert(cursor_cell->type == ID($mux));
+ b_sig.append(cursor_cell->getPort(ID::A));
+ s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort(ID(S))));
+ }
+ remove_cells.insert(cursor_cell);
+ }
+
+ first_cell->setPort(ID::B, b_sig);
+ first_cell->setPort(ID(S), s_sig);
+ first_cell->setParam(ID(S_WIDTH), GetSize(s_sig));
+ first_cell->setPort(ID::Y, last_cell->getPort(ID::Y));
+
+ cursor += cases;
+ }
+ }
+
+ void cleanup()
+ {
+ for (auto cell : remove_cells)
+ module->remove(cell);
+
+ remove_cells.clear();
+ sig_chain_next.clear();
+ sig_chain_prev.clear();
+ chain_start_cells.clear();
+ candidate_cells.clear();
+ }
+
+ MuxpackWorker(Module *module) :
+ module(module), sigmap(module), mux_count(0), pmux_count(0), excl_db(module, sigmap)
+ {
+ make_sig_chain_next_prev();
+ find_chain_start_cells();
+
+ for (auto c : chain_start_cells) {
+ vector<Cell*> chain = create_chain(c);
+ process_chain(chain);
+ }
+
+ cleanup();
+ }
+};
+
+struct MuxpackPass : public Pass {
+ MuxpackPass() : Pass("muxpack", "$mux/$pmux cascades to $pmux") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" muxpack [selection]\n");
+ log("\n");
+ log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n");
+ log("constructs) and $mux cells (e.g. those created by if-else constructs) into\n");
+ log("$pmux cells.\n");
+ log("\n");
+ log("This optimisation is conservative --- it will only pack $mux or $pmux cells\n");
+ log("whose select lines are driven by '$eq' cells with other such cells if it can be\n");
+ log("certain that their select inputs are mutually exclusive.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ int mux_count = 0;
+ int pmux_count = 0;
+
+ for (auto module : design->selected_modules()) {
+ MuxpackWorker worker(module);
+ mux_count += worker.mux_count;
+ pmux_count += worker.pmux_count;
+ }
+
+ log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count);
+ }
+} MuxpackPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index a4aca2fee..396819883 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -44,7 +44,8 @@ struct OptPass : public Pass {
log(" opt_muxtree\n");
log(" opt_reduce [-fine] [-full]\n");
log(" opt_merge [-share_all]\n");
- log(" opt_rmdff [-keepdc]\n");
+ log(" opt_share (-full only)\n");
+ log(" opt_rmdff [-keepdc] [-sat]\n");
log(" opt_clean [-purge]\n");
log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
log(" while <changed design>\n");
@@ -54,7 +55,7 @@ struct OptPass : public Pass {
log(" do\n");
log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
log(" opt_merge [-share_all]\n");
- log(" opt_rmdff [-keepdc]\n");
+ log(" opt_rmdff [-keepdc] [-sat]\n");
log(" opt_clean [-purge]\n");
log(" while <changed design in opt_rmdff>\n");
log("\n");
@@ -70,6 +71,7 @@ struct OptPass : public Pass {
std::string opt_reduce_args;
std::string opt_merge_args;
std::string opt_rmdff_args;
+ bool opt_share = false;
bool fast_mode = false;
log_header(design, "Executing OPT pass (performing simple optimizations).\n");
@@ -105,6 +107,7 @@ struct OptPass : public Pass {
if (args[argidx] == "-full") {
opt_expr_args += " -full";
opt_reduce_args += " -full";
+ opt_share = true;
continue;
}
if (args[argidx] == "-keepdc") {
@@ -112,6 +115,10 @@ struct OptPass : public Pass {
opt_rmdff_args += " -keepdc";
continue;
}
+ if (args[argidx] == "-sat") {
+ opt_rmdff_args += " -sat";
+ continue;
+ }
if (args[argidx] == "-share_all") {
opt_merge_args += " -share_all";
continue;
@@ -147,6 +154,8 @@ struct OptPass : public Pass {
Pass::call(design, "opt_muxtree");
Pass::call(design, "opt_reduce" + opt_reduce_args);
Pass::call(design, "opt_merge" + opt_merge_args);
+ if (opt_share)
+ Pass::call(design, "opt_share");
Pass::call(design, "opt_rmdff" + opt_rmdff_args);
Pass::call(design, "opt_clean" + opt_clean_args);
Pass::call(design, "opt_expr" + opt_expr_args);
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index cfb0f788a..2f69b3d4c 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -52,7 +52,7 @@ struct keep_cache_t
return cache.at(module);
cache[module] = true;
- if (!module->get_bool_attribute("\\keep")) {
+ if (!module->get_bool_attribute(ID::keep)) {
bool found_keep = false;
for (auto cell : module->cells())
if (query(cell)) found_keep = true;
@@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell)
{
- if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
+ if (cell->type.in(ID($memwr), ID($meminit), ID($assert), ID($assume), ID($live), ID($fair), ID($cover), ID($specify2), ID($specify3), ID($specrule)))
return true;
if (cell->has_keep_attr())
@@ -122,7 +122,7 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto &it : module->wires_) {
Wire *wire = it.second;
- if (wire->port_output || wire->get_bool_attribute("\\keep")) {
+ if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
for (auto bit : sigmap(wire))
for (auto c : wire2driver[bit])
queue.insert(c), unused.erase(c);
@@ -177,8 +177,8 @@ void rmunused_module_cells(Module *module, bool verbose)
int count_nontrivial_wire_attrs(RTLIL::Wire *w)
{
int count = w->attributes.size();
- count -= w->attributes.count("\\src");
- count -= w->attributes.count("\\unused_bits");
+ count -= w->attributes.count(ID(src));
+ count -= w->attributes.count(ID(unused_bits));
return count;
}
@@ -222,10 +222,10 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPoo
bool check_public_name(RTLIL::IdString id)
{
- const std::string &id_str = id.str();
- if (id_str[0] == '$')
+ if (id.begins_with("$"))
return false;
- if (id_str.substr(0, 2) == "\\_" && (id_str[id_str.size()-1] == '_' || id_str.find("_[") != std::string::npos))
+ const std::string &id_str = id.str();
+ if (id.begins_with("\\_") && (id.ends_with("_") || id_str.find("_[") != std::string::npos))
return false;
if (id_str.find(".$") != std::string::npos)
return false;
@@ -297,7 +297,7 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (!wire->port_input)
used_signals_nodrivers.add(sig);
}
- if (wire->get_bool_attribute("\\keep")) {
+ if (wire->get_bool_attribute(ID::keep)) {
RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
assign_map.apply(sig);
used_signals.add(sig);
@@ -311,23 +311,23 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
log_assert(GetSize(s1) == GetSize(s2));
Const initval;
- if (wire->attributes.count("\\init"))
- initval = wire->attributes.at("\\init");
+ if (wire->attributes.count(ID(init)))
+ initval = wire->attributes.at(ID(init));
if (GetSize(initval) != GetSize(wire))
initval.bits.resize(GetSize(wire), State::Sx);
if (initval.is_fully_undef())
- wire->attributes.erase("\\init");
+ wire->attributes.erase(ID(init));
if (GetSize(wire) == 0) {
// delete zero-width wires, unless they are module ports
if (wire->port_id == 0)
goto delete_this_wire;
} else
- if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
+ if (wire->port_id != 0 || wire->get_bool_attribute(ID::keep) || !initval.is_fully_undef()) {
// do not delete anything with "keep" or module ports or initialized wires
} else
- if (!purge_mode && check_public_name(wire->name)) {
- // do not get rid of public names unless in purge mode
+ if (!purge_mode && check_public_name(wire->name) && (raw_used_signals.check_any(s1) || used_signals.check_any(s2) || s1 != s2)) {
+ // do not get rid of public names unless in purge mode or if the wire is entirely unused, not even aliased
} else
if (!raw_used_signals.check_any(s1)) {
// delete wires that aren't used by anything directly
@@ -357,9 +357,9 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
}
if (new_conn.first.size() > 0) {
if (initval.is_fully_undef())
- wire->attributes.erase("\\init");
+ wire->attributes.erase(ID(init));
else
- wire->attributes.at("\\init") = initval;
+ wire->attributes.at(ID(init)) = initval;
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
module->connect(new_conn);
@@ -377,11 +377,11 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
}
}
if (unused_bits.empty() || wire->port_id != 0)
- wire->attributes.erase("\\unused_bits");
+ wire->attributes.erase(ID(unused_bits));
else
- wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
+ wire->attributes[ID(unused_bits)] = RTLIL::Const(unused_bits);
} else {
- wire->attributes.erase("\\unused_bits");
+ wire->attributes.erase(ID(unused_bits));
}
}
}
@@ -413,18 +413,18 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
dict<SigBit, State> qbits;
for (auto cell : module->cells())
- if (fftypes.cell_known(cell->type) && cell->hasPort("\\Q"))
+ if (fftypes.cell_known(cell->type) && cell->hasPort(ID(Q)))
{
- SigSpec sig = cell->getPort("\\Q");
+ SigSpec sig = cell->getPort(ID(Q));
for (int i = 0; i < GetSize(sig); i++)
{
SigBit bit = sig[i];
- if (bit.wire == nullptr || bit.wire->attributes.count("\\init") == 0)
+ if (bit.wire == nullptr || bit.wire->attributes.count(ID(init)) == 0)
continue;
- Const init = bit.wire->attributes.at("\\init");
+ Const init = bit.wire->attributes.at(ID(init));
if (i >= GetSize(init) || init[i] == State::Sx || init[i] == State::Sz)
continue;
@@ -439,10 +439,10 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
if (!purge_mode && wire->name[0] == '\\')
continue;
- if (wire->attributes.count("\\init") == 0)
+ if (wire->attributes.count(ID(init)) == 0)
continue;
- Const init = wire->attributes.at("\\init");
+ Const init = wire->attributes.at(ID(init));
for (int i = 0; i < GetSize(wire) && i < GetSize(init); i++)
{
@@ -465,7 +465,7 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
if (verbose)
log_debug(" removing redundant init attribute on %s.\n", log_id(wire));
- wire->attributes.erase("\\init");
+ wire->attributes.erase(ID(init));
did_something = true;
next_wire:;
}
@@ -480,10 +480,10 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
std::vector<RTLIL::Cell*> delcells;
for (auto cell : module->cells())
- if (cell->type.in("$pos", "$_BUF_")) {
- bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool();
- RTLIL::SigSpec a = cell->getPort("\\A");
- RTLIL::SigSpec y = cell->getPort("\\Y");
+ if (cell->type.in(ID($pos), ID($_BUF_)) && !cell->has_keep_attr()) {
+ bool is_signed = cell->type == ID($pos) && cell->getParam(ID(A_SIGNED)).as_bool();
+ RTLIL::SigSpec a = cell->getPort(ID::A);
+ RTLIL::SigSpec y = cell->getPort(ID::Y);
a.extend_u0(GetSize(y), is_signed);
module->connect(y, a);
delcells.push_back(cell);
@@ -491,7 +491,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
for (auto cell : delcells) {
if (verbose)
log_debug(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
- log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A")));
+ log_signal(cell->getPort(ID::Y)), log_signal(cell->getPort(ID::A)));
module->remove(cell);
}
if (!delcells.empty())
diff --git a/passes/opt/opt_demorgan.cc b/passes/opt/opt_demorgan.cc
index 1699a6454..4bc82815b 100644
--- a/passes/opt/opt_demorgan.cc
+++ b/passes/opt/opt_demorgan.cc
@@ -35,10 +35,10 @@ void demorgan_worker(
//TODO: Add support for reduce_xor
//DeMorgan of XOR is either XOR (if even number of inputs) or XNOR (if odd number)
- if( (cell->type != "$reduce_and") && (cell->type != "$reduce_or") )
+ if( (cell->type != ID($reduce_and)) && (cell->type != ID($reduce_or)) )
return;
- auto insig = sigmap(cell->getPort("\\A"));
+ auto insig = sigmap(cell->getPort(ID::A));
log("Inspecting %s cell %s (%d inputs)\n", log_id(cell->type), log_id(cell->name), GetSize(insig));
int num_inverted = 0;
for(int i=0; i<GetSize(insig); i++)
@@ -51,7 +51,7 @@ void demorgan_worker(
bool inverted = false;
for(auto x : ports)
{
- if(x.port == "\\Y" && x.cell->type == "$_NOT_")
+ if(x.port == ID::Y && x.cell->type == ID($_NOT_))
{
inverted = true;
break;
@@ -85,7 +85,7 @@ void demorgan_worker(
RTLIL::Cell* srcinv = NULL;
for(auto x : ports)
{
- if(x.port == "\\Y" && x.cell->type == "$_NOT_")
+ if(x.port == ID::Y && x.cell->type == ID($_NOT_))
{
srcinv = x.cell;
break;
@@ -103,7 +103,7 @@ void demorgan_worker(
//We ARE inverted - bypass it
//Don't automatically delete the inverter since other stuff might still use it
else
- insig[i] = srcinv->getPort("\\A");
+ insig[i] = srcinv->getPort(ID::A);
}
//Cosmetic fixup: If our input is just a scrambled version of one bus, rearrange it
@@ -151,20 +151,20 @@ void demorgan_worker(
}
//Push the new input signal back to the reduction (after bypassing/adding inverters)
- cell->setPort("\\A", insig);
+ cell->setPort(ID::A, insig);
//Change the cell type
- if(cell->type == "$reduce_and")
- cell->type = "$reduce_or";
- else if(cell->type == "$reduce_or")
- cell->type = "$reduce_and";
+ if(cell->type == ID($reduce_and))
+ cell->type = ID($reduce_or);
+ else if(cell->type == ID($reduce_or))
+ cell->type = ID($reduce_and);
//don't change XOR
//Add an inverter to the output
- auto inverted_output = cell->getPort("\\Y");
+ auto inverted_output = cell->getPort(ID::Y);
auto uninverted_output = m->addWire(NEW_ID);
m->addNot(NEW_ID, RTLIL::SigSpec(uninverted_output), inverted_output);
- cell->setPort("\\Y", uninverted_output);
+ cell->setPort(ID::Y, uninverted_output);
}
struct OptDemorganPass : public Pass {
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 512ef0cbf..00d7d6063 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -51,9 +51,9 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
}
for (auto wire : module->wires()) {
- if (wire->attributes.count("\\init")) {
+ if (wire->attributes.count(ID(init))) {
SigSpec sig = sigmap(wire);
- Const initval = wire->attributes.at("\\init");
+ Const initval = wire->attributes.at(ID(init));
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
if (initval[i] == State::S0 || initval[i] == State::S1)
initbits[sig[i]] = make_pair(wire, initval[i]);
@@ -61,7 +61,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
}
if (wire->port_input)
driven_signals.add(sigmap(wire));
- if (wire->port_output || wire->get_bool_attribute("\\keep"))
+ if (wire->port_output || wire->get_bool_attribute(ID::keep))
used_signals.add(sigmap(wire));
all_signals.add(sigmap(wire));
}
@@ -99,25 +99,26 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
for (auto wire : revisit_initwires) {
SigSpec sig = sm2(wire);
- Const initval = wire->attributes.at("\\init");
+ Const initval = wire->attributes.at(ID(init));
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
if (SigBit(initval[i]) == sig[i])
initval[i] = State::Sx;
}
if (initval.is_fully_undef()) {
log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire));
- wire->attributes.erase("\\init");
+ wire->attributes.erase(ID(init));
did_something = true;
- } else if (initval != wire->attributes.at("\\init")) {
+ } else if (initval != wire->attributes.at(ID(init))) {
log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval));
- wire->attributes["\\init"] = initval;
+ wire->attributes[ID(init)] = initval;
did_something = true;
}
}
}
}
-void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
+void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
+ const std::string &info YS_ATTRIBUTE(unused), IdString out_port, RTLIL::SigSpec out_val)
{
RTLIL::SigSpec Y = cell->getPort(out_port);
out_val.extend_u0(Y.size(), false);
@@ -134,14 +135,14 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
{
- std::string b_name = cell->hasPort("\\B") ? "\\B" : "\\A";
+ IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A;
- bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
- bool b_signed = cell->parameters.at(b_name + "_SIGNED").as_bool();
+ bool a_signed = cell->parameters.at(ID(A_SIGNED)).as_bool();
+ bool b_signed = cell->parameters.at(b_name.str() + "_SIGNED").as_bool();
- RTLIL::SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_a = sigmap(cell->getPort(ID::A));
RTLIL::SigSpec sig_b = sigmap(cell->getPort(b_name));
- RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+ RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y));
sig_a.extend_u0(sig_y.size(), a_signed);
sig_b.extend_u0(sig_y.size(), b_signed);
@@ -156,10 +157,10 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
int group_idx = GRP_DYN;
RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
- if (cell->type == "$or" && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1))
+ if (cell->type == ID($or) && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1))
bit_a = bit_b = RTLIL::State::S1;
- if (cell->type == "$and" && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0))
+ if (cell->type == ID($and) && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0))
bit_a = bit_b = RTLIL::State::S0;
if (bit_a.wire == NULL && bit_b.wire == NULL)
@@ -199,7 +200,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
new_b.append_bit(it.first.second);
}
- if (cell->type.in("$and", "$or") && i == GRP_CONST_A) {
+ if (cell->type.in(ID($and), ID($or)) && i == GRP_CONST_A) {
log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a));
module->connect(new_y, new_b);
module->connect(new_conn);
@@ -208,24 +209,24 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
- c->setPort("\\A", new_a);
- c->parameters["\\A_WIDTH"] = new_a.size();
- c->parameters["\\A_SIGNED"] = false;
+ c->setPort(ID::A, new_a);
+ c->parameters[ID(A_WIDTH)] = new_a.size();
+ c->parameters[ID(A_SIGNED)] = false;
- if (b_name == "\\B") {
- c->setPort("\\B", new_b);
- c->parameters["\\B_WIDTH"] = new_b.size();
- c->parameters["\\B_SIGNED"] = false;
+ if (b_name == ID::B) {
+ c->setPort(ID::B, new_b);
+ c->parameters[ID(B_WIDTH)] = new_b.size();
+ c->parameters[ID(B_SIGNED)] = false;
}
- c->setPort("\\Y", new_y);
- c->parameters["\\Y_WIDTH"] = new_y->width;
+ c->setPort(ID::Y, new_y);
+ c->parameters[ID(Y_WIDTH)] = new_y->width;
c->check();
module->connect(new_conn);
log_debug(" New cell `%s': A=%s", log_id(c), log_signal(new_a));
- if (b_name == "\\B")
+ if (b_name == ID::B)
log_debug(", B=%s", log_signal(new_b));
log_debug("\n");
}
@@ -367,11 +368,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (auto cell : module->cells())
if (design->selected(module, cell) && cell->type[0] == '$') {
- if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") &&
- cell->getPort("\\A").size() == 1 && cell->getPort("\\Y").size() == 1)
- invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\A"));
- if ((cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == SigSpec(State::S1) && cell->getPort("\\B") == SigSpec(State::S0))
- invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\S"));
+ if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) &&
+ GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1)
+ invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID::A));
+ if (cell->type.in(ID($mux), ID($_MUX_)) &&
+ cell->getPort(ID::A) == SigSpec(State::S1) && cell->getPort(ID::B) == SigSpec(State::S0))
+ invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID(S)));
if (ct_combinational.cell_known(cell->type))
for (auto &conn : cell->connections()) {
RTLIL::SigSpec sig = assign_map(conn.second);
@@ -395,66 +397,66 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (auto cell : cells.sorted)
{
#define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
-#define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
+#define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_))
if (clkinv)
{
- if (cell->type.in("$dff", "$dffe", "$dffsr", "$adff", "$fsm", "$memrd", "$memwr"))
- handle_polarity_inv(cell, "\\CLK", "\\CLK_POLARITY", assign_map, invert_map);
+ if (cell->type.in(ID($dff), ID($dffe), ID($dffsr), ID($adff), ID($fsm), ID($memrd), ID($memwr)))
+ handle_polarity_inv(cell, ID(CLK), ID(CLK_POLARITY), assign_map, invert_map);
- if (cell->type.in("$sr", "$dffsr", "$dlatchsr")) {
- handle_polarity_inv(cell, "\\SET", "\\SET_POLARITY", assign_map, invert_map);
- handle_polarity_inv(cell, "\\CLR", "\\CLR_POLARITY", assign_map, invert_map);
+ if (cell->type.in(ID($sr), ID($dffsr), ID($dlatchsr))) {
+ handle_polarity_inv(cell, ID(SET), ID(SET_POLARITY), assign_map, invert_map);
+ handle_polarity_inv(cell, ID(CLR), ID(CLR_POLARITY), assign_map, invert_map);
}
- if (cell->type.in("$dffe", "$dlatch", "$dlatchsr"))
- handle_polarity_inv(cell, "\\EN", "\\EN_POLARITY", assign_map, invert_map);
+ if (cell->type.in(ID($dffe), ID($dlatch), ID($dlatchsr)))
+ handle_polarity_inv(cell, ID(EN), ID(EN_POLARITY), assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_SR_N?_", "$_SR_P?_", "\\S", assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_SR_?N_", "$_SR_?P_", "\\R", assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_SR_N?_", "$_SR_P?_", ID(S), assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_SR_?N_", "$_SR_?P_", ID(R), assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DFF_N_", "$_DFF_P_", "\\C", assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFF_N_", "$_DFF_P_", ID(C), assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DFFE_N?_", "$_DFFE_P?_", "\\C", assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DFFE_?N_", "$_DFFE_?P_", "\\E", assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFE_N?_", "$_DFFE_P?_", ID(C), assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFE_?N_", "$_DFFE_?P_", ID(E), assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DFF_N??_", "$_DFF_P??_", "\\C", assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DFF_?N?_", "$_DFF_?P?_", "\\R", assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFF_N??_", "$_DFF_P??_", ID(C), assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFF_?N?_", "$_DFF_?P?_", ID(R), assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DFFSR_N??_", "$_DFFSR_P??_", "\\C", assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DFFSR_?N?_", "$_DFFSR_?P?_", "\\S", assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DFFSR_??N_", "$_DFFSR_??P_", "\\R", assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFSR_N??_", "$_DFFSR_P??_", ID(C), assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFSR_?N?_", "$_DFFSR_?P?_", ID(S), assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DFFSR_??N_", "$_DFFSR_??P_", ID(R), assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", "\\E", assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", ID(E), assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", "\\E", assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", "\\S", assign_map, invert_map);
- handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", ID(E), assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", ID(S), assign_map, invert_map);
+ handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", ID(R), assign_map, invert_map);
}
bool detect_const_and = false;
bool detect_const_or = false;
- if (cell->type.in("$reduce_and", "$_AND_"))
+ if (cell->type.in(ID($reduce_and), ID($_AND_)))
detect_const_and = true;
- if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
+ if (cell->type.in(ID($and), ID($logic_and)) && GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::B)) == 1 && !cell->getParam(ID(A_SIGNED)).as_bool())
detect_const_and = true;
- if (cell->type.in("$reduce_or", "$reduce_bool", "$_OR_"))
+ if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($_OR_)))
detect_const_or = true;
- if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
+ if (cell->type.in(ID($or), ID($logic_or)) && GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::B)) == 1 && !cell->getParam(ID(A_SIGNED)).as_bool())
detect_const_or = true;
if (detect_const_and || detect_const_or)
{
- pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool();
+ pool<SigBit> input_bits = assign_map(cell->getPort(ID::A)).to_sigbit_pool();
bool found_zero = false, found_one = false, found_undef = false, found_inv = false, many_conconst = false;
SigBit non_const_input = State::Sm;
- if (cell->hasPort("\\B")) {
- vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector();
+ if (cell->hasPort(ID::B)) {
+ vector<SigBit> more_bits = assign_map(cell->getPort(ID::B)).to_sigbit_vector();
input_bits.insert(more_bits.begin(), more_bits.end());
}
@@ -477,52 +479,50 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (detect_const_and && (found_zero || found_inv)) {
cover("opt.opt_expr.const_and");
- replace_cell(assign_map, module, cell, "const_and", "\\Y", RTLIL::State::S0);
+ replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0);
goto next_cell;
}
if (detect_const_or && (found_one || found_inv)) {
cover("opt.opt_expr.const_or");
- replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1);
+ replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1);
goto next_cell;
}
if (non_const_input != State::Sm && !found_undef) {
cover("opt.opt_expr.and_or_buffer");
- replace_cell(assign_map, module, cell, "and_or_buffer", "\\Y", non_const_input);
+ replace_cell(assign_map, module, cell, "and_or_buffer", ID::Y, non_const_input);
goto next_cell;
}
}
- if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
- GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\Y")) == 1)
+ if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool), ID($reduce_xor), ID($reduce_xnor), ID($neg)) &&
+ GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1)
{
- if (cell->type == "$reduce_xnor") {
+ if (cell->type == ID($reduce_xnor)) {
cover("opt.opt_expr.reduce_xnor_not");
log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n",
log_id(cell->type), log_id(cell->name), log_id(module));
- cell->type = "$not";
+ cell->type = ID($not);
did_something = true;
} else {
cover("opt.opt_expr.unary_buffer");
- replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A"));
+ replace_cell(assign_map, module, cell, "unary_buffer", ID::Y, cell->getPort(ID::A));
}
goto next_cell;
}
if (do_fine)
{
- if (cell->type == "$not" || cell->type == "$pos" ||
- cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor")
+ if (cell->type.in(ID($not), ID($pos), ID($and), ID($or), ID($xor), ID($xnor)))
if (group_cell_inputs(module, cell, true, assign_map))
goto next_cell;
- if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" ||
- cell->type == "$reduce_or" || cell->type == "$reduce_and" || cell->type == "$reduce_bool")
+ if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_and), ID($reduce_bool)))
{
- SigBit neutral_bit = cell->type == "$reduce_and" ? State::S1 : State::S0;
+ SigBit neutral_bit = cell->type == ID($reduce_and) ? State::S1 : State::S0;
- RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
RTLIL::SigSpec new_sig_a;
for (auto bit : sig_a)
@@ -535,17 +535,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str());
log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a));
- cell->setPort("\\A", new_sig_a);
- cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a);
+ cell->setPort(ID::A, new_sig_a);
+ cell->parameters.at(ID(A_WIDTH)) = GetSize(new_sig_a);
did_something = true;
}
}
- if (cell->type == "$logic_and" || cell->type == "$logic_or")
+ if (cell->type.in(ID($logic_and), ID($logic_or)))
{
SigBit neutral_bit = State::S0;
- RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
RTLIL::SigSpec new_sig_b;
for (auto bit : sig_b)
@@ -558,15 +558,15 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str());
log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b));
- cell->setPort("\\B", new_sig_b);
- cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b);
+ cell->setPort(ID::B, new_sig_b);
+ cell->parameters.at(ID(B_WIDTH)) = GetSize(new_sig_b);
did_something = true;
}
}
- if (cell->type == "$reduce_and")
+ if (cell->type == ID($reduce_and))
{
- RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
RTLIL::State new_a = RTLIL::State::S1;
for (auto &bit : sig_a.to_sigbit_vector())
@@ -584,15 +584,15 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cover("opt.opt_expr.fine.$reduce_and");
log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
- cell->setPort("\\A", sig_a = new_a);
- cell->parameters.at("\\A_WIDTH") = 1;
+ cell->setPort(ID::A, sig_a = new_a);
+ cell->parameters.at(ID(A_WIDTH)) = 1;
did_something = true;
}
}
- if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$reduce_or" || cell->type == "$reduce_bool")
+ if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_bool)))
{
- RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
RTLIL::State new_a = RTLIL::State::S0;
for (auto &bit : sig_a.to_sigbit_vector())
@@ -610,15 +610,15 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
- cell->setPort("\\A", sig_a = new_a);
- cell->parameters.at("\\A_WIDTH") = 1;
+ cell->setPort(ID::A, sig_a = new_a);
+ cell->parameters.at(ID(A_WIDTH)) = 1;
did_something = true;
}
}
- if (cell->type == "$logic_and" || cell->type == "$logic_or")
+ if (cell->type.in(ID($logic_and), ID($logic_or)))
{
- RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
RTLIL::State new_b = RTLIL::State::S0;
for (auto &bit : sig_b.to_sigbit_vector())
@@ -636,23 +636,93 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str());
log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
- cell->setPort("\\B", sig_b = new_b);
- cell->parameters.at("\\B_WIDTH") = 1;
+ cell->setPort(ID::B, sig_b = new_b);
+ cell->parameters.at(ID(B_WIDTH)) = 1;
+ did_something = true;
+ }
+ }
+
+ if (cell->type.in(ID($add), ID($sub)))
+ {
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
+ bool sub = cell->type == ID($sub);
+
+ int i;
+ for (i = 0; i < GetSize(sig_y); i++) {
+ if (sig_b.at(i, State::Sx) == State::S0 && sig_a.at(i, State::Sx) != State::Sx)
+ module->connect(sig_y[i], sig_a[i]);
+ else if (!sub && sig_a.at(i, State::Sx) == State::S0 && sig_b.at(i, State::Sx) != State::Sx)
+ module->connect(sig_y[i], sig_b[i]);
+ else
+ break;
+ }
+ if (i > 0) {
+ cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str());
+ cell->setPort(ID::A, sig_a.extract_end(i));
+ cell->setPort(ID::B, sig_b.extract_end(i));
+ cell->setPort(ID::Y, sig_y.extract_end(i));
+ cell->fixup_parameters();
+ did_something = true;
+ }
+ }
+
+ if (cell->type == "$alu")
+ {
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
+ RTLIL::SigBit sig_ci = assign_map(cell->getPort(ID(CI)));
+ RTLIL::SigBit sig_bi = assign_map(cell->getPort(ID(BI)));
+ RTLIL::SigSpec sig_x = cell->getPort(ID(X));
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
+ RTLIL::SigSpec sig_co = cell->getPort(ID(CO));
+
+ if (sig_ci.wire || sig_bi.wire)
+ goto next_cell;
+
+ bool sub = (sig_ci == State::S1 && sig_bi == State::S1);
+
+ // If not a subtraction, yet there is a carry or B is inverted
+ // then no optimisation is possible as carry will not be constant
+ if (!sub && (sig_ci != State::S0 || sig_bi != State::S0))
+ goto next_cell;
+
+ int i;
+ for (i = 0; i < GetSize(sig_y); i++) {
+ if (sig_b.at(i, State::Sx) == State::S0 && sig_a.at(i, State::Sx) != State::Sx) {
+ module->connect(sig_x[i], sub ? module->Not(NEW_ID, sig_a[i]).as_bit() : sig_a[i]);
+ module->connect(sig_y[i], sig_a[i]);
+ module->connect(sig_co[i], sub ? State::S1 : State::S0);
+ }
+ else if (!sub && sig_a.at(i, State::Sx) == State::S0 && sig_b.at(i, State::Sx) != State::Sx) {
+ module->connect(sig_x[i], sig_b[i]);
+ module->connect(sig_y[i], sig_b[i]);
+ module->connect(sig_co[i], State::S0);
+ }
+ else
+ break;
+ }
+ if (i > 0) {
+ cover("opt.opt_expr.fine.$alu");
+ cell->setPort(ID::A, sig_a.extract_end(i));
+ cell->setPort(ID::B, sig_b.extract_end(i));
+ cell->setPort(ID(X), sig_x.extract_end(i));
+ cell->setPort(ID::Y, sig_y.extract_end(i));
+ cell->setPort(ID(CO), sig_co.extract_end(i));
+ cell->fixup_parameters();
did_something = true;
}
}
}
- if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" ||
- cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" ||
- cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt" ||
- cell->type == "$neg" || cell->type == "$add" || cell->type == "$sub" ||
- cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || cell->type == "$pow")
+ if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr),
+ ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow)))
{
- RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
- RTLIL::SigSpec sig_b = cell->hasPort("\\B") ? assign_map(cell->getPort("\\B")) : RTLIL::SigSpec();
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec sig_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec();
- if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
+ if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
sig_a = RTLIL::SigSpec();
for (auto &bit : sig_a.to_sigbit_vector())
@@ -667,45 +737,66 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
found_the_x_bit:
cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str());
- if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" ||
- cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt")
- replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::State::Sx);
+ if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt)))
+ replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx);
else
- replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort("\\Y").size()));
+ replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, GetSize(cell->getPort(ID::Y))));
+ goto next_cell;
+ }
+ }
+
+ if (cell->type.in(ID($shiftx), ID($shift))) {
+ SigSpec sig_a = assign_map(cell->getPort(ID::A));
+ int width;
+ bool trim_x = cell->type == ID($shiftx) || !keepdc;
+ bool trim_0 = cell->type == ID($shift);
+ for (width = GetSize(sig_a); width > 1; width--) {
+ if ((trim_x && sig_a[width-1] == State::Sx) ||
+ (trim_0 && sig_a[width-1] == State::S0))
+ continue;
+ break;
+ }
+
+ if (width < GetSize(sig_a)) {
+ cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell->type.str());
+ sig_a.remove(width, GetSize(sig_a)-width);
+ cell->setPort(ID::A, sig_a);
+ cell->setParam(ID(A_WIDTH), width);
+ did_something = true;
goto next_cell;
}
}
- if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 &&
- invert_map.count(assign_map(cell->getPort("\\A"))) != 0) {
+ if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && GetSize(cell->getPort(ID::Y)) == 1 &&
+ invert_map.count(assign_map(cell->getPort(ID::A))) != 0) {
cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
- replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A"))));
+ replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A))));
goto next_cell;
}
- if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
+ if (cell->type.in(ID($_MUX_), ID($mux)) && invert_map.count(assign_map(cell->getPort(ID(S)))) != 0) {
cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
- RTLIL::SigSpec tmp = cell->getPort("\\A");
- cell->setPort("\\A", cell->getPort("\\B"));
- cell->setPort("\\B", tmp);
- cell->setPort("\\S", invert_map.at(assign_map(cell->getPort("\\S"))));
+ RTLIL::SigSpec tmp = cell->getPort(ID::A);
+ cell->setPort(ID::A, cell->getPort(ID::B));
+ cell->setPort(ID::B, tmp);
+ cell->setPort(ID(S), invert_map.at(assign_map(cell->getPort(ID(S)))));
did_something = true;
goto next_cell;
}
- if (cell->type == "$_NOT_") {
- RTLIL::SigSpec input = cell->getPort("\\A");
+ if (cell->type == ID($_NOT_)) {
+ RTLIL::SigSpec input = cell->getPort(ID::A);
assign_map.apply(input);
if (input.match("1")) ACTION_DO_Y(0);
if (input.match("0")) ACTION_DO_Y(1);
if (input.match("*")) ACTION_DO_Y(x);
}
- if (cell->type == "$_AND_") {
+ if (cell->type == ID($_AND_)) {
RTLIL::SigSpec input;
- input.append(cell->getPort("\\B"));
- input.append(cell->getPort("\\A"));
+ input.append(cell->getPort(ID::B));
+ input.append(cell->getPort(ID::A));
assign_map.apply(input);
if (input.match(" 0")) ACTION_DO_Y(0);
if (input.match("0 ")) ACTION_DO_Y(0);
@@ -717,14 +808,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (input.match(" *")) ACTION_DO_Y(0);
if (input.match("* ")) ACTION_DO_Y(0);
}
- if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1));
- if (input.match("1 ")) ACTION_DO("\\Y", input.extract(0, 1));
+ if (input.match(" 1")) ACTION_DO(ID::Y, input.extract(1, 1));
+ if (input.match("1 ")) ACTION_DO(ID::Y, input.extract(0, 1));
}
- if (cell->type == "$_OR_") {
+ if (cell->type == ID($_OR_)) {
RTLIL::SigSpec input;
- input.append(cell->getPort("\\B"));
- input.append(cell->getPort("\\A"));
+ input.append(cell->getPort(ID::B));
+ input.append(cell->getPort(ID::A));
assign_map.apply(input);
if (input.match(" 1")) ACTION_DO_Y(1);
if (input.match("1 ")) ACTION_DO_Y(1);
@@ -736,14 +827,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (input.match(" *")) ACTION_DO_Y(1);
if (input.match("* ")) ACTION_DO_Y(1);
}
- if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1));
- if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1));
+ if (input.match(" 0")) ACTION_DO(ID::Y, input.extract(1, 1));
+ if (input.match("0 ")) ACTION_DO(ID::Y, input.extract(0, 1));
}
- if (cell->type == "$_XOR_") {
+ if (cell->type == ID($_XOR_)) {
RTLIL::SigSpec input;
- input.append(cell->getPort("\\B"));
- input.append(cell->getPort("\\A"));
+ input.append(cell->getPort(ID::B));
+ input.append(cell->getPort(ID::A));
assign_map.apply(input);
if (input.match("00")) ACTION_DO_Y(0);
if (input.match("01")) ACTION_DO_Y(1);
@@ -751,27 +842,27 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (input.match("11")) ACTION_DO_Y(0);
if (input.match(" *")) ACTION_DO_Y(x);
if (input.match("* ")) ACTION_DO_Y(x);
- if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1));
- if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1));
+ if (input.match(" 0")) ACTION_DO(ID::Y, input.extract(1, 1));
+ if (input.match("0 ")) ACTION_DO(ID::Y, input.extract(0, 1));
}
- if (cell->type == "$_MUX_") {
+ if (cell->type == ID($_MUX_)) {
RTLIL::SigSpec input;
- input.append(cell->getPort("\\S"));
- input.append(cell->getPort("\\B"));
- input.append(cell->getPort("\\A"));
+ input.append(cell->getPort(ID(S)));
+ input.append(cell->getPort(ID::B));
+ input.append(cell->getPort(ID::A));
assign_map.apply(input);
if (input.extract(2, 1) == input.extract(1, 1))
- ACTION_DO("\\Y", input.extract(2, 1));
- if (input.match(" 0")) ACTION_DO("\\Y", input.extract(2, 1));
- if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1));
- if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1));
+ ACTION_DO(ID::Y, input.extract(2, 1));
+ if (input.match(" 0")) ACTION_DO(ID::Y, input.extract(2, 1));
+ if (input.match(" 1")) ACTION_DO(ID::Y, input.extract(1, 1));
+ if (input.match("01 ")) ACTION_DO(ID::Y, input.extract(0, 1));
if (input.match("10 ")) {
cover("opt.opt_expr.mux_to_inv");
- cell->type = "$_NOT_";
- cell->setPort("\\A", input.extract(0, 1));
- cell->unsetPort("\\B");
- cell->unsetPort("\\S");
+ cell->type = ID($_NOT_);
+ cell->setPort(ID::A, input.extract(0, 1));
+ cell->unsetPort(ID::B);
+ cell->unsetPort(ID(S));
goto next_cell;
}
if (input.match("11 ")) ACTION_DO_Y(1);
@@ -780,38 +871,38 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (input.match("01*")) ACTION_DO_Y(x);
if (input.match("10*")) ACTION_DO_Y(x);
if (mux_undef) {
- if (input.match("* ")) ACTION_DO("\\Y", input.extract(1, 1));
- if (input.match(" * ")) ACTION_DO("\\Y", input.extract(2, 1));
- if (input.match(" *")) ACTION_DO("\\Y", input.extract(2, 1));
+ if (input.match("* ")) ACTION_DO(ID::Y, input.extract(1, 1));
+ if (input.match(" * ")) ACTION_DO(ID::Y, input.extract(2, 1));
+ if (input.match(" *")) ACTION_DO(ID::Y, input.extract(2, 1));
}
}
- if (cell->type == "$_TBUF_" || cell->type == "$tribuf") {
- RTLIL::SigSpec input = cell->getPort(cell->type == "$_TBUF_" ? "\\E" : "\\EN");
- RTLIL::SigSpec a = cell->getPort("\\A");
+ if (cell->type.in(ID($_TBUF_), ID($tribuf))) {
+ RTLIL::SigSpec input = cell->getPort(cell->type == ID($_TBUF_) ? ID(E) : ID(EN));
+ RTLIL::SigSpec a = cell->getPort(ID::A);
assign_map.apply(input);
assign_map.apply(a);
if (input == State::S1)
- ACTION_DO("\\Y", cell->getPort("\\A"));
+ ACTION_DO(ID::Y, cell->getPort(ID::A));
if (input == State::S0 && !a.is_fully_undef()) {
cover("opt.opt_expr.action_" S__LINE__);
log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str());
- cell->setPort("\\A", SigSpec(State::Sx, GetSize(a)));
+ cell->setPort(ID::A, SigSpec(State::Sx, GetSize(a)));
did_something = true;
goto next_cell;
}
}
- if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex")
+ if (cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex)))
{
- RTLIL::SigSpec a = cell->getPort("\\A");
- RTLIL::SigSpec b = cell->getPort("\\B");
+ RTLIL::SigSpec a = cell->getPort(ID::A);
+ RTLIL::SigSpec b = cell->getPort(ID::B);
- if (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());
+ if (cell->parameters[ID(A_WIDTH)].as_int() != cell->parameters[ID(B_WIDTH)].as_int()) {
+ int width = max(cell->parameters[ID(A_WIDTH)].as_int(), cell->parameters[ID(B_WIDTH)].as_int());
+ a.extend_u0(width, cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool());
+ b.extend_u0(width, cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool());
}
RTLIL::SigSpec new_a, new_b;
@@ -820,9 +911,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (int i = 0; i < GetSize(a); i++) {
if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) {
cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
- RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1);
- new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
- replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y);
+ RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S0 : RTLIL::State::S1);
+ new_y.extend_u0(cell->parameters[ID(Y_WIDTH)].as_int(), false);
+ replace_cell(assign_map, module, cell, "isneq", ID::Y, new_y);
goto next_cell;
}
if (a[i] == b[i])
@@ -833,83 +924,83 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_a.size() == 0) {
cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
- RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0);
- new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
- replace_cell(assign_map, module, cell, "empty", "\\Y", new_y);
+ RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S1 : RTLIL::State::S0);
+ new_y.extend_u0(cell->parameters[ID(Y_WIDTH)].as_int(), false);
+ replace_cell(assign_map, module, cell, "empty", ID::Y, new_y);
goto next_cell;
}
if (new_a.size() < a.size() || new_b.size() < b.size()) {
cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
- cell->setPort("\\A", new_a);
- cell->setPort("\\B", new_b);
- cell->parameters["\\A_WIDTH"] = new_a.size();
- cell->parameters["\\B_WIDTH"] = new_b.size();
+ cell->setPort(ID::A, new_a);
+ cell->setPort(ID::B, new_b);
+ cell->parameters[ID(A_WIDTH)] = new_a.size();
+ cell->parameters[ID(B_WIDTH)] = new_b.size();
}
}
- if ((cell->type == "$eq" || cell->type == "$ne") && cell->parameters["\\Y_WIDTH"].as_int() == 1 &&
- cell->parameters["\\A_WIDTH"].as_int() == 1 && cell->parameters["\\B_WIDTH"].as_int() == 1)
+ if (cell->type.in(ID($eq), ID($ne)) && cell->parameters[ID(Y_WIDTH)].as_int() == 1 &&
+ cell->parameters[ID(A_WIDTH)].as_int() == 1 && cell->parameters[ID(B_WIDTH)].as_int() == 1)
{
- RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
- RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
if (a.is_fully_const() && !b.is_fully_const()) {
cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str());
- cell->setPort("\\A", b);
- cell->setPort("\\B", a);
+ cell->setPort(ID::A, b);
+ cell->setPort(ID::B, a);
std::swap(a, b);
}
if (b.is_fully_const()) {
- if (b.as_bool() == (cell->type == "$eq")) {
+ if (b.as_bool() == (cell->type == ID($eq))) {
RTLIL::SigSpec input = b;
- ACTION_DO("\\Y", cell->getPort("\\A"));
+ ACTION_DO(ID::Y, cell->getPort(ID::A));
} else {
cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
- cell->type = "$not";
- cell->parameters.erase("\\B_WIDTH");
- cell->parameters.erase("\\B_SIGNED");
- cell->unsetPort("\\B");
+ cell->type = ID($not);
+ cell->parameters.erase(ID(B_WIDTH));
+ cell->parameters.erase(ID(B_SIGNED));
+ cell->unsetPort(ID::B);
did_something = true;
}
goto next_cell;
}
}
- if ((cell->type == "$eq" || cell->type == "$ne") &&
- (assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero()))
+ if (cell->type.in(ID($eq), ID($ne)) &&
+ (assign_map(cell->getPort(ID::A)).is_fully_zero() || assign_map(cell->getPort(ID::B)).is_fully_zero()))
{
cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
- cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool";
- if (assign_map(cell->getPort("\\A")).is_fully_zero()) {
- cell->setPort("\\A", cell->getPort("\\B"));
- cell->setParam("\\A_SIGNED", cell->getParam("\\B_SIGNED"));
- cell->setParam("\\A_WIDTH", cell->getParam("\\B_WIDTH"));
+ cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
+ if (assign_map(cell->getPort(ID::A)).is_fully_zero()) {
+ cell->setPort(ID::A, cell->getPort(ID::B));
+ cell->setParam(ID(A_SIGNED), cell->getParam(ID(B_SIGNED)));
+ cell->setParam(ID(A_WIDTH), cell->getParam(ID(B_WIDTH)));
}
- cell->unsetPort("\\B");
- cell->unsetParam("\\B_SIGNED");
- cell->unsetParam("\\B_WIDTH");
+ cell->unsetPort(ID::B);
+ cell->unsetParam(ID(B_SIGNED));
+ cell->unsetParam(ID(B_WIDTH));
did_something = true;
goto next_cell;
}
- if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell->getPort("\\B")).is_fully_const())
+ if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)) && assign_map(cell->getPort(ID::B)).is_fully_const())
{
- bool sign_ext = cell->type == "$sshr" && cell->getParam("\\A_SIGNED").as_bool();
- int shift_bits = assign_map(cell->getPort("\\B")).as_int(cell->type.in("$shift", "$shiftx") && cell->getParam("\\B_SIGNED").as_bool());
+ bool sign_ext = cell->type == ID($sshr) && cell->getParam(ID(A_SIGNED)).as_bool();
+ int shift_bits = assign_map(cell->getPort(ID::B)).as_int(cell->type.in(ID($shift), ID($shiftx)) && cell->getParam(ID(B_SIGNED)).as_bool());
- if (cell->type.in("$shl", "$sshl"))
+ if (cell->type.in(ID($shl), ID($sshl)))
shift_bits *= -1;
- RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
- RTLIL::SigSpec sig_y(cell->type == "$shiftx" ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam("\\Y_WIDTH").as_int());
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec sig_y(cell->type == ID($shiftx) ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam(ID(Y_WIDTH)).as_int());
if (GetSize(sig_a) < GetSize(sig_y))
- sig_a.extend_u0(GetSize(sig_y), cell->getParam("\\A_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID(A_SIGNED)).as_bool());
for (int i = 0; i < GetSize(sig_y); i++) {
int idx = i + shift_bits;
@@ -922,9 +1013,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
- log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
+ log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort(ID::B))), shift_bits, log_id(module), log_signal(sig_y));
- module->connect(cell->getPort("\\Y"), sig_y);
+ module->connect(cell->getPort(ID::Y), sig_y);
module->remove(cell);
did_something = true;
@@ -937,41 +1028,41 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
bool identity_wrt_b = false;
bool arith_inverse = false;
- if (cell->type == "$add" || cell->type == "$sub" || cell->type == "$or" || cell->type == "$xor")
+ if (cell->type.in(ID($add), ID($sub), ID($or), ID($xor)))
{
- RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
- RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
- if (cell->type != "$sub" && a.is_fully_const() && a.as_bool() == false)
+ if (cell->type != ID($sub) && a.is_fully_const() && a.as_bool() == false)
identity_wrt_b = true;
if (b.is_fully_const() && b.as_bool() == false)
identity_wrt_a = true;
}
- if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
+ if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)))
{
- RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
if (b.is_fully_const() && b.as_bool() == false)
identity_wrt_a = true;
}
- if (cell->type == "$mul")
+ if (cell->type == ID($mul))
{
- RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
- RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
- if (a.is_fully_const() && is_one_or_minus_one(a.as_const(), cell->getParam("\\A_SIGNED").as_bool(), arith_inverse))
+ if (a.is_fully_const() && is_one_or_minus_one(a.as_const(), cell->getParam(ID(A_SIGNED)).as_bool(), arith_inverse))
identity_wrt_b = true;
else
- if (b.is_fully_const() && is_one_or_minus_one(b.as_const(), cell->getParam("\\B_SIGNED").as_bool(), arith_inverse))
+ if (b.is_fully_const() && is_one_or_minus_one(b.as_const(), cell->getParam(ID(B_SIGNED)).as_bool(), arith_inverse))
identity_wrt_a = true;
}
- if (cell->type == "$div")
+ if (cell->type == ID($div))
{
- RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1)
identity_wrt_a = true;
@@ -988,15 +1079,15 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
if (!identity_wrt_a) {
- cell->setPort("\\A", cell->getPort("\\B"));
- cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH");
- cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED");
+ cell->setPort(ID::A, cell->getPort(ID::B));
+ cell->parameters.at(ID(A_WIDTH)) = cell->parameters.at(ID(B_WIDTH));
+ cell->parameters.at(ID(A_SIGNED)) = cell->parameters.at(ID(B_SIGNED));
}
- cell->type = arith_inverse ? "$neg" : "$pos";
- cell->unsetPort("\\B");
- cell->parameters.erase("\\B_WIDTH");
- cell->parameters.erase("\\B_SIGNED");
+ cell->type = arith_inverse ? ID($neg) : ID($pos);
+ cell->unsetPort(ID::B);
+ cell->parameters.erase(ID(B_WIDTH));
+ cell->parameters.erase(ID(B_SIGNED));
cell->check();
did_something = true;
@@ -1004,91 +1095,91 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
- if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
- cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
+ if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) &&
+ cell->getPort(ID::A) == State::S0 && cell->getPort(ID::B) == State::S1) {
cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str());
- replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S"));
+ replace_cell(assign_map, module, cell, "mux_bool", ID::Y, cell->getPort(ID(S)));
goto next_cell;
}
- if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
- cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
+ if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) &&
+ cell->getPort(ID::A) == State::S1 && cell->getPort(ID::B) == State::S0) {
cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
- cell->setPort("\\A", cell->getPort("\\S"));
- cell->unsetPort("\\B");
- cell->unsetPort("\\S");
- if (cell->type == "$mux") {
- Const width = cell->parameters["\\WIDTH"];
- cell->parameters["\\A_WIDTH"] = width;
- cell->parameters["\\Y_WIDTH"] = width;
- cell->parameters["\\A_SIGNED"] = 0;
- cell->parameters.erase("\\WIDTH");
- cell->type = "$not";
+ cell->setPort(ID::A, cell->getPort(ID(S)));
+ cell->unsetPort(ID::B);
+ cell->unsetPort(ID(S));
+ if (cell->type == ID($mux)) {
+ Const width = cell->parameters[ID(WIDTH)];
+ cell->parameters[ID(A_WIDTH)] = width;
+ cell->parameters[ID(Y_WIDTH)] = width;
+ cell->parameters[ID(A_SIGNED)] = 0;
+ cell->parameters.erase(ID(WIDTH));
+ cell->type = ID($not);
} else
- cell->type = "$_NOT_";
+ cell->type = ID($_NOT_);
did_something = true;
goto next_cell;
}
- if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
+ if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S0) {
cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
- cell->setPort("\\A", cell->getPort("\\S"));
- cell->unsetPort("\\S");
- if (cell->type == "$mux") {
- Const width = cell->parameters["\\WIDTH"];
- cell->parameters["\\A_WIDTH"] = width;
- cell->parameters["\\B_WIDTH"] = width;
- cell->parameters["\\Y_WIDTH"] = width;
- cell->parameters["\\A_SIGNED"] = 0;
- cell->parameters["\\B_SIGNED"] = 0;
- cell->parameters.erase("\\WIDTH");
- cell->type = "$and";
+ cell->setPort(ID::A, cell->getPort(ID(S)));
+ cell->unsetPort(ID(S));
+ if (cell->type == ID($mux)) {
+ Const width = cell->parameters[ID(WIDTH)];
+ cell->parameters[ID(A_WIDTH)] = width;
+ cell->parameters[ID(B_WIDTH)] = width;
+ cell->parameters[ID(Y_WIDTH)] = width;
+ cell->parameters[ID(A_SIGNED)] = 0;
+ cell->parameters[ID(B_SIGNED)] = 0;
+ cell->parameters.erase(ID(WIDTH));
+ cell->type = ID($and);
} else
- cell->type = "$_AND_";
+ cell->type = ID($_AND_);
did_something = true;
goto next_cell;
}
- if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
+ if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S1) {
cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
- cell->setPort("\\B", cell->getPort("\\S"));
- cell->unsetPort("\\S");
- if (cell->type == "$mux") {
- Const width = cell->parameters["\\WIDTH"];
- cell->parameters["\\A_WIDTH"] = width;
- cell->parameters["\\B_WIDTH"] = width;
- cell->parameters["\\Y_WIDTH"] = width;
- cell->parameters["\\A_SIGNED"] = 0;
- cell->parameters["\\B_SIGNED"] = 0;
- cell->parameters.erase("\\WIDTH");
- cell->type = "$or";
+ cell->setPort(ID::B, cell->getPort(ID(S)));
+ cell->unsetPort(ID(S));
+ if (cell->type == ID($mux)) {
+ Const width = cell->parameters[ID(WIDTH)];
+ cell->parameters[ID(A_WIDTH)] = width;
+ cell->parameters[ID(B_WIDTH)] = width;
+ cell->parameters[ID(Y_WIDTH)] = width;
+ cell->parameters[ID(A_SIGNED)] = 0;
+ cell->parameters[ID(B_SIGNED)] = 0;
+ cell->parameters.erase(ID(WIDTH));
+ cell->type = ID($or);
} else
- cell->type = "$_OR_";
+ cell->type = ID($_OR_);
did_something = true;
goto next_cell;
}
- if (mux_undef && (cell->type == "$mux" || cell->type == "$pmux")) {
+ if (mux_undef && cell->type.in(ID($mux), ID($pmux))) {
RTLIL::SigSpec new_a, new_b, new_s;
- int width = cell->getPort("\\A").size();
- if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) ||
- cell->getPort("\\S").is_fully_undef()) {
+ int width = GetSize(cell->getPort(ID::A));
+ if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) ||
+ cell->getPort(ID(S)).is_fully_undef()) {
cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str());
- replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A"));
+ replace_cell(assign_map, module, cell, "mux_undef", ID::Y, cell->getPort(ID::A));
goto next_cell;
}
- for (int i = 0; i < cell->getPort("\\S").size(); i++) {
- RTLIL::SigSpec old_b = cell->getPort("\\B").extract(i*width, width);
- RTLIL::SigSpec old_s = cell->getPort("\\S").extract(i, 1);
+ for (int i = 0; i < cell->getPort(ID(S)).size(); i++) {
+ RTLIL::SigSpec old_b = cell->getPort(ID::B).extract(i*width, width);
+ RTLIL::SigSpec old_s = cell->getPort(ID(S)).extract(i, 1);
if (old_b.is_fully_undef() || old_s.is_fully_undef())
continue;
new_b.append(old_b);
new_s.append(old_s);
}
- new_a = cell->getPort("\\A");
+ new_a = cell->getPort(ID::A);
if (new_a.is_fully_undef() && new_s.size() > 0) {
new_a = new_b.extract((new_s.size()-1)*width, width);
new_b = new_b.extract(0, (new_s.size()-1)*width);
@@ -1096,27 +1187,27 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_s.size() == 0) {
cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str());
- replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a);
+ replace_cell(assign_map, module, cell, "mux_empty", ID::Y, new_a);
goto next_cell;
}
if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str());
- replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s);
+ replace_cell(assign_map, module, cell, "mux_sel01", ID::Y, new_s);
goto next_cell;
}
- if (cell->getPort("\\S").size() != new_s.size()) {
+ if (cell->getPort(ID(S)).size() != new_s.size()) {
cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
- GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
- cell->setPort("\\A", new_a);
- cell->setPort("\\B", new_b);
- cell->setPort("\\S", new_s);
+ GetSize(cell->getPort(ID(S))) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
+ cell->setPort(ID::A, new_a);
+ cell->setPort(ID::B, new_b);
+ cell->setPort(ID(S), new_s);
if (new_s.size() > 1) {
- cell->type = "$pmux";
- cell->parameters["\\S_WIDTH"] = new_s.size();
+ cell->type = ID($pmux);
+ cell->parameters[ID(S_WIDTH)] = new_s.size();
} else {
- cell->type = "$mux";
- cell->parameters.erase("\\S_WIDTH");
+ cell->type = ID($mux);
+ cell->parameters.erase(ID(S_WIDTH));
}
did_something = true;
}
@@ -1124,30 +1215,30 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
#define FOLD_1ARG_CELL(_t) \
if (cell->type == "$" #_t) { \
- RTLIL::SigSpec a = cell->getPort("\\A"); \
+ RTLIL::SigSpec a = cell->getPort(ID::A); \
assign_map.apply(a); \
if (a.is_fully_const()) { \
RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
- cell->parameters["\\A_SIGNED"].as_bool(), false, \
- cell->parameters["\\Y_WIDTH"].as_int())); \
+ cell->parameters[ID(A_SIGNED)].as_bool(), false, \
+ cell->parameters[ID(Y_WIDTH)].as_int())); \
cover("opt.opt_expr.const.$" #_t); \
- replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
+ replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), ID::Y, y); \
goto next_cell; \
} \
}
#define FOLD_2ARG_CELL(_t) \
if (cell->type == "$" #_t) { \
- RTLIL::SigSpec a = cell->getPort("\\A"); \
- RTLIL::SigSpec b = cell->getPort("\\B"); \
+ RTLIL::SigSpec a = cell->getPort(ID::A); \
+ RTLIL::SigSpec b = cell->getPort(ID::B); \
assign_map.apply(a), assign_map.apply(b); \
if (a.is_fully_const() && b.is_fully_const()) { \
RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
- cell->parameters["\\A_SIGNED"].as_bool(), \
- cell->parameters["\\B_SIGNED"].as_bool(), \
- cell->parameters["\\Y_WIDTH"].as_int())); \
+ cell->parameters[ID(A_SIGNED)].as_bool(), \
+ cell->parameters[ID(B_SIGNED)].as_bool(), \
+ cell->parameters[ID(Y_WIDTH)].as_int())); \
cover("opt.opt_expr.const.$" #_t); \
- replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
+ replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \
goto next_cell; \
} \
}
@@ -1193,25 +1284,25 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
FOLD_1ARG_CELL(neg)
// be very conservative with optimizing $mux cells as we do not want to break mux trees
- if (cell->type == "$mux") {
- RTLIL::SigSpec input = assign_map(cell->getPort("\\S"));
- RTLIL::SigSpec inA = assign_map(cell->getPort("\\A"));
- RTLIL::SigSpec inB = assign_map(cell->getPort("\\B"));
+ if (cell->type == ID($mux)) {
+ RTLIL::SigSpec input = assign_map(cell->getPort(ID(S)));
+ RTLIL::SigSpec inA = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec inB = assign_map(cell->getPort(ID::B));
if (input.is_fully_const())
- ACTION_DO("\\Y", input.as_bool() ? cell->getPort("\\B") : cell->getPort("\\A"));
+ ACTION_DO(ID::Y, input.as_bool() ? cell->getPort(ID::B) : cell->getPort(ID::A));
else if (inA == inB)
- ACTION_DO("\\Y", cell->getPort("\\A"));
+ ACTION_DO(ID::Y, cell->getPort(ID::A));
}
- if (!keepdc && cell->type == "$mul")
+ if (!keepdc && cell->type == ID($mul))
{
- bool a_signed = cell->parameters["\\A_SIGNED"].as_bool();
- bool b_signed = cell->parameters["\\B_SIGNED"].as_bool();
+ bool a_signed = cell->parameters[ID(A_SIGNED)].as_bool();
+ bool b_signed = cell->parameters[ID(B_SIGNED)].as_bool();
bool swapped_ab = false;
- RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
- RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
- RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y"));
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
+ RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID::Y));
if (sig_b.is_fully_const() && sig_b.size() <= 32)
std::swap(sig_a, sig_b), std::swap(a_signed, b_signed), swapped_ab = true;
@@ -1246,9 +1337,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
a_val, cell->name.c_str(), module->name.c_str(), i);
if (!swapped_ab) {
- cell->setPort("\\A", cell->getPort("\\B"));
- cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH");
- cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED");
+ cell->setPort(ID::A, cell->getPort(ID::B));
+ cell->parameters.at(ID(A_WIDTH)) = cell->parameters.at(ID(B_WIDTH));
+ cell->parameters.at(ID(A_SIGNED)) = cell->parameters.at(ID(B_SIGNED));
}
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
@@ -1256,10 +1347,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
new_b.pop_back();
- cell->type = "$shl";
- cell->parameters["\\B_WIDTH"] = GetSize(new_b);
- cell->parameters["\\B_SIGNED"] = false;
- cell->setPort("\\B", new_b);
+ cell->type = ID($shl);
+ cell->parameters[ID(B_WIDTH)] = GetSize(new_b);
+ cell->parameters[ID(B_SIGNED)] = false;
+ cell->setPort(ID::B, new_b);
cell->check();
did_something = true;
@@ -1268,11 +1359,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
- if (!keepdc && cell->type.in("$div", "$mod"))
+ if (!keepdc && cell->type.in(ID($div), ID($mod)))
{
- bool b_signed = cell->parameters["\\B_SIGNED"].as_bool();
- SigSpec sig_b = assign_map(cell->getPort("\\B"));
- SigSpec sig_y = assign_map(cell->getPort("\\Y"));
+ bool b_signed = cell->parameters[ID(B_SIGNED)].as_bool();
+ SigSpec sig_b = assign_map(cell->getPort(ID::B));
+ SigSpec sig_y = assign_map(cell->getPort(ID::Y));
if (sig_b.is_fully_def() && sig_b.size() <= 32)
{
@@ -1295,7 +1386,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++)
if (b_val == (1 << i))
{
- if (cell->type == "$div")
+ if (cell->type == ID($div))
{
cover("opt.opt_expr.div_shift");
@@ -1307,10 +1398,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
new_b.pop_back();
- cell->type = "$shr";
- cell->parameters["\\B_WIDTH"] = GetSize(new_b);
- cell->parameters["\\B_SIGNED"] = false;
- cell->setPort("\\B", new_b);
+ cell->type = ID($shr);
+ cell->parameters[ID(B_WIDTH)] = GetSize(new_b);
+ cell->parameters[ID(B_SIGNED)] = false;
+ cell->setPort(ID::B, new_b);
cell->check();
}
else
@@ -1325,9 +1416,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (b_signed)
new_b.push_back(State::S0);
- cell->type = "$and";
- cell->parameters["\\B_WIDTH"] = GetSize(new_b);
- cell->setPort("\\B", new_b);
+ cell->type = ID($and);
+ cell->parameters[ID(B_WIDTH)] = GetSize(new_b);
+ cell->setPort(ID::B, new_b);
cell->check();
}
@@ -1339,7 +1430,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
// remove redundant pairs of bits in ==, ===, !=, and !==
// replace cell with const driver if inputs can't be equal
- if (do_fine && cell->type.in("$eq", "$ne", "$eqx", "$nex"))
+ if (do_fine && cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex)))
{
pool<pair<SigBit, SigBit>> redundant_cache;
mfp<SigBit> contradiction_cache;
@@ -1347,14 +1438,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
contradiction_cache.promote(State::S0);
contradiction_cache.promote(State::S1);
- int a_width = cell->getParam("\\A_WIDTH").as_int();
- int b_width = cell->getParam("\\B_WIDTH").as_int();
+ int a_width = cell->getParam(ID(A_WIDTH)).as_int();
+ int b_width = cell->getParam(ID(B_WIDTH)).as_int();
- bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
int width = is_signed ? std::min(a_width, b_width) : std::max(a_width, b_width);
- SigSpec sig_a = cell->getPort("\\A");
- SigSpec sig_b = cell->getPort("\\B");
+ SigSpec sig_a = cell->getPort(ID::A);
+ SigSpec sig_b = cell->getPort(ID::B);
int redundant_bits = 0;
@@ -1384,8 +1475,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (contradiction_cache.find(State::S0) == contradiction_cache.find(State::S1))
{
- SigSpec y_sig = cell->getPort("\\Y");
- Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig));
+ SigSpec y_sig = cell->getPort(ID::Y);
+ Const y_value(cell->type.in(ID($eq), ID($eqx)) ? 0 : 1, GetSize(y_sig));
log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n",
log_id(cell), log_id(module), log_signal(y_value));
@@ -1402,10 +1493,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
redundant_bits, log_id(cell->type), log_id(cell), log_id(module));
- cell->setPort("\\A", sig_a);
- cell->setPort("\\B", sig_b);
- cell->setParam("\\A_WIDTH", GetSize(sig_a));
- cell->setParam("\\B_WIDTH", GetSize(sig_b));
+ cell->setPort(ID::A, sig_a);
+ cell->setPort(ID::B, sig_b);
+ cell->setParam(ID(A_WIDTH), GetSize(sig_a));
+ cell->setParam(ID(B_WIDTH), GetSize(sig_b));
did_something = true;
goto next_cell;
@@ -1413,57 +1504,57 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
// simplify comparisons
- if (do_fine && (cell->type == "$lt" || cell->type == "$ge" || cell->type == "$gt" || cell->type == "$le"))
+ if (do_fine && cell->type.in(ID($lt), ID($ge), ID($gt), ID($le)))
{
IdString cmp_type = cell->type;
- SigSpec var_sig = cell->getPort("\\A");
- SigSpec const_sig = cell->getPort("\\B");
- int var_width = cell->parameters["\\A_WIDTH"].as_int();
- int const_width = cell->parameters["\\B_WIDTH"].as_int();
- bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ SigSpec var_sig = cell->getPort(ID::A);
+ SigSpec const_sig = cell->getPort(ID::B);
+ int var_width = cell->parameters[ID(A_WIDTH)].as_int();
+ int const_width = cell->parameters[ID(B_WIDTH)].as_int();
+ bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
if (!const_sig.is_fully_const())
{
std::swap(var_sig, const_sig);
std::swap(var_width, const_width);
- if (cmp_type == "$gt")
- cmp_type = "$lt";
- else if (cmp_type == "$lt")
- cmp_type = "$gt";
- else if (cmp_type == "$ge")
- cmp_type = "$le";
- else if (cmp_type == "$le")
- cmp_type = "$ge";
+ if (cmp_type == ID($gt))
+ cmp_type = ID($lt);
+ else if (cmp_type == ID($lt))
+ cmp_type = ID($gt);
+ else if (cmp_type == ID($ge))
+ cmp_type = ID($le);
+ else if (cmp_type == ID($le))
+ cmp_type = ID($ge);
}
if (const_sig.is_fully_def() && const_sig.is_fully_const())
{
std::string condition, replacement;
- SigSpec replace_sig(State::S0, GetSize(cell->getPort("\\Y")));
+ SigSpec replace_sig(State::S0, GetSize(cell->getPort(ID::Y)));
bool replace = false;
bool remove = false;
if (!is_signed)
{ /* unsigned */
- if (const_sig.is_fully_zero() && cmp_type == "$lt") {
+ if (const_sig.is_fully_zero() && cmp_type == ID($lt)) {
condition = "unsigned X<0";
replacement = "constant 0";
replace_sig[0] = State::S0;
replace = true;
}
- if (const_sig.is_fully_zero() && cmp_type == "$ge") {
+ if (const_sig.is_fully_zero() && cmp_type == ID($ge)) {
condition = "unsigned X>=0";
replacement = "constant 1";
replace_sig[0] = State::S1;
replace = true;
}
- if (const_width == var_width && const_sig.is_fully_ones() && cmp_type == "$gt") {
+ if (const_width == var_width && const_sig.is_fully_ones() && cmp_type == ID($gt)) {
condition = "unsigned X>~0";
replacement = "constant 0";
replace_sig[0] = State::S0;
replace = true;
}
- if (const_width == var_width && const_sig.is_fully_ones() && cmp_type == "$le") {
+ if (const_width == var_width && const_sig.is_fully_ones() && cmp_type == ID($le)) {
condition = "unsigned X<=~0";
replacement = "constant 1";
replace_sig[0] = State::S1;
@@ -1478,18 +1569,18 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
var_high_sig[i - const_bit_hot] = var_sig[i];
}
- if (cmp_type == "$lt")
+ if (cmp_type == ID($lt))
{
condition = stringf("unsigned X<%s", log_signal(const_sig));
replacement = stringf("!X[%d:%d]", var_width - 1, const_bit_hot);
- module->addLogicNot(NEW_ID, var_high_sig, cell->getPort("\\Y"));
+ module->addLogicNot(NEW_ID, var_high_sig, cell->getPort(ID::Y));
remove = true;
}
- if (cmp_type == "$ge")
+ if (cmp_type == ID($ge))
{
condition = stringf("unsigned X>=%s", log_signal(const_sig));
replacement = stringf("|X[%d:%d]", var_width - 1, const_bit_hot);
- module->addReduceOr(NEW_ID, var_high_sig, cell->getPort("\\Y"));
+ module->addReduceOr(NEW_ID, var_high_sig, cell->getPort(ID::Y));
remove = true;
}
}
@@ -1498,19 +1589,19 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if(const_bit_set >= var_width)
{
string cmp_name;
- if (cmp_type == "$lt" || cmp_type == "$le")
+ if (cmp_type == ID($lt) || cmp_type == ID($le))
{
- if (cmp_type == "$lt") cmp_name = "<";
- if (cmp_type == "$le") cmp_name = "<=";
+ if (cmp_type == ID($lt)) cmp_name = "<";
+ if (cmp_type == ID($le)) cmp_name = "<=";
condition = stringf("unsigned X[%d:0]%s%s", var_width - 1, cmp_name.c_str(), log_signal(const_sig));
replacement = "constant 1";
replace_sig[0] = State::S1;
replace = true;
}
- if (cmp_type == "$gt" || cmp_type == "$ge")
+ if (cmp_type == ID($gt) || cmp_type == ID($ge))
{
- if (cmp_type == "$gt") cmp_name = ">";
- if (cmp_type == "$ge") cmp_name = ">=";
+ if (cmp_type == ID($gt)) cmp_name = ">";
+ if (cmp_type == ID($ge)) cmp_name = ">=";
condition = stringf("unsigned X[%d:0]%s%s", var_width - 1, cmp_name.c_str(), log_signal(const_sig));
replacement = "constant 0";
replace_sig[0] = State::S0;
@@ -1520,18 +1611,18 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
else
{ /* signed */
- if (const_sig.is_fully_zero() && cmp_type == "$lt")
+ if (const_sig.is_fully_zero() && cmp_type == ID($lt))
{
condition = "signed X<0";
replacement = stringf("X[%d]", var_width - 1);
replace_sig[0] = var_sig[var_width - 1];
replace = true;
}
- if (const_sig.is_fully_zero() && cmp_type == "$ge")
+ if (const_sig.is_fully_zero() && cmp_type == ID($ge))
{
condition = "signed X>=0";
replacement = stringf("X[%d]", var_width - 1);
- module->addNot(NEW_ID, var_sig[var_width - 1], cell->getPort("\\Y"));
+ module->addNot(NEW_ID, var_sig[var_width - 1], cell->getPort(ID::Y));
remove = true;
}
}
@@ -1541,7 +1632,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n",
log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str());
if (replace)
- module->connect(cell->getPort("\\Y"), replace_sig);
+ module->connect(cell->getPort(ID::Y), replace_sig);
module->remove(cell);
did_something = true;
goto next_cell;
diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc
index 26855fd70..c4f278706 100644
--- a/passes/opt/opt_lut.cc
+++ b/passes/opt/opt_lut.cc
@@ -40,9 +40,9 @@ struct OptLutWorker
bool evaluate_lut(RTLIL::Cell *lut, dict<SigBit, bool> inputs)
{
- SigSpec lut_input = sigmap(lut->getPort("\\A"));
- int lut_width = lut->getParam("\\WIDTH").as_int();
- Const lut_table = lut->getParam("\\LUT");
+ SigSpec lut_input = sigmap(lut->getPort(ID::A));
+ int lut_width = lut->getParam(ID(WIDTH)).as_int();
+ Const lut_table = lut->getParam(ID(LUT));
int lut_index = 0;
for (int i = 0; i < lut_width; i++)
@@ -81,7 +81,7 @@ struct OptLutWorker
}
}
- log("Number of LUTs: %8zu\n", luts.size());
+ log("Number of LUTs: %8d\n", GetSize(luts));
for (int arity = 1; arity <= max_arity; arity++)
{
if (arity_counts[arity])
@@ -99,13 +99,19 @@ struct OptLutWorker
log("Discovering LUTs.\n");
for (auto cell : module->selected_cells())
{
- if (cell->type == "$lut")
+ if (cell->type == ID($lut))
{
- int lut_width = cell->getParam("\\WIDTH").as_int();
- SigSpec lut_input = cell->getPort("\\A");
+ if (cell->has_keep_attr())
+ continue;
+ SigBit lut_output = cell->getPort(ID::Y);
+ if (lut_output.wire->get_bool_attribute(ID::keep))
+ continue;
+
+ int lut_width = cell->getParam(ID(WIDTH)).as_int();
+ SigSpec lut_input = cell->getPort(ID::A);
int lut_arity = 0;
- log("Found $lut\\WIDTH=%d cell %s.%s.\n", lut_width, log_id(module), log_id(cell));
+ log_debug("Found $lut\\WIDTH=%d cell %s.%s.\n", lut_width, log_id(module), log_id(cell));
luts.insert(cell);
// First, find all dedicated logic we're connected to. This results in an overapproximation
@@ -147,15 +153,15 @@ struct OptLutWorker
{
if (lut_width <= dlogic_conn.first)
{
- log(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
- log(" LUT input A[%d] not present.\n", dlogic_conn.first);
+ log_debug(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
+ log_debug(" LUT input A[%d] not present.\n", dlogic_conn.first);
legal = false;
break;
}
if (sigmap(lut_input[dlogic_conn.first]) != sigmap(lut_dlogic->getPort(dlogic_conn.second)))
{
- log(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
- log(" LUT input A[%d] (wire %s) not connected to %s port %s (wire %s).\n", dlogic_conn.first, log_signal(lut_input[dlogic_conn.first]), lut_dlogic->type.c_str(), dlogic_conn.second.c_str(), log_signal(lut_dlogic->getPort(dlogic_conn.second)));
+ log_debug(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
+ log_debug(" LUT input A[%d] (wire %s) not connected to %s port %s (wire %s).\n", dlogic_conn.first, log_signal(lut_input[dlogic_conn.first]), lut_dlogic->type.c_str(), dlogic_conn.second.c_str(), log_signal(lut_dlogic->getPort(dlogic_conn.second)));
legal = false;
break;
}
@@ -163,7 +169,7 @@ struct OptLutWorker
if (legal)
{
- log(" LUT has legal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
+ log_debug(" LUT has legal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic));
lut_legal_dlogics.insert(lut_dlogic);
for (auto &dlogic_conn : dlogic_map)
lut_dlogic_inputs.insert(dlogic_conn.first);
@@ -179,7 +185,7 @@ struct OptLutWorker
lut_arity++;
}
- log(" Cell implements a %d-LUT.\n", lut_arity);
+ log_debug(" Cell implements a %d-LUT.\n", lut_arity);
luts_arity[cell] = lut_arity;
luts_dlogics[cell] = lut_legal_dlogics;
luts_dlogic_inputs[cell] = lut_dlogic_inputs;
@@ -199,7 +205,7 @@ struct OptLutWorker
}
auto lut = worklist.pop();
- SigSpec lut_input = sigmap(lut->getPort("\\A"));
+ SigSpec lut_input = sigmap(lut->getPort(ID::A));
pool<int> &lut_dlogic_inputs = luts_dlogic_inputs[lut];
vector<SigBit> lut_inputs;
@@ -239,31 +245,29 @@ struct OptLutWorker
if (const0_match || const1_match || input_match != -1)
{
- log("Found redundant cell %s.%s.\n", log_id(module), log_id(lut));
+ log_debug("Found redundant cell %s.%s.\n", log_id(module), log_id(lut));
SigBit value;
if (const0_match)
{
- log(" Cell evaluates constant 0.\n");
+ log_debug(" Cell evaluates constant 0.\n");
value = State::S0;
}
if (const1_match)
{
- log(" Cell evaluates constant 1.\n");
+ log_debug(" Cell evaluates constant 1.\n");
value = State::S1;
}
if (input_match != -1) {
- log(" Cell evaluates signal %s.\n", log_signal(lut_inputs[input_match]));
+ log_debug(" Cell evaluates signal %s.\n", log_signal(lut_inputs[input_match]));
value = lut_inputs[input_match];
}
if (lut_dlogic_inputs.size())
- {
- log(" Not eliminating cell (connected to dedicated logic).\n");
- }
+ log_debug(" Not eliminating cell (connected to dedicated logic).\n");
else
{
- SigSpec lut_output = lut->getPort("\\Y");
+ SigSpec lut_output = lut->getPort(ID::Y);
for (auto &port : index.query_ports(lut_output))
{
if (port.cell != lut && luts.count(port.cell))
@@ -299,13 +303,13 @@ struct OptLutWorker
}
auto lutA = worklist.pop();
- SigSpec lutA_input = sigmap(lutA->getPort("\\A"));
- SigSpec lutA_output = sigmap(lutA->getPort("\\Y")[0]);
- int lutA_width = lutA->getParam("\\WIDTH").as_int();
+ SigSpec lutA_input = sigmap(lutA->getPort(ID::A));
+ SigSpec lutA_output = sigmap(lutA->getPort(ID::Y)[0]);
+ int lutA_width = lutA->getParam(ID(WIDTH)).as_int();
int lutA_arity = luts_arity[lutA];
pool<int> &lutA_dlogic_inputs = luts_dlogic_inputs[lutA];
- auto lutA_output_ports = index.query_ports(lutA->getPort("\\Y"));
+ auto lutA_output_ports = index.query_ports(lutA->getPort(ID::Y));
if (lutA_output_ports.size() != 2)
continue;
@@ -317,17 +321,17 @@ struct OptLutWorker
if (luts.count(port.cell))
{
auto lutB = port.cell;
- SigSpec lutB_input = sigmap(lutB->getPort("\\A"));
- SigSpec lutB_output = sigmap(lutB->getPort("\\Y")[0]);
- int lutB_width = lutB->getParam("\\WIDTH").as_int();
+ SigSpec lutB_input = sigmap(lutB->getPort(ID::A));
+ SigSpec lutB_output = sigmap(lutB->getPort(ID::Y)[0]);
+ int lutB_width = lutB->getParam(ID(WIDTH)).as_int();
int lutB_arity = luts_arity[lutB];
pool<int> &lutB_dlogic_inputs = luts_dlogic_inputs[lutB];
- log("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB));
+ log_debug("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB));
- if (index.query_is_output(lutA->getPort("\\Y")))
+ if (index.query_is_output(lutA->getPort(ID::Y)))
{
- log(" Not combining LUTs (cascade connection feeds module output).\n");
+ log_debug(" Not combining LUTs (cascade connection feeds module output).\n");
continue;
}
@@ -353,67 +357,51 @@ struct OptLutWorker
int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size();
if (lutA_dlogic_inputs.size())
- log(" Cell A is a %d-LUT with %zu dedicated connections. ", lutA_arity, lutA_dlogic_inputs.size());
+ log_debug(" Cell A is a %d-LUT with %d dedicated connections. ", lutA_arity, GetSize(lutA_dlogic_inputs));
else
- log(" Cell A is a %d-LUT. ", lutA_arity);
+ log_debug(" Cell A is a %d-LUT. ", lutA_arity);
if (lutB_dlogic_inputs.size())
- log("Cell B is a %d-LUT with %zu dedicated connections.\n", lutB_arity, lutB_dlogic_inputs.size());
+ log_debug("Cell B is a %d-LUT with %d dedicated connections.\n", lutB_arity, GetSize(lutB_dlogic_inputs));
else
- log("Cell B is a %d-LUT.\n", lutB_arity);
- log(" Cells share %zu input(s) and can be merged into one %d-LUT.\n", common_inputs.size(), lutM_arity);
+ log_debug("Cell B is a %d-LUT.\n", lutB_arity);
+ log_debug(" Cells share %d input(s) and can be merged into one %d-LUT.\n", GetSize(common_inputs), lutM_arity);
const int COMBINE_A = 1, COMBINE_B = 2, COMBINE_EITHER = COMBINE_A | COMBINE_B;
int combine_mask = 0;
if (lutM_arity > lutA_width)
- {
- log(" Not combining LUTs into cell A (combined LUT wider than cell A).\n");
- }
+ log_debug(" Not combining LUTs into cell A (combined LUT wider than cell A).\n");
else if (lutB_dlogic_inputs.size() > 0)
- {
- log(" Not combining LUTs into cell A (cell B is connected to dedicated logic).\n");
- }
- else if (lutB->get_bool_attribute("\\lut_keep"))
- {
- log(" Not combining LUTs into cell A (cell B has attribute \\lut_keep).\n");
- }
+ log_debug(" Not combining LUTs into cell A (cell B is connected to dedicated logic).\n");
+ else if (lutB->get_bool_attribute(ID(lut_keep)))
+ log_debug(" Not combining LUTs into cell A (cell B has attribute \\lut_keep).\n");
else
- {
combine_mask |= COMBINE_A;
- }
if (lutM_arity > lutB_width)
- {
- log(" Not combining LUTs into cell B (combined LUT wider than cell B).\n");
- }
+ log_debug(" Not combining LUTs into cell B (combined LUT wider than cell B).\n");
else if (lutA_dlogic_inputs.size() > 0)
- {
- log(" Not combining LUTs into cell B (cell A is connected to dedicated logic).\n");
- }
- else if (lutA->get_bool_attribute("\\lut_keep"))
- {
- log(" Not combining LUTs into cell B (cell A has attribute \\lut_keep).\n");
- }
+ log_debug(" Not combining LUTs into cell B (cell A is connected to dedicated logic).\n");
+ else if (lutA->get_bool_attribute(ID(lut_keep)))
+ log_debug(" Not combining LUTs into cell B (cell A has attribute \\lut_keep).\n");
else
- {
combine_mask |= COMBINE_B;
- }
int combine = combine_mask;
if (combine == COMBINE_EITHER)
{
- log(" Can combine into either cell.\n");
+ log_debug(" Can combine into either cell.\n");
if (lutA_arity == 1)
{
- log(" Cell A is a buffer or inverter, combining into cell B.\n");
+ log_debug(" Cell A is a buffer or inverter, combining into cell B.\n");
combine = COMBINE_B;
}
else if (lutB_arity == 1)
{
- log(" Cell B is a buffer or inverter, combining into cell A.\n");
+ log_debug(" Cell B is a buffer or inverter, combining into cell A.\n");
combine = COMBINE_A;
}
else
{
- log(" Arbitrarily combining into cell A.\n");
+ log_debug(" Arbitrarily combining into cell A.\n");
combine = COMBINE_A;
}
}
@@ -423,7 +411,7 @@ struct OptLutWorker
pool<int> lutM_dlogic_inputs;
if (combine == COMBINE_A)
{
- log(" Combining LUTs into cell A.\n");
+ log_debug(" Combining LUTs into cell A.\n");
lutM = lutA;
lutM_inputs = lutA_inputs;
lutM_dlogic_inputs = lutA_dlogic_inputs;
@@ -432,7 +420,7 @@ struct OptLutWorker
}
else if (combine == COMBINE_B)
{
- log(" Combining LUTs into cell B.\n");
+ log_debug(" Combining LUTs into cell B.\n");
lutM = lutB;
lutM_inputs = lutB_inputs;
lutM_dlogic_inputs = lutB_dlogic_inputs;
@@ -441,7 +429,7 @@ struct OptLutWorker
}
else
{
- log(" Cannot combine LUTs.\n");
+ log_debug(" Cannot combine LUTs.\n");
continue;
}
@@ -452,8 +440,8 @@ struct OptLutWorker
lutR_unique.insert(bit);
}
- int lutM_width = lutM->getParam("\\WIDTH").as_int();
- SigSpec lutM_input = sigmap(lutM->getPort("\\A"));
+ int lutM_width = lutM->getParam(ID(WIDTH)).as_int();
+ SigSpec lutM_input = sigmap(lutM->getPort(ID::A));
std::vector<SigBit> lutM_new_inputs;
for (int i = 0; i < lutM_width; i++)
{
@@ -466,17 +454,17 @@ struct OptLutWorker
if (input_unused && lutR_unique.size())
{
SigBit new_input = lutR_unique.pop();
- log(" Connecting input %d as %s.\n", i, log_signal(new_input));
+ log_debug(" Connecting input %d as %s.\n", i, log_signal(new_input));
lutM_new_inputs.push_back(new_input);
}
else if (sigmap(lutM_input[i]) == lutA_output)
{
- log(" Disconnecting cascade input %d.\n", i);
+ log_debug(" Disconnecting cascade input %d.\n", i);
lutM_new_inputs.push_back(SigBit());
}
else
{
- log(" Leaving input %d as %s.\n", i, log_signal(lutM_input[i]));
+ log_debug(" Leaving input %d as %s.\n", i, log_signal(lutM_input[i]));
lutM_new_inputs.push_back(lutM_input[i]);
}
}
@@ -494,13 +482,13 @@ struct OptLutWorker
lutM_new_table[eval] = (RTLIL::State) evaluate_lut(lutB, eval_inputs);
}
- log(" Cell A truth table: %s.\n", lutA->getParam("\\LUT").as_string().c_str());
- log(" Cell B truth table: %s.\n", lutB->getParam("\\LUT").as_string().c_str());
- log(" Merged truth table: %s.\n", lutM_new_table.as_string().c_str());
+ log_debug(" Cell A truth table: %s.\n", lutA->getParam(ID(LUT)).as_string().c_str());
+ log_debug(" Cell B truth table: %s.\n", lutB->getParam(ID(LUT)).as_string().c_str());
+ log_debug(" Merged truth table: %s.\n", lutM_new_table.as_string().c_str());
- lutM->setParam("\\LUT", lutM_new_table);
- lutM->setPort("\\A", lutM_new_inputs);
- lutM->setPort("\\Y", lutB_output);
+ lutM->setParam(ID(LUT), lutM_new_table);
+ lutM->setPort(ID::A, lutM_new_inputs);
+ lutM->setPort(ID::Y, lutB_output);
luts_arity[lutM] = lutM_arity;
luts.erase(lutR);
diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc
index 7567d4657..aaea6159e 100644
--- a/passes/opt/opt_merge.cc
+++ b/passes/opt/opt_merge.cc
@@ -47,8 +47,8 @@ struct OptMergeWorker
static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
{
- SigSpec sig_s = conn.at("\\S");
- SigSpec sig_b = conn.at("\\B");
+ SigSpec sig_s = conn.at(ID(S));
+ SigSpec sig_b = conn.at(ID::B);
int s_width = GetSize(sig_s);
int width = GetSize(sig_b) / s_width;
@@ -59,12 +59,12 @@ struct OptMergeWorker
std::sort(sb_pairs.begin(), sb_pairs.end());
- conn["\\S"] = SigSpec();
- conn["\\B"] = SigSpec();
+ conn[ID(S)] = SigSpec();
+ conn[ID::B] = SigSpec();
for (auto &it : sb_pairs) {
- conn["\\S"].append(it.first);
- conn["\\B"].append(it.second);
+ conn[ID(S)].append(it.first);
+ conn[ID::B].append(it.second);
}
}
@@ -94,32 +94,32 @@ struct OptMergeWorker
const dict<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections();
dict<RTLIL::IdString, RTLIL::SigSpec> alt_conn;
- if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || cell->type == "$add" || cell->type == "$mul" ||
- cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") {
+ if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul),
+ ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) {
alt_conn = *conn;
- if (assign_map(alt_conn.at("\\A")) < assign_map(alt_conn.at("\\B"))) {
- alt_conn["\\A"] = conn->at("\\B");
- alt_conn["\\B"] = conn->at("\\A");
+ if (assign_map(alt_conn.at(ID::A)) < assign_map(alt_conn.at(ID::B))) {
+ alt_conn[ID::A] = conn->at(ID::B);
+ alt_conn[ID::B] = conn->at(ID::A);
}
conn = &alt_conn;
} else
- if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor") {
+ if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) {
alt_conn = *conn;
- assign_map.apply(alt_conn.at("\\A"));
- alt_conn.at("\\A").sort();
+ assign_map.apply(alt_conn.at(ID::A));
+ alt_conn.at(ID::A).sort();
conn = &alt_conn;
} else
- if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") {
+ if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool))) {
alt_conn = *conn;
- assign_map.apply(alt_conn.at("\\A"));
- alt_conn.at("\\A").sort_and_unify();
+ assign_map.apply(alt_conn.at(ID::A));
+ alt_conn.at(ID::A).sort_and_unify();
conn = &alt_conn;
} else
- if (cell->type == "$pmux") {
+ if (cell->type == ID($pmux)) {
alt_conn = *conn;
- assign_map.apply(alt_conn.at("\\A"));
- assign_map.apply(alt_conn.at("\\B"));
- assign_map.apply(alt_conn.at("\\S"));
+ assign_map.apply(alt_conn.at(ID::A));
+ assign_map.apply(alt_conn.at(ID::B));
+ assign_map.apply(alt_conn.at(ID(S)));
sort_pmux_conn(alt_conn);
conn = &alt_conn;
}
@@ -189,28 +189,28 @@ struct OptMergeWorker
assign_map.apply(it.second);
}
- if (cell1->type == "$and" || cell1->type == "$or" || cell1->type == "$xor" || cell1->type == "$xnor" || cell1->type == "$add" || cell1->type == "$mul" ||
- cell1->type == "$logic_and" || cell1->type == "$logic_or" || cell1->type == "$_AND_" || cell1->type == "$_OR_" || cell1->type == "$_XOR_") {
- if (conn1.at("\\A") < conn1.at("\\B")) {
- RTLIL::SigSpec tmp = conn1["\\A"];
- conn1["\\A"] = conn1["\\B"];
- conn1["\\B"] = tmp;
+ if (cell1->type == ID($and) || cell1->type == ID($or) || cell1->type == ID($xor) || cell1->type == ID($xnor) || cell1->type == ID($add) || cell1->type == ID($mul) ||
+ cell1->type == ID($logic_and) || cell1->type == ID($logic_or) || cell1->type == ID($_AND_) || cell1->type == ID($_OR_) || cell1->type == ID($_XOR_)) {
+ if (conn1.at(ID::A) < conn1.at(ID::B)) {
+ RTLIL::SigSpec tmp = conn1[ID::A];
+ conn1[ID::A] = conn1[ID::B];
+ conn1[ID::B] = tmp;
}
- if (conn2.at("\\A") < conn2.at("\\B")) {
- RTLIL::SigSpec tmp = conn2["\\A"];
- conn2["\\A"] = conn2["\\B"];
- conn2["\\B"] = tmp;
+ if (conn2.at(ID::A) < conn2.at(ID::B)) {
+ RTLIL::SigSpec tmp = conn2[ID::A];
+ conn2[ID::A] = conn2[ID::B];
+ conn2[ID::B] = tmp;
}
} else
- if (cell1->type == "$reduce_xor" || cell1->type == "$reduce_xnor") {
- conn1["\\A"].sort();
- conn2["\\A"].sort();
+ if (cell1->type == ID($reduce_xor) || cell1->type == ID($reduce_xnor)) {
+ conn1[ID::A].sort();
+ conn2[ID::A].sort();
} else
- if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") {
- conn1["\\A"].sort_and_unify();
- conn2["\\A"].sort_and_unify();
+ if (cell1->type == ID($reduce_and) || cell1->type == ID($reduce_or) || cell1->type == ID($reduce_bool)) {
+ conn1[ID::A].sort_and_unify();
+ conn2[ID::A].sort_and_unify();
} else
- if (cell1->type == "$pmux") {
+ if (cell1->type == ID($pmux)) {
sort_pmux_conn(conn1);
sort_pmux_conn(conn2);
}
@@ -222,9 +222,9 @@ struct OptMergeWorker
return true;
}
- if (cell1->type.substr(0, 1) == "$" && conn1.count("\\Q") != 0) {
- std::vector<RTLIL::SigBit> q1 = dff_init_map(cell1->getPort("\\Q")).to_sigbit_vector();
- std::vector<RTLIL::SigBit> q2 = dff_init_map(cell2->getPort("\\Q")).to_sigbit_vector();
+ if (cell1->type.begins_with("$") && conn1.count(ID(Q)) != 0) {
+ std::vector<RTLIL::SigBit> q1 = dff_init_map(cell1->getPort(ID(Q))).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> q2 = dff_init_map(cell2->getPort(ID(Q))).to_sigbit_vector();
for (size_t i = 0; i < q1.size(); i++)
if ((q1.at(i).wire == NULL || q2.at(i).wire == NULL) && q1.at(i) != q2.at(i)) {
lt = q1.at(i) < q2.at(i);
@@ -271,24 +271,24 @@ struct OptMergeWorker
ct.setup_stdcells_mem();
if (mode_nomux) {
- ct.cell_types.erase("$mux");
- ct.cell_types.erase("$pmux");
+ ct.cell_types.erase(ID($mux));
+ ct.cell_types.erase(ID($pmux));
}
- ct.cell_types.erase("$tribuf");
- ct.cell_types.erase("$_TBUF_");
- ct.cell_types.erase("$anyseq");
- ct.cell_types.erase("$anyconst");
- ct.cell_types.erase("$allseq");
- ct.cell_types.erase("$allconst");
+ ct.cell_types.erase(ID($tribuf));
+ ct.cell_types.erase(ID($_TBUF_));
+ ct.cell_types.erase(ID($anyseq));
+ ct.cell_types.erase(ID($anyconst));
+ ct.cell_types.erase(ID($allseq));
+ ct.cell_types.erase(ID($allconst));
log("Finding identical cells in module `%s'.\n", module->name.c_str());
assign_map.set(module);
dff_init_map.set(module);
for (auto &it : module->wires_)
- if (it.second->attributes.count("\\init") != 0) {
- Const initval = it.second->attributes.at("\\init");
+ if (it.second->attributes.count(ID(init)) != 0) {
+ Const initval = it.second->attributes.at(ID(init));
for (int i = 0; i < GetSize(initval) && i < GetSize(it.second); i++)
if (initval[i] == State::S0 || initval[i] == State::S1)
dff_init_map.add(SigBit(it.second, i), initval[i]);
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 6511e091b..3c486bbcc 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -84,12 +84,12 @@ struct OptMuxtreeWorker
// .const_deactivated
for (auto cell : module->cells())
{
- if (cell->type == "$mux" || cell->type == "$pmux")
+ if (cell->type.in(ID($mux), ID($pmux)))
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_b = cell->getPort("\\B");
- RTLIL::SigSpec sig_s = cell->getPort("\\S");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+ RTLIL::SigSpec sig_s = cell->getPort(ID(S));
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
muxinfo_t muxinfo;
muxinfo.cell = cell;
@@ -137,7 +137,7 @@ struct OptMuxtreeWorker
}
}
for (auto wire : module->wires()) {
- if (wire->port_output || wire->get_bool_attribute("\\keep"))
+ if (wire->port_output || wire->get_bool_attribute(ID::keep))
for (int idx : sig2bits(RTLIL::SigSpec(wire)))
bit2info[idx].seen_non_mux = true;
}
@@ -227,10 +227,10 @@ struct OptMuxtreeWorker
continue;
}
- RTLIL::SigSpec sig_a = mi.cell->getPort("\\A");
- RTLIL::SigSpec sig_b = mi.cell->getPort("\\B");
- RTLIL::SigSpec sig_s = mi.cell->getPort("\\S");
- RTLIL::SigSpec sig_y = mi.cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = mi.cell->getPort(ID::A);
+ RTLIL::SigSpec sig_b = mi.cell->getPort(ID::B);
+ RTLIL::SigSpec sig_s = mi.cell->getPort(ID(S));
+ RTLIL::SigSpec sig_y = mi.cell->getPort(ID::Y);
RTLIL::SigSpec sig_ports = sig_b;
sig_ports.append(sig_a);
@@ -255,14 +255,14 @@ struct OptMuxtreeWorker
}
}
- mi.cell->setPort("\\A", new_sig_a);
- mi.cell->setPort("\\B", new_sig_b);
- mi.cell->setPort("\\S", new_sig_s);
+ mi.cell->setPort(ID::A, new_sig_a);
+ mi.cell->setPort(ID::B, new_sig_b);
+ mi.cell->setPort(ID(S), new_sig_s);
if (GetSize(new_sig_s) == 1) {
- mi.cell->type = "$mux";
- mi.cell->parameters.erase("\\S_WIDTH");
+ mi.cell->type = ID($mux);
+ mi.cell->parameters.erase(ID(S_WIDTH));
} else {
- mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(GetSize(new_sig_s));
+ mi.cell->parameters[ID(S_WIDTH)] = RTLIL::Const(GetSize(new_sig_s));
}
}
}
@@ -364,9 +364,9 @@ struct OptMuxtreeWorker
int width = 0;
idict<int> ctrl_bits;
- if (portname == "\\B")
- width = GetSize(muxinfo.cell->getPort("\\A"));
- for (int bit : sig2bits(muxinfo.cell->getPort("\\S"), false))
+ if (portname == ID::B)
+ width = GetSize(muxinfo.cell->getPort(ID::A));
+ for (int bit : sig2bits(muxinfo.cell->getPort(ID(S)), false))
ctrl_bits(bit);
int port_idx = 0, port_off = 0;
@@ -414,8 +414,8 @@ struct OptMuxtreeWorker
// set input ports to constants if we find known active or inactive signals
if (do_replace_known) {
- replace_known(knowledge, muxinfo, "\\A");
- replace_known(knowledge, muxinfo, "\\B");
+ replace_known(knowledge, muxinfo, ID::A);
+ replace_known(knowledge, muxinfo, ID::B);
}
// if there is a constant activated port we just use it
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index d99f1ca6a..6a8d8cabd 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -43,13 +43,13 @@ struct OptReduceWorker
return;
cells.erase(cell);
- RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
pool<RTLIL::SigBit> new_sig_a_bits;
for (auto &bit : sig_a.to_sigbit_set())
{
if (bit == RTLIL::State::S0) {
- if (cell->type == "$reduce_and") {
+ if (cell->type == ID($reduce_and)) {
new_sig_a_bits.clear();
new_sig_a_bits.insert(RTLIL::State::S0);
break;
@@ -57,7 +57,7 @@ struct OptReduceWorker
continue;
}
if (bit == RTLIL::State::S1) {
- if (cell->type == "$reduce_or") {
+ if (cell->type == ID($reduce_or)) {
new_sig_a_bits.clear();
new_sig_a_bits.insert(RTLIL::State::S1);
break;
@@ -73,8 +73,8 @@ struct OptReduceWorker
for (auto child_cell : drivers.find(bit)) {
if (child_cell->type == cell->type) {
opt_reduce(cells, drivers, child_cell);
- if (child_cell->getPort("\\Y")[0] == bit) {
- pool<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort("\\A")).to_sigbit_pool();
+ if (child_cell->getPort(ID::Y)[0] == bit) {
+ pool<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort(ID::A)).to_sigbit_pool();
new_sig_a_bits.insert(child_sig_a_bits.begin(), child_sig_a_bits.end());
} else
new_sig_a_bits.insert(RTLIL::State::S0);
@@ -87,22 +87,22 @@ struct OptReduceWorker
RTLIL::SigSpec new_sig_a(new_sig_a_bits);
- if (new_sig_a != sig_a || sig_a.size() != cell->getPort("\\A").size()) {
+ if (new_sig_a != sig_a || sig_a.size() != cell->getPort(ID::A).size()) {
log(" New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a));
did_something = true;
total_count++;
}
- cell->setPort("\\A", new_sig_a);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(new_sig_a.size());
+ cell->setPort(ID::A, new_sig_a);
+ cell->parameters[ID(A_WIDTH)] = RTLIL::Const(new_sig_a.size());
return;
}
void opt_mux(RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
- RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
- RTLIL::SigSpec sig_s = assign_map(cell->getPort("\\S"));
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
+ RTLIL::SigSpec sig_s = assign_map(cell->getPort(ID(S)));
RTLIL::SigSpec new_sig_b, new_sig_s;
pool<RTLIL::SigSpec> handled_sig;
@@ -123,15 +123,15 @@ struct OptReduceWorker
if (this_s.size() > 1)
{
- RTLIL::Cell *reduce_or_cell = module->addCell(NEW_ID, "$reduce_or");
- reduce_or_cell->setPort("\\A", this_s);
- reduce_or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- reduce_or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(this_s.size());
- reduce_or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+ RTLIL::Cell *reduce_or_cell = module->addCell(NEW_ID, ID($reduce_or));
+ reduce_or_cell->setPort(ID::A, this_s);
+ reduce_or_cell->parameters[ID(A_SIGNED)] = RTLIL::Const(0);
+ reduce_or_cell->parameters[ID(A_WIDTH)] = RTLIL::Const(this_s.size());
+ reduce_or_cell->parameters[ID(Y_WIDTH)] = RTLIL::Const(1);
RTLIL::Wire *reduce_or_wire = module->addWire(NEW_ID);
this_s = RTLIL::SigSpec(reduce_or_wire);
- reduce_or_cell->setPort("\\Y", this_s);
+ reduce_or_cell->setPort(ID::Y, this_s);
}
new_sig_b.append(this_b);
@@ -147,28 +147,28 @@ struct OptReduceWorker
if (new_sig_s.size() == 0)
{
- module->connect(RTLIL::SigSig(cell->getPort("\\Y"), cell->getPort("\\A")));
- assign_map.add(cell->getPort("\\Y"), cell->getPort("\\A"));
+ module->connect(RTLIL::SigSig(cell->getPort(ID::Y), cell->getPort(ID::A)));
+ assign_map.add(cell->getPort(ID::Y), cell->getPort(ID::A));
module->remove(cell);
}
else
{
- cell->setPort("\\B", new_sig_b);
- cell->setPort("\\S", new_sig_s);
+ cell->setPort(ID::B, new_sig_b);
+ cell->setPort(ID(S), new_sig_s);
if (new_sig_s.size() > 1) {
- cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.size());
+ cell->parameters[ID(S_WIDTH)] = RTLIL::Const(new_sig_s.size());
} else {
- cell->type = "$mux";
- cell->parameters.erase("\\S_WIDTH");
+ cell->type = ID($mux);
+ cell->parameters.erase(ID(S_WIDTH));
}
}
}
void opt_mux_bits(RTLIL::Cell *cell)
{
- std::vector<RTLIL::SigBit> sig_a = assign_map(cell->getPort("\\A")).to_sigbit_vector();
- std::vector<RTLIL::SigBit> sig_b = assign_map(cell->getPort("\\B")).to_sigbit_vector();
- std::vector<RTLIL::SigBit> sig_y = assign_map(cell->getPort("\\Y")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_a = assign_map(cell->getPort(ID::A)).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_b = assign_map(cell->getPort(ID::B)).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_y = assign_map(cell->getPort(ID::Y)).to_sigbit_vector();
std::vector<RTLIL::SigBit> new_sig_y;
RTLIL::SigSig old_sig_conn;
@@ -209,29 +209,29 @@ struct OptReduceWorker
if (new_sig_y.size() != sig_y.size())
{
log(" Consolidated identical input bits for %s cell %s:\n", cell->type.c_str(), cell->name.c_str());
- log(" Old ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort("\\A")),
- log_signal(cell->getPort("\\B")), log_signal(cell->getPort("\\Y")));
+ log(" Old ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort(ID::A)),
+ log_signal(cell->getPort(ID::B)), log_signal(cell->getPort(ID::Y)));
- cell->setPort("\\A", RTLIL::SigSpec());
+ cell->setPort(ID::A, RTLIL::SigSpec());
for (auto &in_tuple : consolidated_in_tuples) {
- RTLIL::SigSpec new_a = cell->getPort("\\A");
+ RTLIL::SigSpec new_a = cell->getPort(ID::A);
new_a.append(in_tuple.at(0));
- cell->setPort("\\A", new_a);
+ cell->setPort(ID::A, new_a);
}
- cell->setPort("\\B", RTLIL::SigSpec());
- for (int i = 1; i <= cell->getPort("\\S").size(); i++)
+ cell->setPort(ID::B, RTLIL::SigSpec());
+ for (int i = 1; i <= cell->getPort(ID(S)).size(); i++)
for (auto &in_tuple : consolidated_in_tuples) {
- RTLIL::SigSpec new_b = cell->getPort("\\B");
+ RTLIL::SigSpec new_b = cell->getPort(ID::B);
new_b.append(in_tuple.at(i));
- cell->setPort("\\B", new_b);
+ cell->setPort(ID::B, new_b);
}
- cell->parameters["\\WIDTH"] = RTLIL::Const(new_sig_y.size());
- cell->setPort("\\Y", new_sig_y);
+ cell->parameters[ID(WIDTH)] = RTLIL::Const(new_sig_y.size());
+ cell->setPort(ID::Y, new_sig_y);
- log(" New ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort("\\A")),
- log_signal(cell->getPort("\\B")), log_signal(cell->getPort("\\Y")));
+ log(" New ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort(ID::A)),
+ log_signal(cell->getPort(ID::B)), log_signal(cell->getPort(ID::Y)));
log(" New connections: %s = %s\n", log_signal(old_sig_conn.first), log_signal(old_sig_conn.second));
module->connect(old_sig_conn);
@@ -253,15 +253,15 @@ struct OptReduceWorker
SigPool mem_wren_sigs;
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
- if (cell->type == "$mem")
- mem_wren_sigs.add(assign_map(cell->getPort("\\WR_EN")));
- if (cell->type == "$memwr")
- mem_wren_sigs.add(assign_map(cell->getPort("\\EN")));
+ if (cell->type == ID($mem))
+ mem_wren_sigs.add(assign_map(cell->getPort(ID(WR_EN))));
+ if (cell->type == ID($memwr))
+ mem_wren_sigs.add(assign_map(cell->getPort(ID(EN))));
}
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
- if (cell->type == "$dff" && mem_wren_sigs.check_any(assign_map(cell->getPort("\\Q"))))
- mem_wren_sigs.add(assign_map(cell->getPort("\\D")));
+ if (cell->type == ID($dff) && mem_wren_sigs.check_any(assign_map(cell->getPort(ID(Q)))))
+ mem_wren_sigs.add(assign_map(cell->getPort(ID(D))));
}
bool keep_expanding_mem_wren_sigs = true;
@@ -269,12 +269,12 @@ struct OptReduceWorker
keep_expanding_mem_wren_sigs = false;
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
- if (cell->type == "$mux" && mem_wren_sigs.check_any(assign_map(cell->getPort("\\Y")))) {
- if (!mem_wren_sigs.check_all(assign_map(cell->getPort("\\A"))) ||
- !mem_wren_sigs.check_all(assign_map(cell->getPort("\\B"))))
+ if (cell->type == ID($mux) && mem_wren_sigs.check_any(assign_map(cell->getPort(ID::Y)))) {
+ if (!mem_wren_sigs.check_all(assign_map(cell->getPort(ID::A))) ||
+ !mem_wren_sigs.check_all(assign_map(cell->getPort(ID::B))))
keep_expanding_mem_wren_sigs = true;
- mem_wren_sigs.add(assign_map(cell->getPort("\\A")));
- mem_wren_sigs.add(assign_map(cell->getPort("\\B")));
+ mem_wren_sigs.add(assign_map(cell->getPort(ID::A)));
+ mem_wren_sigs.add(assign_map(cell->getPort(ID::B)));
}
}
}
@@ -286,7 +286,7 @@ struct OptReduceWorker
// merge trees of reduce_* cells to one single cell and unify input vectors
// (only handle reduce_and and reduce_or for various reasons)
- const char *type_list[] = { "$reduce_or", "$reduce_and" };
+ const IdString type_list[] = { ID($reduce_or), ID($reduce_and) };
for (auto type : type_list)
{
SigSet<RTLIL::Cell*> drivers;
@@ -296,7 +296,7 @@ struct OptReduceWorker
RTLIL::Cell *cell = cell_it.second;
if (cell->type != type || !design->selected(module, cell))
continue;
- drivers.insert(assign_map(cell->getPort("\\Y")), cell);
+ drivers.insert(assign_map(cell->getPort(ID::Y)), cell);
cells.insert(cell);
}
@@ -311,14 +311,14 @@ struct OptReduceWorker
std::vector<RTLIL::Cell*> cells;
for (auto &it : module->cells_)
- if ((it.second->type == "$mux" || it.second->type == "$pmux") && design->selected(module, it.second))
+ if ((it.second->type == ID($mux) || it.second->type == ID($pmux)) && design->selected(module, it.second))
cells.push_back(it.second);
for (auto cell : cells)
{
// this optimization is to aggressive for most coarse-grain applications.
// but we always want it for multiplexers driving write enable ports.
- if (do_fine || mem_wren_sigs.check_any(assign_map(cell->getPort("\\Y"))))
+ if (do_fine || mem_wren_sigs.check_any(assign_map(cell->getPort(ID::Y))))
opt_mux_bits(cell);
opt_mux(cell);
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index eeb992a3e..0bf74098a 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -17,26 +17,31 @@
*
*/
+#include "kernel/log.h"
#include "kernel/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/satgen.h"
#include "kernel/sigtools.h"
-#include "kernel/log.h"
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
SigMap assign_map, dff_init_map;
SigSet<RTLIL::Cell*> mux_drivers;
+dict<SigBit, RTLIL::Cell*> bit2driver;
dict<SigBit, pool<SigBit>> init_attributes;
+
bool keepdc;
+bool sat;
void remove_init_attr(SigSpec sig)
{
for (auto bit : assign_map(sig))
if (init_attributes.count(bit))
for (auto wbit : init_attributes.at(bit))
- wbit.wire->attributes.at("\\init")[wbit.offset] = State::Sx;
+ wbit.wire->attributes.at(ID(init))[wbit.offset] = State::Sx;
}
bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
@@ -44,39 +49,39 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
SigSpec sig_set, sig_clr;
State pol_set, pol_clr;
- if (cell->hasPort("\\S"))
- sig_set = cell->getPort("\\S");
+ if (cell->hasPort(ID(S)))
+ sig_set = cell->getPort(ID(S));
- if (cell->hasPort("\\R"))
- sig_clr = cell->getPort("\\R");
+ if (cell->hasPort(ID(R)))
+ sig_clr = cell->getPort(ID(R));
- if (cell->hasPort("\\SET"))
- sig_set = cell->getPort("\\SET");
+ if (cell->hasPort(ID(SET)))
+ sig_set = cell->getPort(ID(SET));
- if (cell->hasPort("\\CLR"))
- sig_clr = cell->getPort("\\CLR");
+ if (cell->hasPort(ID(CLR)))
+ sig_clr = cell->getPort(ID(CLR));
log_assert(GetSize(sig_set) == GetSize(sig_clr));
- if (cell->type.substr(0,8) == "$_DFFSR_") {
+ if (cell->type.begins_with("$_DFFSR_")) {
pol_set = cell->type[9] == 'P' ? State::S1 : State::S0;
pol_clr = cell->type[10] == 'P' ? State::S1 : State::S0;
} else
- if (cell->type.substr(0,11) == "$_DLATCHSR_") {
+ if (cell->type.begins_with("$_DLATCHSR_")) {
pol_set = cell->type[12] == 'P' ? State::S1 : State::S0;
pol_clr = cell->type[13] == 'P' ? State::S1 : State::S0;
} else
- if (cell->type == "$dffsr" || cell->type == "$dlatchsr") {
- pol_set = cell->parameters["\\SET_POLARITY"].as_bool() ? State::S1 : State::S0;
- pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool() ? State::S1 : State::S0;
+ if (cell->type.in(ID($dffsr), ID($dlatchsr))) {
+ pol_set = cell->parameters[ID(SET_POLARITY)].as_bool() ? State::S1 : State::S0;
+ pol_clr = cell->parameters[ID(CLR_POLARITY)].as_bool() ? State::S1 : State::S0;
} else
log_abort();
State npol_set = pol_set == State::S0 ? State::S1 : State::S0;
State npol_clr = pol_clr == State::S0 ? State::S1 : State::S0;
- SigSpec sig_d = cell->getPort("\\D");
- SigSpec sig_q = cell->getPort("\\Q");
+ SigSpec sig_d = cell->getPort(ID(D));
+ SigSpec sig_q = cell->getPort(ID(Q));
bool did_something = false;
bool proper_sr = false;
@@ -132,20 +137,20 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
return true;
}
- if (cell->type == "$dffsr" || cell->type == "$dlatchsr")
+ if (cell->type.in(ID($dffsr), ID($dlatchsr)))
{
- cell->setParam("\\WIDTH", GetSize(sig_d));
- cell->setPort("\\SET", sig_set);
- cell->setPort("\\CLR", sig_clr);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ cell->setParam(ID(WIDTH), GetSize(sig_d));
+ cell->setPort(ID(SET), sig_set);
+ cell->setPort(ID(CLR), sig_clr);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
}
else
{
- cell->setPort("\\S", sig_set);
- cell->setPort("\\R", sig_clr);
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ cell->setPort(ID(S), sig_set);
+ cell->setPort(ID(R), sig_clr);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
}
if (proper_sr)
@@ -154,36 +159,36 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
if (used_pol_set && used_pol_clr && pol_set != pol_clr)
return did_something;
- if (cell->type == "$dlatchsr")
+ if (cell->type == ID($dlatchsr))
return did_something;
State unified_pol = used_pol_set ? pol_set : pol_clr;
- if (cell->type == "$dffsr")
+ if (cell->type == ID($dffsr))
{
if (hasreset)
{
log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$adff", log_id(mod));
- cell->type = "$adff";
- cell->setParam("\\ARST_POLARITY", unified_pol);
- cell->setParam("\\ARST_VALUE", reset_val);
- cell->setPort("\\ARST", sig_reset);
+ cell->type = ID($adff);
+ cell->setParam(ID(ARST_POLARITY), unified_pol);
+ cell->setParam(ID(ARST_VALUE), reset_val);
+ cell->setPort(ID(ARST), sig_reset);
- cell->unsetParam("\\SET_POLARITY");
- cell->unsetParam("\\CLR_POLARITY");
- cell->unsetPort("\\SET");
- cell->unsetPort("\\CLR");
+ cell->unsetParam(ID(SET_POLARITY));
+ cell->unsetParam(ID(CLR_POLARITY));
+ cell->unsetPort(ID(SET));
+ cell->unsetPort(ID(CLR));
}
else
{
log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$dff", log_id(mod));
- cell->type = "$dff";
- cell->unsetParam("\\SET_POLARITY");
- cell->unsetParam("\\CLR_POLARITY");
- cell->unsetPort("\\SET");
- cell->unsetPort("\\CLR");
+ cell->type = ID($dff);
+ cell->unsetParam(ID(SET_POLARITY));
+ cell->unsetParam(ID(CLR_POLARITY));
+ cell->unsetPort(ID(SET));
+ cell->unsetPort(ID(CLR));
}
return true;
@@ -193,9 +198,9 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
{
IdString new_type;
- if (cell->type.substr(0,8) == "$_DFFSR_")
+ if (cell->type.begins_with("$_DFFSR_"))
new_type = stringf("$_DFF_%c_", cell->type[8]);
- else if (cell->type.substr(0,11) == "$_DLATCHSR_")
+ else if (cell->type.begins_with("$_DLATCHSR_"))
new_type = stringf("$_DLATCH_%c_", cell->type[11]);
else
log_abort();
@@ -203,8 +208,8 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), log_id(new_type), log_id(mod));
cell->type = new_type;
- cell->unsetPort("\\S");
- cell->unsetPort("\\R");
+ cell->unsetPort(ID(S));
+ cell->unsetPort(ID(R));
return true;
}
@@ -217,18 +222,18 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
SigSpec sig_e;
State on_state, off_state;
- if (dlatch->type == "$dlatch") {
- sig_e = assign_map(dlatch->getPort("\\EN"));
- on_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S1 : State::S0;
- off_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S0 : State::S1;
+ if (dlatch->type == ID($dlatch)) {
+ sig_e = assign_map(dlatch->getPort(ID(EN)));
+ on_state = dlatch->getParam(ID(EN_POLARITY)).as_bool() ? State::S1 : State::S0;
+ off_state = dlatch->getParam(ID(EN_POLARITY)).as_bool() ? State::S0 : State::S1;
} else
- if (dlatch->type == "$_DLATCH_P_") {
- sig_e = assign_map(dlatch->getPort("\\E"));
+ if (dlatch->type == ID($_DLATCH_P_)) {
+ sig_e = assign_map(dlatch->getPort(ID(E)));
on_state = State::S1;
off_state = State::S0;
} else
- if (dlatch->type == "$_DLATCH_N_") {
- sig_e = assign_map(dlatch->getPort("\\E"));
+ if (dlatch->type == ID($_DLATCH_N_)) {
+ sig_e = assign_map(dlatch->getPort(ID(E)));
on_state = State::S0;
off_state = State::S1;
} else
@@ -237,15 +242,15 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
if (sig_e == off_state)
{
RTLIL::Const val_init;
- for (auto bit : dff_init_map(dlatch->getPort("\\Q")))
+ for (auto bit : dff_init_map(dlatch->getPort(ID(Q))))
val_init.bits.push_back(bit.wire == NULL ? bit.data : State::Sx);
- mod->connect(dlatch->getPort("\\Q"), val_init);
+ mod->connect(dlatch->getPort(ID(Q)), val_init);
goto delete_dlatch;
}
if (sig_e == on_state)
{
- mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D"));
+ mod->connect(dlatch->getPort(ID(Q)), dlatch->getPort(ID(D)));
goto delete_dlatch;
}
@@ -253,7 +258,7 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
delete_dlatch:
log("Removing %s (%s) from module %s.\n", log_id(dlatch), log_id(dlatch->type), log_id(mod));
- remove_init_attr(dlatch->getPort("\\Q"));
+ remove_init_attr(dlatch->getPort(ID(Q)));
mod->remove(dlatch);
return true;
}
@@ -263,64 +268,64 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r, sig_e;
RTLIL::Const val_cp, val_rp, val_rv, val_ep;
- if (dff->type == "$_FF_") {
- sig_d = dff->getPort("\\D");
- sig_q = dff->getPort("\\Q");
+ if (dff->type == ID($_FF_)) {
+ sig_d = dff->getPort(ID(D));
+ sig_q = dff->getPort(ID(Q));
}
- else if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") {
- sig_d = dff->getPort("\\D");
- sig_q = dff->getPort("\\Q");
- sig_c = dff->getPort("\\C");
- val_cp = RTLIL::Const(dff->type == "$_DFF_P_", 1);
+ else if (dff->type == ID($_DFF_N_) || dff->type == ID($_DFF_P_)) {
+ sig_d = dff->getPort(ID(D));
+ sig_q = dff->getPort(ID(Q));
+ sig_c = dff->getPort(ID(C));
+ val_cp = RTLIL::Const(dff->type == ID($_DFF_P_), 1);
}
- else if (dff->type.substr(0,6) == "$_DFF_" && dff->type.substr(9) == "_" &&
+ else if (dff->type.begins_with("$_DFF_") && dff->type.compare(9, 1, "_") == 0 &&
(dff->type[6] == 'N' || dff->type[6] == 'P') &&
(dff->type[7] == 'N' || dff->type[7] == 'P') &&
(dff->type[8] == '0' || dff->type[8] == '1')) {
- sig_d = dff->getPort("\\D");
- sig_q = dff->getPort("\\Q");
- sig_c = dff->getPort("\\C");
- sig_r = dff->getPort("\\R");
+ sig_d = dff->getPort(ID(D));
+ sig_q = dff->getPort(ID(Q));
+ sig_c = dff->getPort(ID(C));
+ sig_r = dff->getPort(ID(R));
val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
val_rv = RTLIL::Const(dff->type[8] == '1', 1);
}
- else if (dff->type.substr(0,7) == "$_DFFE_" && dff->type.substr(9) == "_" &&
+ else if (dff->type.begins_with("$_DFFE_") && dff->type.compare(9, 1, "_") == 0 &&
(dff->type[7] == 'N' || dff->type[7] == 'P') &&
(dff->type[8] == 'N' || dff->type[8] == 'P')) {
- sig_d = dff->getPort("\\D");
- sig_q = dff->getPort("\\Q");
- sig_c = dff->getPort("\\C");
- sig_e = dff->getPort("\\E");
+ sig_d = dff->getPort(ID(D));
+ sig_q = dff->getPort(ID(Q));
+ sig_c = dff->getPort(ID(C));
+ sig_e = dff->getPort(ID(E));
val_cp = RTLIL::Const(dff->type[7] == 'P', 1);
val_ep = RTLIL::Const(dff->type[8] == 'P', 1);
}
- else if (dff->type == "$ff") {
- sig_d = dff->getPort("\\D");
- sig_q = dff->getPort("\\Q");
+ else if (dff->type == ID($ff)) {
+ sig_d = dff->getPort(ID(D));
+ sig_q = dff->getPort(ID(Q));
}
- else if (dff->type == "$dff") {
- sig_d = dff->getPort("\\D");
- sig_q = dff->getPort("\\Q");
- sig_c = dff->getPort("\\CLK");
- val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
+ else if (dff->type == ID($dff)) {
+ sig_d = dff->getPort(ID(D));
+ sig_q = dff->getPort(ID(Q));
+ sig_c = dff->getPort(ID(CLK));
+ val_cp = RTLIL::Const(dff->parameters[ID(CLK_POLARITY)].as_bool(), 1);
}
- else if (dff->type == "$dffe") {
- sig_e = dff->getPort("\\EN");
- sig_d = dff->getPort("\\D");
- sig_q = dff->getPort("\\Q");
- sig_c = dff->getPort("\\CLK");
- val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
- val_ep = RTLIL::Const(dff->parameters["\\EN_POLARITY"].as_bool(), 1);
+ else if (dff->type == ID($dffe)) {
+ sig_e = dff->getPort(ID(EN));
+ sig_d = dff->getPort(ID(D));
+ sig_q = dff->getPort(ID(Q));
+ sig_c = dff->getPort(ID(CLK));
+ val_cp = RTLIL::Const(dff->parameters[ID(CLK_POLARITY)].as_bool(), 1);
+ val_ep = RTLIL::Const(dff->parameters[ID(EN_POLARITY)].as_bool(), 1);
}
- else if (dff->type == "$adff") {
- sig_d = dff->getPort("\\D");
- sig_q = dff->getPort("\\Q");
- sig_c = dff->getPort("\\CLK");
- sig_r = dff->getPort("\\ARST");
- val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
- val_rp = RTLIL::Const(dff->parameters["\\ARST_POLARITY"].as_bool(), 1);
- val_rv = dff->parameters["\\ARST_VALUE"];
+ else if (dff->type == ID($adff)) {
+ sig_d = dff->getPort(ID(D));
+ sig_q = dff->getPort(ID(Q));
+ sig_c = dff->getPort(ID(CLK));
+ sig_r = dff->getPort(ID(ARST));
+ val_cp = RTLIL::Const(dff->parameters[ID(CLK_POLARITY)].as_bool(), 1);
+ val_rp = RTLIL::Const(dff->parameters[ID(ARST_POLARITY)].as_bool(), 1);
+ val_rv = dff->parameters[ID(ARST_VALUE)];
}
else
log_abort();
@@ -338,12 +343,12 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
}
- if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) {
+ if (dff->type.in(ID($ff), ID($dff)) && mux_drivers.has(sig_d)) {
std::set<RTLIL::Cell*> muxes;
mux_drivers.find(sig_d, muxes);
for (auto mux : muxes) {
- RTLIL::SigSpec sig_a = assign_map(mux->getPort("\\A"));
- RTLIL::SigSpec sig_b = assign_map(mux->getPort("\\B"));
+ RTLIL::SigSpec sig_a = assign_map(mux->getPort(ID::A));
+ RTLIL::SigSpec sig_b = assign_map(mux->getPort(ID::B));
if (sig_a == sig_q && sig_b.is_fully_const() && (!has_init || val_init == sig_b.as_const())) {
mod->connect(sig_q, sig_b);
goto delete_dff;
@@ -415,17 +420,17 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
- if (dff->type == "$adff") {
- dff->type = "$dff";
- dff->unsetPort("\\ARST");
- dff->unsetParam("\\ARST_POLARITY");
- dff->unsetParam("\\ARST_VALUE");
+ if (dff->type == ID($adff)) {
+ dff->type = ID($dff);
+ dff->unsetPort(ID(ARST));
+ dff->unsetParam(ID(ARST_POLARITY));
+ dff->unsetParam(ID(ARST_VALUE));
return true;
}
- log_assert(dff->type.substr(0,6) == "$_DFF_");
+ log_assert(dff->type.begins_with("$_DFF_"));
dff->type = stringf("$_DFF_%c_", + dff->type[6]);
- dff->unsetPort("\\R");
+ dff->unsetPort(ID(R));
}
// If enable signal is present, and is fully constant
@@ -440,24 +445,96 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
log("Removing unused enable from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
- if (dff->type == "$dffe") {
- dff->type = "$dff";
- dff->unsetPort("\\EN");
- dff->unsetParam("\\EN_POLARITY");
+ if (dff->type == ID($dffe)) {
+ dff->type = ID($dff);
+ dff->unsetPort(ID(EN));
+ dff->unsetParam(ID(EN_POLARITY));
return true;
}
- log_assert(dff->type.substr(0,7) == "$_DFFE_");
+ log_assert(dff->type.begins_with("$_DFFE_"));
dff->type = stringf("$_DFF_%c_", + dff->type[7]);
- dff->unsetPort("\\E");
+ dff->unsetPort(ID(E));
}
+ if (sat && has_init && (!sig_r.size() || val_init == val_rv))
+ {
+ bool removed_sigbits = false;
+
+ ezSatPtr ez;
+ SatGen satgen(ez.get(), &assign_map);
+ pool<Cell*> sat_cells;
+
+ std::function<void(Cell*)> sat_import_cell = [&](Cell *c) {
+ if (!sat_cells.insert(c).second)
+ return;
+ if (!satgen.importCell(c))
+ return;
+ for (auto &conn : c->connections()) {
+ if (!c->input(conn.first))
+ continue;
+ for (auto bit : assign_map(conn.second))
+ if (bit2driver.count(bit))
+ sat_import_cell(bit2driver.at(bit));
+ }
+ };
+
+ // For each register bit, try to prove that it cannot change from the initial value. If so, remove it
+ for (int position = 0; position < GetSize(sig_d); position += 1) {
+ RTLIL::SigBit q_sigbit = sig_q[position];
+ RTLIL::SigBit d_sigbit = sig_d[position];
+
+ if ((!q_sigbit.wire) || (!d_sigbit.wire))
+ continue;
+
+ if (!bit2driver.count(d_sigbit))
+ continue;
+
+ sat_import_cell(bit2driver.at(d_sigbit));
+
+ RTLIL::State sigbit_init_val = val_init[position];
+ if (sigbit_init_val != State::S0 && sigbit_init_val != State::S1)
+ continue;
+
+ int init_sat_pi = satgen.importSigSpec(sigbit_init_val).front();
+ int q_sat_pi = satgen.importSigBit(q_sigbit);
+ int d_sat_pi = satgen.importSigBit(d_sigbit);
+
+ // Try to find out whether the register bit can change under some circumstances
+ bool counter_example_found = ez->solve(ez->IFF(q_sat_pi, init_sat_pi), ez->NOT(ez->IFF(d_sat_pi, init_sat_pi)));
+
+ // If the register bit cannot change, we can replace it with a constant
+ if (!counter_example_found)
+ {
+ log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", sigbit_init_val ? 1 : 0,
+ position, log_id(dff), log_id(dff->type), log_id(mod));
+
+ SigSpec tmp = dff->getPort(ID(D));
+ tmp[position] = sigbit_init_val;
+ dff->setPort(ID(D), tmp);
+
+ removed_sigbits = true;
+ }
+ }
+
+ if (removed_sigbits) {
+ handle_dff(mod, dff);
+ return true;
+ }
+ }
+
+
return false;
delete_dff:
log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
- remove_init_attr(dff->getPort("\\Q"));
+ remove_init_attr(dff->getPort(ID(Q)));
mod->remove(dff);
+
+ for (auto &entry : bit2driver)
+ if (entry.second == dff)
+ bit2driver.erase(entry.first);
+
return true;
}
@@ -467,11 +544,15 @@ struct OptRmdffPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt_rmdff [-keepdc] [selection]\n");
+ log(" opt_rmdff [-keepdc] [-sat] [selection]\n");
log("\n");
log("This pass identifies flip-flops with constant inputs and replaces them with\n");
log("a constant driver.\n");
log("\n");
+ log(" -sat\n");
+ log(" additionally invoke SAT solver to detect and remove flip-flops (with \n");
+ log(" non-constant inputs) that can also be replaced with a constant driver\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -479,6 +560,7 @@ struct OptRmdffPass : public Pass {
log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
keepdc = false;
+ sat = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -486,24 +568,28 @@ struct OptRmdffPass : public Pass {
keepdc = true;
continue;
}
+ if (args[argidx] == "-sat") {
+ sat = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- for (auto module : design->selected_modules())
- {
+ for (auto module : design->selected_modules()) {
pool<SigBit> driven_bits;
dict<SigBit, State> init_bits;
assign_map.set(module);
dff_init_map.set(module);
mux_drivers.clear();
+ bit2driver.clear();
init_attributes.clear();
for (auto wire : module->wires())
{
- if (wire->attributes.count("\\init") != 0) {
- Const initval = wire->attributes.at("\\init");
+ if (wire->attributes.count(ID(init)) != 0) {
+ Const initval = wire->attributes.at(ID(init));
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
if (initval[i] == State::S0 || initval[i] == State::S1)
dff_init_map.add(SigBit(wire, i), initval[i]);
@@ -522,41 +608,45 @@ struct OptRmdffPass : public Pass {
driven_bits.insert(bit);
}
}
- mux_drivers.clear();
std::vector<RTLIL::IdString> dff_list;
std::vector<RTLIL::IdString> dffsr_list;
std::vector<RTLIL::IdString> dlatch_list;
for (auto cell : module->cells())
{
- for (auto &conn : cell->connections())
- if (cell->output(conn.first) || !cell->known())
- for (auto bit : assign_map(conn.second))
+ for (auto &conn : cell->connections()) {
+ bool is_output = cell->output(conn.first);
+ if (is_output || !cell->known())
+ for (auto bit : assign_map(conn.second)) {
+ if (is_output)
+ bit2driver[bit] = cell;
driven_bits.insert(bit);
+ }
+ }
- if (cell->type == "$mux" || cell->type == "$pmux") {
- if (cell->getPort("\\A").size() == cell->getPort("\\B").size())
- mux_drivers.insert(assign_map(cell->getPort("\\Y")), cell);
+ if (cell->type.in(ID($mux), ID($pmux))) {
+ if (cell->getPort(ID::A).size() == cell->getPort(ID::B).size())
+ mux_drivers.insert(assign_map(cell->getPort(ID::Y)), cell);
continue;
}
if (!design->selected(module, cell))
continue;
- if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
- "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", "$dffsr",
- "$_DLATCHSR_NNN_", "$_DLATCHSR_NNP_", "$_DLATCHSR_NPN_", "$_DLATCHSR_NPP_",
- "$_DLATCHSR_PNN_", "$_DLATCHSR_PNP_", "$_DLATCHSR_PPN_", "$_DLATCHSR_PPP_", "$dlatchsr"))
+ if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
+ ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_), ID($dffsr),
+ ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_),
+ ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), ID($dlatchsr)))
dffsr_list.push_back(cell->name);
- if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
- "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
- "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
- "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_",
- "$ff", "$dff", "$dffe", "$adff"))
+ if (cell->type.in(ID($_FF_), ID($_DFF_N_), ID($_DFF_P_),
+ ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
+ ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
+ ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_),
+ ID($ff), ID($dff), ID($dffe), ID($adff)))
dff_list.push_back(cell->name);
- if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
+ if (cell->type.in(ID($dlatch), ID($_DLATCH_P_), ID($_DLATCH_N_)))
dlatch_list.push_back(cell->name);
}
@@ -604,6 +694,7 @@ struct OptRmdffPass : public Pass {
assign_map.clear();
mux_drivers.clear();
+ bit2driver.clear();
init_attributes.clear();
if (total_count || total_initdrv)
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
new file mode 100644
index 000000000..c53fb3113
--- /dev/null
+++ b/passes/opt/opt_share.cc
@@ -0,0 +1,649 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Bogdan Vukobratovic <bogdan.vukobratovic@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/log.h"
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/sigtools.h"
+#include <algorithm>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+SigMap assign_map;
+
+struct OpMuxConn {
+ RTLIL::SigSpec sig;
+ RTLIL::Cell *mux;
+ RTLIL::Cell *op;
+ int mux_port_id;
+ int mux_port_offset;
+ int op_outsig_offset;
+
+ bool operator<(const OpMuxConn &other) const
+ {
+ if (mux != other.mux)
+ return mux < other.mux;
+
+ if (mux_port_id != other.mux_port_id)
+ return mux_port_id < other.mux_port_id;
+
+ return mux_port_offset < other.mux_port_offset;
+ }
+};
+
+// Helper class to track additiona information about a SigSpec, like whether it is signed and the semantics of the port it is connected to
+struct ExtSigSpec {
+ RTLIL::SigSpec sig;
+ RTLIL::SigSpec sign;
+ bool is_signed;
+ RTLIL::IdString semantics;
+
+ ExtSigSpec() {}
+
+ ExtSigSpec(RTLIL::SigSpec s, RTLIL::SigSpec sign = RTLIL::Const(0, 1), bool is_signed = false, RTLIL::IdString semantics = RTLIL::IdString()) : sig(s), sign(sign), is_signed(is_signed), semantics(semantics) {}
+
+ bool empty() const { return sig.empty(); }
+
+ bool operator<(const ExtSigSpec &other) const
+ {
+ if (sig != other.sig)
+ return sig < other.sig;
+
+ if (sign != other.sign)
+ return sign < other.sign;
+
+ if (is_signed != other.is_signed)
+ return is_signed < other.is_signed;
+
+ return semantics < other.semantics;
+ }
+
+ bool operator==(const RTLIL::SigSpec &other) const { return (sign != RTLIL::Const(0, 1)) ? false : sig == other; }
+ bool operator==(const ExtSigSpec &other) const { return is_signed == other.is_signed && sign == other.sign && sig == other.sig && semantics == other.semantics; }
+};
+
+#define BITWISE_OPS ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($and), ID($or), ID($xor), ID($xnor)
+
+#define REDUCTION_OPS ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($reduce_nand)
+
+#define LOGICAL_OPS ID($logic_and), ID($logic_or)
+
+#define SHIFT_OPS ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)
+
+#define RELATIONAL_OPS ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt)
+
+bool cell_supported(RTLIL::Cell *cell)
+{
+ if (cell->type.in(ID($alu))) {
+ RTLIL::SigSpec sig_bi = cell->getPort(ID(BI));
+ RTLIL::SigSpec sig_ci = cell->getPort(ID(CI));
+
+ if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci)
+ return true;
+ } else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($concat))) {
+ return true;
+ }
+
+ return false;
+}
+
+std::map<IdString, IdString> mergeable_type_map{
+ {ID($sub), ID($add)},
+};
+
+bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b)
+{
+ auto a_type = a->type;
+ if (mergeable_type_map.count(a_type))
+ a_type = mergeable_type_map.at(a_type);
+
+ auto b_type = b->type;
+ if (mergeable_type_map.count(b_type))
+ b_type = mergeable_type_map.at(b_type);
+
+ return a_type == b_type;
+}
+
+RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_name)
+{
+ if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($concat), SHIFT_OPS) && port_name == ID::B)
+ return port_name;
+
+ return "";
+}
+
+RTLIL::SigSpec decode_port_sign(RTLIL::Cell *cell, RTLIL::IdString port_name) {
+
+ if (cell->type == ID($alu) && port_name == ID::B)
+ return cell->getPort(ID(BI));
+ else if (cell->type == ID($sub) && port_name == ID::B)
+ return RTLIL::Const(1, 1);
+
+ return RTLIL::Const(0, 1);
+}
+
+bool decode_port_signed(RTLIL::Cell *cell, RTLIL::IdString port_name)
+{
+ if (cell->type.in(BITWISE_OPS, LOGICAL_OPS))
+ return false;
+
+ if (cell->hasParam(port_name.str() + "_SIGNED"))
+ return cell->getParam(port_name.str() + "_SIGNED").as_bool();
+
+ return false;
+}
+
+ExtSigSpec decode_port(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sigmap)
+{
+ auto sig = (*sigmap)(cell->getPort(port_name));
+
+ RTLIL::SigSpec sign = decode_port_sign(cell, port_name);
+ RTLIL::IdString semantics = decode_port_semantics(cell, port_name);
+
+ bool is_signed = decode_port_signed(cell, port_name);
+
+ return ExtSigSpec(sig, sign, is_signed, semantics);
+}
+
+void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<OpMuxConn> &ports, const ExtSigSpec &operand)
+{
+ std::vector<ExtSigSpec> muxed_operands;
+ int max_width = 0;
+ for (const auto& p : ports) {
+ auto op = p.op;
+
+ RTLIL::IdString muxed_port_name = ID::A;
+ if (decode_port(op, ID::A, &assign_map) == operand)
+ muxed_port_name = ID::B;
+
+ auto operand = decode_port(op, muxed_port_name, &assign_map);
+ if (operand.sig.size() > max_width)
+ max_width = operand.sig.size();
+
+ muxed_operands.push_back(operand);
+ }
+
+ auto shared_op = ports[0].op;
+
+ if (std::any_of(muxed_operands.begin(), muxed_operands.end(), [&](ExtSigSpec &op) { return op.sign != muxed_operands[0].sign; }))
+ max_width = std::max(max_width, shared_op->getParam(ID(Y_WIDTH)).as_int());
+
+
+ for (auto &operand : muxed_operands)
+ operand.sig.extend_u0(max_width, operand.is_signed);
+
+ for (const auto& p : ports) {
+ auto op = p.op;
+ if (op == shared_op)
+ continue;
+ module->remove(op);
+ }
+
+ for (auto &muxed_op : muxed_operands)
+ if (muxed_op.sign != muxed_operands[0].sign)
+ muxed_op = ExtSigSpec(module->Neg(NEW_ID, muxed_op.sig, muxed_op.is_signed));
+
+ RTLIL::SigSpec mux_y = mux->getPort(ID::Y);
+ RTLIL::SigSpec mux_a = mux->getPort(ID::A);
+ RTLIL::SigSpec mux_b = mux->getPort(ID::B);
+ RTLIL::SigSpec mux_s = mux->getPort(ID(S));
+
+ RTLIL::SigSpec shared_pmux_a = RTLIL::Const(RTLIL::State::Sx, max_width);
+ RTLIL::SigSpec shared_pmux_b;
+ RTLIL::SigSpec shared_pmux_s;
+
+ int conn_width = ports[0].sig.size();
+ int conn_offset = ports[0].mux_port_offset;
+
+ shared_op->setPort(ID::Y, shared_op->getPort(ID::Y).extract(0, conn_width));
+
+ if (mux->type == ID($pmux)) {
+ shared_pmux_s = RTLIL::SigSpec();
+
+ for (const auto &p : ports) {
+ shared_pmux_s.append(mux_s[p.mux_port_id]);
+ mux_b.replace(p.mux_port_id * mux_a.size() + conn_offset, shared_op->getPort(ID::Y));
+ }
+ } else {
+ shared_pmux_s = RTLIL::SigSpec{mux_s, module->Not(NEW_ID, mux_s)};
+ mux_a.replace(conn_offset, shared_op->getPort(ID::Y));
+ mux_b.replace(conn_offset, shared_op->getPort(ID::Y));
+ }
+
+ mux->setPort(ID::A, mux_a);
+ mux->setPort(ID::B, mux_b);
+ mux->setPort(ID::Y, mux_y);
+ mux->setPort(ID(S), mux_s);
+
+ for (const auto &op : muxed_operands)
+ shared_pmux_b.append(op.sig);
+
+ auto mux_to_oper = module->Pmux(NEW_ID, shared_pmux_a, shared_pmux_b, shared_pmux_s);
+
+ if (shared_op->type.in(ID($alu))) {
+ RTLIL::SigSpec alu_x = shared_op->getPort(ID(X));
+ RTLIL::SigSpec alu_co = shared_op->getPort(ID(CO));
+
+ shared_op->setPort(ID(X), alu_x.extract(0, conn_width));
+ shared_op->setPort(ID(CO), alu_co.extract(0, conn_width));
+ }
+
+ shared_op->setParam(ID(Y_WIDTH), conn_width);
+
+ if (decode_port(shared_op, ID::A, &assign_map) == operand) {
+ shared_op->setPort(ID::B, mux_to_oper);
+ shared_op->setParam(ID(B_WIDTH), max_width);
+ } else {
+ shared_op->setPort(ID::A, mux_to_oper);
+ shared_op->setParam(ID(A_WIDTH), max_width);
+ }
+}
+
+typedef struct {
+ RTLIL::Cell *mux;
+ std::vector<OpMuxConn> ports;
+ ExtSigSpec shared_operand;
+} merged_op_t;
+
+
+template <typename T> void remove_val(std::vector<T> &v, const std::vector<T> &vals)
+{
+ auto val_iter = vals.rbegin();
+ for (auto i = v.rbegin(); i != v.rend(); ++i)
+ if ((val_iter != vals.rend()) && (*i == *val_iter)) {
+ v.erase(i.base() - 1);
+ ++val_iter;
+ }
+}
+
+void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpec &shared_operand)
+{
+ auto it = ports.begin();
+ ExtSigSpec seed;
+
+ while (it != ports.end()) {
+ auto p = *it;
+ auto op = p->op;
+
+ RTLIL::IdString muxed_port_name = ID::A;
+ if (decode_port(op, ID::A, &assign_map) == shared_operand) {
+ muxed_port_name = ID::B;
+ }
+
+ auto operand = decode_port(op, muxed_port_name, &assign_map);
+
+ if (seed.empty())
+ seed = operand;
+
+ if (operand.is_signed != seed.is_signed) {
+ ports.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+ExtSigSpec find_shared_operand(const OpMuxConn* seed, std::vector<const OpMuxConn *> &ports, const std::map<ExtSigSpec, std::set<RTLIL::Cell *>> &operand_to_users)
+{
+ std::set<RTLIL::Cell *> ops_using_operand;
+ std::set<RTLIL::Cell *> ops_set;
+ for(const auto& p: ports)
+ ops_set.insert(p->op);
+
+ ExtSigSpec oper;
+
+ auto op_a = seed->op;
+
+ for (RTLIL::IdString port_name : {ID::A, ID::B}) {
+ oper = decode_port(op_a, port_name, &assign_map);
+ auto operand_users = operand_to_users.at(oper);
+
+ if (operand_users.size() == 1)
+ continue;
+
+ ops_using_operand.clear();
+ for (auto mux_ops: ops_set)
+ if (operand_users.count(mux_ops))
+ ops_using_operand.insert(mux_ops);
+
+ if (ops_using_operand.size() > 1) {
+ ports.erase(std::remove_if(ports.begin(), ports.end(), [&](const OpMuxConn *p) { return !ops_using_operand.count(p->op); }),
+ ports.end());
+ return oper;
+ }
+ }
+
+ return ExtSigSpec();
+}
+
+dict<RTLIL::SigSpec, OpMuxConn> find_valid_op_mux_conns(RTLIL::Module *module, dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig,
+ dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator,
+ dict<RTLIL::SigBit, RTLIL::SigSpec> &op_aux_to_outsig)
+{
+ dict<RTLIL::SigSpec, int> op_outsig_user_track;
+ dict<RTLIL::SigSpec, OpMuxConn> op_mux_conn_map;
+
+ std::function<void(RTLIL::SigSpec)> remove_outsig = [&](RTLIL::SigSpec outsig) {
+ for (auto op_outbit : outsig)
+ op_outbit_to_outsig.erase(op_outbit);
+
+ if (op_mux_conn_map.count(outsig))
+ op_mux_conn_map.erase(outsig);
+ };
+
+ std::function<void(RTLIL::SigBit)> remove_outsig_from_aux_bit = [&](RTLIL::SigBit auxbit) {
+ auto aux_outsig = op_aux_to_outsig.at(auxbit);
+ auto op = outsig_to_operator.at(aux_outsig);
+ auto op_outsig = assign_map(op->getPort(ID::Y));
+ remove_outsig(op_outsig);
+
+ for (auto aux_outbit : aux_outsig)
+ op_aux_to_outsig.erase(aux_outbit);
+ };
+
+ std::function<void(RTLIL::Cell *)> find_op_mux_conns = [&](RTLIL::Cell *mux) {
+ RTLIL::SigSpec sig;
+ int mux_port_size;
+
+ if (mux->type.in(ID($mux), ID($_MUX_))) {
+ mux_port_size = mux->getPort(ID::A).size();
+ sig = RTLIL::SigSpec{mux->getPort(ID::B), mux->getPort(ID::A)};
+ } else {
+ mux_port_size = mux->getPort(ID::A).size();
+ sig = mux->getPort(ID::B);
+ }
+
+ auto mux_insig = assign_map(sig);
+
+ for (int i = 0; i < mux_insig.size(); ++i) {
+ if (op_aux_to_outsig.count(mux_insig[i])) {
+ remove_outsig_from_aux_bit(mux_insig[i]);
+ continue;
+ }
+
+ if (!op_outbit_to_outsig.count(mux_insig[i]))
+ continue;
+
+ auto op_outsig = op_outbit_to_outsig.at(mux_insig[i]);
+
+ if (op_mux_conn_map.count(op_outsig)) {
+ remove_outsig(op_outsig);
+ continue;
+ }
+
+ int mux_port_id = i / mux_port_size;
+ int mux_port_offset = i % mux_port_size;
+
+ int op_outsig_offset;
+ for (op_outsig_offset = 0; op_outsig[op_outsig_offset] != mux_insig[i]; ++op_outsig_offset)
+ ;
+
+ int j = op_outsig_offset;
+ do {
+ if (!op_outbit_to_outsig.count(mux_insig[i]))
+ break;
+
+ if (op_outbit_to_outsig.at(mux_insig[i]) != op_outsig)
+ break;
+
+ ++i;
+ ++j;
+ } while ((i / mux_port_size == mux_port_id) && (j < op_outsig.size()));
+
+ int op_conn_width = j - op_outsig_offset;
+ OpMuxConn inp = {
+ op_outsig.extract(op_outsig_offset, op_conn_width),
+ mux,
+ outsig_to_operator.at(op_outsig),
+ mux_port_id,
+ mux_port_offset,
+ op_outsig_offset,
+ };
+
+ op_mux_conn_map[op_outsig] = inp;
+
+ --i;
+ }
+ };
+
+ std::function<void(RTLIL::SigSpec)> remove_connected_ops = [&](RTLIL::SigSpec sig) {
+ auto mux_insig = assign_map(sig);
+ for (auto outbit : mux_insig) {
+ if (op_aux_to_outsig.count(outbit)) {
+ remove_outsig_from_aux_bit(outbit);
+ continue;
+ }
+
+ if (!op_outbit_to_outsig.count(outbit))
+ continue;
+
+ remove_outsig(op_outbit_to_outsig.at(outbit));
+ }
+ };
+
+ for (auto cell : module->cells()) {
+ if (cell->type.in(ID($mux), ID($_MUX_), ID($pmux))) {
+ remove_connected_ops(cell->getPort(ID(S)));
+ find_op_mux_conns(cell);
+ } else {
+ for (auto &conn : cell->connections())
+ if (cell->input(conn.first))
+ remove_connected_ops(conn.second);
+ }
+ }
+
+ for (auto w : module->wires()) {
+ if (!w->port_output)
+ continue;
+
+ remove_connected_ops(w);
+ }
+
+ return op_mux_conn_map;
+}
+
+struct OptSharePass : public Pass {
+ OptSharePass() : Pass("opt_share", "merge mutually exclusive cells of the same type that share an input signal") {}
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" opt_share [selection]\n");
+ log("\n");
+
+ log("This pass identifies mutually exclusive cells of the same type that:\n");
+ log(" (a) share an input signal,\n");
+ log(" (b) drive the same $mux, $_MUX_, or $pmux multiplexing cell,\n");
+ log("\n");
+ log("allowing the cell to be merged and the multiplexer to be moved from\n");
+ log("multiplexing its output to multiplexing the non-shared input signals.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+
+ log_header(design, "Executing OPT_SHARE pass.\n");
+
+ extra_args(args, 1, design);
+ for (auto module : design->selected_modules()) {
+ assign_map.clear();
+ assign_map.set(module);
+
+ std::map<ExtSigSpec, std::set<RTLIL::Cell *>> operand_to_users;
+ dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator;
+ dict<RTLIL::SigBit, RTLIL::SigSpec> op_outbit_to_outsig;
+ dict<RTLIL::SigBit, RTLIL::SigSpec> op_aux_to_outsig;
+ bool any_shared_operands = false;
+ std::vector<ExtSigSpec> op_insigs;
+
+ for (auto cell : module->cells()) {
+ if (!cell_supported(cell))
+ continue;
+
+ if (cell->type == ID($alu)) {
+ for (RTLIL::IdString port_name : {ID(X), ID(CO)}) {
+ auto mux_insig = assign_map(cell->getPort(port_name));
+ outsig_to_operator[mux_insig] = cell;
+ for (auto outbit : mux_insig)
+ op_aux_to_outsig[outbit] = mux_insig;
+ }
+ }
+
+ auto mux_insig = assign_map(cell->getPort(ID::Y));
+ outsig_to_operator[mux_insig] = cell;
+ for (auto outbit : mux_insig)
+ op_outbit_to_outsig[outbit] = mux_insig;
+
+ for (RTLIL::IdString port_name : {ID::A, ID::B}) {
+ auto op_insig = decode_port(cell, port_name, &assign_map);
+ op_insigs.push_back(op_insig);
+ operand_to_users[op_insig].insert(cell);
+ if (operand_to_users[op_insig].size() > 1)
+ any_shared_operands = true;
+ }
+ }
+
+ if (!any_shared_operands)
+ continue;
+
+ // Operator outputs need to be exclusively connected to the $mux inputs in order to be mergeable. Hence we count to
+ // how many points are operator output bits connected.
+ dict<RTLIL::SigSpec, OpMuxConn> op_mux_conn_map =
+ find_valid_op_mux_conns(module, op_outbit_to_outsig, outsig_to_operator, op_aux_to_outsig);
+
+ // Group op connections connected to same ports of the same $mux. Sort them in ascending order of their port offset
+ dict<RTLIL::Cell*, std::vector<std::set<OpMuxConn>>> mux_port_op_conns;
+ for (auto& val: op_mux_conn_map) {
+ OpMuxConn p = val.second;
+ auto& mux_port_conns = mux_port_op_conns[p.mux];
+
+ if (mux_port_conns.size() == 0) {
+ int mux_port_num;
+
+ if (p.mux->type.in(ID($mux), ID($_MUX_)))
+ mux_port_num = 2;
+ else
+ mux_port_num = p.mux->getPort(ID(S)).size();
+
+ mux_port_conns.resize(mux_port_num);
+ }
+
+ mux_port_conns[p.mux_port_id].insert(p);
+ }
+
+ std::vector<merged_op_t> merged_ops;
+ for (auto& val: mux_port_op_conns) {
+
+ RTLIL::Cell* cell = val.first;
+ auto &mux_port_conns = val.second;
+
+ const OpMuxConn *seed = NULL;
+
+ // Look through the bits of the $mux inputs and see which of them are connected to the operator
+ // results. Operator results can be concatenated with other signals before led to the $mux.
+ while (true) {
+
+ // Remove either the merged ports from the last iteration or the seed that failed to yield a merger
+ if (seed != NULL) {
+ mux_port_conns[seed->mux_port_id].erase(*seed);
+ seed = NULL;
+ }
+
+ // For a new merger, find the seed op connection that starts at lowest port offset among port connections
+ for (auto &port_conns : mux_port_conns) {
+ if (!port_conns.size())
+ continue;
+
+ const OpMuxConn *next_p = &(*port_conns.begin());
+
+ if ((seed == NULL) || (seed->mux_port_offset > next_p->mux_port_offset))
+ seed = next_p;
+ }
+
+ // Cannot find the seed -> nothing to do for this $mux anymore
+ if (seed == NULL)
+ break;
+
+ // Find all other op connections that start from the same port offset, and whose ops can be merged with the seed op
+ std::vector<const OpMuxConn *> mergeable_conns;
+ for (auto &port_conns : mux_port_conns) {
+ if (!port_conns.size())
+ continue;
+
+ const OpMuxConn *next_p = &(*port_conns.begin());
+
+ if ((next_p->op_outsig_offset == seed->op_outsig_offset) &&
+ (next_p->mux_port_offset == seed->mux_port_offset) && mergeable(next_p->op, seed->op) &&
+ next_p->sig.size() == seed->sig.size())
+ mergeable_conns.push_back(next_p);
+ }
+
+ // We need at least two mergeable connections for the merger
+ if (mergeable_conns.size() < 2)
+ continue;
+
+ // Filter mergeable connections whose ops share an operand with seed connection's op
+ auto shared_operand = find_shared_operand(seed, mergeable_conns, operand_to_users);
+
+ if (shared_operand.empty())
+ continue;
+
+ check_muxed_operands(mergeable_conns, shared_operand);
+
+ if (mergeable_conns.size() < 2)
+ continue;
+
+ // Remember the combination for the merger
+ std::vector<OpMuxConn> merged_ports;
+ for (auto p : mergeable_conns) {
+ merged_ports.push_back(*p);
+ mux_port_conns[p->mux_port_id].erase(*p);
+ }
+
+ seed = NULL;
+
+ merged_ops.push_back(merged_op_t{cell, merged_ports, shared_operand});
+
+ design->scratchpad_set_bool("opt.did_something", true);
+ }
+
+ }
+
+ for (auto &shared : merged_ops) {
+ log(" Found cells that share an operand and can be merged by moving the %s %s in front "
+ "of "
+ "them:\n",
+ log_id(shared.mux->type), log_id(shared.mux));
+ for (const auto& op : shared.ports)
+ log(" %s\n", log_id(op.op));
+ log("\n");
+
+ merge_operators(module, shared.mux, shared.ports, shared.shared_operand);
+ }
+ }
+ }
+
+} OptSharePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc
index 29870f510..92b5794ac 100644
--- a/passes/opt/pmux2shiftx.cc
+++ b/passes/opt/pmux2shiftx.cc
@@ -46,7 +46,7 @@ struct OnehotDatabase
for (auto wire : module->wires())
{
- auto it = wire->attributes.find("\\init");
+ auto it = wire->attributes.find(ID(init));
if (it == wire->attributes.end())
continue;
@@ -63,19 +63,19 @@ struct OnehotDatabase
vector<SigSpec> inputs;
SigSpec output;
- if (cell->type.in("$adff", "$dff", "$dffe", "$dlatch", "$ff"))
+ if (cell->type.in(ID($adff), ID($dff), ID($dffe), ID($dlatch), ID($ff)))
{
- output = cell->getPort("\\Q");
- if (cell->type == "$adff")
- inputs.push_back(cell->getParam("\\ARST_VALUE"));
- inputs.push_back(cell->getPort("\\D"));
+ output = cell->getPort(ID(Q));
+ if (cell->type == ID($adff))
+ inputs.push_back(cell->getParam(ID(ARST_VALUE)));
+ inputs.push_back(cell->getPort(ID(D)));
}
- if (cell->type.in("$mux", "$pmux"))
+ if (cell->type.in(ID($mux), ID($pmux)))
{
- output = cell->getPort("\\Y");
- inputs.push_back(cell->getPort("\\A"));
- SigSpec B = cell->getPort("\\B");
+ output = cell->getPort(ID::Y);
+ inputs.push_back(cell->getPort(ID::A));
+ SigSpec B = cell->getPort(ID::B);
for (int i = 0; i < GetSize(B); i += GetSize(output))
inputs.push_back(B.extract(i, GetSize(output)));
}
@@ -221,6 +221,9 @@ struct Pmux2ShiftxPass : public Pass {
log(" select strategy for one-hot encoded control signals\n");
log(" default: pmux\n");
log("\n");
+ log(" -norange\n");
+ log(" disable $sub inference for \"range decoders\"\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -230,6 +233,7 @@ struct Pmux2ShiftxPass : public Pass {
bool optimize_onehot = true;
bool verbose = false;
bool verbose_onehot = false;
+ bool norange = false;
log_header(design, "Executing PMUX2SHIFTX pass.\n");
@@ -270,6 +274,10 @@ struct Pmux2ShiftxPass : public Pass {
verbose_onehot = true;
continue;
}
+ if (args[argidx] == "-norange") {
+ norange = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -284,23 +292,23 @@ struct Pmux2ShiftxPass : public Pass {
for (auto cell : module->cells())
{
- if (cell->type == "$eq")
+ if (cell->type == ID($eq))
{
dict<SigBit, State> bits;
- SigSpec A = sigmap(cell->getPort("\\A"));
- SigSpec B = sigmap(cell->getPort("\\B"));
+ SigSpec A = sigmap(cell->getPort(ID::A));
+ SigSpec B = sigmap(cell->getPort(ID::B));
- int a_width = cell->getParam("\\A_WIDTH").as_int();
- int b_width = cell->getParam("\\B_WIDTH").as_int();
+ int a_width = cell->getParam(ID(A_WIDTH)).as_int();
+ int b_width = cell->getParam(ID(B_WIDTH)).as_int();
if (a_width < b_width) {
- bool a_signed = cell->getParam("\\A_SIGNED").as_int();
+ bool a_signed = cell->getParam(ID(A_SIGNED)).as_int();
A.extend_u0(b_width, a_signed);
}
if (b_width < a_width) {
- bool b_signed = cell->getParam("\\B_SIGNED").as_int();
+ bool b_signed = cell->getParam(ID(B_SIGNED)).as_int();
B.extend_u0(a_width, b_signed);
}
@@ -327,15 +335,15 @@ struct Pmux2ShiftxPass : public Pass {
entry.second.bits.push_back(it.second);
}
- eqdb[sigmap(cell->getPort("\\Y")[0])] = entry;
+ eqdb[sigmap(cell->getPort(ID::Y)[0])] = entry;
goto next_cell;
}
- if (cell->type == "$logic_not")
+ if (cell->type == ID($logic_not))
{
dict<SigBit, State> bits;
- SigSpec A = sigmap(cell->getPort("\\A"));
+ SigSpec A = sigmap(cell->getPort(ID::A));
for (int i = 0; i < GetSize(A); i++)
bits[A[i]] = State::S0;
@@ -348,7 +356,7 @@ struct Pmux2ShiftxPass : public Pass {
entry.second.bits.push_back(it.second);
}
- eqdb[sigmap(cell->getPort("\\Y")[0])] = entry;
+ eqdb[sigmap(cell->getPort(ID::Y)[0])] = entry;
goto next_cell;
}
next_cell:;
@@ -356,11 +364,11 @@ struct Pmux2ShiftxPass : public Pass {
for (auto cell : module->selected_cells())
{
- if (cell->type != "$pmux")
+ if (cell->type != ID($pmux))
continue;
string src = cell->get_src_attribute();
- int width = cell->getParam("\\WIDTH").as_int();
+ int width = cell->getParam(ID(WIDTH)).as_int();
int width_bits = ceil_log2(width);
int extwidth = width;
@@ -369,9 +377,9 @@ struct Pmux2ShiftxPass : public Pass {
dict<SigSpec, pool<int>> seldb;
- SigSpec A = cell->getPort("\\A");
- SigSpec B = cell->getPort("\\B");
- SigSpec S = sigmap(cell->getPort("\\S"));
+ SigSpec A = cell->getPort(ID::A);
+ SigSpec B = cell->getPort(ID::B);
+ SigSpec S = sigmap(cell->getPort(ID(S)));
for (int i = 0; i < GetSize(S); i++)
{
if (!eqdb.count(S[i]))
@@ -392,8 +400,8 @@ struct Pmux2ShiftxPass : public Pass {
log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits);
}
- SigSpec updated_S = cell->getPort("\\S");
- SigSpec updated_B = cell->getPort("\\B");
+ SigSpec updated_S = cell->getPort(ID(S));
+ SigSpec updated_B = cell->getPort(ID::B);
while (!seldb.empty())
{
@@ -559,7 +567,7 @@ struct Pmux2ShiftxPass : public Pass {
int this_inv_delta = this_maxval - this_minval;
bool this_inv = false;
- if (this_delta != this_inv_delta)
+ if (!norange && this_delta != this_inv_delta)
this_inv = this_inv_delta < this_delta;
else if (this_maxval != this_inv_maxval)
this_inv = this_inv_maxval < this_maxval;
@@ -574,7 +582,7 @@ struct Pmux2ShiftxPass : public Pass {
if (best_src_col < 0)
this_is_better = true;
- else if (this_delta != best_delta)
+ else if (!norange && this_delta != best_delta)
this_is_better = this_delta < best_delta;
else if (this_maxval != best_maxval)
this_is_better = this_maxval < best_maxval;
@@ -656,7 +664,7 @@ struct Pmux2ShiftxPass : public Pass {
// check density percentages
Const offset(State::S0, GetSize(sig));
- if (absolute_density < min_density && range_density >= min_density)
+ if (!norange && absolute_density < min_density && range_density >= min_density)
{
offset = Const(min_choice, GetSize(sig));
log(" offset: %s\n", log_signal(offset));
@@ -719,9 +727,9 @@ struct Pmux2ShiftxPass : public Pass {
}
// update $pmux cell
- cell->setPort("\\S", updated_S);
- cell->setPort("\\B", updated_B);
- cell->setParam("\\S_WIDTH", GetSize(updated_S));
+ cell->setPort(ID(S), updated_S);
+ cell->setPort(ID::B, updated_B);
+ cell->setParam(ID(S_WIDTH), GetSize(updated_S));
}
}
}
@@ -771,22 +779,22 @@ struct OnehotPass : public Pass {
for (auto cell : module->selected_cells())
{
- if (cell->type != "$eq")
+ if (cell->type != ID($eq))
continue;
- SigSpec A = sigmap(cell->getPort("\\A"));
- SigSpec B = sigmap(cell->getPort("\\B"));
+ SigSpec A = sigmap(cell->getPort(ID::A));
+ SigSpec B = sigmap(cell->getPort(ID::B));
- int a_width = cell->getParam("\\A_WIDTH").as_int();
- int b_width = cell->getParam("\\B_WIDTH").as_int();
+ int a_width = cell->getParam(ID(A_WIDTH)).as_int();
+ int b_width = cell->getParam(ID(B_WIDTH)).as_int();
if (a_width < b_width) {
- bool a_signed = cell->getParam("\\A_SIGNED").as_int();
+ bool a_signed = cell->getParam(ID(A_SIGNED)).as_int();
A.extend_u0(b_width, a_signed);
}
if (b_width < a_width) {
- bool b_signed = cell->getParam("\\B_SIGNED").as_int();
+ bool b_signed = cell->getParam(ID(B_SIGNED)).as_int();
B.extend_u0(a_width, b_signed);
}
@@ -822,7 +830,7 @@ struct OnehotPass : public Pass {
continue;
}
- SigSpec Y = cell->getPort("\\Y");
+ SigSpec Y = cell->getPort(ID::Y);
if (not_onehot)
{
diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc
index fc1596ebf..32363dd68 100644
--- a/passes/opt/rmports.cc
+++ b/passes/opt/rmports.cc
@@ -171,7 +171,7 @@ struct RmportsPassPass : public Pass {
wire->port_output = false;
wire->port_id = 0;
}
- log("Removed %zu unused ports.\n", unused_ports.size());
+ log("Removed %d unused ports.\n", GetSize(unused_ports));
// Re-number all of the wires that DO have ports still on them
for(size_t i=0; i<module->ports.size(); i++)
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index c85c27427..92ce3fd11 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -89,8 +89,8 @@ struct ShareWorker
queue_bits.clear();
for (auto &pbit : portbits) {
- if (pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") {
- pool<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->getPort("\\S")).to_sigbit_pool();
+ if (pbit.cell->type == ID($mux) || pbit.cell->type == ID($pmux)) {
+ pool<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->getPort(ID(S))).to_sigbit_pool();
terminal_bits.insert(bits.begin(), bits.end());
queue_bits.insert(bits.begin(), bits.end());
visited_cells.insert(pbit.cell);
@@ -128,7 +128,7 @@ struct ShareWorker
static int bits_macc(RTLIL::Cell *c)
{
Macc m(c);
- int width = GetSize(c->getPort("\\Y"));
+ int width = GetSize(c->getPort(ID::Y));
return bits_macc(m, width);
}
@@ -242,7 +242,7 @@ struct ShareWorker
{
Macc m1(c1), m2(c2), supermacc;
- int w1 = GetSize(c1->getPort("\\Y")), w2 = GetSize(c2->getPort("\\Y"));
+ int w1 = GetSize(c1->getPort(ID::Y)), w2 = GetSize(c2->getPort(ID::Y));
int width = max(w1, w2);
m1.optimize(w1);
@@ -328,11 +328,11 @@ struct ShareWorker
{
RTLIL::SigSpec sig_y = module->addWire(NEW_ID, width);
- supercell_aux->insert(module->addPos(NEW_ID, sig_y, c1->getPort("\\Y")));
- supercell_aux->insert(module->addPos(NEW_ID, sig_y, c2->getPort("\\Y")));
+ supercell_aux->insert(module->addPos(NEW_ID, sig_y, c1->getPort(ID::Y)));
+ supercell_aux->insert(module->addPos(NEW_ID, sig_y, c2->getPort(ID::Y)));
- supercell->setParam("\\Y_WIDTH", width);
- supercell->setPort("\\Y", sig_y);
+ supercell->setParam(ID(Y_WIDTH), width);
+ supercell->setPort(ID::Y, sig_y);
supermacc.optimize(width);
supermacc.to_cell(supercell);
@@ -368,22 +368,22 @@ struct ShareWorker
continue;
}
- if (cell->type == "$memrd") {
- if (cell->parameters.at("\\CLK_ENABLE").as_bool())
+ if (cell->type == ID($memrd)) {
+ if (cell->parameters.at(ID(CLK_ENABLE)).as_bool())
continue;
- if (config.opt_aggressive || !modwalker.sigmap(cell->getPort("\\ADDR")).is_fully_const())
+ if (config.opt_aggressive || !modwalker.sigmap(cell->getPort(ID(ADDR))).is_fully_const())
shareable_cells.insert(cell);
continue;
}
- if (cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod") {
- if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 4)
+ if (cell->type.in(ID($mul), ID($div), ID($mod))) {
+ if (config.opt_aggressive || cell->parameters.at(ID(Y_WIDTH)).as_int() >= 4)
shareable_cells.insert(cell);
continue;
}
- if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr") {
- if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 8)
+ if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr))) {
+ if (config.opt_aggressive || cell->parameters.at(ID(Y_WIDTH)).as_int() >= 8)
shareable_cells.insert(cell);
continue;
}
@@ -401,9 +401,9 @@ struct ShareWorker
if (c1->type != c2->type)
return false;
- if (c1->type == "$memrd")
+ if (c1->type == ID($memrd))
{
- if (c1->parameters.at("\\MEMID").decode_string() != c2->parameters.at("\\MEMID").decode_string())
+ if (c1->parameters.at(ID(MEMID)).decode_string() != c2->parameters.at(ID(MEMID)).decode_string())
return false;
return true;
@@ -413,11 +413,11 @@ struct ShareWorker
{
if (!config.opt_aggressive)
{
- int a1_width = c1->parameters.at("\\A_WIDTH").as_int();
- int y1_width = c1->parameters.at("\\Y_WIDTH").as_int();
+ int a1_width = c1->parameters.at(ID(A_WIDTH)).as_int();
+ int y1_width = c1->parameters.at(ID(Y_WIDTH)).as_int();
- int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
- int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
+ int a2_width = c2->parameters.at(ID(A_WIDTH)).as_int();
+ int y2_width = c2->parameters.at(ID(Y_WIDTH)).as_int();
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;
@@ -426,17 +426,17 @@ struct ShareWorker
return true;
}
- if (config.generic_bin_ops.count(c1->type) || c1->type == "$alu")
+ if (config.generic_bin_ops.count(c1->type) || c1->type == ID($alu))
{
if (!config.opt_aggressive)
{
- int a1_width = c1->parameters.at("\\A_WIDTH").as_int();
- int b1_width = c1->parameters.at("\\B_WIDTH").as_int();
- int y1_width = c1->parameters.at("\\Y_WIDTH").as_int();
+ int a1_width = c1->parameters.at(ID(A_WIDTH)).as_int();
+ int b1_width = c1->parameters.at(ID(B_WIDTH)).as_int();
+ int y1_width = c1->parameters.at(ID(Y_WIDTH)).as_int();
- int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
- int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
- int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
+ int a2_width = c2->parameters.at(ID(A_WIDTH)).as_int();
+ int b2_width = c2->parameters.at(ID(B_WIDTH)).as_int();
+ int y2_width = c2->parameters.at(ID(Y_WIDTH)).as_int();
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;
@@ -450,13 +450,13 @@ struct ShareWorker
{
if (!config.opt_aggressive)
{
- int a1_width = c1->parameters.at("\\A_WIDTH").as_int();
- int b1_width = c1->parameters.at("\\B_WIDTH").as_int();
- int y1_width = c1->parameters.at("\\Y_WIDTH").as_int();
+ int a1_width = c1->parameters.at(ID(A_WIDTH)).as_int();
+ int b1_width = c1->parameters.at(ID(B_WIDTH)).as_int();
+ int y1_width = c1->parameters.at(ID(Y_WIDTH)).as_int();
- int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
- int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
- int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
+ int a2_width = c2->parameters.at(ID(A_WIDTH)).as_int();
+ int b2_width = c2->parameters.at(ID(B_WIDTH)).as_int();
+ int y2_width = c2->parameters.at(ID(Y_WIDTH)).as_int();
int min1_width = min(a1_width, b1_width);
int max1_width = max(a1_width, b1_width);
@@ -472,7 +472,7 @@ struct ShareWorker
return true;
}
- if (c1->type == "$macc")
+ if (c1->type == ID($macc))
{
if (!config.opt_aggressive)
if (share_macc(c1, c2) > 2 * min(bits_macc(c1), bits_macc(c2))) return false;
@@ -510,27 +510,27 @@ struct ShareWorker
if (config.generic_uni_ops.count(c1->type))
{
- if (c1->parameters.at("\\A_SIGNED").as_bool() != c2->parameters.at("\\A_SIGNED").as_bool())
+ if (c1->parameters.at(ID(A_SIGNED)).as_bool() != c2->parameters.at(ID(A_SIGNED)).as_bool())
{
- RTLIL::Cell *unsigned_cell = c1->parameters.at("\\A_SIGNED").as_bool() ? c2 : c1;
- if (unsigned_cell->getPort("\\A").to_sigbit_vector().back() != RTLIL::State::S0) {
- unsigned_cell->parameters.at("\\A_WIDTH") = unsigned_cell->parameters.at("\\A_WIDTH").as_int() + 1;
- RTLIL::SigSpec new_a = unsigned_cell->getPort("\\A");
+ RTLIL::Cell *unsigned_cell = c1->parameters.at(ID(A_SIGNED)).as_bool() ? c2 : c1;
+ if (unsigned_cell->getPort(ID::A).to_sigbit_vector().back() != RTLIL::State::S0) {
+ unsigned_cell->parameters.at(ID(A_WIDTH)) = unsigned_cell->parameters.at(ID(A_WIDTH)).as_int() + 1;
+ RTLIL::SigSpec new_a = unsigned_cell->getPort(ID::A);
new_a.append_bit(RTLIL::State::S0);
- unsigned_cell->setPort("\\A", new_a);
+ unsigned_cell->setPort(ID::A, new_a);
}
- unsigned_cell->parameters.at("\\A_SIGNED") = true;
+ unsigned_cell->parameters.at(ID(A_SIGNED)) = true;
unsigned_cell->check();
}
- bool a_signed = c1->parameters.at("\\A_SIGNED").as_bool();
- log_assert(a_signed == c2->parameters.at("\\A_SIGNED").as_bool());
+ bool a_signed = c1->parameters.at(ID(A_SIGNED)).as_bool();
+ log_assert(a_signed == c2->parameters.at(ID(A_SIGNED)).as_bool());
- RTLIL::SigSpec a1 = c1->getPort("\\A");
- RTLIL::SigSpec y1 = c1->getPort("\\Y");
+ RTLIL::SigSpec a1 = c1->getPort(ID::A);
+ RTLIL::SigSpec y1 = c1->getPort(ID::Y);
- RTLIL::SigSpec a2 = c2->getPort("\\A");
- RTLIL::SigSpec y2 = c2->getPort("\\Y");
+ RTLIL::SigSpec a2 = c2->getPort(ID::A);
+ RTLIL::SigSpec y2 = c2->getPort(ID::Y);
int a_width = max(a1.size(), a2.size());
int y_width = max(y1.size(), y2.size());
@@ -544,11 +544,11 @@ struct ShareWorker
RTLIL::Wire *y = module->addWire(NEW_ID, y_width);
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
- supercell->parameters["\\A_SIGNED"] = a_signed;
- supercell->parameters["\\A_WIDTH"] = a_width;
- supercell->parameters["\\Y_WIDTH"] = y_width;
- supercell->setPort("\\A", a);
- supercell->setPort("\\Y", y);
+ supercell->parameters[ID(A_SIGNED)] = a_signed;
+ supercell->parameters[ID(A_WIDTH)] = a_width;
+ supercell->parameters[ID(Y_WIDTH)] = y_width;
+ supercell->setPort(ID::A, a);
+ supercell->setPort(ID::Y, y);
supercell_aux.insert(module->addPos(NEW_ID, y, y1));
supercell_aux.insert(module->addPos(NEW_ID, y, y2));
@@ -557,54 +557,54 @@ struct ShareWorker
return supercell;
}
- if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type) || c1->type == "$alu")
+ if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type) || c1->type == ID($alu))
{
bool modified_src_cells = false;
if (config.generic_cbin_ops.count(c1->type))
{
- 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_unflipped = max(c1->parameters.at(ID(A_WIDTH)).as_int(), c2->parameters.at(ID(A_WIDTH)).as_int()) +
+ max(c1->parameters.at(ID(B_WIDTH)).as_int(), c2->parameters.at(ID(B_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());
+ int score_flipped = max(c1->parameters.at(ID(A_WIDTH)).as_int(), c2->parameters.at(ID(B_WIDTH)).as_int()) +
+ max(c1->parameters.at(ID(B_WIDTH)).as_int(), c2->parameters.at(ID(A_WIDTH)).as_int());
if (score_flipped < score_unflipped)
{
- RTLIL::SigSpec tmp = c2->getPort("\\A");
- c2->setPort("\\A", c2->getPort("\\B"));
- c2->setPort("\\B", tmp);
+ RTLIL::SigSpec tmp = c2->getPort(ID::A);
+ c2->setPort(ID::A, c2->getPort(ID::B));
+ c2->setPort(ID::B, tmp);
- std::swap(c2->parameters.at("\\A_WIDTH"), c2->parameters.at("\\B_WIDTH"));
- std::swap(c2->parameters.at("\\A_SIGNED"), c2->parameters.at("\\B_SIGNED"));
+ std::swap(c2->parameters.at(ID(A_WIDTH)), c2->parameters.at(ID(B_WIDTH)));
+ std::swap(c2->parameters.at(ID(A_SIGNED)), c2->parameters.at(ID(B_SIGNED)));
modified_src_cells = true;
}
}
- if (c1->parameters.at("\\A_SIGNED").as_bool() != c2->parameters.at("\\A_SIGNED").as_bool())
+ if (c1->parameters.at(ID(A_SIGNED)).as_bool() != c2->parameters.at(ID(A_SIGNED)).as_bool())
{
- RTLIL::Cell *unsigned_cell = c1->parameters.at("\\A_SIGNED").as_bool() ? c2 : c1;
- if (unsigned_cell->getPort("\\A").to_sigbit_vector().back() != RTLIL::State::S0) {
- unsigned_cell->parameters.at("\\A_WIDTH") = unsigned_cell->parameters.at("\\A_WIDTH").as_int() + 1;
- RTLIL::SigSpec new_a = unsigned_cell->getPort("\\A");
+ RTLIL::Cell *unsigned_cell = c1->parameters.at(ID(A_SIGNED)).as_bool() ? c2 : c1;
+ if (unsigned_cell->getPort(ID::A).to_sigbit_vector().back() != RTLIL::State::S0) {
+ unsigned_cell->parameters.at(ID(A_WIDTH)) = unsigned_cell->parameters.at(ID(A_WIDTH)).as_int() + 1;
+ RTLIL::SigSpec new_a = unsigned_cell->getPort(ID::A);
new_a.append_bit(RTLIL::State::S0);
- unsigned_cell->setPort("\\A", new_a);
+ unsigned_cell->setPort(ID::A, new_a);
}
- unsigned_cell->parameters.at("\\A_SIGNED") = true;
+ unsigned_cell->parameters.at(ID(A_SIGNED)) = true;
modified_src_cells = true;
}
- if (c1->parameters.at("\\B_SIGNED").as_bool() != c2->parameters.at("\\B_SIGNED").as_bool())
+ if (c1->parameters.at(ID(B_SIGNED)).as_bool() != c2->parameters.at(ID(B_SIGNED)).as_bool())
{
- RTLIL::Cell *unsigned_cell = c1->parameters.at("\\B_SIGNED").as_bool() ? c2 : c1;
- if (unsigned_cell->getPort("\\B").to_sigbit_vector().back() != RTLIL::State::S0) {
- unsigned_cell->parameters.at("\\B_WIDTH") = unsigned_cell->parameters.at("\\B_WIDTH").as_int() + 1;
- RTLIL::SigSpec new_b = unsigned_cell->getPort("\\B");
+ RTLIL::Cell *unsigned_cell = c1->parameters.at(ID(B_SIGNED)).as_bool() ? c2 : c1;
+ if (unsigned_cell->getPort(ID::B).to_sigbit_vector().back() != RTLIL::State::S0) {
+ unsigned_cell->parameters.at(ID(B_WIDTH)) = unsigned_cell->parameters.at(ID(B_WIDTH)).as_int() + 1;
+ RTLIL::SigSpec new_b = unsigned_cell->getPort(ID::B);
new_b.append_bit(RTLIL::State::S0);
- unsigned_cell->setPort("\\B", new_b);
+ unsigned_cell->setPort(ID::B, new_b);
}
- unsigned_cell->parameters.at("\\B_SIGNED") = true;
+ unsigned_cell->parameters.at(ID(B_SIGNED)) = true;
modified_src_cells = true;
}
@@ -613,28 +613,28 @@ struct ShareWorker
c2->check();
}
- bool a_signed = c1->parameters.at("\\A_SIGNED").as_bool();
- bool b_signed = c1->parameters.at("\\B_SIGNED").as_bool();
+ bool a_signed = c1->parameters.at(ID(A_SIGNED)).as_bool();
+ bool b_signed = c1->parameters.at(ID(B_SIGNED)).as_bool();
- log_assert(a_signed == c2->parameters.at("\\A_SIGNED").as_bool());
- log_assert(b_signed == c2->parameters.at("\\B_SIGNED").as_bool());
+ log_assert(a_signed == c2->parameters.at(ID(A_SIGNED)).as_bool());
+ log_assert(b_signed == c2->parameters.at(ID(B_SIGNED)).as_bool());
- if (c1->type == "$shl" || c1->type == "$shr" || c1->type == "$sshl" || c1->type == "$sshr")
+ if (c1->type == ID($shl) || c1->type == ID($shr) || c1->type == ID($sshl) || c1->type == ID($sshr))
b_signed = false;
- RTLIL::SigSpec a1 = c1->getPort("\\A");
- RTLIL::SigSpec b1 = c1->getPort("\\B");
- RTLIL::SigSpec y1 = c1->getPort("\\Y");
+ RTLIL::SigSpec a1 = c1->getPort(ID::A);
+ RTLIL::SigSpec b1 = c1->getPort(ID::B);
+ RTLIL::SigSpec y1 = c1->getPort(ID::Y);
- RTLIL::SigSpec a2 = c2->getPort("\\A");
- RTLIL::SigSpec b2 = c2->getPort("\\B");
- RTLIL::SigSpec y2 = c2->getPort("\\Y");
+ RTLIL::SigSpec a2 = c2->getPort(ID::A);
+ RTLIL::SigSpec b2 = c2->getPort(ID::B);
+ RTLIL::SigSpec y2 = c2->getPort(ID::Y);
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)
+ if (c1->type == ID($shr) && a_signed)
{
a_width = max(y_width, a_width);
@@ -660,43 +660,43 @@ struct ShareWorker
supercell_aux.insert(module->addMux(NEW_ID, b2, b1, act, b));
RTLIL::Wire *y = module->addWire(NEW_ID, y_width);
- RTLIL::Wire *x = c1->type == "$alu" ? module->addWire(NEW_ID, y_width) : nullptr;
- RTLIL::Wire *co = c1->type == "$alu" ? module->addWire(NEW_ID, y_width) : nullptr;
+ RTLIL::Wire *x = c1->type == ID($alu) ? module->addWire(NEW_ID, y_width) : nullptr;
+ RTLIL::Wire *co = c1->type == ID($alu) ? module->addWire(NEW_ID, y_width) : nullptr;
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
- supercell->parameters["\\A_SIGNED"] = a_signed;
- supercell->parameters["\\B_SIGNED"] = b_signed;
- supercell->parameters["\\A_WIDTH"] = a_width;
- supercell->parameters["\\B_WIDTH"] = b_width;
- supercell->parameters["\\Y_WIDTH"] = y_width;
- supercell->setPort("\\A", a);
- supercell->setPort("\\B", b);
- supercell->setPort("\\Y", y);
- if (c1->type == "$alu") {
+ supercell->parameters[ID(A_SIGNED)] = a_signed;
+ supercell->parameters[ID(B_SIGNED)] = b_signed;
+ supercell->parameters[ID(A_WIDTH)] = a_width;
+ supercell->parameters[ID(B_WIDTH)] = b_width;
+ supercell->parameters[ID(Y_WIDTH)] = y_width;
+ supercell->setPort(ID::A, a);
+ supercell->setPort(ID::B, b);
+ supercell->setPort(ID::Y, y);
+ if (c1->type == ID($alu)) {
RTLIL::Wire *ci = module->addWire(NEW_ID), *bi = module->addWire(NEW_ID);
- supercell_aux.insert(module->addMux(NEW_ID, c2->getPort("\\CI"), c1->getPort("\\CI"), act, ci));
- supercell_aux.insert(module->addMux(NEW_ID, c2->getPort("\\BI"), c1->getPort("\\BI"), act, bi));
- supercell->setPort("\\CI", ci);
- supercell->setPort("\\BI", bi);
- supercell->setPort("\\CO", co);
- supercell->setPort("\\X", x);
+ supercell_aux.insert(module->addMux(NEW_ID, c2->getPort(ID(CI)), c1->getPort(ID(CI)), act, ci));
+ supercell_aux.insert(module->addMux(NEW_ID, c2->getPort(ID(BI)), c1->getPort(ID(BI)), act, bi));
+ supercell->setPort(ID(CI), ci);
+ supercell->setPort(ID(BI), bi);
+ supercell->setPort(ID(CO), co);
+ supercell->setPort(ID(X), x);
}
supercell->check();
supercell_aux.insert(module->addPos(NEW_ID, y, y1));
supercell_aux.insert(module->addPos(NEW_ID, y, y2));
- if (c1->type == "$alu") {
- supercell_aux.insert(module->addPos(NEW_ID, co, c1->getPort("\\CO")));
- supercell_aux.insert(module->addPos(NEW_ID, co, c2->getPort("\\CO")));
- supercell_aux.insert(module->addPos(NEW_ID, x, c1->getPort("\\X")));
- supercell_aux.insert(module->addPos(NEW_ID, x, c2->getPort("\\X")));
+ if (c1->type == ID($alu)) {
+ supercell_aux.insert(module->addPos(NEW_ID, co, c1->getPort(ID(CO))));
+ supercell_aux.insert(module->addPos(NEW_ID, co, c2->getPort(ID(CO))));
+ supercell_aux.insert(module->addPos(NEW_ID, x, c1->getPort(ID(X))));
+ supercell_aux.insert(module->addPos(NEW_ID, x, c2->getPort(ID(X))));
}
supercell_aux.insert(supercell);
return supercell;
}
- if (c1->type == "$macc")
+ if (c1->type == ID($macc))
{
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
supercell_aux.insert(supercell);
@@ -705,18 +705,18 @@ struct ShareWorker
return supercell;
}
- if (c1->type == "$memrd")
+ if (c1->type == ID($memrd))
{
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1);
- RTLIL::SigSpec addr1 = c1->getPort("\\ADDR");
- RTLIL::SigSpec addr2 = c2->getPort("\\ADDR");
+ RTLIL::SigSpec addr1 = c1->getPort(ID(ADDR));
+ RTLIL::SigSpec addr2 = c2->getPort(ID(ADDR));
if (GetSize(addr1) < GetSize(addr2))
addr1.extend_u0(GetSize(addr2));
else
addr2.extend_u0(GetSize(addr1));
- supercell->setPort("\\ADDR", addr1 != addr2 ? module->Mux(NEW_ID, addr2, addr1, act) : addr1);
- supercell->parameters["\\ABITS"] = RTLIL::Const(GetSize(addr1));
- supercell_aux.insert(module->addPos(NEW_ID, supercell->getPort("\\DATA"), c2->getPort("\\DATA")));
+ supercell->setPort(ID(ADDR), addr1 != addr2 ? module->Mux(NEW_ID, addr2, addr1, act) : addr1);
+ supercell->parameters[ID(ABITS)] = RTLIL::Const(GetSize(addr1));
+ supercell_aux.insert(module->addPos(NEW_ID, supercell->getPort(ID(DATA)), c2->getPort(ID(DATA))));
supercell_aux.insert(supercell);
return supercell;
}
@@ -747,8 +747,8 @@ struct ShareWorker
modwalker.get_consumers(pbits, modwalker.cell_outputs[cell]);
for (auto &bit : pbits) {
- if ((bit.cell->type == "$mux" || bit.cell->type == "$pmux") && bit.port == "\\S")
- forbidden_controls_cache[cell].insert(bit.cell->getPort("\\S").extract(bit.offset, 1));
+ if ((bit.cell->type == ID($mux) || bit.cell->type == ID($pmux)) && bit.port == ID(S))
+ forbidden_controls_cache[cell].insert(bit.cell->getPort(ID(S)).extract(bit.offset, 1));
consumer_cells.insert(bit.cell);
}
@@ -874,7 +874,7 @@ struct ShareWorker
}
for (auto &pbit : modwalker.signal_consumers[bit]) {
log_assert(fwd_ct.cell_known(pbit.cell->type));
- if ((pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") && (pbit.port == "\\A" || pbit.port == "\\B"))
+ if ((pbit.cell->type == ID($mux) || pbit.cell->type == ID($pmux)) && (pbit.port == ID::A || pbit.port == ID::B))
driven_data_muxes.insert(pbit.cell);
else
driven_cells.insert(pbit.cell);
@@ -890,10 +890,10 @@ struct ShareWorker
bool used_in_a = false;
std::set<int> used_in_b_parts;
- int width = c->parameters.at("\\WIDTH").as_int();
- std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->getPort("\\A"));
- std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->getPort("\\B"));
- std::vector<RTLIL::SigBit> sig_s = modwalker.sigmap(c->getPort("\\S"));
+ int width = c->parameters.at(ID(WIDTH)).as_int();
+ std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->getPort(ID::A));
+ std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->getPort(ID::B));
+ std::vector<RTLIL::SigBit> sig_s = modwalker.sigmap(c->getPort(ID(S)));
for (auto &bit : sig_a)
if (cell_out_bits.count(bit))
@@ -1132,14 +1132,14 @@ struct ShareWorker
fwd_ct.setup_internals();
cone_ct.setup_internals();
- cone_ct.cell_types.erase("$mul");
- cone_ct.cell_types.erase("$mod");
- cone_ct.cell_types.erase("$div");
- cone_ct.cell_types.erase("$pow");
- cone_ct.cell_types.erase("$shl");
- cone_ct.cell_types.erase("$shr");
- cone_ct.cell_types.erase("$sshl");
- cone_ct.cell_types.erase("$sshr");
+ cone_ct.cell_types.erase(ID($mul));
+ cone_ct.cell_types.erase(ID($mod));
+ cone_ct.cell_types.erase(ID($div));
+ cone_ct.cell_types.erase(ID($pow));
+ cone_ct.cell_types.erase(ID($shl));
+ cone_ct.cell_types.erase(ID($shr));
+ cone_ct.cell_types.erase(ID($sshl));
+ cone_ct.cell_types.erase(ID($sshr));
modwalker.setup(design, module);
@@ -1153,9 +1153,9 @@ struct ShareWorker
GetSize(shareable_cells), log_id(module));
for (auto cell : module->cells())
- if (cell->type == "$pmux")
- for (auto bit : cell->getPort("\\S"))
- for (auto other_bit : cell->getPort("\\S"))
+ if (cell->type == ID($pmux))
+ for (auto bit : cell->getPort(ID(S)))
+ for (auto other_bit : cell->getPort(ID(S)))
if (bit < other_bit)
exclusive_ctrls.push_back(std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit, other_bit));
@@ -1466,43 +1466,43 @@ struct SharePass : public Pass {
config.opt_aggressive = false;
config.opt_fast = false;
- config.generic_uni_ops.insert("$not");
- // config.generic_uni_ops.insert("$pos");
- config.generic_uni_ops.insert("$neg");
-
- config.generic_cbin_ops.insert("$and");
- config.generic_cbin_ops.insert("$or");
- config.generic_cbin_ops.insert("$xor");
- config.generic_cbin_ops.insert("$xnor");
-
- config.generic_bin_ops.insert("$shl");
- config.generic_bin_ops.insert("$shr");
- config.generic_bin_ops.insert("$sshl");
- config.generic_bin_ops.insert("$sshr");
-
- config.generic_bin_ops.insert("$lt");
- config.generic_bin_ops.insert("$le");
- config.generic_bin_ops.insert("$eq");
- config.generic_bin_ops.insert("$ne");
- config.generic_bin_ops.insert("$eqx");
- config.generic_bin_ops.insert("$nex");
- config.generic_bin_ops.insert("$ge");
- config.generic_bin_ops.insert("$gt");
-
- config.generic_cbin_ops.insert("$add");
- config.generic_cbin_ops.insert("$mul");
-
- config.generic_bin_ops.insert("$sub");
- config.generic_bin_ops.insert("$div");
- config.generic_bin_ops.insert("$mod");
- // config.generic_bin_ops.insert("$pow");
-
- config.generic_uni_ops.insert("$logic_not");
- config.generic_cbin_ops.insert("$logic_and");
- config.generic_cbin_ops.insert("$logic_or");
-
- config.generic_other_ops.insert("$alu");
- config.generic_other_ops.insert("$macc");
+ config.generic_uni_ops.insert(ID($not));
+ // config.generic_uni_ops.insert(ID($pos));
+ config.generic_uni_ops.insert(ID($neg));
+
+ config.generic_cbin_ops.insert(ID($and));
+ config.generic_cbin_ops.insert(ID($or));
+ config.generic_cbin_ops.insert(ID($xor));
+ config.generic_cbin_ops.insert(ID($xnor));
+
+ config.generic_bin_ops.insert(ID($shl));
+ config.generic_bin_ops.insert(ID($shr));
+ config.generic_bin_ops.insert(ID($sshl));
+ config.generic_bin_ops.insert(ID($sshr));
+
+ config.generic_bin_ops.insert(ID($lt));
+ config.generic_bin_ops.insert(ID($le));
+ config.generic_bin_ops.insert(ID($eq));
+ config.generic_bin_ops.insert(ID($ne));
+ config.generic_bin_ops.insert(ID($eqx));
+ config.generic_bin_ops.insert(ID($nex));
+ config.generic_bin_ops.insert(ID($ge));
+ config.generic_bin_ops.insert(ID($gt));
+
+ config.generic_cbin_ops.insert(ID($add));
+ config.generic_cbin_ops.insert(ID($mul));
+
+ config.generic_bin_ops.insert(ID($sub));
+ config.generic_bin_ops.insert(ID($div));
+ config.generic_bin_ops.insert(ID($mod));
+ // config.generic_bin_ops.insert(ID($pow));
+
+ config.generic_uni_ops.insert(ID($logic_not));
+ config.generic_cbin_ops.insert(ID($logic_and));
+ config.generic_cbin_ops.insert(ID($logic_or));
+
+ config.generic_other_ops.insert(ID($alu));
+ config.generic_other_ops.insert(ID($macc));
log_header(design, "Executing SHARE pass (SAT-based resource sharing).\n");
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 1fbc41082..c02c355cb 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -22,7 +22,6 @@
#include "kernel/modtools.h"
USING_YOSYS_NAMESPACE
-using namespace RTLIL;
PRIVATE_NAMESPACE_BEGIN
@@ -34,13 +33,13 @@ struct WreduceConfig
WreduceConfig()
{
supported_cell_types = pool<IdString>({
- "$not", "$pos", "$neg",
- "$and", "$or", "$xor", "$xnor",
- "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
- "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
- "$add", "$sub", "$mul", // "$div", "$mod", "$pow",
- "$mux", "$pmux",
- "$dff", "$adff"
+ ID($not), ID($pos), ID($neg),
+ ID($and), ID($or), ID($xor), ID($xnor),
+ ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
+ ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
+ ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($pow),
+ ID($mux), ID($pmux),
+ ID($dff), ID($adff)
});
}
};
@@ -64,10 +63,10 @@ struct WreduceWorker
{
// Reduce size of MUX if inputs agree on a value for a bit or a output bit is unused
- SigSpec sig_a = mi.sigmap(cell->getPort("\\A"));
- SigSpec sig_b = mi.sigmap(cell->getPort("\\B"));
- SigSpec sig_s = mi.sigmap(cell->getPort("\\S"));
- SigSpec sig_y = mi.sigmap(cell->getPort("\\Y"));
+ SigSpec sig_a = mi.sigmap(cell->getPort(ID::A));
+ SigSpec sig_b = mi.sigmap(cell->getPort(ID::B));
+ SigSpec sig_s = mi.sigmap(cell->getPort(ID(S)));
+ SigSpec sig_y = mi.sigmap(cell->getPort(ID::Y));
std::vector<SigBit> bits_removed;
if (sig_y.has_const())
@@ -77,15 +76,15 @@ struct WreduceWorker
{
auto info = mi.query(sig_y[i]);
if (!info->is_output && GetSize(info->ports) <= 1 && !keep_bits.count(mi.sigmap(sig_y[i]))) {
- bits_removed.push_back(Sx);
+ bits_removed.push_back(State::Sx);
continue;
}
SigBit ref = sig_a[i];
for (int k = 0; k < GetSize(sig_s); k++) {
- if ((config->keepdc || (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx)) && ref != sig_b[k*GetSize(sig_a) + i])
+ if ((config->keepdc || (ref != State::Sx && sig_b[k*GetSize(sig_a) + i] != State::Sx)) && ref != sig_b[k*GetSize(sig_a) + i])
goto no_match_ab;
- if (sig_b[k*GetSize(sig_a) + i] != Sx)
+ if (sig_b[k*GetSize(sig_a) + i] != State::Sx)
ref = sig_b[k*GetSize(sig_a) + i];
}
if (0)
@@ -130,9 +129,9 @@ struct WreduceWorker
for (auto bit : new_work_queue_bits)
work_queue_bits.insert(bit);
- cell->setPort("\\A", new_sig_a);
- cell->setPort("\\B", new_sig_b);
- cell->setPort("\\Y", new_sig_y);
+ cell->setPort(ID::A, new_sig_a);
+ cell->setPort(ID::B, new_sig_b);
+ cell->setPort(ID::Y, new_sig_y);
cell->fixup_parameters();
module->connect(sig_y.extract(n_kept, n_removed), sig_removed);
@@ -142,8 +141,8 @@ struct WreduceWorker
{
// Reduce size of FF if inputs are just sign/zero extended or output bit is not used
- SigSpec sig_d = mi.sigmap(cell->getPort("\\D"));
- SigSpec sig_q = mi.sigmap(cell->getPort("\\Q"));
+ SigSpec sig_d = mi.sigmap(cell->getPort(ID(D)));
+ SigSpec sig_q = mi.sigmap(cell->getPort(ID(Q)));
Const initval;
int width_before = GetSize(sig_q);
@@ -214,14 +213,14 @@ struct WreduceWorker
work_queue_bits.insert(bit);
// Narrow ARST_VALUE parameter to new size.
- if (cell->parameters.count("\\ARST_VALUE")) {
- Const arst_value = cell->getParam("\\ARST_VALUE");
+ if (cell->parameters.count(ID(ARST_VALUE))) {
+ Const arst_value = cell->getParam(ID(ARST_VALUE));
arst_value.bits.resize(GetSize(sig_q));
- cell->setParam("\\ARST_VALUE", arst_value);
+ cell->setParam(ID(ARST_VALUE), arst_value);
}
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", sig_q);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), sig_q);
cell->fixup_parameters();
}
@@ -230,7 +229,7 @@ struct WreduceWorker
port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool();
SigSpec sig = mi.sigmap(cell->getPort(stringf("\\%c", port)));
- if (port == 'B' && cell->type.in("$shl", "$shr", "$sshl", "$sshr"))
+ if (port == 'B' && cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr)))
port_signed = false;
int bits_removed = 0;
@@ -245,7 +244,7 @@ struct WreduceWorker
while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == sig[GetSize(sig)-2])
work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
} else {
- while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == S0)
+ while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == State::S0)
work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
}
@@ -264,13 +263,13 @@ struct WreduceWorker
if (!cell->type.in(config->supported_cell_types))
return;
- if (cell->type.in("$mux", "$pmux"))
+ if (cell->type.in(ID($mux), ID($pmux)))
return run_cell_mux(cell);
- if (cell->type.in("$dff", "$adff"))
+ if (cell->type.in(ID($dff), ID($adff)))
return run_cell_dff(cell);
- SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
+ SigSpec sig = mi.sigmap(cell->getPort(ID::Y));
if (sig.has_const())
return;
@@ -278,10 +277,10 @@ struct WreduceWorker
// Reduce size of ports A and B based on constant input bits and size of output port
- int max_port_a_size = cell->hasPort("\\A") ? GetSize(cell->getPort("\\A")) : -1;
- int max_port_b_size = cell->hasPort("\\B") ? GetSize(cell->getPort("\\B")) : -1;
+ int max_port_a_size = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : -1;
+ int max_port_b_size = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : -1;
- if (cell->type.in("$not", "$pos", "$neg", "$and", "$or", "$xor", "$add", "$sub")) {
+ if (cell->type.in(ID($not), ID($pos), ID($neg), ID($and), ID($or), ID($xor), ID($add), ID($sub))) {
max_port_a_size = min(max_port_a_size, GetSize(sig));
max_port_b_size = min(max_port_b_size, GetSize(sig));
}
@@ -289,32 +288,32 @@ struct WreduceWorker
bool port_a_signed = false;
bool port_b_signed = false;
- if (max_port_a_size >= 0 && cell->type != "$shiftx")
+ if (max_port_a_size >= 0 && cell->type != ID($shiftx))
run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something);
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 (cell->hasPort(ID::A) && cell->hasPort(ID::B) && port_a_signed && port_b_signed) {
+ SigSpec sig_a = mi.sigmap(cell->getPort(ID::A)), sig_b = mi.sigmap(cell->getPort(ID::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);
+ cell->setParam(ID(A_SIGNED), 0);
+ cell->setParam(ID(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 (cell->hasPort(ID::A) && !cell->hasPort(ID::B) && port_a_signed) {
+ SigSpec sig_a = mi.sigmap(cell->getPort(ID::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);
+ cell->setParam(ID(A_SIGNED), 0);
port_a_signed = false;
did_something = true;
}
@@ -324,7 +323,7 @@ struct WreduceWorker
// 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") {
+ if (port_a_signed && cell->type == ID($shr)) {
// do not reduce size of output on $shr cells with signed A inputs
} else {
while (GetSize(sig) > 0)
@@ -342,24 +341,24 @@ struct WreduceWorker
}
}
- if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor"))
+ if (cell->type.in(ID($pos), ID($add), ID($mul), ID($and), ID($or), ID($xor), ID($sub)))
{
- bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool() || cell->type == ID($sub);
int a_size = 0, b_size = 0;
- if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A"));
- if (cell->hasPort("\\B")) b_size = GetSize(cell->getPort("\\B"));
+ if (cell->hasPort(ID::A)) a_size = GetSize(cell->getPort(ID::A));
+ if (cell->hasPort(ID::B)) b_size = GetSize(cell->getPort(ID::B));
int max_y_size = max(a_size, b_size);
- if (cell->type == "$add")
+ if (cell->type.in(ID($add), ID($sub)))
max_y_size++;
- if (cell->type == "$mul")
+ if (cell->type == ID($mul))
max_y_size = a_size + b_size;
while (GetSize(sig) > 1 && GetSize(sig) > max_y_size) {
- module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : S0);
+ module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : State::S0);
sig.remove(GetSize(sig)-1);
bits_removed++;
}
@@ -374,7 +373,7 @@ struct WreduceWorker
if (bits_removed) {
log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n",
bits_removed, GetSize(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
- cell->setPort("\\Y", sig);
+ cell->setPort(ID::Y, sig);
did_something = true;
}
@@ -387,8 +386,8 @@ struct WreduceWorker
static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
{
int count = w->attributes.size();
- count -= w->attributes.count("\\src");
- count -= w->attributes.count("\\unused_bits");
+ count -= w->attributes.count(ID(src));
+ count -= w->attributes.count(ID(unused_bits));
return count;
}
@@ -398,11 +397,11 @@ struct WreduceWorker
SigMap init_attr_sigmap = mi.sigmap;
for (auto w : module->wires()) {
- if (w->get_bool_attribute("\\keep"))
+ if (w->get_bool_attribute(ID::keep))
for (auto bit : mi.sigmap(w))
keep_bits.insert(bit);
- if (w->attributes.count("\\init")) {
- Const initval = w->attributes.at("\\init");
+ if (w->attributes.count(ID(init))) {
+ Const initval = w->attributes.at(ID(init));
SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++)
@@ -459,8 +458,8 @@ struct WreduceWorker
if (!remove_init_bits.empty()) {
for (auto w : module->wires()) {
- if (w->attributes.count("\\init")) {
- Const initval = w->attributes.at("\\init");
+ if (w->attributes.count(ID(init))) {
+ Const initval = w->attributes.at(ID(init));
Const new_initval(State::Sx, GetSize(w));
SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig));
@@ -468,7 +467,7 @@ struct WreduceWorker
if (!remove_init_bits.count(initsig[i]))
new_initval[i] = initval[i];
}
- w->attributes.at("\\init") = new_initval;
+ w->attributes.at(ID(init)) = new_initval;
}
}
}
@@ -528,23 +527,23 @@ struct WreducePass : public Pass {
for (auto c : module->selected_cells())
{
- if (c->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
- "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
- "$logic_not", "$logic_and", "$logic_or") && GetSize(c->getPort("\\Y")) > 1) {
- SigSpec sig = c->getPort("\\Y");
+ if (c->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool),
+ ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
+ ID($logic_not), ID($logic_and), ID($logic_or)) && GetSize(c->getPort(ID::Y)) > 1) {
+ SigSpec sig = c->getPort(ID::Y);
if (!sig.has_const()) {
- c->setPort("\\Y", sig[0]);
- c->setParam("\\Y_WIDTH", 1);
+ c->setPort(ID::Y, sig[0]);
+ c->setParam(ID(Y_WIDTH), 1);
sig.remove(0);
module->connect(sig, Const(0, GetSize(sig)));
}
}
- if (c->type.in("$div", "$mod", "$pow"))
+ if (c->type.in(ID($div), ID($mod), ID($pow)))
{
- SigSpec A = c->getPort("\\A");
+ SigSpec A = c->getPort(ID::A);
int original_a_width = GetSize(A);
- if (c->getParam("\\A_SIGNED").as_bool()) {
+ if (c->getParam(ID(A_SIGNED)).as_bool()) {
while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0)
A.remove(GetSize(A)-1, 1);
} else {
@@ -554,13 +553,13 @@ struct WreducePass : public Pass {
if (original_a_width != GetSize(A)) {
log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n",
original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type));
- c->setPort("\\A", A);
- c->setParam("\\A_WIDTH", GetSize(A));
+ c->setPort(ID::A, A);
+ c->setParam(ID(A_WIDTH), GetSize(A));
}
- SigSpec B = c->getPort("\\B");
+ SigSpec B = c->getPort(ID::B);
int original_b_width = GetSize(B);
- if (c->getParam("\\B_SIGNED").as_bool()) {
+ if (c->getParam(ID(B_SIGNED)).as_bool()) {
while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0)
B.remove(GetSize(B)-1, 1);
} else {
@@ -570,24 +569,24 @@ struct WreducePass : public Pass {
if (original_b_width != GetSize(B)) {
log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n",
original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type));
- c->setPort("\\B", B);
- c->setParam("\\B_WIDTH", GetSize(B));
+ c->setPort(ID::B, B);
+ c->setParam(ID(B_WIDTH), GetSize(B));
}
}
- if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) {
- IdString memid = c->getParam("\\MEMID").decode_string();
+ if (!opt_memx && c->type.in(ID($memrd), ID($memwr), ID($meminit))) {
+ IdString memid = c->getParam(ID(MEMID)).decode_string();
RTLIL::Memory *mem = module->memories.at(memid);
if (mem->start_offset >= 0) {
- int cur_addrbits = c->getParam("\\ABITS").as_int();
+ int cur_addrbits = c->getParam(ID(ABITS)).as_int();
int max_addrbits = ceil_log2(mem->start_offset + mem->size);
if (cur_addrbits > max_addrbits) {
log("Removed top %d address bits (of %d) from memory %s port %s.%s (%s).\n",
cur_addrbits-max_addrbits, cur_addrbits,
- c->type == "$memrd" ? "read" : c->type == "$memwr" ? "write" : "init",
+ c->type == ID($memrd) ? "read" : c->type == ID($memwr) ? "write" : "init",
log_id(module), log_id(c), log_id(memid));
- c->setParam("\\ABITS", max_addrbits);
- c->setPort("\\ADDR", c->getPort("\\ADDR").extract(0, max_addrbits));
+ c->setParam(ID(ABITS), max_addrbits);
+ c->setPort(ID(ADDR), c->getPort(ID(ADDR)).extract(0, max_addrbits));
}
}
}
diff --git a/passes/pmgen/.gitignore b/passes/pmgen/.gitignore
index 0ad36ea2c..6b319b8c3 100644
--- a/passes/pmgen/.gitignore
+++ b/passes/pmgen/.gitignore
@@ -1,2 +1 @@
-/ice40_dsp_pm.h
-/peepopt_pm.h
+/*_pm.h \ No newline at end of file
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
index 7911132db..8e0cbdca8 100644
--- a/passes/pmgen/Makefile.inc
+++ b/passes/pmgen/Makefile.inc
@@ -1,20 +1,29 @@
-OBJS += passes/pmgen/ice40_dsp.o
-OBJS += passes/pmgen/peepopt.o
+%_pm.h: passes/pmgen/pmgen.py %.pmg
+ $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p $(subst _pm.h,,$(notdir $@)) $(filter-out $<,$^)
+
+# --------------------------------------
+
+OBJS += passes/pmgen/test_pmgen.o
+passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h
+$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h))
# --------------------------------------
+OBJS += passes/pmgen/ice40_dsp.o
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
-EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h
-.SECONDARY: passes/pmgen/ice40_dsp_pm.h
+$(eval $(call add_extra_objs,passes/pmgen/ice40_dsp_pm.h))
+
+# --------------------------------------
-passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
- $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^)
+OBJS += passes/pmgen/ice40_wrapcarry.o
+passes/pmgen/ice40_wrapcarry.o: passes/pmgen/ice40_wrapcarry_pm.h
+$(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
# --------------------------------------
+OBJS += passes/pmgen/peepopt.o
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
-EXTRA_OBJS += passes/pmgen/peepopt_pm.h
-.SECONDARY: passes/pmgen/peepopt_pm.h
+$(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h))
PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md
index 2f0b1fd5a..0856c9ba3 100644
--- a/passes/pmgen/README.md
+++ b/passes/pmgen/README.md
@@ -45,9 +45,9 @@ of type `foobar_pm::state_<pattern_name>_t`.)
Similarly the `.pmg` file declares user data variables that become members of
`.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`.
-There are four versions of the `run_<pattern_name>()` method: Without callback,
-callback without arguments, callback with reference to `pm`, and callback with
-reference to `pm.st_<pattern_name>`.
+There are three versions of the `run_<pattern_name>()` method: Without callback,
+callback without arguments, and callback with reference to `pm`. All versions
+of the `run_<pattern_name>()` method return the number of found matches.
The .pmg File Format
@@ -118,8 +118,8 @@ write matchers:
connected to any of the given signal bits, plus one if any of the signal
bits is also a primary input or primary output.
-- In `code..endcode` blocks there exist `accept`, `reject`, and `branch`
- statements.
+- In `code..endcode` blocks there exist `accept`, `reject`, `branch`,
+ `finish`, and `subpattern` statements.
- In `index` statements there is a special `===` operator for the index
lookup.
@@ -175,6 +175,48 @@ explore the case where `mul` is set to `nullptr`. Without the `optional`
statement a match may only be assigned nullptr when one of the `if` expressions
evaluates to `false`.
+The `semioptional` statement marks matches that must match if at least one
+matching cell exists, but if no matching cell exists it is set to `nullptr`.
+
+Slices and choices
+------------------
+
+Cell matches can contain "slices" and "choices". Slices can be used to
+create matches for different sections of a cell. For example:
+
+ state <int> pmux_slice
+
+ match pmux
+ select pmux->type == $pmux
+ slice idx GetSize(port(pmux, \S))
+ index <SigBit> port(pmux, \S)[idx] === port(eq, \Y)
+ set pmux_slice idx
+ endmatch
+
+The first argument to `slice` is the local variable name used to identify the
+slice. The second argument is the number of slices that should be created for
+this cell. The `set` statement can be used to copy that index into a state
+variable so that later matches and/or code blocks can refer to it.
+
+A similar mechanism is "choices", where a list of options is given as
+second argument, and the matcher will iterate over those options:
+
+ state <SigSpec> foo bar
+ state <IdString> eq_ab eq_ba
+
+ match eq
+ select eq->type == $eq
+ choice <IdString> AB {\A, \B}
+ define <IdString> BA (AB == \A ? \B : \A)
+ index <SigSpec> port(eq, AB) === foo
+ index <SigSpec> port(eq, BA) === bar
+ set eq_ab AB
+ set eq_ba BA
+ generate
+
+Notice how `define` can be used to define additional local variables similar
+to the loop variables defined by `slice` and `choice`.
+
Additional code
---------------
@@ -232,5 +274,111 @@ But in some cases it is more natural to utilize the implicit branch statement:
portAB = \B;
endcode
-There is an implicit `code..endcode` block at the end of each `.pmg` file
-that just accepts everything that gets all the way there.
+There is an implicit `code..endcode` block at the end of each (sub)pattern
+that just rejects.
+
+A `code..finally..endcode` block executes the code after `finally` during
+back-tracking. This is useful for maintaining user data state or printing
+debug messages. For example:
+
+ udata <vector<Cell*>> stack
+
+ code
+ stack.push_back(addAB);
+ ...
+ finally
+ stack.pop_back();
+ endcode
+
+`accept` and `finish` statements can be used inside the `finally` section,
+but not `reject`, `branch`, or `subpattern`.
+
+Declaring a subpattern
+----------------------
+
+A subpattern starts with a line containing the `subpattern` keyword followed
+by the name of the subpattern. Subpatterns can be called from a `code` block
+using a `subpattern(<subpattern_name>);` C statement.
+
+Arguments may be passed to subpattern via state variables. The `subpattern`
+line must be followed by a `arg <arg1> <arg2> ...` line that lists the
+state variables used to pass arguments.
+
+ state <IdString> foobar_type
+ state <bool> foobar_state
+
+ code foobar_type foobar_state
+ foobar_state = false;
+ foobar_type = $add;
+ subpattern(foo);
+ foobar_type = $sub;
+ subpattern(bar);
+ endcode
+
+ subpattern foo
+ arg foobar_type foobar_state
+
+ match addsub
+ index <IdString> addsub->type === foobar_type
+ ...
+ endmatch
+
+ code
+ if (foobar_state) {
+ subpattern(tail);
+ } else {
+ foobar_state = true;
+ subpattern(bar);
+ }
+ endcode
+
+ subpattern bar
+ arg foobar_type foobar_state
+
+ match addsub
+ index <IdString> addsub->type === foobar_type
+ ...
+ endmatch
+
+ code
+ if (foobar_state) {
+ subpattern(tail);
+ } else {
+ foobar_state = true;
+ subpattern(foo);
+ }
+ endcode
+
+ subpattern tail
+ ...
+
+Subpatterns cann be called recursively.
+
+If a `subpattern` statement is preceded by a `fallthrough` statement, this is
+equivalent to calling the subpattern at the end of the preceding block.
+
+Generate Blocks
+---------------
+
+Match blocks may contain an optional `generate` section that is used for automatic
+test-case generation. For example:
+
+ match mul
+ ...
+ generate 10 0
+ SigSpec Y = port(ff, \D);
+ SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
+ SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
+ module->addMul(NEW_ID, A, B, Y, rng(2));
+ endmatch
+
+The expression `rng(n)` returns a non-negative integer less than `n`.
+
+The first argument to `generate` is the chance of this generate block being
+executed when the match block did not match anything, in percent.
+
+The second argument to `generate` is the chance of this generate block being
+executed when the match block did match something, in percent.
+
+The special statement `finish` can be used within generate blocks to terminate
+the current pattern matcher run.
diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg
index 1f3590d4e..7003092bb 100644
--- a/passes/pmgen/ice40_dsp.pmg
+++ b/passes/pmgen/ice40_dsp.pmg
@@ -159,4 +159,5 @@ code clock clock_pol clock_vld
clock_pol = cp;
clock_vld = true;
}
+ accept;
endcode
diff --git a/passes/pmgen/ice40_wrapcarry.cc b/passes/pmgen/ice40_wrapcarry.cc
new file mode 100644
index 000000000..69ef3cd82
--- /dev/null
+++ b/passes/pmgen/ice40_wrapcarry.cc
@@ -0,0 +1,90 @@
+/*
+ * 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
+
+#include "passes/pmgen/ice40_wrapcarry_pm.h"
+
+void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm)
+{
+ auto &st = pm.st_ice40_wrapcarry;
+
+#if 0
+ log("\n");
+ log("carry: %s\n", log_id(st.carry, "--"));
+ log("lut: %s\n", log_id(st.lut, "--"));
+#endif
+
+ log(" replacing SB_LUT + SB_CARRY with $__ICE40_CARRY_WRAPPER cell.\n");
+
+ Cell *cell = pm.module->addCell(NEW_ID, "$__ICE40_CARRY_WRAPPER");
+ pm.module->swap_names(cell, st.carry);
+
+ cell->setPort("\\A", st.carry->getPort("\\I0"));
+ cell->setPort("\\B", st.carry->getPort("\\I1"));
+ cell->setPort("\\CI", st.carry->getPort("\\CI"));
+ cell->setPort("\\CO", st.carry->getPort("\\CO"));
+
+ cell->setPort("\\I0", st.lut->getPort("\\I0"));
+ cell->setPort("\\I3", st.lut->getPort("\\I3"));
+ cell->setPort("\\O", st.lut->getPort("\\O"));
+ cell->setParam("\\LUT", st.lut->getParam("\\LUT_INIT"));
+
+ pm.autoremove(st.carry);
+ pm.autoremove(st.lut);
+}
+
+struct Ice40WrapCarryPass : public Pass {
+ Ice40WrapCarryPass() : Pass("ice40_wrapcarry", "iCE40: wrap carries") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ice40_wrapcarry [selection]\n");
+ log("\n");
+ log("Wrap manually instantiated SB_CARRY cells, along with their associated SB_LUTs,\n");
+ log("into an internal $__ICE40_CARRY_WRAPPER cell for preservation across technology\n");
+ log("mapping.");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing ICE40_WRAPCARRY pass (wrap carries).\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())
+ ice40_wrapcarry_pm(module, module->selected_cells()).run_ice40_wrapcarry(create_ice40_wrapcarry);
+ }
+} Ice40WrapCarryPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/ice40_wrapcarry.pmg b/passes/pmgen/ice40_wrapcarry.pmg
new file mode 100644
index 000000000..9e64c7467
--- /dev/null
+++ b/passes/pmgen/ice40_wrapcarry.pmg
@@ -0,0 +1,11 @@
+pattern ice40_wrapcarry
+
+match carry
+ select carry->type.in(\SB_CARRY)
+endmatch
+
+match lut
+ select lut->type.in(\SB_LUT4)
+ index <SigSpec> port(lut, \I1) === port(carry, \I0)
+ index <SigSpec> port(lut, \I2) === port(carry, \I1)
+endmatch
diff --git a/passes/pmgen/peepopt_muldiv.pmg b/passes/pmgen/peepopt_muldiv.pmg
index 06c275834..7cad759d0 100644
--- a/passes/pmgen/peepopt_muldiv.pmg
+++ b/passes/pmgen/peepopt_muldiv.pmg
@@ -32,5 +32,5 @@ code
log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div));
module->connect(div_y, val_y);
autoremove(div);
- reject;
+ accept;
endcode
diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg
index 6adab4e5f..d4748ae19 100644
--- a/passes/pmgen/peepopt_shiftmul.pmg
+++ b/passes/pmgen/peepopt_shiftmul.pmg
@@ -34,6 +34,7 @@ match mul
endmatch
code
+{
IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B;
IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED;
Const const_factor_cnst = port(mul, const_factor_port).as_const();
@@ -90,5 +91,6 @@ code
shift->setParam(\B_WIDTH, GetSize(new_b));
blacklist(shift);
- reject;
+ accept;
+}
endcode
diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py
index 81052afce..573722d68 100644
--- a/passes/pmgen/pmgen.py
+++ b/passes/pmgen/pmgen.py
@@ -38,7 +38,10 @@ for a in args:
assert prefix is not None
current_pattern = None
+current_subpattern = None
patterns = dict()
+subpatterns = dict()
+subpattern_args = dict()
state_types = dict()
udata_types = dict()
blocks = list()
@@ -104,9 +107,12 @@ def rewrite_cpp(s):
return "".join(t)
-def process_pmgfile(f):
+def process_pmgfile(f, filename):
+ linenr = 0
global current_pattern
+ global current_subpattern
while True:
+ linenr += 1
line = f.readline()
if line == "": break
line = line.strip()
@@ -119,19 +125,52 @@ def process_pmgfile(f):
if current_pattern is not None:
block = dict()
block["type"] = "final"
- block["pattern"] = current_pattern
+ block["pattern"] = (current_pattern, current_subpattern)
blocks.append(block)
line = line.split()
assert len(line) == 2
assert line[1] not in patterns
current_pattern = line[1]
+ current_subpattern = ""
patterns[current_pattern] = len(blocks)
+ subpatterns[(current_pattern, current_subpattern)] = len(blocks)
+ subpattern_args[(current_pattern, current_subpattern)] = list()
state_types[current_pattern] = dict()
udata_types[current_pattern] = dict()
continue
assert current_pattern is not None
+ if cmd == "fallthrough":
+ block = dict()
+ block["type"] = "fallthrough"
+ blocks.append(block)
+ line = line.split()
+ assert len(line) == 1
+ continue
+
+ if cmd == "subpattern":
+ if len(blocks) == 0 or blocks[-1]["type"] != "fallthrough":
+ block = dict()
+ block["type"] = "final"
+ block["pattern"] = (current_pattern, current_subpattern)
+ blocks.append(block)
+ elif len(blocks) and blocks[-1]["type"] == "fallthrough":
+ del blocks[-1]
+ line = line.split()
+ assert len(line) == 2
+ current_subpattern = line[1]
+ subpattern_args[(current_pattern, current_subpattern)] = list()
+ assert (current_pattern, current_subpattern) not in subpatterns
+ subpatterns[(current_pattern, current_subpattern)] = len(blocks)
+ continue
+
+ if cmd == "arg":
+ line = line.split()
+ assert len(line) > 1
+ subpattern_args[(current_pattern, current_subpattern)] += line[1:]
+ continue
+
if cmd == "state":
m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
assert m
@@ -155,21 +194,28 @@ def process_pmgfile(f):
if cmd == "match":
block = dict()
block["type"] = "match"
- block["pattern"] = current_pattern
+ block["src"] = "%s:%d" % (filename, linenr)
+ block["pattern"] = (current_pattern, current_subpattern)
+
+ block["genargs"] = None
+ block["gencode"] = None
line = line.split()
assert len(line) == 2
- assert line[1] not in state_types[current_pattern]
+ assert (line[1] not in state_types[current_pattern]) or (state_types[current_pattern][line[1]] == "Cell*")
block["cell"] = line[1]
state_types[current_pattern][line[1]] = "Cell*";
block["if"] = list()
- block["select"] = list()
+ block["setup"] = list()
block["index"] = list()
block["filter"] = list()
+ block["sets"] = list()
block["optional"] = False
+ block["semioptional"] = False
while True:
+ linenr += 1
l = f.readline()
assert l != ""
a = l.split()
@@ -183,7 +229,22 @@ def process_pmgfile(f):
if a[0] == "select":
b = l.lstrip()[6:]
- block["select"].append(rewrite_cpp(b.strip()))
+ block["setup"].append(("select", rewrite_cpp(b.strip())))
+ continue
+
+ if a[0] == "slice":
+ m = re.match(r"^\s*slice\s+(\S+)\s+(.*?)\s*$", l)
+ block["setup"].append(("slice", m.group(1), rewrite_cpp(m.group(2))))
+ continue
+
+ if a[0] == "choice":
+ m = re.match(r"^\s*choice\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l)
+ block["setup"].append(("choice", m.group(1), m.group(2), rewrite_cpp(m.group(3))))
+ continue
+
+ if a[0] == "define":
+ m = re.match(r"^\s*define\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l)
+ block["setup"].append(("define", m.group(1), m.group(2), rewrite_cpp(m.group(3))))
continue
if a[0] == "index":
@@ -197,35 +258,71 @@ def process_pmgfile(f):
block["filter"].append(rewrite_cpp(b.strip()))
continue
+ if a[0] == "set":
+ m = re.match(r"^\s*set\s+(\S+)\s+(.*?)\s*$", l)
+ block["sets"].append((m.group(1), rewrite_cpp(m.group(2))))
+ continue
+
if a[0] == "optional":
block["optional"] = True
continue
+ if a[0] == "semioptional":
+ block["semioptional"] = True
+ continue
+
+ if a[0] == "generate":
+ block["genargs"] = list([int(s) for s in a[1:]])
+ if len(block["genargs"]) == 0: block["genargs"].append(100)
+ if len(block["genargs"]) == 1: block["genargs"].append(0)
+ assert len(block["genargs"]) == 2
+ block["gencode"] = list()
+ while True:
+ linenr += 1
+ l = f.readline()
+ assert l != ""
+ a = l.split()
+ if len(a) == 1 and a[0] == "endmatch": break
+ block["gencode"].append(rewrite_cpp(l.rstrip()))
+ break
+
assert False
+ if block["optional"]:
+ assert not block["semioptional"]
+
blocks.append(block)
continue
if cmd == "code":
block = dict()
block["type"] = "code"
- block["pattern"] = current_pattern
+ block["src"] = "%s:%d" % (filename, linenr)
+ block["pattern"] = (current_pattern, current_subpattern)
block["code"] = list()
+ block["fcode"] = list()
block["states"] = set()
for s in line.split()[1:]:
assert s in state_types[current_pattern]
block["states"].add(s)
+ codetype = "code"
+
while True:
+ linenr += 1
l = f.readline()
assert l != ""
a = l.split()
if len(a) == 0: continue
if a[0] == "endcode": break
- block["code"].append(rewrite_cpp(l.rstrip()))
+ if a[0] == "finally":
+ codetype = "fcode"
+ continue
+
+ block[codetype].append(rewrite_cpp(l.rstrip()))
blocks.append(block)
continue
@@ -234,15 +331,16 @@ def process_pmgfile(f):
for fn in pmgfiles:
with open(fn, "r") as f:
- process_pmgfile(f)
+ process_pmgfile(f, fn)
if current_pattern is not None:
block = dict()
block["type"] = "final"
- block["pattern"] = current_pattern
+ block["pattern"] = (current_pattern, current_subpattern)
blocks.append(block)
current_pattern = None
+current_subpattern = None
if debug:
pp.pprint(blocks)
@@ -262,7 +360,18 @@ with open(outfile, "w") as f:
print("struct {}_pm {{".format(prefix), file=f)
print(" Module *module;", file=f)
print(" SigMap sigmap;", file=f)
- print(" std::function<void()> on_accept;".format(prefix), file=f)
+ print(" std::function<void()> on_accept;", file=f)
+ print(" bool generate_mode;", file=f)
+ print(" int accept_cnt;", file=f)
+ print("", file=f)
+
+ print(" uint32_t rngseed;", file=f)
+ print(" int rng(unsigned int n) {", file=f)
+ print(" rngseed ^= rngseed << 13;", file=f)
+ print(" rngseed ^= rngseed >> 17;", file=f)
+ print(" rngseed ^= rngseed << 5;", file=f)
+ print(" return rngseed % n;", file=f)
+ print(" }", file=f)
print("", file=f)
for index in range(len(blocks)):
@@ -271,12 +380,21 @@ with open(outfile, "w") as f:
index_types = list()
for entry in block["index"]:
index_types.append(entry[0])
+ value_types = ["Cell*"]
+ for entry in block["setup"]:
+ if entry[0] == "slice":
+ value_types.append("int")
+ if entry[0] == "choice":
+ value_types.append(entry[1])
+ if entry[0] == "define":
+ value_types.append(entry[1])
print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f)
- print(" dict<index_{}_key_type, vector<Cell*>> index_{};".format(index, index), file=f)
+ print(" typedef std::tuple<{}> index_{}_value_type;".format(", ".join(value_types), index), file=f)
+ print(" dict<index_{}_key_type, vector<index_{}_value_type>> index_{};".format(index, index, index), file=f)
print(" dict<SigBit, pool<Cell*>> sigusers;", file=f)
print(" pool<Cell*> blacklist_cells;", file=f)
print(" pool<Cell*> autoremove_cells;", file=f)
- print(" bool blacklist_dirty;", file=f)
+ print(" dict<Cell*,int> rollback_cache;", file=f)
print(" int rollback;", file=f)
print("", file=f)
@@ -304,47 +422,30 @@ with open(outfile, "w") as f:
print(" void add_siguser(const SigSpec &sig, Cell *cell) {", file=f)
print(" for (auto bit : sigmap(sig)) {", file=f)
print(" if (bit.wire == nullptr) continue;", file=f)
- print(" if (sigusers.count(bit) == 0 && bit.wire->port_id)", file=f)
- print(" sigusers[bit].insert(nullptr);", file=f)
print(" sigusers[bit].insert(cell);", file=f)
print(" }", file=f)
print(" }", file=f)
print("", file=f)
print(" void blacklist(Cell *cell) {", file=f)
- print(" if (cell != nullptr) {", file=f)
- print(" if (blacklist_cells.insert(cell).second)", file=f)
- print(" blacklist_dirty = true;", file=f)
+ print(" if (cell != nullptr && blacklist_cells.insert(cell).second) {", file=f)
+ print(" auto ptr = rollback_cache.find(cell);", file=f)
+ print(" if (ptr == rollback_cache.end()) return;", file=f)
+ print(" int rb = ptr->second;", file=f)
+ print(" if (rollback == 0 || rollback > rb)", file=f)
+ print(" rollback = rb;", file=f)
print(" }", file=f)
print(" }", file=f)
print("", file=f)
print(" void autoremove(Cell *cell) {", file=f)
print(" if (cell != nullptr) {", file=f)
- print(" if (blacklist_cells.insert(cell).second)", file=f)
- print(" blacklist_dirty = true;", file=f)
print(" autoremove_cells.insert(cell);", file=f)
+ print(" blacklist(cell);", file=f)
print(" }", file=f)
print(" }", file=f)
print("", file=f)
- for current_pattern in sorted(patterns.keys()):
- print(" void check_blacklist_{}() {{".format(current_pattern), file=f)
- print(" if (!blacklist_dirty)", file=f)
- print(" return;", file=f)
- print(" blacklist_dirty = false;", file=f)
- for index in range(len(blocks)):
- block = blocks[index]
- if block["pattern"] != current_pattern:
- continue
- if block["type"] == "match":
- print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f)
- print(" rollback = {};".format(index+1), file=f)
- print(" return;", file=f)
- print(" }", file=f)
- print(" rollback = 0;", file=f)
- print(" }", file=f)
- print("", file=f)
current_pattern = None
print(" SigSpec port(Cell *cell, IdString portname) {", file=f)
@@ -367,7 +468,7 @@ with open(outfile, "w") as f:
print("", file=f)
print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
- print(" module(module), sigmap(module) {", file=f)
+ print(" module(module), sigmap(module), generate_mode(false), rngseed(12345678) {", file=f)
for current_pattern in sorted(patterns.keys()):
for s, t in sorted(udata_types[current_pattern].items()):
if t.endswith("*"):
@@ -375,10 +476,11 @@ with open(outfile, "w") as f:
else:
print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
current_pattern = None
- print(" for (auto cell : module->cells()) {", file=f)
+ print(" for (auto port : module->ports)", file=f)
+ print(" add_siguser(module->wire(port), nullptr);", file=f)
+ print(" for (auto cell : module->cells())", file=f)
print(" for (auto &conn : cell->connections())", file=f)
print(" add_siguser(conn.second, cell);", file=f)
- print(" }", file=f)
print(" for (auto cell : cells) {", file=f)
for index in range(len(blocks)):
@@ -386,12 +488,34 @@ with open(outfile, "w") as f:
if block["type"] == "match":
print(" do {", file=f)
print(" Cell *{} = cell;".format(block["cell"]), file=f)
- for expr in block["select"]:
- print(" if (!({})) break;".format(expr), file=f)
+ print(" index_{}_value_type value;".format(index), file=f)
+ print(" std::get<0>(value) = cell;", file=f)
+ loopcnt = 0
+ valueidx = 1
+ for item in block["setup"]:
+ if item[0] == "select":
+ print(" if (!({})) continue;".format(item[1]), file=f)
+ if item[0] == "slice":
+ print(" int &{} = std::get<{}>(value);".format(item[1], valueidx), file=f)
+ print(" for ({} = 0; {} < {}; {}++) {{".format(item[1], item[1], item[2], item[1]), file=f)
+ valueidx += 1
+ loopcnt += 1
+ if item[0] == "choice":
+ print(" vector<{}> _pmg_choices_{} = {};".format(item[1], item[2], item[3]), file=f)
+ print(" for (const {} &{} : _pmg_choices_{}) {{".format(item[1], item[2], item[2]), file=f)
+ print(" std::get<{}>(value) = {};".format(valueidx, item[2]), file=f)
+ valueidx += 1
+ loopcnt += 1
+ if item[0] == "define":
+ print(" {} &{} = std::get<{}>(value);".format(item[1], item[2], valueidx), file=f)
+ print(" {} = {};".format(item[2], item[3]), file=f)
+ valueidx += 1
print(" index_{}_key_type key;".format(index), file=f)
for field, entry in enumerate(block["index"]):
print(" std::get<{}>(key) = {};".format(field, entry[1]), file=f)
- print(" index_{}[key].push_back(cell);".format(index), file=f)
+ print(" index_{}[key].push_back(value);".format(index), file=f)
+ for i in range(loopcnt):
+ print(" }", file=f)
print(" } while (0);", file=f)
print(" }", file=f)
@@ -405,41 +529,47 @@ with open(outfile, "w") as f:
print("", file=f)
for current_pattern in sorted(patterns.keys()):
- print(" void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
+ print(" int run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
+ print(" accept_cnt = 0;", file=f)
print(" on_accept = on_accept_f;", file=f)
print(" rollback = 0;", file=f)
- print(" blacklist_dirty = false;", file=f)
for s, t in sorted(state_types[current_pattern].items()):
if t.endswith("*"):
print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f)
else:
print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
- print(" block_{}();".format(patterns[current_pattern]), file=f)
+ print(" block_{}(1);".format(patterns[current_pattern]), file=f)
+ print(" log_assert(rollback_cache.empty());", file=f)
+ print(" return accept_cnt;", file=f)
print(" }", file=f)
print("", file=f)
- print(" void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
- print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f)
+ print(" int run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
+ print(" return run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f)
print(" }", file=f)
print("", file=f)
- print(" void run_{}(std::function<void(state_{}_t&)> on_accept_f) {{".format(current_pattern, current_pattern), file=f)
- print(" run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f)
+ print(" int run_{}() {{".format(current_pattern), file=f)
+ print(" return run_{}([](){{}});".format(current_pattern, current_pattern), file=f)
print(" }", file=f)
print("", file=f)
- print(" void run_{}() {{".format(current_pattern), file=f)
- print(" run_{}([](){{}});".format(current_pattern, current_pattern), file=f)
- print(" }", file=f)
+
+ if len(subpatterns):
+ for p, s in sorted(subpatterns.keys()):
+ print(" void block_subpattern_{}_{}(int recursion) {{ block_{}(recursion); }}".format(p, s, subpatterns[(p, s)]), file=f)
print("", file=f)
+
current_pattern = None
+ current_subpattern = None
for index in range(len(blocks)):
block = blocks[index]
- print(" void block_{}() {{".format(index), file=f)
- current_pattern = block["pattern"]
+ if block["type"] in ("match", "code"):
+ print(" // {}".format(block["src"]), file=f)
+
+ print(" void block_{}(int recursion YS_ATTRIBUTE(unused)) {{".format(index), file=f)
+ current_pattern, current_subpattern = block["pattern"]
if block["type"] == "final":
- print(" on_accept();", file=f)
- print(" check_blacklist_{}();".format(current_pattern), file=f)
print(" }", file=f)
if index+1 != len(blocks):
print("", file=f)
@@ -449,12 +579,17 @@ with open(outfile, "w") as f:
nonconst_st = set()
restore_st = set()
- for i in range(patterns[current_pattern], index):
+ for s in subpattern_args[(current_pattern, current_subpattern)]:
+ const_st.add(s)
+
+ for i in range(subpatterns[(current_pattern, current_subpattern)], index):
if blocks[i]["type"] == "code":
for s in blocks[i]["states"]:
const_st.add(s)
elif blocks[i]["type"] == "match":
const_st.add(blocks[i]["cell"])
+ for item in blocks[i]["sets"]:
+ const_st.add(item[0])
else:
assert False
@@ -468,6 +603,10 @@ with open(outfile, "w") as f:
s = block["cell"]
assert s not in const_st
nonconst_st.add(s)
+ for item in block["sets"]:
+ if item[0] in const_st:
+ const_st.remove(item[0])
+ nonconst_st.add(item[0])
else:
assert False
@@ -482,37 +621,55 @@ with open(outfile, "w") as f:
t = state_types[current_pattern][s]
print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
+ for u in sorted(udata_types[current_pattern].keys()):
+ t = udata_types[current_pattern][u]
+ print(" {} &{} YS_ATTRIBUTE(unused) = ud_{}.{};".format(t, u, current_pattern, u), file=f)
+
if len(restore_st):
print("", file=f)
for s in sorted(restore_st):
t = state_types[current_pattern][s]
- print(" {} backup_{} = {};".format(t, s, s), file=f)
+ print(" {} _pmg_backup_{} = {};".format(t, s, s), file=f)
if block["type"] == "code":
print("", file=f)
- print(" do {", file=f)
- print("#define reject do {{ check_blacklist_{}(); goto rollback_label; }} while(0)".format(current_pattern), file=f)
- print("#define accept do {{ on_accept(); check_blacklist_{}(); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f)
- print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
+ print("#define reject do { goto rollback_label; } while(0)", file=f)
+ print("#define accept do { accept_cnt++; on_accept(); if (rollback) goto rollback_label; } while(0)", file=f)
+ print("#define finish do { rollback = -1; goto rollback_label; } while(0)", file=f)
+ print("#define branch do {{ block_{}(recursion+1); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
+ print("#define subpattern(pattern_name) do {{ block_subpattern_{}_ ## pattern_name (recursion+1); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f)
for line in block["code"]:
- print(" " + line, file=f)
+ print(" " + line, file=f)
print("", file=f)
- print(" block_{}();".format(index+1), file=f)
+ print(" block_{}(recursion+1);".format(index+1), file=f)
+
print("#undef reject", file=f)
print("#undef accept", file=f)
+ print("#undef finish", file=f)
print("#undef branch", file=f)
- print(" } while (0);", file=f)
+ print("#undef subpattern", file=f)
+
print("", file=f)
print("rollback_label:", file=f)
print(" YS_ATTRIBUTE(unused);", file=f)
+ if len(block["fcode"]):
+ print("#define accept do { accept_cnt++; on_accept(); } while(0)", file=f)
+ print("#define finish do { rollback = -1; goto finish_label; } while(0)", file=f)
+ for line in block["fcode"]:
+ print(" " + line, file=f)
+ print("finish_label:", file=f)
+ print(" YS_ATTRIBUTE(unused);", file=f)
+ print("#undef accept", file=f)
+ print("#undef finish", file=f)
+
if len(restore_st) or len(nonconst_st):
print("", file=f)
for s in sorted(restore_st):
t = state_types[current_pattern][s]
- print(" {} = backup_{};".format(s, s), file=f)
+ print(" {} = _pmg_backup_{};".format(s, s), file=f)
for s in sorted(nonconst_st):
if s not in restore_st:
t = state_types[current_pattern][s]
@@ -524,12 +681,15 @@ with open(outfile, "w") as f:
elif block["type"] == "match":
assert len(restore_st) == 0
+ print(" Cell* _pmg_backup_{} = {};".format(block["cell"], block["cell"]), file=f)
+
if len(block["if"]):
for expr in block["if"]:
print("", file=f)
print(" if (!({})) {{".format(expr), file=f)
print(" {} = nullptr;".format(block["cell"]), file=f)
- print(" block_{}();".format(index+1), file=f)
+ print(" block_{}(recursion+1);".format(index+1), file=f)
+ print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
print(" return;", file=f)
print(" }", file=f)
@@ -537,21 +697,48 @@ with open(outfile, "w") as f:
print(" index_{}_key_type key;".format(index), file=f)
for field, entry in enumerate(block["index"]):
print(" std::get<{}>(key) = {};".format(field, entry[2]), file=f)
- print(" const vector<Cell*> &cells = index_{}[key];".format(index), file=f)
+ print(" auto cells_ptr = index_{}.find(key);".format(index), file=f)
+
+ if block["semioptional"] or block["genargs"] is not None:
+ print(" bool found_any_match = false;", file=f)
print("", file=f)
- print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f)
- print(" {} = cells[idx];".format(block["cell"]), file=f)
- print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f)
+ print(" if (cells_ptr != index_{}.end()) {{".format(index), file=f)
+ print(" const vector<index_{}_value_type> &cells = cells_ptr->second;".format(index), file=f)
+ print(" for (int _pmg_idx = 0; _pmg_idx < GetSize(cells); _pmg_idx++) {", file=f)
+ print(" {} = std::get<0>(cells[_pmg_idx]);".format(block["cell"]), file=f)
+ valueidx = 1
+ for item in block["setup"]:
+ if item[0] == "slice":
+ print(" const int &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], valueidx), file=f)
+ valueidx += 1
+ if item[0] == "choice":
+ print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
+ valueidx += 1
+ if item[0] == "define":
+ print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
+ valueidx += 1
+ print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f)
for expr in block["filter"]:
- print(" if (!({})) continue;".format(expr), file=f)
- print(" block_{}();".format(index+1), file=f)
- print(" if (rollback) {", file=f)
- print(" if (rollback != {}) {{".format(index+1), file=f)
- print(" {} = nullptr;".format(block["cell"]), file=f)
- print(" return;", file=f)
+ print(" if (!({})) continue;".format(expr), file=f)
+ if block["semioptional"] or block["genargs"] is not None:
+ print(" found_any_match = true;", file=f)
+ for item in block["sets"]:
+ print(" auto _pmg_backup_{} = {};".format(item[0], item[0]), file=f)
+ print(" {} = {};".format(item[0], item[1]), file=f)
+ print(" auto rollback_ptr = rollback_cache.insert(make_pair(std::get<0>(cells[_pmg_idx]), recursion));", file=f)
+ print(" block_{}(recursion+1);".format(index+1), file=f)
+ for item in block["sets"]:
+ print(" {} = _pmg_backup_{};".format(item[0], item[0]), file=f)
+ print(" if (rollback_ptr.second)", file=f)
+ print(" rollback_cache.erase(rollback_ptr.first);", file=f)
+ print(" if (rollback) {", file=f)
+ print(" if (rollback != recursion) {{".format(index+1), file=f)
+ print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
+ print(" return;", file=f)
+ print(" }", file=f)
+ print(" rollback = 0;", file=f)
print(" }", file=f)
- print(" rollback = 0;", file=f)
print(" }", file=f)
print(" }", file=f)
@@ -559,8 +746,20 @@ with open(outfile, "w") as f:
print(" {} = nullptr;".format(block["cell"]), file=f)
if block["optional"]:
- print(" block_{}();".format(index+1), file=f)
+ print(" block_{}(recursion+1);".format(index+1), file=f)
+ if block["semioptional"]:
+ print(" if (!found_any_match) block_{}(recursion+1);".format(index+1), file=f)
+
+ print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
+
+ if block["genargs"] is not None:
+ print("#define finish do { rollback = -1; return; } while(0)", file=f)
+ print(" if (generate_mode && rng(100) < (found_any_match ? {} : {})) {{".format(block["genargs"][1], block["genargs"][0]), file=f)
+ for line in block["gencode"]:
+ print(" " + line, file=f)
+ print(" }", file=f)
+ print("#undef finish", file=f)
else:
assert False
diff --git a/passes/pmgen/test_pmgen.cc b/passes/pmgen/test_pmgen.cc
new file mode 100644
index 000000000..0ad769dfd
--- /dev/null
+++ b/passes/pmgen/test_pmgen.cc
@@ -0,0 +1,379 @@
+/*
+ * 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
+
+// for peepopt_pm
+bool did_something;
+
+#include "passes/pmgen/test_pmgen_pm.h"
+#include "passes/pmgen/ice40_dsp_pm.h"
+#include "passes/pmgen/peepopt_pm.h"
+
+void reduce_chain(test_pmgen_pm &pm)
+{
+ auto &st = pm.st_reduce;
+ auto &ud = pm.ud_reduce;
+
+ if (ud.longest_chain.empty())
+ return;
+
+ log("Found chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type));
+
+ SigSpec A;
+ SigSpec Y = ud.longest_chain.front().first->getPort(ID(Y));
+ auto last_cell = ud.longest_chain.back().first;
+
+ for (auto it : ud.longest_chain) {
+ auto cell = it.first;
+ if (cell == last_cell) {
+ A.append(cell->getPort(ID(A)));
+ A.append(cell->getPort(ID(B)));
+ } else {
+ A.append(cell->getPort(it.second == ID(A) ? ID(B) : ID(A)));
+ }
+ log(" %s\n", log_id(cell));
+ pm.autoremove(cell);
+ }
+
+ Cell *c;
+
+ if (last_cell->type == ID($_AND_))
+ c = pm.module->addReduceAnd(NEW_ID, A, Y);
+ else if (last_cell->type == ID($_OR_))
+ c = pm.module->addReduceOr(NEW_ID, A, Y);
+ else if (last_cell->type == ID($_XOR_))
+ c = pm.module->addReduceXor(NEW_ID, A, Y);
+ else
+ log_abort();
+
+ log(" -> %s (%s)\n", log_id(c), log_id(c->type));
+}
+
+void reduce_tree(test_pmgen_pm &pm)
+{
+ auto &st = pm.st_reduce;
+ auto &ud = pm.ud_reduce;
+
+ if (ud.longest_chain.empty())
+ return;
+
+ SigSpec A = ud.leaves;
+ SigSpec Y = st.first->getPort(ID(Y));
+ pm.autoremove(st.first);
+
+ log("Found %s tree with %d leaves for %s (%s).\n", log_id(st.first->type),
+ GetSize(A), log_signal(Y), log_id(st.first));
+
+ Cell *c;
+
+ if (st.first->type == ID($_AND_))
+ c = pm.module->addReduceAnd(NEW_ID, A, Y);
+ else if (st.first->type == ID($_OR_))
+ c = pm.module->addReduceOr(NEW_ID, A, Y);
+ else if (st.first->type == ID($_XOR_))
+ c = pm.module->addReduceXor(NEW_ID, A, Y);
+ else
+ log_abort();
+
+ log(" -> %s (%s)\n", log_id(c), log_id(c->type));
+}
+
+void opt_eqpmux(test_pmgen_pm &pm)
+{
+ auto &st = pm.st_eqpmux;
+
+ SigSpec Y = st.pmux->getPort(ID::Y);
+ int width = GetSize(Y);
+
+ SigSpec EQ = st.pmux->getPort(ID::B).extract(st.pmux_slice_eq*width, width);
+ SigSpec NE = st.pmux->getPort(ID::B).extract(st.pmux_slice_ne*width, width);
+
+ log("Found eqpmux circuit driving %s (eq=%s, ne=%s, pmux=%s).\n",
+ log_signal(Y), log_id(st.eq), log_id(st.ne), log_id(st.pmux));
+
+ pm.autoremove(st.pmux);
+ Cell *c = pm.module->addMux(NEW_ID, NE, EQ, st.eq->getPort(ID::Y), Y);
+ log(" -> %s (%s)\n", log_id(c), log_id(c->type));
+}
+
+#define GENERATE_PATTERN(pmclass, pattern) \
+ generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
+
+void pmtest_addports(Module *module)
+{
+ pool<SigBit> driven_bits, used_bits;
+ SigMap sigmap(module);
+ int icnt = 0, ocnt = 0;
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections())
+ {
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ used_bits.insert(bit);
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ driven_bits.insert(bit);
+ }
+
+ for (auto wire : vector<Wire*>(module->wires()))
+ {
+ SigSpec ibits, obits;
+ for (auto bit : sigmap(wire)) {
+ if (!used_bits.count(bit))
+ obits.append(bit);
+ if (!driven_bits.count(bit))
+ ibits.append(bit);
+ }
+ if (!ibits.empty()) {
+ Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits));
+ w->port_input = true;
+ module->connect(ibits, w);
+ }
+ if (!obits.empty()) {
+ Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits));
+ w->port_output = true;
+ module->connect(w, obits);
+ }
+ }
+
+ module->fixup_ports();
+}
+
+template <class pm>
+void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design)
+{
+ log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
+
+ int modcnt = 0;
+ int maxmodcnt = 100;
+ int maxsubcnt = 4;
+ int timeout = 0;
+ vector<Module*> mods;
+
+ while (modcnt < maxmodcnt)
+ {
+ int submodcnt = 0, itercnt = 0, cellcnt = 0;
+ Module *mod = design->addModule(NEW_ID);
+
+ while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
+ {
+ if (timeout++ > 10000)
+ log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n");
+
+ pm matcher(mod, mod->cells());
+
+ matcher.rng(1);
+ matcher.rngseed += modcnt;
+ matcher.rng(1);
+ matcher.rngseed += submodcnt;
+ matcher.rng(1);
+ matcher.rngseed += itercnt;
+ matcher.rng(1);
+ matcher.rngseed += cellcnt;
+ matcher.rng(1);
+
+ if (GetSize(mod->cells()) != cellcnt)
+ {
+ bool found_match = false;
+ run(matcher, [&](){ found_match = true; });
+ cellcnt = GetSize(mod->cells());
+
+ if (found_match) {
+ Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d",
+ pmclass, pattern, modcnt++));
+ log("Creating module %s with %d cells.\n", log_id(m), cellcnt);
+ mod->cloneInto(m);
+ pmtest_addports(m);
+ mods.push_back(m);
+ submodcnt++;
+ timeout = 0;
+ }
+ }
+
+ matcher.generate_mode = true;
+ run(matcher, [](){});
+ }
+
+ if (submodcnt)
+ maxsubcnt *= 2;
+
+ design->remove(mod);
+ }
+
+ Module *m = design->addModule(stringf("\\pmtest_%s_%s", pmclass, pattern));
+ log("Creating module %s with %d cells.\n", log_id(m), GetSize(mods));
+ for (auto mod : mods) {
+ Cell *c = m->addCell(mod->name, mod->name);
+ for (auto port : mod->ports) {
+ Wire *w = m->addWire(NEW_ID, GetSize(mod->wire(port)));
+ c->setPort(port, w);
+ }
+ }
+ pmtest_addports(m);
+}
+
+struct TestPmgenPass : public Pass {
+ TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" test_pmgen -reduce_chain [options] [selection]\n");
+ log("\n");
+ log("Demo for recursive pmgen patterns. Map chains of AND/OR/XOR to $reduce_*.\n");
+ log("\n");
+
+ log("\n");
+ log(" test_pmgen -reduce_tree [options] [selection]\n");
+ log("\n");
+ log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n");
+ log("\n");
+
+ log("\n");
+ log(" test_pmgen -eqpmux [options] [selection]\n");
+ log("\n");
+ log("Demo for recursive pmgen patterns. Optimize EQ/NE/PMUX circuits.\n");
+ log("\n");
+
+ log("\n");
+ log(" test_pmgen -generate [options] <pattern_name>\n");
+ log("\n");
+ log("Create modules that match the specified pattern.\n");
+ log("\n");
+ }
+
+ void execute_reduce_chain(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing TEST_PMGEN pass (-reduce_chain).\n");
+
+ size_t argidx;
+ for (argidx = 2; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ while (test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_chain)) {}
+ }
+
+ void execute_reduce_tree(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing TEST_PMGEN pass (-reduce_tree).\n");
+
+ size_t argidx;
+ for (argidx = 2; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree);
+ }
+
+ void execute_eqpmux(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing TEST_PMGEN pass (-eqpmux).\n");
+
+ size_t argidx;
+ for (argidx = 2; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ test_pmgen_pm(module, module->selected_cells()).run_eqpmux(opt_eqpmux);
+ }
+
+ void execute_generate(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing TEST_PMGEN pass (-generate).\n");
+
+ size_t argidx;
+ for (argidx = 2; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+
+ if (argidx+1 != args.size())
+ log_cmd_error("Expected exactly one pattern.\n");
+
+ string pattern = args[argidx];
+
+ if (pattern == "reduce")
+ return GENERATE_PATTERN(test_pmgen_pm, reduce);
+
+ if (pattern == "eqpmux")
+ return GENERATE_PATTERN(test_pmgen_pm, eqpmux);
+
+ if (pattern == "ice40_dsp")
+ return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
+
+ if (pattern == "peepopt-muldiv")
+ return GENERATE_PATTERN(peepopt_pm, muldiv);
+
+ if (pattern == "peepopt-shiftmul")
+ return GENERATE_PATTERN(peepopt_pm, shiftmul);
+
+ log_cmd_error("Unkown pattern: %s\n", pattern.c_str());
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ if (GetSize(args) > 1)
+ {
+ if (args[1] == "-reduce_chain")
+ return execute_reduce_chain(args, design);
+ if (args[1] == "-reduce_tree")
+ return execute_reduce_tree(args, design);
+ if (args[1] == "-eqpmux")
+ return execute_eqpmux(args, design);
+ if (args[1] == "-generate")
+ return execute_generate(args, design);
+ }
+ help();
+ log_cmd_error("Missing or unsupported mode parameter.\n");
+ }
+} TestPmgenPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/test_pmgen.pmg b/passes/pmgen/test_pmgen.pmg
new file mode 100644
index 000000000..287ed97d8
--- /dev/null
+++ b/passes/pmgen/test_pmgen.pmg
@@ -0,0 +1,189 @@
+pattern reduce
+
+state <IdString> portname
+udata <vector<pair<Cell*, IdString>>> chain longest_chain
+udata <pool<Cell*>> non_first_cells
+udata <SigSpec> leaves
+
+code
+ non_first_cells.clear();
+ subpattern(setup);
+endcode
+
+match first
+ select first->type.in($_AND_, $_OR_, $_XOR_)
+ filter !non_first_cells.count(first)
+generate
+ SigSpec A = module->addWire(NEW_ID);
+ SigSpec B = module->addWire(NEW_ID);
+ SigSpec Y = module->addWire(NEW_ID);
+ switch (rng(3))
+ {
+ case 0:
+ module->addAndGate(NEW_ID, A, B, Y);
+ break;
+ case 1:
+ module->addOrGate(NEW_ID, A, B, Y);
+ break;
+ case 2:
+ module->addXorGate(NEW_ID, A, B, Y);
+ break;
+ }
+endmatch
+
+code
+ leaves = SigSpec();
+ longest_chain.clear();
+ chain.push_back(make_pair(first, \A));
+ subpattern(tail);
+ chain.back().second = \B;
+ subpattern(tail);
+finally
+ chain.pop_back();
+ log_assert(chain.empty());
+ if (GetSize(longest_chain) > 1)
+ accept;
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern setup
+
+match first
+ select first->type.in($_AND_, $_OR_, $_XOR_)
+endmatch
+
+code portname
+ portname = \A;
+ branch;
+ portname = \B;
+endcode
+
+match next
+ select next->type.in($_AND_, $_OR_, $_XOR_)
+ select nusers(port(next, \Y)) == 2
+ index <IdString> next->type === first->type
+ index <SigSpec> port(next, \Y) === port(first, portname)
+endmatch
+
+code
+ non_first_cells.insert(next);
+endcode
+
+// ------------------------------------------------------------------
+
+subpattern tail
+arg first
+
+match next
+ semioptional
+ select next->type.in($_AND_, $_OR_, $_XOR_)
+ select nusers(port(next, \Y)) == 2
+ index <IdString> next->type === chain.back().first->type
+ index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second)
+generate 10
+ SigSpec A = module->addWire(NEW_ID);
+ SigSpec B = module->addWire(NEW_ID);
+ SigSpec Y = port(chain.back().first, chain.back().second);
+ Cell *c = module->addAndGate(NEW_ID, A, B, Y);
+ c->type = chain.back().first->type;
+endmatch
+
+code
+ if (next) {
+ chain.push_back(make_pair(next, \A));
+ subpattern(tail);
+ chain.back().second = \B;
+ subpattern(tail);
+ } else {
+ if (GetSize(chain) > GetSize(longest_chain))
+ longest_chain = chain;
+ leaves.append(port(chain.back().first, chain.back().second));
+ }
+finally
+ if (next)
+ chain.pop_back();
+endcode
+
+// ==================================================================
+
+pattern eqpmux
+
+state <bool> eq_ne_signed
+state <SigSpec> eq_inA eq_inB
+state <int> pmux_slice_eq pmux_slice_ne
+
+match eq
+ select eq->type == $eq
+ choice <IdString> AB {\A, \B}
+ define <IdString> BA AB == \A ? \B : \A
+ set eq_inA port(eq, \A)
+ set eq_inB port(eq, \B)
+ set eq_ne_signed param(eq, \A_SIGNED).as_bool()
+generate 100 10
+ SigSpec A = module->addWire(NEW_ID, rng(7)+1);
+ SigSpec B = module->addWire(NEW_ID, rng(7)+1);
+ SigSpec Y = module->addWire(NEW_ID);
+ module->addEq(NEW_ID, A, B, Y, rng(2));
+endmatch
+
+match pmux
+ select pmux->type == $pmux
+ slice idx GetSize(port(pmux, \S))
+ index <SigBit> port(pmux, \S)[idx] === port(eq, \Y)
+ set pmux_slice_eq idx
+generate 100 10
+ int width = rng(7) + 1;
+ int numsel = rng(4) + 1;
+ int idx = rng(numsel);
+
+ SigSpec A = module->addWire(NEW_ID, width);
+ SigSpec Y = module->addWire(NEW_ID, width);
+
+ SigSpec B, S;
+ for (int i = 0; i < numsel; i++) {
+ B.append(module->addWire(NEW_ID, width));
+ S.append(i == idx ? port(eq, \Y) : module->addWire(NEW_ID));
+ }
+
+ module->addPmux(NEW_ID, A, B, S, Y);
+endmatch
+
+match ne
+ select ne->type == $ne
+ choice <IdString> AB {\A, \B}
+ define <IdString> BA (AB == \A ? \B : \A)
+ index <SigSpec> port(ne, AB) === eq_inA
+ index <SigSpec> port(ne, BA) === eq_inB
+ index <int> param(ne, \A_SIGNED).as_bool() === eq_ne_signed
+generate 100 10
+ SigSpec A = eq_inA, B = eq_inB, Y;
+ if (rng(2)) {
+ std::swap(A, B);
+ }
+ if (rng(2)) {
+ for (auto bit : port(pmux, \S)) {
+ if (nusers(bit) < 2)
+ Y.append(bit);
+ }
+ if (GetSize(Y))
+ Y = Y[rng(GetSize(Y))];
+ else
+ Y = module->addWire(NEW_ID);
+ } else {
+ Y = module->addWire(NEW_ID);
+ }
+ module->addNe(NEW_ID, A, B, Y, rng(2));
+endmatch
+
+match pmux2
+ select pmux2->type == $pmux
+ slice idx GetSize(port(pmux2, \S))
+ index <Cell*> pmux2 === pmux
+ index <SigBit> port(pmux2, \S)[idx] === port(ne, \Y)
+ set pmux_slice_ne idx
+endmatch
+
+code
+ accept;
+endcode
diff --git a/passes/proc/Makefile.inc b/passes/proc/Makefile.inc
index 397fe46a1..4b56979f8 100644
--- a/passes/proc/Makefile.inc
+++ b/passes/proc/Makefile.inc
@@ -1,5 +1,6 @@
OBJS += passes/proc/proc.o
+OBJS += passes/proc/proc_prune.o
OBJS += passes/proc/proc_clean.o
OBJS += passes/proc/proc_rmdead.o
OBJS += passes/proc/proc_init.o
@@ -7,4 +8,3 @@ OBJS += passes/proc/proc_arst.o
OBJS += passes/proc/proc_mux.o
OBJS += passes/proc/proc_dlatch.o
OBJS += passes/proc/proc_dff.o
-
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
index ef7cb0f71..a5b4a3112 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -37,6 +37,7 @@ struct ProcPass : public Pass {
log("\n");
log(" proc_clean\n");
log(" proc_rmdead\n");
+ log(" proc_prune\n");
log(" proc_init\n");
log(" proc_arst\n");
log(" proc_mux\n");
@@ -83,6 +84,7 @@ struct ProcPass : public Pass {
Pass::call(design, "proc_clean");
if (!ifxmode)
Pass::call(design, "proc_rmdead");
+ Pass::call(design, "proc_prune");
Pass::call(design, "proc_init");
if (global_arst.empty())
Pass::call(design, "proc_arst");
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index b69eba3f9..c606deb88 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -55,7 +55,7 @@ bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref,
return check_signal(mod, cell->getPort("\\A"), ref, polarity);
}
- if ((cell->type == "$eq" || cell->type == "$eqx") && cell->getPort("\\Y") == signal) {
+ if (cell->type.in("$eq", "$eqx") && cell->getPort("\\Y") == signal) {
if (cell->getPort("\\A").is_fully_const()) {
if (!cell->getPort("\\A").as_bool())
polarity = !polarity;
@@ -68,7 +68,7 @@ bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref,
}
}
- if ((cell->type == "$ne" || cell->type == "$nex") && cell->getPort("\\Y") == signal) {
+ if (cell->type.in("$ne", "$nex") && cell->getPort("\\Y") == signal) {
if (cell->getPort("\\A").is_fully_const()) {
if (cell->getPort("\\A").as_bool())
polarity = !polarity;
@@ -172,7 +172,7 @@ restart_proc_arst:
sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
}
for (auto &action : sync->actions) {
- RTLIL::SigSpec rspec = action.second;
+ RTLIL::SigSpec rspec = assign_map(action.second);
RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
for (int i = 0; i < GetSize(rspec); i++)
if (rspec[i].wire == NULL)
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 52141a8ec..114c6ab03 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -69,8 +69,7 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did
did_something = true;
for (auto &action : sw->cases[0]->actions)
parent->actions.push_back(action);
- for (auto sw2 : sw->cases[0]->switches)
- parent->switches.push_back(sw2);
+ parent->switches.insert(parent->switches.begin(), sw->cases[0]->switches.begin(), sw->cases[0]->switches.end());
sw->cases[0]->switches.clear();
delete sw->cases[0];
sw->cases.clear();
@@ -143,7 +142,7 @@ void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int m
YOSYS_NAMESPACE_END
PRIVATE_NAMESPACE_BEGIN
-void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)
+void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count, bool quiet)
{
int count = 0;
bool did_something = true;
@@ -160,7 +159,7 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)
did_something = false;
proc_clean_case(&proc->root_case, did_something, count, -1);
}
- if (count > 0)
+ if (count > 0 && !quiet)
log("Found and cleaned up %d empty switch%s in `%s.%s'.\n", count, count == 1 ? "" : "es", mod->name.c_str(), proc->name.c_str());
total_count += count;
}
@@ -171,7 +170,10 @@ struct ProcCleanPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" proc_clean [selection]\n");
+ log(" proc_clean [options] [selection]\n");
+ log("\n");
+ log(" -quiet\n");
+ log(" do not print any messages.\n");
log("\n");
log("This pass removes empty parts of processes and ultimately removes a process\n");
log("if it contains only empty structures.\n");
@@ -180,9 +182,20 @@ struct ProcCleanPass : public Pass {
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int total_count = 0;
- log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
+ bool quiet = false;
+
+ if (find(args.begin(), args.end(), "-quiet") == args.end())
+ log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
- extra_args(args, 1, design);
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-quiet") {
+ quiet = true;
+ continue;
+ }
+ }
+ extra_args(args, argidx, design);
for (auto mod : design->modules()) {
std::vector<RTLIL::IdString> delme;
@@ -191,10 +204,11 @@ struct ProcCleanPass : public Pass {
for (auto &proc_it : mod->processes) {
if (!design->selected(mod, proc_it.second))
continue;
- proc_clean(mod, proc_it.second, total_count);
+ proc_clean(mod, proc_it.second, total_count, quiet);
if (proc_it.second->syncs.size() == 0 && proc_it.second->root_case.switches.size() == 0 &&
proc_it.second->root_case.actions.size() == 0) {
- log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str());
+ if (!quiet)
+ log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str());
delme.push_back(proc_it.first);
}
}
@@ -204,7 +218,8 @@ struct ProcCleanPass : public Pass {
}
}
- log("Cleaned up %d empty switch%s.\n", total_count, total_count == 1 ? "" : "es");
+ if (!quiet)
+ log("Cleaned up %d empty switch%s.\n", total_count, total_count == 1 ? "" : "es");
}
} ProcCleanPass;
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index e2dc07e53..462a384b7 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -26,21 +26,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
-{
- log_assert(rule.compare.size() == 0);
-
- while (1) {
- RTLIL::SigSpec tmp = sig;
- for (auto &it : rule.actions)
- tmp.replace(it.first, it.second);
- if (tmp == sig)
- break;
- sig = tmp;
- }
-}
-
-void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
+void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc)
{
bool found_init = false;
@@ -53,9 +39,7 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
for (auto &action : sync->actions)
{
RTLIL::SigSpec lhs = action.first;
- RTLIL::SigSpec rhs = action.second;
-
- proc_get_const(rhs, proc->root_case);
+ RTLIL::SigSpec rhs = sigmap(action.second);
if (!rhs.is_fully_const())
log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs));
@@ -120,10 +104,12 @@ struct ProcInitPass : public Pass {
extra_args(args, 1, design);
for (auto mod : design->modules())
- if (design->selected(mod))
+ if (design->selected(mod)) {
+ SigMap sigmap(mod);
for (auto &proc_it : mod->processes)
if (design->selected(mod, proc_it.second))
- proc_init(mod, proc_it.second);
+ proc_init(mod, sigmap, proc_it.second);
+ }
}
} ProcInitPass;
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index aac0b121c..d029282fd 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -144,7 +144,13 @@ struct SnippetSwCache
}
};
-RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw, bool ifxmode)
+void apply_attrs(RTLIL::Cell *cell, const RTLIL::SwitchRule *sw, const RTLIL::CaseRule *cs)
+{
+ cell->attributes = sw->attributes;
+ cell->add_strpool_attribute("\\src", cs->get_strpool_attribute("\\src"));
+}
+
+RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode)
{
std::stringstream sstr;
sstr << "$procmux$" << (autoidx++);
@@ -173,7 +179,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
{
// create compare cell
RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), ifxmode ? "$eqx" : "$eq");
- eq_cell->attributes = sw->attributes;
+ apply_attrs(eq_cell, sw, cs);
eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(0);
@@ -199,7 +205,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
// reduce cmp vector to one logic signal
RTLIL::Cell *any_cell = mod->addCell(sstr.str() + "_ANY", "$reduce_or");
- any_cell->attributes = sw->attributes;
+ apply_attrs(any_cell, sw, cs);
any_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
any_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cmp_wire->width);
@@ -212,7 +218,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
return RTLIL::SigSpec(ctrl_wire);
}
-RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode)
+RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode)
{
log_assert(when_signal.size() == else_signal.size());
@@ -224,7 +230,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
return when_signal;
// compare results
- RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode);
+ RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode);
if (ctrl_sig.size() == 0)
return when_signal;
log_assert(ctrl_sig.size() == 1);
@@ -234,7 +240,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
// create the multiplexer itself
RTLIL::Cell *mux_cell = mod->addCell(sstr.str(), "$mux");
- mux_cell->attributes = sw->attributes;
+ apply_attrs(mux_cell, sw, cs);
mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.size());
mux_cell->setPort("\\A", else_signal);
@@ -246,7 +252,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
return RTLIL::SigSpec(result_wire);
}
-void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode)
+void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode)
{
log_assert(last_mux_cell != NULL);
log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size());
@@ -254,7 +260,7 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve
if (when_signal == last_mux_cell->getPort("\\A"))
return;
- RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode);
+ RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, cs, ifxmode);
log_assert(ctrl_sig.size() == 1);
last_mux_cell->type = "$pmux";
@@ -395,9 +401,9 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
RTLIL::CaseRule *cs2 = sw->cases[case_idx];
RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val, ifxmode);
if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1])
- append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode);
+ append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, cs2, ifxmode);
else
- result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode);
+ result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, cs2, ifxmode);
}
}
diff --git a/passes/proc/proc_prune.cc b/passes/proc/proc_prune.cc
new file mode 100644
index 000000000..d4aee9df0
--- /dev/null
+++ b/passes/proc/proc_prune.cc
@@ -0,0 +1,165 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2019 whitequark <whitequark@whitequark.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct PruneWorker
+{
+ RTLIL::Module *module;
+ SigMap sigmap;
+
+ int removed_count = 0, promoted_count = 0;
+
+ PruneWorker(RTLIL::Module *mod) : module(mod), sigmap(mod) {}
+
+ pool<RTLIL::SigBit> do_switch(RTLIL::SwitchRule *sw, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected)
+ {
+ pool<RTLIL::SigBit> all_assigned;
+ bool full_case = sw->get_bool_attribute("\\full_case");
+ bool first = true;
+ for (auto it : sw->cases) {
+ if (it->compare.empty())
+ full_case = true;
+ pool<RTLIL::SigBit> case_assigned = do_case(it, assigned, affected);
+ if (first) {
+ first = false;
+ all_assigned = case_assigned;
+ } else {
+ for (auto &bit : all_assigned)
+ if (!case_assigned[bit])
+ all_assigned.erase(bit);
+ }
+ }
+ if (full_case)
+ assigned.insert(all_assigned.begin(), all_assigned.end());
+ return assigned;
+ }
+
+ pool<RTLIL::SigBit> do_case(RTLIL::CaseRule *cs, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected,
+ bool root = false)
+ {
+ for (auto it = cs->switches.rbegin(); it != cs->switches.rend(); ++it) {
+ pool<RTLIL::SigBit> sw_assigned = do_switch((*it), assigned, affected);
+ assigned.insert(sw_assigned.begin(), sw_assigned.end());
+ }
+ for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ) {
+ RTLIL::SigSpec lhs = sigmap(it->first);
+ bool redundant = true;
+ for (auto &bit : lhs) {
+ if (bit.wire && !assigned[bit]) {
+ redundant = false;
+ break;
+ }
+ }
+ bool remove = false;
+ if (redundant) {
+ removed_count++;
+ remove = true;
+ } else {
+ if (root) {
+ bool promotable = true;
+ for (auto &bit : lhs) {
+ if (bit.wire && affected[bit] && !assigned[bit]) {
+ promotable = false;
+ break;
+ }
+ }
+ if (promotable) {
+ RTLIL::SigSpec rhs = sigmap(it->second);
+ RTLIL::SigSig conn;
+ for (int i = 0; i < GetSize(lhs); i++) {
+ RTLIL::SigBit lhs_bit = lhs[i];
+ if (lhs_bit.wire && !assigned[lhs_bit]) {
+ conn.first.append_bit(lhs_bit);
+ conn.second.append(rhs.extract(i));
+ }
+ }
+ promoted_count++;
+ module->connect(conn);
+ remove = true;
+ }
+ }
+ for (auto &bit : lhs)
+ if (bit.wire)
+ assigned.insert(bit);
+ for (auto &bit : lhs)
+ if (bit.wire)
+ affected.insert(bit);
+ }
+ if (remove)
+ cs->actions.erase((it++).base() - 1);
+ else it++;
+ }
+ return assigned;
+ }
+
+ void do_process(RTLIL::Process *pr)
+ {
+ pool<RTLIL::SigBit> affected;
+ do_case(&pr->root_case, {}, affected, /*root=*/true);
+ }
+};
+
+struct ProcPrunePass : public Pass {
+ ProcPrunePass() : Pass("proc_prune", "remove redundant assignments") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" proc_prune [selection]\n");
+ log("\n");
+ log("This pass identifies assignments in processes that are always overwritten by\n");
+ log("a later assignment to the same signal and removes them.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ int total_removed_count = 0, total_promoted_count = 0;
+ log_header(design, "Executing PROC_PRUNE pass (remove redundant assignments in processes).\n");
+
+ extra_args(args, 1, design);
+
+ for (auto mod : design->modules()) {
+ if (!design->selected(mod))
+ continue;
+ PruneWorker worker(mod);
+ for (auto &proc_it : mod->processes) {
+ if (!design->selected(mod, proc_it.second))
+ continue;
+ worker.do_process(proc_it.second);
+ }
+ total_removed_count += worker.removed_count;
+ total_promoted_count += worker.promoted_count;
+ }
+
+ log("Removed %d redundant assignment%s.\n",
+ total_removed_count, total_removed_count == 1 ? "" : "s");
+ log("Promoted %d assignment%s to connection%s.\n",
+ total_promoted_count, total_promoted_count == 1 ? "" : "s", total_promoted_count == 1 ? "" : "s");
+ }
+} ProcPrunePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc
index 509cb0ba9..3b432c461 100644
--- a/passes/sat/assertpmux.cc
+++ b/passes/sat/assertpmux.cc
@@ -180,7 +180,7 @@ struct AssertpmuxWorker
};
struct AssertpmuxPass : public Pass {
- AssertpmuxPass() : Pass("assertpmux", "convert internal signals to module ports") { }
+ AssertpmuxPass() : Pass("assertpmux", "adds asserts for parallel muxes") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@@ -195,8 +195,8 @@ struct AssertpmuxPass : public Pass {
log("\n");
log(" -always\n");
log(" usually the $pmux condition is only checked when the $pmux output\n");
- log(" is used be the mux tree it drives. this option will deactivate this\n");
- log(" additional constrained and check the $pmux condition always.\n");
+ log(" is used by the mux tree it drives. this option will deactivate this\n");
+ log(" additional constraint and check the $pmux condition always.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc
index 49ec795d3..4bb4aa047 100644
--- a/passes/sat/clk2fflogic.cc
+++ b/passes/sat/clk2fflogic.cc
@@ -253,6 +253,13 @@ struct Clk2fflogicPass : public Pass {
SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
Const rstval = cell->parameters["\\ARST_VALUE"];
+ Wire *past_arst = module->addWire(NEW_ID);
+ module->addFf(NEW_ID, arst, past_arst);
+ if (cell->parameters["\\ARST_POLARITY"].as_bool())
+ arst = module->LogicOr(NEW_ID, arst, past_arst);
+ else
+ arst = module->LogicAnd(NEW_ID, arst, past_arst);
+
if (cell->parameters["\\ARST_POLARITY"].as_bool())
module->addMux(NEW_ID, qval, rstval, arst, sig_q);
else
diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc
index 048aec7f3..b4549bc39 100644
--- a/passes/sat/cutpoint.cc
+++ b/passes/sat/cutpoint.cc
@@ -24,7 +24,7 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct CutpointPass : public Pass {
- CutpointPass() : Pass("cutpoint", "add hi/lo cover cells for each wire bit") { }
+ CutpointPass() : Pass("cutpoint", "adds formal cut points to the design") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index 008cd2dfa..e0bb439f4 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -47,8 +47,8 @@ struct BruteForceEquivChecker
{
if (inputs.size() < mod1_inputs.size()) {
RTLIL::SigSpec inputs0 = inputs, inputs1 = inputs;
- inputs0.append(RTLIL::Const(0, 1));
- inputs1.append(RTLIL::Const(1, 1));
+ inputs0.append(State::S0);
+ inputs1.append(State::S1);
run_checker(inputs0);
run_checker(inputs1);
return;
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index 71ce1683d..29dfc7b19 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -143,7 +143,7 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De
continue;
}
- if (info.cell->type == "$_DFF_N_" || info.cell->type == "$_DFF_P_") {
+ if (info.cell->type.in("$_DFF_N_", "$_DFF_P_")) {
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")).as_bit();
@@ -151,7 +151,7 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De
continue;
}
- if (info.cell->type.size() == 10 && info.cell->type.substr(0, 6) == "$_DFF_") {
+ if (info.cell->type.size() == 10 && info.cell->type.begins_with("$_DFF_")) {
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';
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index 1a886af70..49ef40061 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -59,7 +59,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
}
break;
}
- if (argidx+3 != args.size() || args[argidx].substr(0, 1) == "-")
+ if (argidx+3 != args.size() || args[argidx].compare(0, 1, "-") == 0)
that->cmd_error(args, argidx, "command argument error");
RTLIL::IdString gold_name = RTLIL::escape_id(args[argidx++]);
@@ -236,7 +236,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
if (flag_make_assert) {
RTLIL::Cell *assert_cell = miter_module->addCell(NEW_ID, "$assert");
assert_cell->setPort("\\A", all_conditions);
- assert_cell->setPort("\\EN", RTLIL::SigSpec(1, 1));
+ assert_cell->setPort("\\EN", State::S1);
}
RTLIL::Wire *w_trigger = miter_module->addWire("\\trigger");
@@ -279,7 +279,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
}
break;
}
- if ((argidx+1 != args.size() && argidx+2 != args.size()) || args[argidx].substr(0, 1) == "-")
+ if ((argidx+1 != args.size() && argidx+2 != args.size()) || args[argidx].compare(0, 1, "-") == 0)
that->cmd_error(args, argidx, "command argument error");
IdString module_name = RTLIL::escape_id(args[argidx++]);
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index cbba738f0..dd56d8c71 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -519,7 +519,7 @@ struct SatHelper
for (auto &p : d->connections()) {
if (d->type == "$dff" && p.first == "\\CLK")
continue;
- if (d->type.substr(0, 6) == "$_DFF_" && p.first == "\\C")
+ if (d->type.begins_with("$_DFF_") && p.first == "\\C")
continue;
queued_signals.add(handled_signals.remove(sigmap(p.second)));
}
@@ -659,6 +659,7 @@ struct SatHelper
void dump_model_to_vcd(std::string vcd_file_name)
{
+ rewrite_filename(vcd_file_name);
FILE *f = fopen(vcd_file_name.c_str(), "w");
if (!f)
log_cmd_error("Can't open output file `%s' for writing: %s\n", vcd_file_name.c_str(), strerror(errno));
@@ -761,6 +762,7 @@ struct SatHelper
void dump_model_to_json(std::string json_file_name)
{
+ rewrite_filename(json_file_name);
FILE *f = fopen(json_file_name.c_str(), "w");
if (!f)
log_cmd_error("Can't open output file `%s' for writing: %s\n", json_file_name.c_str(), strerror(errno));
@@ -795,7 +797,7 @@ struct SatHelper
vector<string> data;
string name = wd.first.c_str();
- while (name.substr(0, 1) == "\\")
+ while (name.compare(0, 1, "\\") == 0)
name = name.substr(1);
fprintf(f, " { \"name\": \"%s\", \"wave\": \"", name.c_str());
@@ -1351,7 +1353,7 @@ struct SatPass : public Pass {
if (show_regs) {
pool<Wire*> reg_wires;
for (auto cell : module->cells()) {
- if (cell->type == "$dff" || cell->type.substr(0, 6) == "$_DFF_")
+ if (cell->type == "$dff" || cell->type.begins_with("$_DFF_"))
for (auto bit : cell->getPort("\\Q"))
if (bit.wire)
reg_wires.insert(bit.wire);
@@ -1505,6 +1507,7 @@ struct SatPass : public Pass {
{
if (!cnf_file_name.empty())
{
+ rewrite_filename(cnf_file_name);
FILE *f = fopen(cnf_file_name.c_str(), "w");
if (!f)
log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
@@ -1608,6 +1611,7 @@ struct SatPass : public Pass {
if (!cnf_file_name.empty())
{
+ rewrite_filename(cnf_file_name);
FILE *f = fopen(cnf_file_name.c_str(), "w");
if (!f)
log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index cf9e198ad..56f05eca4 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -7,8 +7,10 @@ OBJS += passes/techmap/libparse.o
ifeq ($(ENABLE_ABC),1)
OBJS += passes/techmap/abc.o
+OBJS += passes/techmap/abc9.o
ifneq ($(ABCEXTERNAL),)
passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
+passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
endif
endif
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 5b19d84fb..b29480e26 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -49,6 +49,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <cctype>
#include <cerrno>
#include <sstream>
#include <climits>
@@ -81,6 +82,7 @@ enum class gate_type_t {
G_ANDNOT,
G_ORNOT,
G_MUX,
+ G_NMUX,
G_AOI3,
G_OAI3,
G_AOI4,
@@ -111,7 +113,7 @@ std::vector<gate_t> signal_list;
std::map<RTLIL::SigBit, int> signal_map;
std::map<RTLIL::SigBit, RTLIL::State> signal_init;
pool<std::string> enabled_gates;
-bool recover_init;
+bool recover_init, cmos_cost;
bool clk_polarity, en_polarity;
RTLIL::SigSpec clk_sig, en_sig;
@@ -164,39 +166,39 @@ void mark_port(RTLIL::SigSpec sig)
void extract_cell(RTLIL::Cell *cell, bool keepff)
{
- if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
{
- if (clk_polarity != (cell->type == "$_DFF_P_"))
+ if (clk_polarity != (cell->type == ID($_DFF_P_)))
return;
- if (clk_sig != assign_map(cell->getPort("\\C")))
+ if (clk_sig != assign_map(cell->getPort(ID(C))))
return;
if (GetSize(en_sig) != 0)
return;
goto matching_dff;
}
- if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+ if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
{
- if (clk_polarity != (cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_"))
+ if (clk_polarity != cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)))
return;
- if (en_polarity != (cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_"))
+ if (en_polarity != cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
return;
- if (clk_sig != assign_map(cell->getPort("\\C")))
+ if (clk_sig != assign_map(cell->getPort(ID(C))))
return;
- if (en_sig != assign_map(cell->getPort("\\E")))
+ if (en_sig != assign_map(cell->getPort(ID(E))))
return;
goto matching_dff;
}
if (0) {
matching_dff:
- RTLIL::SigSpec sig_d = cell->getPort("\\D");
- RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+ RTLIL::SigSpec sig_d = cell->getPort(ID(D));
+ RTLIL::SigSpec sig_q = cell->getPort(ID(Q));
if (keepff)
for (auto &c : sig_q.chunks())
if (c.wire != NULL)
- c.wire->attributes["\\keep"] = 1;
+ c.wire->attributes[ID::keep] = 1;
assign_map.apply(sig_d);
assign_map.apply(sig_q);
@@ -207,25 +209,25 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
return;
}
- if (cell->type.in("$_BUF_", "$_NOT_"))
+ if (cell->type.in(ID($_BUF_), ID($_NOT_)))
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
assign_map.apply(sig_a);
assign_map.apply(sig_y);
- map_signal(sig_y, cell->type == "$_BUF_" ? G(BUF) : G(NOT), map_signal(sig_a));
+ map_signal(sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(sig_a));
module->remove(cell);
return;
}
- if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
+ if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_)))
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_b = cell->getPort("\\B");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
assign_map.apply(sig_a);
assign_map.apply(sig_b);
@@ -234,21 +236,21 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
int mapped_a = map_signal(sig_a);
int mapped_b = map_signal(sig_b);
- if (cell->type == "$_AND_")
+ if (cell->type == ID($_AND_))
map_signal(sig_y, G(AND), mapped_a, mapped_b);
- else if (cell->type == "$_NAND_")
+ else if (cell->type == ID($_NAND_))
map_signal(sig_y, G(NAND), mapped_a, mapped_b);
- else if (cell->type == "$_OR_")
+ else if (cell->type == ID($_OR_))
map_signal(sig_y, G(OR), mapped_a, mapped_b);
- else if (cell->type == "$_NOR_")
+ else if (cell->type == ID($_NOR_))
map_signal(sig_y, G(NOR), mapped_a, mapped_b);
- else if (cell->type == "$_XOR_")
+ else if (cell->type == ID($_XOR_))
map_signal(sig_y, G(XOR), mapped_a, mapped_b);
- else if (cell->type == "$_XNOR_")
+ else if (cell->type == ID($_XNOR_))
map_signal(sig_y, G(XNOR), mapped_a, mapped_b);
- else if (cell->type == "$_ANDNOT_")
+ else if (cell->type == ID($_ANDNOT_))
map_signal(sig_y, G(ANDNOT), mapped_a, mapped_b);
- else if (cell->type == "$_ORNOT_")
+ else if (cell->type == ID($_ORNOT_))
map_signal(sig_y, G(ORNOT), mapped_a, mapped_b);
else
log_abort();
@@ -257,12 +259,12 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
return;
}
- if (cell->type == "$_MUX_")
+ if (cell->type.in(ID($_MUX_), ID($_NMUX_)))
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_b = cell->getPort("\\B");
- RTLIL::SigSpec sig_s = cell->getPort("\\S");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+ RTLIL::SigSpec sig_s = cell->getPort(ID(S));
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
assign_map.apply(sig_a);
assign_map.apply(sig_b);
@@ -273,18 +275,18 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
int mapped_b = map_signal(sig_b);
int mapped_s = map_signal(sig_s);
- map_signal(sig_y, G(MUX), mapped_a, mapped_b, mapped_s);
+ map_signal(sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s);
module->remove(cell);
return;
}
- if (cell->type.in("$_AOI3_", "$_OAI3_"))
+ if (cell->type.in(ID($_AOI3_), ID($_OAI3_)))
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_b = cell->getPort("\\B");
- RTLIL::SigSpec sig_c = cell->getPort("\\C");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+ RTLIL::SigSpec sig_c = cell->getPort(ID(C));
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
assign_map.apply(sig_a);
assign_map.apply(sig_b);
@@ -295,19 +297,19 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
int mapped_b = map_signal(sig_b);
int mapped_c = map_signal(sig_c);
- map_signal(sig_y, cell->type == "$_AOI3_" ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c);
+ map_signal(sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c);
module->remove(cell);
return;
}
- if (cell->type.in("$_AOI4_", "$_OAI4_"))
+ if (cell->type.in(ID($_AOI4_), ID($_OAI4_)))
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_b = cell->getPort("\\B");
- RTLIL::SigSpec sig_c = cell->getPort("\\C");
- RTLIL::SigSpec sig_d = cell->getPort("\\D");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+ RTLIL::SigSpec sig_c = cell->getPort(ID(C));
+ RTLIL::SigSpec sig_d = cell->getPort(ID(D));
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
assign_map.apply(sig_a);
assign_map.apply(sig_b);
@@ -320,7 +322,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
int mapped_c = map_signal(sig_c);
int mapped_d = map_signal(sig_d);
- map_signal(sig_y, cell->type == "$_AOI4_" ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d);
+ map_signal(sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d);
module->remove(cell);
return;
@@ -331,17 +333,17 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp
{
std::string abc_sname = abc_name.substr(1);
bool isnew = false;
- if (abc_sname.substr(0, 4) == "new_")
+ if (abc_sname.compare(0, 4, "new_") == 0)
{
abc_sname.erase(0, 4);
isnew = true;
}
- if (abc_sname.substr(0, 5) == "ys__n")
+ if (abc_sname.compare(0, 5, "ys__n") == 0)
{
abc_sname.erase(0, 5);
if (std::isdigit(abc_sname.at(0)))
{
- int sid = std::stoi(abc_sname);
+ int sid = std::atoi(abc_sname.c_str());
size_t postfix_start = abc_sname.find_first_not_of("0123456789");
std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : "";
@@ -350,23 +352,20 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp
auto sig = signal_list.at(sid);
if (sig.bit.wire != nullptr)
{
- std::stringstream sstr;
- sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
+ std::string s = stringf("$abc$%d$%s", map_autoidx, sig.bit.wire->name.c_str()+1);
if (sig.bit.wire->width != 1)
- sstr << "[" << sig.bit.offset << "]";
+ s += stringf("[%d]", sig.bit.offset);
if (isnew)
- sstr << "_new";
- sstr << postfix;
+ s += "_new";
+ s += postfix;
if (orig_wire != nullptr)
*orig_wire = sig.bit.wire;
- return sstr.str();
+ return s;
}
}
}
}
- std::stringstream sstr;
- sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
- return sstr.str();
+ return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1);
}
void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std::set<int> &workpool, std::vector<int> &in_counts)
@@ -788,7 +787,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
extract_cell(c, keepff);
for (auto &wire_it : module->wires_) {
- if (wire_it.second->port_id > 0 || wire_it.second->get_bool_attribute("\\keep"))
+ if (wire_it.second->port_id > 0 || wire_it.second->get_bool_attribute(ID::keep))
mark_port(RTLIL::SigSpec(wire_it.second));
}
@@ -885,6 +884,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
fprintf(f, "1-0 1\n");
fprintf(f, "-11 1\n");
+ } else if (si.type == G(NMUX)) {
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
+ fprintf(f, "0-0 1\n");
+ fprintf(f, "-01 1\n");
} else if (si.type == G(AOI3)) {
fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
fprintf(f, "-00 1\n");
@@ -925,46 +928,50 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
{
log_header(design, "Executing ABC.\n");
+ auto &cell_cost = cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost();
+
buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt");
if (f == NULL)
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
fprintf(f, "GATE ONE 1 Y=CONST1;\n");
- fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
- fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
- if (enabled_gates.empty() || enabled_gates.count("AND"))
- fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
- if (enabled_gates.empty() || enabled_gates.count("NAND"))
- fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
- if (enabled_gates.empty() || enabled_gates.count("OR"))
- fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
- if (enabled_gates.empty() || enabled_gates.count("NOR"))
- fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
- if (enabled_gates.empty() || enabled_gates.count("XOR"))
- fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
- if (enabled_gates.empty() || enabled_gates.count("XNOR"))
- fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
- if (enabled_gates.empty() || enabled_gates.count("ANDNOT"))
- fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ANDNOT_"));
- if (enabled_gates.empty() || enabled_gates.count("ORNOT"))
- fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ORNOT_"));
- if (enabled_gates.empty() || enabled_gates.count("AOI3"))
- fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
- if (enabled_gates.empty() || enabled_gates.count("OAI3"))
- fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
- if (enabled_gates.empty() || enabled_gates.count("AOI4"))
- fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
- if (enabled_gates.empty() || enabled_gates.count("OAI4"))
- fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
- if (enabled_gates.empty() || enabled_gates.count("MUX"))
- fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_BUF_)));
+ fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NOT_)));
+ if (enabled_gates.count("AND"))
+ fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_AND_)));
+ if (enabled_gates.count("NAND"))
+ fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NAND_)));
+ if (enabled_gates.count("OR"))
+ fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_OR_)));
+ if (enabled_gates.count("NOR"))
+ fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NOR_)));
+ if (enabled_gates.count("XOR"))
+ fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_XOR_)));
+ if (enabled_gates.count("XNOR"))
+ fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_XNOR_)));
+ if (enabled_gates.count("ANDNOT"))
+ fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_ANDNOT_)));
+ if (enabled_gates.count("ORNOT"))
+ fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_ORNOT_)));
+ if (enabled_gates.count("AOI3"))
+ fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_AOI3_)));
+ if (enabled_gates.count("OAI3"))
+ fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_OAI3_)));
+ if (enabled_gates.count("AOI4"))
+ fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_AOI4_)));
+ if (enabled_gates.count("OAI4"))
+ fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_OAI4_)));
+ if (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", cell_cost.at(ID($_MUX_)));
+ if (enabled_gates.count("NMUX"))
+ fprintf(f, "GATE NMUX %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_NMUX_)));
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_"));
+ 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*cell_cost.at(ID($_MUX_)));
if (map_mux8)
- fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost.at(ID($_MUX_)));
if (map_mux16)
- fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_"));
+ 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*cell_cost.at(ID($_MUX_)));
fclose(f);
if (!lut_costs.empty()) {
@@ -1009,21 +1016,21 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
bool builtin_lib = liberty_file.empty();
RTLIL::Design *mapped_design = new RTLIL::Design;
- parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_", false, sop_mode);
+ parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode);
ifs.close();
log_header(design, "Re-integrating ABC results.\n");
- RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"];
+ RTLIL::Module *mapped_mod = mapped_design->modules_[ID(netlist)];
if (mapped_mod == NULL)
log_error("ABC output file does not contain a module `netlist'.\n");
for (auto &it : mapped_mod->wires_) {
RTLIL::Wire *w = it.second;
RTLIL::Wire *orig_wire = nullptr;
RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire));
- if (orig_wire != nullptr && orig_wire->attributes.count("\\src"))
- wire->attributes["\\src"] = orig_wire->attributes["\\src"];
- if (markgroups) wire->attributes["\\abcgroup"] = map_autoidx;
+ if (orig_wire != nullptr && orig_wire->attributes.count(ID(src)))
+ wire->attributes[ID(src)] = orig_wire->attributes[ID(src)];
+ if (markgroups) wire->attributes[ID(abcgroup)] = map_autoidx;
design->select(module, wire);
}
@@ -1033,183 +1040,182 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (builtin_lib)
{
cell_stats[RTLIL::unescape_id(c->type)]++;
- if (c->type == "\\ZERO" || c->type == "\\ONE") {
+ if (c->type.in(ID(ZERO), ID(ONE))) {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]);
- conn.second = RTLIL::SigSpec(c->type == "\\ZERO" ? 0 : 1, 1);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]);
+ conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1);
module->connect(conn);
continue;
}
- if (c->type == "\\BUF") {
+ if (c->type == ID(BUF)) {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]);
- conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]);
+ conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]);
module->connect(conn);
continue;
}
- if (c->type == "\\NOT") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_NOT_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ if (c->type == ID(NOT)) {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_));
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+ cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
design->select(module, cell);
continue;
}
- if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" ||
- c->type == "\\XNOR" || c->type == "\\ANDNOT" || c->type == "\\ORNOT") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+ cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
+ cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
design->select(module, cell);
continue;
}
- if (c->type == "\\MUX") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ if (c->type.in(ID(MUX), ID(NMUX))) {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+ cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
+ cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)]));
+ cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
design->select(module, cell);
continue;
}
- if (c->type == "\\MUX4") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX4_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
- cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ if (c->type == ID(MUX4)) {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_));
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+ cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
+ cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
+ cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
+ cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)]));
+ cell->setPort(ID(T), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(T)).as_wire()->name)]));
+ cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
design->select(module, cell);
continue;
}
- if (c->type == "\\MUX8") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX8_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\E", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\E").as_wire()->name)]));
- cell->setPort("\\F", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\F").as_wire()->name)]));
- cell->setPort("\\G", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\G").as_wire()->name)]));
- cell->setPort("\\H", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\H").as_wire()->name)]));
- cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
- cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)]));
- cell->setPort("\\U", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\U").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ if (c->type == ID(MUX8)) {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_));
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+ cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
+ cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
+ cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
+ cell->setPort(ID(E), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(E)).as_wire()->name)]));
+ cell->setPort(ID(F), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(F)).as_wire()->name)]));
+ cell->setPort(ID(G), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(G)).as_wire()->name)]));
+ cell->setPort(ID(H), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(H)).as_wire()->name)]));
+ cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)]));
+ cell->setPort(ID(T), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(T)).as_wire()->name)]));
+ cell->setPort(ID(U), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(U)).as_wire()->name)]));
+ cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
design->select(module, cell);
continue;
}
- if (c->type == "\\MUX16") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX16_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\E", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\E").as_wire()->name)]));
- cell->setPort("\\F", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\F").as_wire()->name)]));
- cell->setPort("\\G", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\G").as_wire()->name)]));
- cell->setPort("\\H", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\H").as_wire()->name)]));
- cell->setPort("\\I", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\I").as_wire()->name)]));
- cell->setPort("\\J", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\J").as_wire()->name)]));
- cell->setPort("\\K", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\K").as_wire()->name)]));
- cell->setPort("\\L", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\L").as_wire()->name)]));
- cell->setPort("\\M", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\M").as_wire()->name)]));
- cell->setPort("\\N", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\N").as_wire()->name)]));
- cell->setPort("\\O", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\O").as_wire()->name)]));
- cell->setPort("\\P", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\P").as_wire()->name)]));
- cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
- cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)]));
- cell->setPort("\\U", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\U").as_wire()->name)]));
- cell->setPort("\\V", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\V").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ if (c->type == ID(MUX16)) {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_));
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+ cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
+ cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
+ cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
+ cell->setPort(ID(E), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(E)).as_wire()->name)]));
+ cell->setPort(ID(F), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(F)).as_wire()->name)]));
+ cell->setPort(ID(G), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(G)).as_wire()->name)]));
+ cell->setPort(ID(H), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(H)).as_wire()->name)]));
+ cell->setPort(ID(I), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(I)).as_wire()->name)]));
+ cell->setPort(ID(J), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(J)).as_wire()->name)]));
+ cell->setPort(ID(K), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(K)).as_wire()->name)]));
+ cell->setPort(ID(L), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(L)).as_wire()->name)]));
+ cell->setPort(ID(M), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(M)).as_wire()->name)]));
+ cell->setPort(ID(N), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(N)).as_wire()->name)]));
+ cell->setPort(ID(O), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(O)).as_wire()->name)]));
+ cell->setPort(ID(P), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(P)).as_wire()->name)]));
+ cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)]));
+ cell->setPort(ID(T), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(T)).as_wire()->name)]));
+ cell->setPort(ID(U), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(U)).as_wire()->name)]));
+ cell->setPort(ID(V), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(V)).as_wire()->name)]));
+ cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
design->select(module, cell);
continue;
}
- if (c->type == "\\AOI3" || c->type == "\\OAI3") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ if (c->type.in(ID(AOI3), ID(OAI3))) {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+ cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
+ cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
+ cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
design->select(module, cell);
continue;
}
- if (c->type == "\\AOI4" || c->type == "\\OAI4") {
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
- cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
- cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ if (c->type.in(ID(AOI4), ID(OAI4))) {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
+ cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
+ cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)]));
+ cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
+ cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
design->select(module, cell);
continue;
}
- if (c->type == "\\DFF") {
+ if (c->type == ID(DFF)) {
log_assert(clk_sig.size() == 1);
RTLIL::Cell *cell;
if (en_sig.size() == 0) {
- cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_));
} else {
log_assert(en_sig.size() == 1);
cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
- cell->setPort("\\E", en_sig);
+ cell->setPort(ID(E), en_sig);
}
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
- cell->setPort("\\C", clk_sig);
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
+ cell->setPort(ID(Q), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Q)).as_wire()->name)]));
+ cell->setPort(ID(C), clk_sig);
design->select(module, cell);
continue;
}
}
+ else
+ cell_stats[RTLIL::unescape_id(c->type)]++;
- cell_stats[RTLIL::unescape_id(c->type)]++;
-
- if (c->type == "\\_const0_" || c->type == "\\_const1_") {
+ if (c->type.in(ID(_const0_), ID(_const1_))) {
RTLIL::SigSig conn;
conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]);
- conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1);
+ conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1);
module->connect(conn);
continue;
}
- if (c->type == "\\_dff_") {
+ if (c->type == ID(_dff_)) {
log_assert(clk_sig.size() == 1);
RTLIL::Cell *cell;
if (en_sig.size() == 0) {
- cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_));
} else {
log_assert(en_sig.size() == 1);
cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
- cell->setPort("\\E", en_sig);
+ cell->setPort(ID(E), en_sig);
}
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
- cell->setPort("\\C", clk_sig);
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)]));
+ cell->setPort(ID(Q), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Q)).as_wire()->name)]));
+ cell->setPort(ID(C), clk_sig);
design->select(module, cell);
continue;
}
- if (c->type == "$lut" && GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
- SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
- SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
+ if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)).as_int() == 2) {
+ SigSpec my_a = module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)];
+ SigSpec my_y = module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)];
module->connect(my_y, my_a);
continue;
}
RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
cell->parameters = c->parameters;
for (auto &conn : c->connections()) {
RTLIL::SigSpec newsig;
@@ -1234,10 +1240,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (recover_init)
for (auto wire : mapped_mod->wires()) {
- if (wire->attributes.count("\\init")) {
+ if (wire->attributes.count(ID(init))) {
Wire *w = module->wires_[remap_name(wire->name)];
- log_assert(w->attributes.count("\\init") == 0);
- w->attributes["\\init"] = wire->attributes.at("\\init");
+ log_assert(w->attributes.count(ID(init)) == 0);
+ w->attributes[ID(init)] = wire->attributes.at(ID(init));
}
}
@@ -1401,20 +1407,27 @@ struct AbcPass : public Pass {
// log("\n");
log(" -g type1,type2,...\n");
log(" Map to the specified list of gate types. Supported gates types are:\n");
- log(" AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4.\n");
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log(" AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX,\n");
+ log(" NMUX, AOI3, OAI3, AOI4, OAI4.\n");
log(" (The NOT gate is always added to this list automatically.)\n");
log("\n");
log(" The following aliases can be used to reference common sets of gate types:\n");
log(" simple: AND OR XOR MUX\n");
- log(" cmos2: NAND NOR\n");
- log(" cmos3: NAND NOR AOI3 OAI3\n");
- log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n");
- log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n");
- log(" aig: AND NAND OR NOR ANDNOT ORNOT\n");
+ log(" cmos2: NAND NOR\n");
+ log(" cmos3: NAND NOR AOI3 OAI3\n");
+ log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n");
+ log(" cmos: NAND NOR AOI3 OAI3 AOI4 OAI4 NMUX MUX XOR XNOR\n");
+ log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n");
+ log(" aig: AND NAND OR NOR ANDNOT ORNOT\n");
+ log("\n");
+ log(" The alias 'all' represent the full set of all gate types.\n");
log("\n");
log(" Prefix a gate type with a '-' to remove it from the list. For example\n");
log(" the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.\n");
log("\n");
+ log(" The default is 'all,-NMUX,-AOI3,-OAI3,-AOI4,-OAI4'.\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");
@@ -1453,7 +1466,7 @@ struct AbcPass : public Pass {
log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
log("ABC on logic snippets extracted from your design. You will not get any useful\n");
log("output when passing an ABC script that writes a file. Instead write your full\n");
- log("design as BLIF file with write_blif and the load that into ABC externally if\n");
+ log("design as BLIF file with write_blif and then load that into ABC externally if\n");
log("you want to use ABC to convert your design into another format.\n");
log("\n");
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
@@ -1488,6 +1501,7 @@ struct AbcPass : public Pass {
map_mux8 = false;
map_mux16 = false;
enabled_gates.clear();
+ cmos_cost = false;
#ifdef _WIN32
#ifndef ABCEXTERNAL
@@ -1572,7 +1586,7 @@ struct AbcPass : public Pass {
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()))
+ while (GetSize(lut_costs) < std::atoi(parts.at(0).c_str()))
lut_costs.push_back(atoi(parts.at(1).c_str()));
else
log_cmd_error("Invalid -luts syntax.\n");
@@ -1616,6 +1630,7 @@ struct AbcPass : public Pass {
if (g == "ANDNOT") goto ok_gate;
if (g == "ORNOT") goto ok_gate;
if (g == "MUX") goto ok_gate;
+ if (g == "NMUX") goto ok_gate;
if (g == "AOI3") goto ok_gate;
if (g == "OAI3") goto ok_gate;
if (g == "AOI4") goto ok_gate;
@@ -1628,11 +1643,15 @@ struct AbcPass : public Pass {
goto ok_alias;
}
if (g == "cmos2") {
+ if (!remove_gates)
+ cmos_cost = true;
gate_list.push_back("NAND");
gate_list.push_back("NOR");
goto ok_alias;
}
if (g == "cmos3") {
+ if (!remove_gates)
+ cmos_cost = true;
gate_list.push_back("NAND");
gate_list.push_back("NOR");
gate_list.push_back("AOI3");
@@ -1640,6 +1659,8 @@ struct AbcPass : public Pass {
goto ok_alias;
}
if (g == "cmos4") {
+ if (!remove_gates)
+ cmos_cost = true;
gate_list.push_back("NAND");
gate_list.push_back("NOR");
gate_list.push_back("AOI3");
@@ -1648,6 +1669,21 @@ struct AbcPass : public Pass {
gate_list.push_back("OAI4");
goto ok_alias;
}
+ if (g == "cmos") {
+ if (!remove_gates)
+ cmos_cost = true;
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ gate_list.push_back("AOI4");
+ gate_list.push_back("OAI4");
+ gate_list.push_back("NMUX");
+ gate_list.push_back("MUX");
+ gate_list.push_back("XOR");
+ gate_list.push_back("XNOR");
+ goto ok_alias;
+ }
if (g == "gates") {
gate_list.push_back("AND");
gate_list.push_back("NAND");
@@ -1668,6 +1704,22 @@ struct AbcPass : public Pass {
gate_list.push_back("ORNOT");
goto ok_alias;
}
+ if (g == "all") {
+ gate_list.push_back("AND");
+ gate_list.push_back("NAND");
+ gate_list.push_back("OR");
+ gate_list.push_back("NOR");
+ gate_list.push_back("XOR");
+ gate_list.push_back("XNOR");
+ gate_list.push_back("ANDNOT");
+ gate_list.push_back("ORNOT");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ gate_list.push_back("AOI4");
+ gate_list.push_back("OAI4");
+ gate_list.push_back("MUX");
+ gate_list.push_back("NMUX");
+ }
cmd_error(args, argidx, stringf("Unsupported gate type: %s", g.c_str()));
ok_gate:
gate_list.push_back(g);
@@ -1719,6 +1771,23 @@ struct AbcPass : public Pass {
if (!constr_file.empty() && liberty_file.empty())
log_cmd_error("Got -constr but no -liberty!\n");
+ if (enabled_gates.empty()) {
+ enabled_gates.insert("AND");
+ enabled_gates.insert("NAND");
+ enabled_gates.insert("OR");
+ enabled_gates.insert("NOR");
+ enabled_gates.insert("XOR");
+ enabled_gates.insert("XNOR");
+ enabled_gates.insert("ANDNOT");
+ enabled_gates.insert("ORNOT");
+ // enabled_gates.insert("AOI3");
+ // enabled_gates.insert("OAI3");
+ // enabled_gates.insert("AOI4");
+ // enabled_gates.insert("OAI4");
+ enabled_gates.insert("MUX");
+ // enabled_gates.insert("NMUX");
+ }
+
for (auto mod : design->selected_modules())
{
if (mod->processes.size() > 0) {
@@ -1730,9 +1799,9 @@ struct AbcPass : public Pass {
signal_init.clear();
for (Wire *wire : mod->wires())
- if (wire->attributes.count("\\init")) {
+ if (wire->attributes.count(ID(init))) {
SigSpec initsig = assign_map(wire);
- Const initval = wire->attributes.at("\\init");
+ Const initval = wire->attributes.at(ID(init));
for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
switch (initval[i]) {
case State::S0:
@@ -1789,16 +1858,16 @@ struct AbcPass : public Pass {
}
}
- if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
{
- key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec());
+ key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec());
}
else
- if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+ if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
{
- bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_";
- bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_";
- key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E")));
+ bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_));
+ bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_));
+ key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E))));
}
else
continue;
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
new file mode 100644
index 000000000..84cb2c04f
--- /dev/null
+++ b/passes/techmap/abc9.cc
@@ -0,0 +1,1310 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// [[CITE]] ABC
+// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
+// http://www.eecs.berkeley.edu/~alanmi/abc/
+
+#if 0
+// Based on &flow3 - better QoR but more experimental
+#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \
+ "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\
+ "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\
+ "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\
+ "&mfs; &ps -l"
+#else
+#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l"
+#endif
+
+
+#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}"
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/cost.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <cerrno>
+#include <sstream>
+#include <climits>
+
+#ifndef _WIN32
+# include <unistd.h>
+# include <dirent.h>
+#endif
+
+#include "frontends/aiger/aigerparse.h"
+#include "kernel/utils.h"
+
+#ifdef YOSYS_LINK_ABC
+extern "C" int Abc_RealMain(int argc, char *argv[]);
+#endif
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool markgroups;
+int map_autoidx;
+SigMap assign_map;
+RTLIL::Module *module;
+
+bool clk_polarity, en_polarity;
+RTLIL::SigSpec clk_sig, en_sig;
+
+inline std::string remap_name(RTLIL::IdString abc_name)
+{
+ return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1);
+}
+
+void handle_loops(RTLIL::Design *design,
+ const dict<IdString,pool<IdString>> &scc_break_inputs)
+{
+ Pass::call(design, "scc -set_attr abc_scc_id {}");
+
+ // For every unique SCC found, (arbitrarily) find the first
+ // cell in the component, and select (and mark) all its output
+ // wires
+ pool<RTLIL::Const> ids_seen;
+ for (auto cell : module->cells()) {
+ auto it = cell->attributes.find(ID(abc_scc_id));
+ if (it != cell->attributes.end()) {
+ auto r = ids_seen.insert(it->second);
+ if (r.second) {
+ for (auto &c : cell->connections_) {
+ if (c.second.is_fully_const()) continue;
+ if (cell->output(c.first)) {
+ SigBit b = c.second.as_bit();
+ Wire *w = b.wire;
+ log_assert(!w->port_input);
+ w->port_input = true;
+ w = module->wire(stringf("%s.abci", w->name.c_str()));
+ if (!w) {
+ w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire));
+ w->port_output = true;
+ }
+ else {
+ log_assert(w->port_input);
+ log_assert(b.offset < GetSize(w));
+ }
+ w->set_bool_attribute(ID(abc_scc_break));
+ module->swap_names(b.wire, w);
+ c.second = RTLIL::SigBit(w, b.offset);
+ }
+ }
+ }
+ cell->attributes.erase(it);
+ }
+
+ auto jt = scc_break_inputs.find(cell->type);
+ if (jt != scc_break_inputs.end())
+ for (auto port_name : jt->second) {
+ RTLIL::SigSpec sig;
+ auto &rhs = cell->connections_.at(port_name);
+ for (auto b : rhs) {
+ Wire *w = b.wire;
+ if (!w) continue;
+ w->port_output = true;
+ w->set_bool_attribute(ID(abc_scc_break));
+ w = module->wire(stringf("%s.abci", w->name.c_str()));
+ if (!w) {
+ w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire));
+ w->port_input = true;
+ }
+ else {
+ log_assert(b.offset < GetSize(w));
+ log_assert(w->port_input);
+ }
+ sig.append(RTLIL::SigBit(w, b.offset));
+ }
+ rhs = sig;
+ }
+ }
+
+ module->fixup_ports();
+}
+
+std::string add_echos_to_abc_cmd(std::string str)
+{
+ std::string new_str, token;
+ for (size_t i = 0; i < str.size(); i++) {
+ token += str[i];
+ if (str[i] == ';') {
+ while (i+1 < str.size() && str[i+1] == ' ')
+ i++;
+ new_str += "echo + " + token + " " + token + " ";
+ token.clear();
+ }
+ }
+
+ if (!token.empty()) {
+ if (!new_str.empty())
+ new_str += "echo + " + token + "; ";
+ new_str += token;
+ }
+
+ return new_str;
+}
+
+std::string fold_abc_cmd(std::string str)
+{
+ std::string token, new_str = " ";
+ int char_counter = 10;
+
+ for (size_t i = 0; i <= str.size(); i++) {
+ if (i < str.size())
+ token += str[i];
+ if (i == str.size() || str[i] == ';') {
+ if (char_counter + token.size() > 75)
+ new_str += "\n ", char_counter = 14;
+ new_str += token, char_counter += token.size();
+ token.clear();
+ }
+ }
+
+ return new_str;
+}
+
+std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir)
+{
+ if (show_tempdir)
+ return text;
+
+ while (1) {
+ size_t pos = text.find(tempdir_name);
+ if (pos == std::string::npos)
+ break;
+ text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(tempdir_name));
+ }
+
+ std::string selfdir_name = proc_self_dirname();
+ if (selfdir_name != "/") {
+ while (1) {
+ size_t pos = text.find(selfdir_name);
+ if (pos == std::string::npos)
+ break;
+ text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
+ }
+ }
+
+ return text;
+}
+
+struct abc_output_filter
+{
+ bool got_cr;
+ int escape_seq_state;
+ std::string linebuf;
+ std::string tempdir_name;
+ bool show_tempdir;
+
+ abc_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir)
+ {
+ got_cr = false;
+ escape_seq_state = 0;
+ }
+
+ void next_char(char ch)
+ {
+ if (escape_seq_state == 0 && ch == '\033') {
+ escape_seq_state = 1;
+ return;
+ }
+ if (escape_seq_state == 1) {
+ escape_seq_state = ch == '[' ? 2 : 0;
+ return;
+ }
+ if (escape_seq_state == 2) {
+ if ((ch < '0' || '9' < ch) && ch != ';')
+ escape_seq_state = 0;
+ return;
+ }
+ escape_seq_state = 0;
+ if (ch == '\r') {
+ got_cr = true;
+ return;
+ }
+ if (ch == '\n') {
+ log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str());
+ got_cr = false, linebuf.clear();
+ return;
+ }
+ if (got_cr)
+ got_cr = false, linebuf.clear();
+ linebuf += ch;
+ }
+
+ void next_line(const std::string &line)
+ {
+ //int pi, po;
+ //if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) {
+ // log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n",
+ // pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???",
+ // po, po_map.count(po) ? po_map.at(po).c_str() : "???");
+ // return;
+ //}
+
+ for (char ch : line)
+ next_char(ch);
+ }
+};
+
+void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
+ bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
+ bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
+ bool show_tempdir, std::string box_file, std::string lut_file,
+ std::string wire_delay, const dict<int,IdString> &box_lookup,
+ const dict<IdString,pool<IdString>> &scc_break_inputs
+)
+{
+ module = current_module;
+ map_autoidx = autoidx++;
+
+ if (clk_str != "$")
+ {
+ clk_polarity = true;
+ clk_sig = RTLIL::SigSpec();
+
+ en_polarity = true;
+ en_sig = RTLIL::SigSpec();
+ }
+
+ if (!clk_str.empty() && clk_str != "$")
+ {
+ if (clk_str.find(',') != std::string::npos) {
+ int pos = clk_str.find(',');
+ std::string en_str = clk_str.substr(pos+1);
+ clk_str = clk_str.substr(0, pos);
+ if (en_str[0] == '!') {
+ en_polarity = false;
+ en_str = en_str.substr(1);
+ }
+ if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
+ en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
+ }
+ if (clk_str[0] == '!') {
+ clk_polarity = false;
+ clk_str = clk_str.substr(1);
+ }
+ if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
+ clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
+ }
+
+ if (dff_mode && clk_sig.empty())
+ log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
+
+ std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
+ if (!cleanup)
+ tempdir_name[0] = tempdir_name[4] = '_';
+ tempdir_name = make_temp_dir(tempdir_name);
+ log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n",
+ module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
+
+ std::string abc_script;
+
+ if (!lut_costs.empty()) {
+ abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
+ if (!box_file.empty())
+ abc_script += stringf("read_box -v %s; ", box_file.c_str());
+ }
+ else
+ if (!lut_file.empty()) {
+ abc_script += stringf("read_lut %s; ", lut_file.c_str());
+ if (!box_file.empty())
+ abc_script += stringf("read_box -v %s; ", box_file.c_str());
+ }
+ else
+ log_abort();
+
+ abc_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());
+
+ if (!script_file.empty()) {
+ if (script_file[0] == '+') {
+ for (size_t i = 1; i < script_file.size(); i++)
+ if (script_file[i] == '\'')
+ abc_script += "'\\''";
+ else if (script_file[i] == ',')
+ abc_script += " ";
+ else
+ abc_script += script_file[i];
+ } else
+ abc_script += stringf("source %s", script_file.c_str());
+ } else if (!lut_costs.empty() || !lut_file.empty()) {
+ //bool all_luts_cost_same = true;
+ //for (int this_cost : lut_costs)
+ // if (this_cost != lut_costs.front())
+ // all_luts_cost_same = false;
+ abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
+ //if (all_luts_cost_same && !fast_mode)
+ // abc_script += "; lutpack {S}";
+ } else
+ log_abort();
+
+ //if (script_file.empty() && !delay_target.empty())
+ // for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
+ // abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
+
+ for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+ abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
+
+ //for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
+ // abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
+
+ for (size_t pos = abc_script.find("{W}"); pos != std::string::npos; pos = abc_script.find("{W}", pos))
+ abc_script = abc_script.substr(0, pos) + wire_delay + abc_script.substr(pos+3);
+
+ abc_script += stringf("; &write %s/output.aig", tempdir_name.c_str());
+ abc_script = add_echos_to_abc_cmd(abc_script);
+
+ for (size_t i = 0; i+1 < abc_script.size(); i++)
+ if (abc_script[i] == ';' && abc_script[i+1] == ' ')
+ abc_script[i+1] = '\n';
+
+ FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt");
+ fprintf(f, "%s\n", abc_script.c_str());
+ fclose(f);
+
+ if (dff_mode || !clk_str.empty())
+ {
+ if (clk_sig.size() == 0)
+ log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching");
+ else {
+ log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
+ if (en_sig.size() != 0)
+ log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
+ log("\n");
+ }
+ }
+
+ bool count_output = false;
+ for (auto port_name : module->ports) {
+ RTLIL::Wire *port_wire = module->wire(port_name);
+ log_assert(port_wire);
+ if (port_wire->port_output) {
+ count_output = true;
+ break;
+ }
+ }
+
+ log_push();
+
+ if (count_output)
+ {
+ design->selection_stack.emplace_back(false);
+ RTLIL::Selection& sel = design->selection_stack.back();
+ sel.select(module);
+
+ handle_loops(design, scc_break_inputs);
+
+ Pass::call(design, "aigmap");
+
+ //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
+ // count_gates, GetSize(signal_list), count_input, count_output);
+
+ Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
+
+ std::string buffer;
+ std::ifstream ifs;
+#if 0
+ buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig");
+ ifs.open(buffer);
+ if (ifs.fail())
+ log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
+ buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym");
+ log_assert(!design->module(ID($__abc9__)));
+ {
+ AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */);
+ reader.parse_xaiger();
+ }
+ ifs.close();
+ Pass::call(design, stringf("write_verilog -noexpr -norename"));
+ design->remove(design->module(ID($__abc9__)));
+#endif
+
+ design->selection_stack.pop_back();
+
+ // Now 'unexpose' those wires by undoing
+ // the expose operation -- remove them from PO/PI
+ // and re-connecting them back together
+ for (auto wire : module->wires()) {
+ auto it = wire->attributes.find(ID(abc_scc_break));
+ if (it != wire->attributes.end()) {
+ wire->attributes.erase(it);
+ log_assert(wire->port_output);
+ wire->port_output = false;
+ RTLIL::Wire *i_wire = module->wire(wire->name.str() + ".abci");
+ log_assert(i_wire);
+ log_assert(i_wire->port_input);
+ i_wire->port_input = false;
+ module->connect(i_wire, wire);
+ }
+ }
+ module->fixup_ports();
+
+ log_header(design, "Executing ABC9.\n");
+
+ 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 < GetSize(lut_costs); i++)
+ fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i));
+ fclose(f);
+ }
+
+ buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
+ log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
+
+#ifndef YOSYS_LINK_ABC
+ abc_output_filter filt(tempdir_name, show_tempdir);
+ int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
+#else
+ // These needs to be mutable, supposedly due to getopt
+ char *abc_argv[5];
+ string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str());
+ abc_argv[0] = strdup(exe_file.c_str());
+ abc_argv[1] = strdup("-s");
+ abc_argv[2] = strdup("-f");
+ abc_argv[3] = strdup(tmp_script_name.c_str());
+ abc_argv[4] = 0;
+ int ret = Abc_RealMain(4, abc_argv);
+ free(abc_argv[0]);
+ free(abc_argv[1]);
+ free(abc_argv[2]);
+ free(abc_argv[3]);
+#endif
+ if (ret != 0)
+ log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
+
+ buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig");
+ ifs.open(buffer);
+ if (ifs.fail())
+ log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
+
+ buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym");
+ log_assert(!design->module(ID($__abc9__)));
+
+ AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */);
+ reader.parse_xaiger(box_lookup);
+ ifs.close();
+
+#if 0
+ Pass::call(design, stringf("write_verilog -noexpr -norename"));
+#endif
+
+ log_header(design, "Re-integrating ABC9 results.\n");
+ RTLIL::Module *mapped_mod = design->module(ID($__abc9__));
+ if (mapped_mod == NULL)
+ log_error("ABC output file does not contain a module `$__abc9__'.\n");
+
+ pool<RTLIL::SigBit> output_bits;
+ for (auto &it : mapped_mod->wires_) {
+ RTLIL::Wire *w = it.second;
+ RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w));
+ if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx;
+ if (w->port_output) {
+ RTLIL::Wire *wire = module->wire(w->name);
+ log_assert(wire);
+ for (int i = 0; i < GetSize(w); i++)
+ output_bits.insert({wire, i});
+ }
+ }
+
+ for (auto &it : module->connections_) {
+ auto &signal = it.first;
+ auto bits = signal.bits();
+ for (auto &b : bits)
+ if (output_bits.count(b))
+ b = module->addWire(NEW_ID);
+ signal = std::move(bits);
+ }
+
+ dict<IdString, bool> abc_box;
+ vector<RTLIL::Cell*> boxes;
+ for (const auto &it : module->cells_) {
+ auto cell = it.second;
+ if (cell->type.in(ID($_AND_), ID($_NOT_))) {
+ module->remove(cell);
+ continue;
+ }
+ auto jt = abc_box.find(cell->type);
+ if (jt == abc_box.end()) {
+ RTLIL::Module* box_module = design->module(cell->type);
+ jt = abc_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc_box_id)))).first;
+ }
+ if (jt->second)
+ boxes.emplace_back(cell);
+ }
+
+ dict<SigBit, pool<IdString>> bit_drivers, bit_users;
+ TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
+ dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers;
+ dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
+
+ std::map<IdString, int> cell_stats;
+ for (auto c : mapped_mod->cells())
+ {
+ toposort.node(c->name);
+
+ RTLIL::Cell *cell = nullptr;
+ if (c->type == ID($_NOT_)) {
+ RTLIL::SigBit a_bit = c->getPort(ID::A);
+ RTLIL::SigBit y_bit = c->getPort(ID::Y);
+ bit_users[a_bit].insert(c->name);
+ bit_drivers[y_bit].insert(c->name);
+
+ if (!a_bit.wire) {
+ c->setPort(ID::Y, module->addWire(NEW_ID));
+ RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
+ log_assert(wire);
+ module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
+ }
+ else if (!lut_costs.empty() || !lut_file.empty()) {
+ RTLIL::Cell* driver_lut = nullptr;
+ // ABC can return NOT gates that drive POs
+ if (!a_bit.wire->port_input) {
+ // If it's not a NOT gate that that comes from a PI directly,
+ // find the driver LUT and clone that to guarantee that we won't
+ // increase the max logic depth
+ // (TODO: Optimise by not cloning unless will increase depth)
+ RTLIL::IdString driver_name;
+ if (GetSize(a_bit.wire) == 1)
+ driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
+ else
+ driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
+ driver_lut = mapped_mod->cell(driver_name);
+ }
+
+ if (!driver_lut) {
+ // If a driver couldn't be found (could be from PI or box CI)
+ // then implement using a LUT
+ cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
+ RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
+ RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
+ RTLIL::Const::from_string("01"));
+ bit2sinks[cell->getPort(ID::A)].push_back(cell);
+ cell_stats[ID($lut)]++;
+ }
+ else
+ not2drivers[c] = driver_lut;
+ continue;
+ }
+ else
+ log_abort();
+ if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ continue;
+ }
+ cell_stats[c->type]++;
+
+ RTLIL::Cell *existing_cell = nullptr;
+ if (c->type == ID($lut)) {
+ if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
+ SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name));
+ SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name));
+ module->connect(my_y, my_a);
+ if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx;
+ log_abort();
+ continue;
+ }
+ cell = module->addCell(remap_name(c->name), c->type);
+ }
+ else {
+ existing_cell = module->cell(c->name);
+ log_assert(existing_cell);
+ cell = module->addCell(remap_name(c->name), c->type);
+ module->swap_names(cell, existing_cell);
+ }
+
+ if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
+ if (existing_cell) {
+ cell->parameters = existing_cell->parameters;
+ cell->attributes = existing_cell->attributes;
+ }
+ else {
+ cell->parameters = c->parameters;
+ cell->attributes = c->attributes;
+ }
+ for (auto &conn : c->connections()) {
+ RTLIL::SigSpec newsig;
+ for (auto c : conn.second.chunks()) {
+ if (c.width == 0)
+ continue;
+ //log_assert(c.width == 1);
+ if (c.wire)
+ c.wire = module->wires_.at(remap_name(c.wire->name));
+ newsig.append(c);
+ }
+ cell->setPort(conn.first, newsig);
+
+ if (cell->input(conn.first)) {
+ for (auto i : newsig)
+ bit2sinks[i].push_back(cell);
+ for (auto i : conn.second)
+ bit_users[i].insert(c->name);
+ }
+ if (cell->output(conn.first))
+ for (auto i : conn.second)
+ bit_drivers[i].insert(c->name);
+ }
+ }
+
+ for (auto cell : boxes)
+ module->remove(cell);
+
+ // Copy connections (and rename) from mapped_mod to module
+ for (auto conn : mapped_mod->connections()) {
+ if (!conn.first.is_fully_const()) {
+ auto chunks = conn.first.chunks();
+ for (auto &c : chunks)
+ c.wire = module->wires_.at(remap_name(c.wire->name));
+ conn.first = std::move(chunks);
+ }
+ if (!conn.second.is_fully_const()) {
+ auto chunks = conn.second.chunks();
+ for (auto &c : chunks)
+ if (c.wire)
+ c.wire = module->wires_.at(remap_name(c.wire->name));
+ conn.second = std::move(chunks);
+ }
+ module->connect(conn);
+ }
+
+ for (auto &it : cell_stats)
+ log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
+ int in_wires = 0, out_wires = 0;
+
+ // Stitch in mapped_mod's inputs/outputs into module
+ for (auto &it : mapped_mod->wires_) {
+ RTLIL::Wire *w = it.second;
+ if (!w->port_input && !w->port_output)
+ continue;
+ RTLIL::Wire *wire = module->wire(w->name);
+ log_assert(wire);
+ RTLIL::Wire *remap_wire = module->wire(remap_name(w->name));
+ RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
+ log_assert(GetSize(signal) >= GetSize(remap_wire));
+
+ log_assert(w->port_input || w->port_output);
+ RTLIL::SigSig conn;
+ if (w->port_input) {
+ conn.first = remap_wire;
+ conn.second = signal;
+ in_wires++;
+ module->connect(conn);
+ }
+ if (w->port_output) {
+ conn.first = signal;
+ conn.second = remap_wire;
+ out_wires++;
+ module->connect(conn);
+ }
+ }
+
+ 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);
+ bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
+ log_assert(no_loops);
+
+ for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) {
+ RTLIL::Cell *not_cell = mapped_mod->cell(*ii);
+ log_assert(not_cell);
+ if (not_cell->type != ID($_NOT_))
+ continue;
+ auto it = not2drivers.find(not_cell);
+ if (it == not2drivers.end())
+ continue;
+ RTLIL::Cell *driver_lut = it->second;
+ RTLIL::SigBit a_bit = not_cell->getPort(ID::A);
+ RTLIL::SigBit y_bit = not_cell->getPort(ID::Y);
+ RTLIL::Const driver_mask;
+
+ a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name));
+ y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name));
+
+ auto jt = bit2sinks.find(a_bit);
+ if (jt == bit2sinks.end())
+ goto clone_lut;
+
+ for (auto sink_cell : jt->second)
+ if (sink_cell->type != ID($lut))
+ goto clone_lut;
+
+ // Push downstream LUTs past inverter
+ for (auto sink_cell : jt->second) {
+ SigSpec A = sink_cell->getPort(ID::A);
+ RTLIL::Const mask = sink_cell->getParam(ID(LUT));
+ int index = 0;
+ for (; index < GetSize(A); index++)
+ if (A[index] == a_bit)
+ break;
+ log_assert(index < GetSize(A));
+ int i = 0;
+ while (i < GetSize(mask)) {
+ for (int j = 0; j < (1 << index); j++)
+ std::swap(mask[i+j], mask[i+j+(1 << index)]);
+ i += 1 << (index+1);
+ }
+ A[index] = y_bit;
+ sink_cell->setPort(ID::A, A);
+ sink_cell->setParam(ID(LUT), mask);
+ }
+
+ // Since we have rewritten all sinks (which we know
+ // to be only LUTs) to be after the inverter, we can
+ // go ahead and clone the LUT with the expectation
+ // that the original driving LUT will become dangling
+ // and get cleaned away
+clone_lut:
+ driver_mask = driver_lut->getParam(ID(LUT));
+ for (auto &b : driver_mask.bits) {
+ if (b == RTLIL::State::S0) b = RTLIL::State::S1;
+ else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
+ }
+ auto cell = module->addLut(NEW_ID,
+ driver_lut->getPort(ID::A),
+ y_bit,
+ driver_mask);
+ for (auto &bit : cell->connections_.at(ID::A)) {
+ bit.wire = module->wires_.at(remap_name(bit.wire->name));
+ bit2sinks[bit].push_back(cell);
+ }
+ }
+
+ //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
+ log("ABC RESULTS: input signals: %8d\n", in_wires);
+ log("ABC RESULTS: output signals: %8d\n", out_wires);
+
+ design->remove(mapped_mod);
+ }
+ else
+ {
+ log("Don't call ABC as there is nothing to map.\n");
+ }
+
+ if (cleanup)
+ {
+ log("Removing temp directory.\n");
+ remove_directory(tempdir_name);
+ }
+
+ log_pop();
+}
+
+struct Abc9Pass : public Pass {
+ Abc9Pass() : Pass("abc9", "use ABC9 for technology mapping") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" abc9 [options] [selection]\n");
+ log("\n");
+ log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n");
+ log("library to a target architecture.\n");
+ log("\n");
+ log(" -exe <command>\n");
+#ifdef ABCEXTERNAL
+ log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
+#else
+ log(" use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n");
+#endif
+ log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n");
+ log("\n");
+ log(" -script <file>\n");
+ log(" use the specified ABC script file instead of the default script.\n");
+ log("\n");
+ log(" if <file> starts with a plus sign (+), then the rest of the filename\n");
+ log(" string is interpreted as the command string to be passed to ABC. The\n");
+ log(" leading plus sign is removed and all commas (,) in the string are\n");
+ log(" replaced with blanks before the string is passed to ABC.\n");
+ log("\n");
+ log(" if no -script parameter is given, the following scripts are used:\n");
+ log("\n");
+ log(" for -lut/-luts (only one LUT size):\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str());
+ log("\n");
+ log(" for -lut/-luts (different LUT sizes):\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
+ log("\n");
+ log(" -fast\n");
+ log(" use different default scripts that are slightly faster (at the cost\n");
+ log(" of output quality):\n");
+ log("\n");
+ log(" for -lut/-luts:\n");
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str());
+ log("\n");
+ log(" -D <picoseconds>\n");
+ log(" set delay target. the string {D} in the default scripts above is\n");
+ log(" replaced by this option when used, and an empty string otherwise\n");
+ log(" (indicating best possible delay).\n");
+// log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n");
+// log(" default scripts above.\n");
+ log("\n");
+// log(" -S <num>\n");
+// log(" maximum number of LUT inputs shared.\n");
+// log(" (replaces {S} in the default scripts above, default: -S 1)\n");
+// log("\n");
+ log(" -lut <width>\n");
+ log(" generate netlist using luts of (max) the specified width.\n");
+ log("\n");
+ log(" -lut <w1>:<w2>\n");
+ log(" generate netlist using luts of (max) the specified width <w2>. All\n");
+ log(" luts with width <= <w1> have constant cost. for luts larger than <w1>\n");
+ 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(" -lut <file>\n");
+ log(" pass this file with lut library to ABC.\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(" -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");
+// log(" domain is passed through ABC independently.\n");
+// log("\n");
+// log(" -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
+// log(" use only the specified clock domain. this is like -dff, but only FF\n");
+// log(" cells that belong to the specified clock domain are used.\n");
+// log("\n");
+// log(" -keepff\n");
+// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
+// log(" them, for example for equivalence checking.)\n");
+// log("\n");
+ log(" -nocleanup\n");
+ log(" when this option is used, the temporary files created by this pass\n");
+ log(" are not removed. this is useful for debugging.\n");
+ log("\n");
+ log(" -showtmp\n");
+ log(" print the temp dir name in log. usually this is suppressed so that the\n");
+ log(" command output is identical across runs.\n");
+ log("\n");
+ log(" -markgroups\n");
+ log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n");
+ log(" this attribute is a unique integer for each ABC process started. This\n");
+ log(" is useful for debugging the partitioning of clock domains.\n");
+ log("\n");
+ log(" -box <file>\n");
+ log(" pass this file with box library to ABC. Use with -lut.\n");
+ log("\n");
+ log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
+ log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
+ log("ABC on logic snippets extracted from your design. You will not get any useful\n");
+ log("output when passing an ABC script that writes a file. Instead write your full\n");
+ log("design as BLIF file with write_blif and then load that into ABC externally if\n");
+ log("you want to use ABC to convert your design into another format.\n");
+ log("\n");
+ log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n");
+ log_push();
+
+ assign_map.clear();
+
+#ifdef ABCEXTERNAL
+ std::string exe_file = ABCEXTERNAL;
+#else
+ std::string exe_file = proc_self_dirname() + "yosys-abc";
+#endif
+ std::string script_file, clk_str, box_file, lut_file;
+ std::string delay_target, lutin_shared = "-S 1", wire_delay;
+ bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
+ bool show_tempdir = false;
+ vector<int> lut_costs;
+ markgroups = false;
+
+#if 0
+ cleanup = false;
+ show_tempdir = true;
+#endif
+
+#ifdef _WIN32
+#ifndef ABCEXTERNAL
+ if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
+ exe_file = proc_self_dirname() + "..\\yosys-abc";
+#endif
+#endif
+
+ size_t argidx;
+ char pwd [PATH_MAX];
+ if (!getcwd(pwd, sizeof(pwd))) {
+ log_cmd_error("getcwd failed: %s\n", strerror(errno));
+ log_abort();
+ }
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-exe" && argidx+1 < args.size()) {
+ exe_file = args[++argidx];
+ continue;
+ }
+ if (arg == "-script" && argidx+1 < args.size()) {
+ script_file = args[++argidx];
+ rewrite_filename(script_file);
+ if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
+ script_file = std::string(pwd) + "/" + script_file;
+ continue;
+ }
+ if (arg == "-D" && argidx+1 < args.size()) {
+ delay_target = "-D " + args[++argidx];
+ continue;
+ }
+ //if (arg == "-S" && argidx+1 < args.size()) {
+ // lutin_shared = "-S " + args[++argidx];
+ // continue;
+ //}
+ 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());
+ } else {
+ pos = arg.find_first_of('.');
+ if (pos != string::npos) {
+ lut_file = arg;
+ rewrite_filename(lut_file);
+ if (!lut_file.empty() && !is_absolute_path(lut_file))
+ lut_file = std::string(pwd) + "/" + lut_file;
+ }
+ else {
+ 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 == "-fast") {
+ fast_mode = true;
+ continue;
+ }
+ //if (arg == "-dff") {
+ // dff_mode = true;
+ // continue;
+ //}
+ //if (arg == "-clk" && argidx+1 < args.size()) {
+ // clk_str = args[++argidx];
+ // dff_mode = true;
+ // continue;
+ //}
+ //if (arg == "-keepff") {
+ // keepff = true;
+ // continue;
+ //}
+ if (arg == "-nocleanup") {
+ cleanup = false;
+ continue;
+ }
+ if (arg == "-showtmp") {
+ show_tempdir = true;
+ continue;
+ }
+ if (arg == "-markgroups") {
+ markgroups = true;
+ continue;
+ }
+ if (arg == "-box" && argidx+1 < args.size()) {
+ box_file = args[++argidx];
+ rewrite_filename(box_file);
+ if (!box_file.empty() && !is_absolute_path(box_file))
+ box_file = std::string(pwd) + "/" + box_file;
+ continue;
+ }
+ if (arg == "-W" && argidx+1 < args.size()) {
+ wire_delay = "-W " + args[++argidx];
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ dict<int,IdString> box_lookup;
+ dict<IdString,pool<IdString>> scc_break_inputs;
+ for (auto m : design->modules()) {
+ auto it = m->attributes.find(ID(abc_box_id));
+ if (it == m->attributes.end())
+ continue;
+ if (m->name.begins_with("$paramod"))
+ continue;
+ auto id = it->second.as_int();
+ auto r = box_lookup.insert(std::make_pair(id, m->name));
+ if (!r.second)
+ log_error("Module '%s' has the same abc_box_id = %d value as '%s'.\n",
+ log_id(m), id, log_id(r.first->second));
+ log_assert(r.second);
+
+ RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
+ for (auto p : m->ports) {
+ auto w = m->wire(p);
+ log_assert(w);
+ if (w->port_input) {
+ if (w->attributes.count(ID(abc_scc_break)))
+ scc_break_inputs[m->name].insert(p);
+ if (w->attributes.count(ID(abc_carry))) {
+ if (carry_in)
+ log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m));
+ carry_in = w;
+ }
+ }
+ if (w->port_output) {
+ if (w->attributes.count(ID(abc_carry))) {
+ if (carry_out)
+ log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m));
+ carry_out = w;
+ }
+ }
+ }
+ if (carry_in || carry_out) {
+ if (carry_in && !carry_out)
+ log_error("Module '%s' contains an 'abc_carry' input port but no output port.\n", log_id(m));
+ if (!carry_in && carry_out)
+ log_error("Module '%s' contains an 'abc_carry' output port but no input port.\n", log_id(m));
+ // Make carry_in the last PI, and carry_out the last PO
+ // since ABC requires it this way
+ auto &ports = m->ports;
+ for (auto it = ports.begin(); it != ports.end(); ) {
+ RTLIL::Wire* w = m->wire(*it);
+ log_assert(w);
+ if (w == carry_in || w == carry_out) {
+ it = ports.erase(it);
+ continue;
+ }
+ if (w->port_id > carry_in->port_id)
+ --w->port_id;
+ if (w->port_id > carry_out->port_id)
+ --w->port_id;
+ log_assert(w->port_input || w->port_output);
+ log_assert(ports[w->port_id-1] == w->name);
+ ++it;
+ }
+ ports.push_back(carry_in->name);
+ carry_in->port_id = ports.size();
+ ports.push_back(carry_out->name);
+ carry_out->port_id = ports.size();
+ }
+ }
+
+ for (auto mod : design->selected_modules())
+ {
+ if (mod->attributes.count(ID(abc_box_id)))
+ continue;
+
+ if (mod->processes.size() > 0) {
+ log("Skipping module %s as it contains processes.\n", log_id(mod));
+ continue;
+ }
+
+ assign_map.set(mod);
+
+ if (!dff_mode || !clk_str.empty()) {
+ abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
+ delay_target, lutin_shared, fast_mode, show_tempdir,
+ box_file, lut_file, wire_delay, box_lookup, scc_break_inputs);
+ continue;
+ }
+
+ CellTypes ct(design);
+
+ std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
+ std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
+
+ std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
+ std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
+ std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
+
+ 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;
+
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
+
+ for (auto cell : all_cells)
+ {
+ clkdomain_t key;
+
+ for (auto &conn : cell->connections())
+ for (auto bit : conn.second) {
+ bit = assign_map(bit);
+ if (bit.wire != nullptr) {
+ cell_to_bit[cell].insert(bit);
+ bit_to_cell[bit].insert(cell);
+ if (ct.cell_input(cell->type, conn.first)) {
+ cell_to_bit_up[cell].insert(bit);
+ bit_to_cell_down[bit].insert(cell);
+ }
+ if (ct.cell_output(cell->type, conn.first)) {
+ cell_to_bit_down[cell].insert(bit);
+ bit_to_cell_up[bit].insert(cell);
+ }
+ }
+ }
+
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
+ {
+ key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec());
+ }
+ else
+ if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
+ {
+ bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_));
+ bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_));
+ key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E))));
+ }
+ else
+ continue;
+
+ unassigned_cells.erase(cell);
+ expand_queue.insert(cell);
+ expand_queue_up.insert(cell);
+ expand_queue_down.insert(cell);
+
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
+ }
+
+ while (!expand_queue_up.empty() || !expand_queue_down.empty())
+ {
+ if (!expand_queue_up.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue_up.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue_up.erase(cell);
+
+ for (auto bit : cell_to_bit_up[cell])
+ for (auto c : bit_to_cell_up[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue_up.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ expand_queue.insert(c);
+ }
+ }
+
+ if (!expand_queue_down.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue_down.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue_down.erase(cell);
+
+ for (auto bit : cell_to_bit_down[cell])
+ for (auto c : bit_to_cell_down[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue_up.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ expand_queue.insert(c);
+ }
+ }
+
+ if (expand_queue_up.empty() && expand_queue_down.empty()) {
+ expand_queue_up.swap(next_expand_queue_up);
+ expand_queue_down.swap(next_expand_queue_down);
+ }
+ }
+
+ while (!expand_queue.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue.erase(cell);
+
+ for (auto bit : cell_to_bit.at(cell)) {
+ for (auto c : bit_to_cell[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ }
+ bit_to_cell[bit].clear();
+ }
+
+ if (expand_queue.empty())
+ expand_queue.swap(next_expand_queue);
+ }
+
+ clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
+ for (auto cell : unassigned_cells) {
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
+ }
+
+ log_header(design, "Summary of detected clock domains:\n");
+ for (auto &it : assigned_cells)
+ log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
+ std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
+ std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
+
+ for (auto &it : assigned_cells) {
+ clk_polarity = std::get<0>(it.first);
+ 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));
+ abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$",
+ keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
+ box_file, lut_file, wire_delay, box_lookup, scc_break_inputs);
+ assign_map.set(mod);
+ }
+ }
+
+ assign_map.clear();
+
+ // The "clean" pass also contains a design->check() call
+ Pass::call(design, "clean");
+
+ log_pop();
+ }
+} Abc9Pass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc
index 35df2ff79..1d5e1286b 100644
--- a/passes/techmap/aigmap.cc
+++ b/passes/techmap/aigmap.cc
@@ -66,10 +66,10 @@ struct AigmapPass : public Pass {
{
Aig aig(cell);
- if (cell->type == "$_AND_" || cell->type == "$_NOT_")
+ if (cell->type.in(ID($_AND_), ID($_NOT_)))
aig.name.clear();
- if (nand_mode && cell->type == "$_NAND_")
+ if (nand_mode && cell->type == ID($_NAND_))
aig.name.clear();
if (aig.name.empty()) {
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index dc7d416b0..5b168d524 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -61,7 +61,7 @@ struct AlumaccWorker
RTLIL::SigSpec get_eq() {
if (GetSize(cached_eq) == 0)
- cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"), false, alu_cell->get_src_attribute());
+ cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort(ID(X)), false, alu_cell->get_src_attribute());
return cached_eq;
}
@@ -73,7 +73,7 @@ struct AlumaccWorker
RTLIL::SigSpec get_cf() {
if (GetSize(cached_cf) == 0) {
- cached_cf = alu_cell->getPort("\\CO");
+ cached_cf = alu_cell->getPort(ID(CO));
log_assert(GetSize(cached_cf) >= 1);
cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1], false, alu_cell->get_src_attribute());
}
@@ -82,7 +82,7 @@ struct AlumaccWorker
RTLIL::SigSpec get_of() {
if (GetSize(cached_of) == 0) {
- cached_of = {alu_cell->getPort("\\CO"), alu_cell->getPort("\\CI")};
+ cached_of = {alu_cell->getPort(ID(CO)), alu_cell->getPort(ID(CI))};
log_assert(GetSize(cached_of) >= 2);
cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(cached_of)-1], cached_of[GetSize(cached_of)-2]);
}
@@ -91,7 +91,7 @@ struct AlumaccWorker
RTLIL::SigSpec get_sf() {
if (GetSize(cached_sf) == 0) {
- cached_sf = alu_cell->getPort("\\Y");
+ cached_sf = alu_cell->getPort(ID::Y);
cached_sf = cached_sf[GetSize(cached_sf)-1];
}
return cached_sf;
@@ -125,7 +125,7 @@ struct AlumaccWorker
{
for (auto cell : module->selected_cells())
{
- if (!cell->type.in("$pos", "$neg", "$add", "$sub", "$mul"))
+ if (!cell->type.in(ID($pos), ID($neg), ID($add), ID($sub), ID($mul)))
continue;
log(" creating $macc model for %s (%s).\n", log_id(cell), log_id(cell->type));
@@ -134,38 +134,38 @@ struct AlumaccWorker
Macc::port_t new_port;
n->cell = cell;
- n->y = sigmap(cell->getPort("\\Y"));
+ n->y = sigmap(cell->getPort(ID::Y));
n->users = 0;
for (auto bit : n->y)
n->users = max(n->users, bit_users.at(bit) - 1);
- if (cell->type.in("$pos", "$neg"))
+ if (cell->type.in(ID($pos), ID($neg)))
{
- new_port.in_a = sigmap(cell->getPort("\\A"));
- new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool();
- new_port.do_subtract = cell->type == "$neg";
+ new_port.in_a = sigmap(cell->getPort(ID::A));
+ new_port.is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
+ new_port.do_subtract = cell->type == ID($neg);
n->macc.ports.push_back(new_port);
}
- if (cell->type.in("$add", "$sub"))
+ if (cell->type.in(ID($add), ID($sub)))
{
- new_port.in_a = sigmap(cell->getPort("\\A"));
- new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ new_port.in_a = sigmap(cell->getPort(ID::A));
+ new_port.is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
new_port.do_subtract = false;
n->macc.ports.push_back(new_port);
- new_port.in_a = sigmap(cell->getPort("\\B"));
- new_port.is_signed = cell->getParam("\\B_SIGNED").as_bool();
- new_port.do_subtract = cell->type == "$sub";
+ new_port.in_a = sigmap(cell->getPort(ID::B));
+ new_port.is_signed = cell->getParam(ID(B_SIGNED)).as_bool();
+ new_port.do_subtract = cell->type == ID($sub);
n->macc.ports.push_back(new_port);
}
- if (cell->type.in("$mul"))
+ if (cell->type.in(ID($mul)))
{
- new_port.in_a = sigmap(cell->getPort("\\A"));
- new_port.in_b = sigmap(cell->getPort("\\B"));
- new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ new_port.in_a = sigmap(cell->getPort(ID::A));
+ new_port.in_b = sigmap(cell->getPort(ID::B));
+ new_port.is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
new_port.do_subtract = false;
n->macc.ports.push_back(new_port);
}
@@ -315,7 +315,7 @@ struct AlumaccWorker
}
if (subtract_b)
- C.append(RTLIL::S1);
+ C.append(State::S1);
if (GetSize(C) > 1)
goto next_macc;
@@ -351,7 +351,7 @@ struct AlumaccWorker
for (auto &it : sig_macc)
{
auto n = it.second;
- auto cell = module->addCell(NEW_ID, "$macc");
+ auto cell = module->addCell(NEW_ID, ID($macc));
macc_counter++;
@@ -361,7 +361,7 @@ struct AlumaccWorker
n->macc.optimize(GetSize(n->y));
n->macc.to_cell(cell);
- cell->setPort("\\Y", n->y);
+ cell->setPort(ID::Y, n->y);
cell->fixup_parameters();
module->remove(n->cell);
delete n;
@@ -376,9 +376,9 @@ struct AlumaccWorker
for (auto cell : module->selected_cells())
{
- if (cell->type.in("$lt", "$le", "$ge", "$gt"))
+ if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)))
lge_cells.push_back(cell);
- if (cell->type.in("$eq", "$eqx", "$ne", "$nex"))
+ if (cell->type.in(ID($eq), ID($eqx), ID($ne), ID($nex)))
eq_cells.push_back(cell);
}
@@ -386,13 +386,13 @@ struct AlumaccWorker
{
log(" creating $alu model for %s (%s):", log_id(cell), log_id(cell->type));
- bool cmp_less = cell->type.in("$lt", "$le");
- bool cmp_equal = cell->type.in("$le", "$ge");
- bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ bool cmp_less = cell->type.in(ID($lt), ID($le));
+ bool cmp_equal = cell->type.in(ID($le), ID($ge));
+ bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
- RTLIL::SigSpec A = sigmap(cell->getPort("\\A"));
- RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
- RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
+ RTLIL::SigSpec A = sigmap(cell->getPort(ID::A));
+ RTLIL::SigSpec B = sigmap(cell->getPort(ID::B));
+ RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y));
if (B < A && GetSize(B)) {
cmp_less = !cmp_less;
@@ -402,7 +402,7 @@ struct AlumaccWorker
alunode_t *n = nullptr;
for (auto node : sig_alu[RTLIL::SigSig(A, B)])
- if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) {
+ if (node->is_signed == is_signed && node->invert_b && node->c == State::S1) {
n = node;
break;
}
@@ -411,7 +411,7 @@ struct AlumaccWorker
n = new alunode_t;
n->a = A;
n->b = B;
- n->c = RTLIL::S1;
+ n->c = State::S1;
n->y = module->addWire(NEW_ID, max(GetSize(A), GetSize(B)));
n->is_signed = is_signed;
n->invert_b = true;
@@ -427,12 +427,12 @@ struct AlumaccWorker
for (auto cell : eq_cells)
{
- bool cmp_equal = cell->type.in("$eq", "$eqx");
- bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ bool cmp_equal = cell->type.in(ID($eq), ID($eqx));
+ bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool();
- RTLIL::SigSpec A = sigmap(cell->getPort("\\A"));
- RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
- RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
+ RTLIL::SigSpec A = sigmap(cell->getPort(ID::A));
+ RTLIL::SigSpec B = sigmap(cell->getPort(ID::B));
+ RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y));
if (B < A && GetSize(B))
std::swap(A, B);
@@ -440,7 +440,7 @@ struct AlumaccWorker
alunode_t *n = nullptr;
for (auto node : sig_alu[RTLIL::SigSig(A, B)])
- if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) {
+ if (node->is_signed == is_signed && node->invert_b && node->c == State::S1) {
n = node;
break;
}
@@ -471,7 +471,7 @@ struct AlumaccWorker
goto delete_node;
}
- n->alu_cell = module->addCell(NEW_ID, "$alu");
+ n->alu_cell = module->addCell(NEW_ID, ID($alu));
alu_counter++;
log(" creating $alu cell for ");
@@ -482,13 +482,13 @@ struct AlumaccWorker
if (n->cells.size() > 0)
n->alu_cell->set_src_attribute(n->cells[0]->get_src_attribute());
- n->alu_cell->setPort("\\A", n->a);
- n->alu_cell->setPort("\\B", n->b);
- n->alu_cell->setPort("\\CI", GetSize(n->c) ? n->c : RTLIL::S0);
- n->alu_cell->setPort("\\BI", n->invert_b ? RTLIL::S1 : RTLIL::S0);
- n->alu_cell->setPort("\\Y", n->y);
- n->alu_cell->setPort("\\X", module->addWire(NEW_ID, GetSize(n->y)));
- n->alu_cell->setPort("\\CO", module->addWire(NEW_ID, GetSize(n->y)));
+ n->alu_cell->setPort(ID::A, n->a);
+ n->alu_cell->setPort(ID::B, n->b);
+ n->alu_cell->setPort(ID(CI), GetSize(n->c) ? n->c : State::S0);
+ n->alu_cell->setPort(ID(BI), n->invert_b ? State::S1 : State::S0);
+ n->alu_cell->setPort(ID::Y, n->y);
+ n->alu_cell->setPort(ID(X), module->addWire(NEW_ID, GetSize(n->y)));
+ n->alu_cell->setPort(ID(CO), module->addWire(NEW_ID, GetSize(n->y)));
n->alu_cell->fixup_parameters(n->is_signed, n->is_signed);
for (auto &it : n->cmp)
diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc
index aa48e1125..a38638e0b 100644
--- a/passes/techmap/attrmap.cc
+++ b/passes/techmap/attrmap.cc
@@ -263,6 +263,25 @@ struct AttrmapPass : public Pass {
for (auto cell : module->selected_cells())
attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->attributes);
+
+ for (auto proc : module->processes)
+ {
+ if (!design->selected(module, proc.second))
+ continue;
+ attrmap_apply(stringf("%s.%s", log_id(module), log_id(proc.first)), actions, proc.second->attributes);
+
+ std::vector<RTLIL::CaseRule*> all_cases = {&proc.second->root_case};
+ while (!all_cases.empty()) {
+ RTLIL::CaseRule *cs = all_cases.back();
+ all_cases.pop_back();
+ attrmap_apply(stringf("%s.%s (case)", log_id(module), log_id(proc.first)), actions, cs->attributes);
+
+ for (auto &sw : cs->switches) {
+ attrmap_apply(stringf("%s.%s (switch)", log_id(module), log_id(proc.first)), actions, sw->attributes);
+ all_cases.insert(all_cases.end(), sw->cases.begin(), sw->cases.end());
+ }
+ }
+ }
}
}
}
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
index 47d0ff416..b976b401b 100644
--- a/passes/techmap/deminout.cc
+++ b/passes/techmap/deminout.cc
@@ -83,13 +83,13 @@ struct DeminoutPass : public Pass {
for (auto bit : sigmap(conn.second))
bits_used.insert(bit);
- if (conn.first == "\\Y" && cell->type.in("$mux", "$pmux", "$_MUX_", "$_TBUF_", "$tribuf"))
+ if (conn.first == ID::Y && cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_TBUF_), ID($tribuf)))
{
- bool tribuf = (cell->type == "$_TBUF_" || cell->type == "$tribuf");
+ bool tribuf = cell->type.in(ID($_TBUF_), ID($tribuf));
if (!tribuf) {
for (auto &c : cell->connections()) {
- if (!c.first.in("\\A", "\\B"))
+ if (!c.first.in(ID::A, ID::B))
continue;
for (auto b : sigmap(c.second))
if (b == State::Sz)
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
index 7e1040963..0242256e5 100644
--- a/passes/techmap/dff2dffe.cc
+++ b/passes/techmap/dff2dffe.cc
@@ -52,13 +52,13 @@ struct Dff2dffeWorker
}
for (auto cell : module->cells()) {
- if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") {
- RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+ if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
+ RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y));
for (int i = 0; i < GetSize(sig_y); i++)
bit2mux[sig_y[i]] = cell_int_t(cell, i);
}
if (direct_dict.empty()) {
- if (cell->type == "$dff" || cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+ if (cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_)))
dff_cells.push_back(cell);
} else {
if (direct_dict.count(cell->type))
@@ -86,9 +86,9 @@ struct Dff2dffeWorker
return ret;
cell_int_t mux_cell_int = bit2mux.at(d);
- RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort("\\A"));
- RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort("\\B"));
- RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort("\\S"));
+ RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort(ID::A));
+ RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort(ID::B));
+ RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort(ID(S)));
int width = GetSize(sig_a), index = mux_cell_int.second;
for (int i = 0; i < GetSize(sig_s); i++)
@@ -97,9 +97,9 @@ struct Dff2dffeWorker
ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path);
if (sig_b[i*width + index] == q) {
- RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B");
+ RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B);
s[i*width + index] = RTLIL::Sx;
- mux_cell_int.first->setPort("\\B", s);
+ mux_cell_int.first->setPort(ID::B, s);
}
return ret;
@@ -120,9 +120,9 @@ struct Dff2dffeWorker
ret.insert(pat);
if (sig_b[i*width + index] == q) {
- RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B");
+ RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B);
s[i*width + index] = RTLIL::Sx;
- mux_cell_int.first->setPort("\\B", s);
+ mux_cell_int.first->setPort(ID::B, s);
}
}
@@ -130,9 +130,9 @@ struct Dff2dffeWorker
ret.insert(pat);
if (sig_a[index] == q) {
- RTLIL::SigSpec s = mux_cell_int.first->getPort("\\A");
+ RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::A);
s[index] = RTLIL::Sx;
- mux_cell_int.first->setPort("\\A", s);
+ mux_cell_int.first->setPort(ID::A, s);
}
return ret;
@@ -167,7 +167,7 @@ struct Dff2dffeWorker
}
if (GetSize(or_input) == 0)
- return RTLIL::S1;
+ return State::S1;
if (GetSize(or_input) == 1)
return or_input;
@@ -185,8 +185,8 @@ struct Dff2dffeWorker
void handle_dff_cell(RTLIL::Cell *dff_cell)
{
- RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort("\\D"));
- RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort("\\Q"));
+ RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort(ID(D)));
+ RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort(ID(Q)));
std::map<patterns_t, std::set<int>> grouped_patterns;
std::set<int> remaining_indices;
@@ -208,16 +208,16 @@ struct Dff2dffeWorker
}
if (!direct_dict.empty()) {
log(" converting %s cell %s to %s for %s -> %s.\n", log_id(dff_cell->type), log_id(dff_cell), log_id(direct_dict.at(dff_cell->type)), log_signal(new_sig_d), log_signal(new_sig_q));
- dff_cell->setPort("\\E", make_patterns_logic(it.first, true));
+ dff_cell->setPort(ID(E), make_patterns_logic(it.first, true));
dff_cell->type = direct_dict.at(dff_cell->type);
} else
- if (dff_cell->type == "$dff") {
- RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort("\\CLK"), make_patterns_logic(it.first, false),
- new_sig_d, new_sig_q, dff_cell->getParam("\\CLK_POLARITY").as_bool(), true);
+ if (dff_cell->type == ID($dff)) {
+ RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort(ID(CLK)), make_patterns_logic(it.first, false),
+ new_sig_d, new_sig_q, dff_cell->getParam(ID(CLK_POLARITY)).as_bool(), true);
log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
} else {
- RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort("\\C"), make_patterns_logic(it.first, true),
- new_sig_d, new_sig_q, dff_cell->type == "$_DFF_P_", true);
+ RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort(ID(C)), make_patterns_logic(it.first, true),
+ new_sig_d, new_sig_q, dff_cell->type == ID($_DFF_P_), true);
log(" created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
}
}
@@ -235,9 +235,9 @@ struct Dff2dffeWorker
new_sig_d.append(sig_d[i]);
new_sig_q.append(sig_q[i]);
}
- dff_cell->setPort("\\D", new_sig_d);
- dff_cell->setPort("\\Q", new_sig_q);
- dff_cell->setParam("\\WIDTH", GetSize(remaining_indices));
+ dff_cell->setPort(ID(D), new_sig_d);
+ dff_cell->setPort(ID(Q), new_sig_q);
+ dff_cell->setParam(ID(WIDTH), GetSize(remaining_indices));
}
}
@@ -265,7 +265,7 @@ struct Dff2dffePass : public Pass {
log("\n");
log(" -unmap\n");
log(" operate in the opposite direction: replace $dffe cells with combinations\n");
- log(" of $dff and $mux cells. the options below are ignore in unmap mode.\n");
+ log(" of $dff and $mux cells. the options below are ignored in unmap mode.\n");
log("\n");
log(" -unmap-mince N\n");
log(" Same as -unmap but only unmap $dffe where the clock enable port\n");
@@ -304,7 +304,7 @@ struct Dff2dffePass : public Pass {
}
if (args[argidx] == "-unmap-mince" && argidx + 1 < args.size()) {
unmap_mode = true;
- min_ce_use = std::stoi(args[++argidx]);
+ min_ce_use = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-direct" && argidx + 2 < args.size()) {
@@ -316,25 +316,25 @@ struct Dff2dffePass : public Pass {
if (args[argidx] == "-direct-match" && argidx + 1 < args.size()) {
bool found_match = false;
const char *pattern = args[++argidx].c_str();
- if (patmatch(pattern, "$_DFF_P_" )) found_match = true, direct_dict["$_DFF_P_" ] = "$_DFFE_PP_";
- if (patmatch(pattern, "$_DFF_N_" )) found_match = true, direct_dict["$_DFF_N_" ] = "$_DFFE_NP_";
- if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict["$_DFF_NN0_"] = "$__DFFE_NN0";
- if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict["$_DFF_NN1_"] = "$__DFFE_NN1";
- if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict["$_DFF_NP0_"] = "$__DFFE_NP0";
- if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict["$_DFF_NP1_"] = "$__DFFE_NP1";
- if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict["$_DFF_PN0_"] = "$__DFFE_PN0";
- if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict["$_DFF_PN1_"] = "$__DFFE_PN1";
- if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict["$_DFF_PP0_"] = "$__DFFE_PP0";
- if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict["$_DFF_PP1_"] = "$__DFFE_PP1";
-
- if (patmatch(pattern, "$__DFFS_NN0_")) found_match = true, direct_dict["$__DFFS_NN0_"] = "$__DFFSE_NN0";
- if (patmatch(pattern, "$__DFFS_NN1_")) found_match = true, direct_dict["$__DFFS_NN1_"] = "$__DFFSE_NN1";
- if (patmatch(pattern, "$__DFFS_NP0_")) found_match = true, direct_dict["$__DFFS_NP0_"] = "$__DFFSE_NP0";
- if (patmatch(pattern, "$__DFFS_NP1_")) found_match = true, direct_dict["$__DFFS_NP1_"] = "$__DFFSE_NP1";
- if (patmatch(pattern, "$__DFFS_PN0_")) found_match = true, direct_dict["$__DFFS_PN0_"] = "$__DFFSE_PN0";
- if (patmatch(pattern, "$__DFFS_PN1_")) found_match = true, direct_dict["$__DFFS_PN1_"] = "$__DFFSE_PN1";
- if (patmatch(pattern, "$__DFFS_PP0_")) found_match = true, direct_dict["$__DFFS_PP0_"] = "$__DFFSE_PP0";
- if (patmatch(pattern, "$__DFFS_PP1_")) found_match = true, direct_dict["$__DFFS_PP1_"] = "$__DFFSE_PP1";
+ if (patmatch(pattern, "$_DFF_P_" )) found_match = true, direct_dict[ID($_DFF_P_) ] = ID($_DFFE_PP_);
+ if (patmatch(pattern, "$_DFF_N_" )) found_match = true, direct_dict[ID($_DFF_N_) ] = ID($_DFFE_NP_);
+ if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict[ID($_DFF_NN0_)] = ID($__DFFE_NN0);
+ if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict[ID($_DFF_NN1_)] = ID($__DFFE_NN1);
+ if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict[ID($_DFF_NP0_)] = ID($__DFFE_NP0);
+ if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict[ID($_DFF_NP1_)] = ID($__DFFE_NP1);
+ if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict[ID($_DFF_PN0_)] = ID($__DFFE_PN0);
+ if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict[ID($_DFF_PN1_)] = ID($__DFFE_PN1);
+ if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict[ID($_DFF_PP0_)] = ID($__DFFE_PP0);
+ if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict[ID($_DFF_PP1_)] = ID($__DFFE_PP1);
+
+ if (patmatch(pattern, "$__DFFS_NN0_")) found_match = true, direct_dict[ID($__DFFS_NN0_)] = ID($__DFFSE_NN0);
+ if (patmatch(pattern, "$__DFFS_NN1_")) found_match = true, direct_dict[ID($__DFFS_NN1_)] = ID($__DFFSE_NN1);
+ if (patmatch(pattern, "$__DFFS_NP0_")) found_match = true, direct_dict[ID($__DFFS_NP0_)] = ID($__DFFSE_NP0);
+ if (patmatch(pattern, "$__DFFS_NP1_")) found_match = true, direct_dict[ID($__DFFS_NP1_)] = ID($__DFFSE_NP1);
+ if (patmatch(pattern, "$__DFFS_PN0_")) found_match = true, direct_dict[ID($__DFFS_PN0_)] = ID($__DFFSE_PN0);
+ if (patmatch(pattern, "$__DFFS_PN1_")) found_match = true, direct_dict[ID($__DFFS_PN1_)] = ID($__DFFSE_PN1);
+ if (patmatch(pattern, "$__DFFS_PP0_")) found_match = true, direct_dict[ID($__DFFS_PP0_)] = ID($__DFFSE_PP0);
+ if (patmatch(pattern, "$__DFFS_PP1_")) found_match = true, direct_dict[ID($__DFFS_PP1_)] = ID($__DFFSE_PP1);
if (!found_match)
log_cmd_error("No cell types matched pattern '%s'.\n", pattern);
continue;
@@ -355,49 +355,49 @@ struct Dff2dffePass : public Pass {
if (unmap_mode) {
SigMap sigmap(mod);
for (auto cell : mod->selected_cells()) {
- if (cell->type == "$dffe") {
+ if (cell->type == ID($dffe)) {
if (min_ce_use >= 0) {
int ce_use = 0;
for (auto cell_other : mod->selected_cells()) {
if (cell_other->type != cell->type)
continue;
- if (sigmap(cell->getPort("\\EN")) == sigmap(cell_other->getPort("\\EN")))
+ if (sigmap(cell->getPort(ID(EN))) == sigmap(cell_other->getPort(ID(EN))))
ce_use++;
}
if (ce_use >= min_ce_use)
continue;
}
- RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort("\\D")));
- mod->addDff(NEW_ID, cell->getPort("\\CLK"), tmp, cell->getPort("\\Q"), cell->getParam("\\CLK_POLARITY").as_bool());
- if (cell->getParam("\\EN_POLARITY").as_bool())
- mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\EN"), tmp);
+ RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort(ID(D))));
+ mod->addDff(NEW_ID, cell->getPort(ID(CLK)), tmp, cell->getPort(ID(Q)), cell->getParam(ID(CLK_POLARITY)).as_bool());
+ if (cell->getParam(ID(EN_POLARITY)).as_bool())
+ mod->addMux(NEW_ID, cell->getPort(ID(Q)), cell->getPort(ID(D)), cell->getPort(ID(EN)), tmp);
else
- mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\EN"), tmp);
+ mod->addMux(NEW_ID, cell->getPort(ID(D)), cell->getPort(ID(Q)), cell->getPort(ID(EN)), tmp);
mod->remove(cell);
continue;
}
- if (cell->type.substr(0, 7) == "$_DFFE_") {
+ if (cell->type.begins_with("$_DFFE_")) {
if (min_ce_use >= 0) {
int ce_use = 0;
for (auto cell_other : mod->selected_cells()) {
if (cell_other->type != cell->type)
continue;
- if (sigmap(cell->getPort("\\E")) == sigmap(cell_other->getPort("\\E")))
+ if (sigmap(cell->getPort(ID(E))) == sigmap(cell_other->getPort(ID(E))))
ce_use++;
}
if (ce_use >= min_ce_use)
continue;
}
- bool clk_pol = cell->type.substr(7, 1) == "P";
- bool en_pol = cell->type.substr(8, 1) == "P";
+ bool clk_pol = cell->type.compare(7, 1, "P") == 0;
+ bool en_pol = cell->type.compare(8, 1, "P") == 0;
RTLIL::SigSpec tmp = mod->addWire(NEW_ID);
- mod->addDff(NEW_ID, cell->getPort("\\C"), tmp, cell->getPort("\\Q"), clk_pol);
+ mod->addDff(NEW_ID, cell->getPort(ID(C)), tmp, cell->getPort(ID(Q)), clk_pol);
if (en_pol)
- mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\E"), tmp);
+ mod->addMux(NEW_ID, cell->getPort(ID(Q)), cell->getPort(ID(D)), cell->getPort(ID(E)), tmp);
else
- mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\E"), tmp);
+ mod->addMux(NEW_ID, cell->getPort(ID(D)), cell->getPort(ID(Q)), cell->getPort(ID(E)), tmp);
mod->remove(cell);
continue;
}
diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc
index 39a4f6ade..0ea033513 100644
--- a/passes/techmap/dff2dffs.cc
+++ b/passes/techmap/dff2dffs.cc
@@ -51,8 +51,8 @@ struct Dff2dffsPass : public Pass {
extra_args(args, argidx, design);
pool<IdString> dff_types;
- dff_types.insert("$_DFF_N_");
- dff_types.insert("$_DFF_P_");
+ dff_types.insert(ID($_DFF_N_));
+ dff_types.insert(ID($_DFF_P_));
for (auto module : design->selected_modules())
{
@@ -69,19 +69,19 @@ struct Dff2dffsPass : public Pass {
continue;
}
- if (cell->type != "$_MUX_")
+ if (cell->type != ID($_MUX_))
continue;
- SigBit bit_a = sigmap(cell->getPort("\\A"));
- SigBit bit_b = sigmap(cell->getPort("\\B"));
+ SigBit bit_a = sigmap(cell->getPort(ID::A));
+ SigBit bit_b = sigmap(cell->getPort(ID::B));
if (bit_a.wire == nullptr || bit_b.wire == nullptr)
- sr_muxes[sigmap(cell->getPort("\\Y"))] = cell;
+ sr_muxes[sigmap(cell->getPort(ID::Y))] = cell;
}
for (auto cell : ff_cells)
{
- SigSpec sig_d = cell->getPort("\\D");
+ SigSpec sig_d = cell->getPort(ID(D));
if (GetSize(sig_d) < 1)
continue;
@@ -92,9 +92,9 @@ struct Dff2dffsPass : public Pass {
continue;
Cell *mux_cell = sr_muxes.at(bit_d);
- SigBit bit_a = sigmap(mux_cell->getPort("\\A"));
- SigBit bit_b = sigmap(mux_cell->getPort("\\B"));
- SigBit bit_s = sigmap(mux_cell->getPort("\\S"));
+ SigBit bit_a = sigmap(mux_cell->getPort(ID::A));
+ SigBit bit_b = sigmap(mux_cell->getPort(ID::B));
+ SigBit bit_s = sigmap(mux_cell->getPort(ID(S)));
log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
@@ -114,26 +114,26 @@ struct Dff2dffsPass : public Pass {
}
if (sr_val == State::S1) {
- if (cell->type == "$_DFF_N_") {
- if (invert_sr) cell->type = "$__DFFS_NN1_";
- else cell->type = "$__DFFS_NP1_";
+ if (cell->type == ID($_DFF_N_)) {
+ if (invert_sr) cell->type = ID($__DFFS_NN1_);
+ else cell->type = ID($__DFFS_NP1_);
} else {
- log_assert(cell->type == "$_DFF_P_");
- if (invert_sr) cell->type = "$__DFFS_PN1_";
- else cell->type = "$__DFFS_PP1_";
+ log_assert(cell->type == ID($_DFF_P_));
+ if (invert_sr) cell->type = ID($__DFFS_PN1_);
+ else cell->type = ID($__DFFS_PP1_);
}
} else {
- if (cell->type == "$_DFF_N_") {
- if (invert_sr) cell->type = "$__DFFS_NN0_";
- else cell->type = "$__DFFS_NP0_";
+ if (cell->type == ID($_DFF_N_)) {
+ if (invert_sr) cell->type = ID($__DFFS_NN0_);
+ else cell->type = ID($__DFFS_NP0_);
} else {
- log_assert(cell->type == "$_DFF_P_");
- if (invert_sr) cell->type = "$__DFFS_PN0_";
- else cell->type = "$__DFFS_PP0_";
+ log_assert(cell->type == ID($_DFF_P_));
+ if (invert_sr) cell->type = ID($__DFFS_PN0_);
+ else cell->type = ID($__DFFS_PP0_);
}
}
- cell->setPort("\\R", sr_sig);
- cell->setPort("\\D", bit_d);
+ cell->setPort(ID(R), sr_sig);
+ cell->setPort(ID(D), bit_d);
}
}
}
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index 0ad33dc0e..cf9301442 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -99,8 +99,8 @@ struct DffinitPass : public Pass {
pool<SigBit> used_bits;
for (auto wire : module->selected_wires()) {
- if (wire->attributes.count("\\init")) {
- Const value = wire->attributes.at("\\init");
+ if (wire->attributes.count(ID(init))) {
+ Const value = wire->attributes.at(ID(init));
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
if (value[i] != State::Sx)
init_bits[sigmap(SigBit(wire, i))] = value[i];
@@ -161,8 +161,8 @@ struct DffinitPass : public Pass {
}
for (auto wire : module->selected_wires())
- if (wire->attributes.count("\\init")) {
- Const &value = wire->attributes.at("\\init");
+ if (wire->attributes.count(ID(init))) {
+ Const &value = wire->attributes.at(ID(init));
bool do_cleanup = true;
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) {
SigBit bit = sigmap(SigBit(wire, i));
@@ -173,7 +173,7 @@ struct DffinitPass : public Pass {
}
if (do_cleanup) {
log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire));
- wire->attributes.erase("\\init");
+ wire->attributes.erase(ID(init));
}
}
}
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index b5c0498d0..b15109cd3 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -27,12 +27,12 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct cell_mapping {
- std::string cell_name;
+ IdString cell_name;
std::map<std::string, char> ports;
};
static std::map<RTLIL::IdString, cell_mapping> cell_mappings;
-static void logmap(std::string dff)
+static void logmap(IdString dff)
{
if (cell_mappings.count(dff) == 0) {
log(" unmapped dff cell: %s\n", dff.c_str());
@@ -54,26 +54,26 @@ static void logmap(std::string dff)
static void logmap_all()
{
- logmap("$_DFF_N_");
- logmap("$_DFF_P_");
-
- logmap("$_DFF_NN0_");
- logmap("$_DFF_NN1_");
- logmap("$_DFF_NP0_");
- logmap("$_DFF_NP1_");
- logmap("$_DFF_PN0_");
- logmap("$_DFF_PN1_");
- logmap("$_DFF_PP0_");
- logmap("$_DFF_PP1_");
-
- logmap("$_DFFSR_NNN_");
- logmap("$_DFFSR_NNP_");
- logmap("$_DFFSR_NPN_");
- logmap("$_DFFSR_NPP_");
- logmap("$_DFFSR_PNN_");
- logmap("$_DFFSR_PNP_");
- logmap("$_DFFSR_PPN_");
- logmap("$_DFFSR_PPP_");
+ logmap(ID($_DFF_N_));
+ logmap(ID($_DFF_P_));
+
+ logmap(ID($_DFF_NN0_));
+ logmap(ID($_DFF_NN1_));
+ logmap(ID($_DFF_NP0_));
+ logmap(ID($_DFF_NP1_));
+ logmap(ID($_DFF_PN0_));
+ logmap(ID($_DFF_PN1_));
+ logmap(ID($_DFF_PP0_));
+ logmap(ID($_DFF_PP1_));
+
+ logmap(ID($_DFFSR_NNN_));
+ logmap(ID($_DFFSR_NNP_));
+ logmap(ID($_DFFSR_NPN_));
+ logmap(ID($_DFFSR_NPP_));
+ logmap(ID($_DFFSR_PNN_));
+ logmap(ID($_DFFSR_PNP_));
+ logmap(ID($_DFFSR_PPN_));
+ logmap(ID($_DFFSR_PPP_));
}
static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, bool &pin_pol)
@@ -115,7 +115,7 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name,
return false;
}
-static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode)
+static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode)
{
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
@@ -230,13 +230,13 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
cell_mappings[cell_type].ports["D"] = 'D';
cell_mappings[cell_type].ports["Q"] = 'Q';
} else {
- cell_mappings[cell_type].cell_name = best_cell->args[0];
+ cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]);
cell_mappings[cell_type].ports = best_cell_ports;
}
}
}
-static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode)
+static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode)
{
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
@@ -347,7 +347,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
cell_mappings[cell_type].ports["D"] = 'D';
cell_mappings[cell_type].ports["Q"] = 'Q';
} else {
- cell_mappings[cell_type].cell_name = best_cell->args[0];
+ cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]);
cell_mappings[cell_type].ports = best_cell_ports;
}
}
@@ -404,7 +404,7 @@ static bool expand_cellmap(std::string pattern, std::string inv)
return return_status;
}
-static void map_sr_to_arst(const char *from, const char *to)
+static void map_sr_to_arst(IdString from, IdString to)
{
if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
return;
@@ -419,7 +419,7 @@ static void map_sr_to_arst(const char *from, const char *to)
log_assert(from_clk_pol == to_clk_pol);
log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol);
- log(" create mapping for %s from mapping for %s.\n", to, from);
+ log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str());
cell_mappings[to].cell_name = cell_mappings[from].cell_name;
cell_mappings[to].ports = cell_mappings[from].ports;
@@ -450,7 +450,7 @@ static void map_sr_to_arst(const char *from, const char *to)
}
}
-static void map_adff_to_dff(const char *from, const char *to)
+static void map_adff_to_dff(IdString from, IdString to)
{
if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
return;
@@ -461,7 +461,7 @@ static void map_adff_to_dff(const char *from, const char *to)
log_assert(from_clk_pol == to_clk_pol);
- log(" create mapping for %s from mapping for %s.\n", to, from);
+ log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str());
cell_mappings[to].cell_name = cell_mappings[from].cell_name;
cell_mappings[to].ports = cell_mappings[from].ports;
@@ -484,8 +484,8 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
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);
+ if (it.second->type == ID($_NOT_))
+ notmap[sigmap(it.second->getPort(ID::A))].insert(it.second);
}
std::map<std::string, int> stats;
@@ -499,7 +499,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
module->remove(cell);
cell_mapping &cm = cell_mappings[cell_type];
- RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : "\\" + cm.cell_name);
+ RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : cm.cell_name);
new_cell->set_src_attribute(src);
@@ -519,8 +519,8 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
sig = module->addWire(NEW_ID, GetSize(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)));
+ module->connect(it->getPort(ID::Y), sig);
+ it->setPort(ID::Y, module->addWire(NEW_ID, GetSize(old_sig)));
}
} else {
module->addNotGate(NEW_ID, sig, old_sig);
@@ -599,26 +599,26 @@ struct DfflibmapPass : public Pass {
LibertyParser libparser(f);
f.close();
- find_cell(libparser.ast, "$_DFF_N_", false, false, false, false, prepare_mode);
- find_cell(libparser.ast, "$_DFF_P_", true, false, false, false, prepare_mode);
-
- find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false, prepare_mode);
- find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true, prepare_mode);
- find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false, prepare_mode);
- find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true, prepare_mode);
- find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false, prepare_mode);
- find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true, prepare_mode);
- find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false, prepare_mode);
- find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true, prepare_mode);
-
- find_cell_sr(libparser.ast, "$_DFFSR_NNN_", false, false, false, prepare_mode);
- find_cell_sr(libparser.ast, "$_DFFSR_NNP_", false, false, true, prepare_mode);
- find_cell_sr(libparser.ast, "$_DFFSR_NPN_", false, true, false, prepare_mode);
- find_cell_sr(libparser.ast, "$_DFFSR_NPP_", false, true, true, prepare_mode);
- find_cell_sr(libparser.ast, "$_DFFSR_PNN_", true, false, false, prepare_mode);
- find_cell_sr(libparser.ast, "$_DFFSR_PNP_", true, false, true, prepare_mode);
- find_cell_sr(libparser.ast, "$_DFFSR_PPN_", true, true, false, prepare_mode);
- find_cell_sr(libparser.ast, "$_DFFSR_PPP_", true, true, true, prepare_mode);
+ find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, prepare_mode);
+ find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, prepare_mode);
+
+ find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, prepare_mode);
+ find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, prepare_mode);
+ find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, prepare_mode);
+ find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, prepare_mode);
+ find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, prepare_mode);
+ find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, prepare_mode);
+ find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, prepare_mode);
+ find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, prepare_mode);
+
+ find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, prepare_mode);
+ find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, prepare_mode);
+ find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, prepare_mode);
+ find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, prepare_mode);
+ find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, prepare_mode);
+ find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, prepare_mode);
+ find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, prepare_mode);
+ find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, prepare_mode);
// try to implement as many cells as possible just by inverting
// the SET and RESET pins. If necessary, implement cell types
@@ -642,23 +642,23 @@ struct DfflibmapPass : public Pass {
break;
}
- map_sr_to_arst("$_DFFSR_NNN_", "$_DFF_NN0_");
- map_sr_to_arst("$_DFFSR_NNN_", "$_DFF_NN1_");
- map_sr_to_arst("$_DFFSR_NPP_", "$_DFF_NP0_");
- map_sr_to_arst("$_DFFSR_NPP_", "$_DFF_NP1_");
- map_sr_to_arst("$_DFFSR_PNN_", "$_DFF_PN0_");
- map_sr_to_arst("$_DFFSR_PNN_", "$_DFF_PN1_");
- 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_");
+ map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN0_));
+ map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN1_));
+ map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP0_));
+ map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP1_));
+ map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN0_));
+ map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN1_));
+ map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP0_));
+ map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP1_));
+
+ map_adff_to_dff(ID($_DFF_NN0_), ID($_DFF_N_));
+ map_adff_to_dff(ID($_DFF_NN1_), ID($_DFF_N_));
+ map_adff_to_dff(ID($_DFF_NP0_), ID($_DFF_N_));
+ map_adff_to_dff(ID($_DFF_NP1_), ID($_DFF_N_));
+ map_adff_to_dff(ID($_DFF_PN0_), ID($_DFF_P_));
+ map_adff_to_dff(ID($_DFF_PN1_), ID($_DFF_P_));
+ map_adff_to_dff(ID($_DFF_PP0_), ID($_DFF_P_));
+ map_adff_to_dff(ID($_DFF_PP1_), ID($_DFF_P_));
log(" final dff cell mappings:\n");
logmap_all();
diff --git a/passes/techmap/dffsr2dff.cc b/passes/techmap/dffsr2dff.cc
index 086a1d2fa..61b06fdc1 100644
--- a/passes/techmap/dffsr2dff.cc
+++ b/passes/techmap/dffsr2dff.cc
@@ -25,17 +25,17 @@ PRIVATE_NAMESPACE_BEGIN
void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell)
{
- if (cell->type == "$dffsr")
+ if (cell->type == ID($dffsr))
{
- int width = cell->getParam("\\WIDTH").as_int();
- bool setpol = cell->getParam("\\SET_POLARITY").as_bool();
- bool clrpol = cell->getParam("\\CLR_POLARITY").as_bool();
+ int width = cell->getParam(ID(WIDTH)).as_int();
+ bool setpol = cell->getParam(ID(SET_POLARITY)).as_bool();
+ bool clrpol = cell->getParam(ID(CLR_POLARITY)).as_bool();
SigBit setunused = setpol ? State::S0 : State::S1;
SigBit clrunused = clrpol ? State::S0 : State::S1;
- SigSpec setsig = sigmap(cell->getPort("\\SET"));
- SigSpec clrsig = sigmap(cell->getPort("\\CLR"));
+ SigSpec setsig = sigmap(cell->getPort(ID(SET)));
+ SigSpec clrsig = sigmap(cell->getPort(ID(CLR)));
Const reset_val;
SigSpec setctrl, clrctrl;
@@ -78,32 +78,32 @@ void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell)
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);
+ cell->setPort(ID(ARST), setctrl);
+ cell->setParam(ID(ARST_POLARITY), setpol);
} else {
- cell->setPort("\\ARST", clrctrl);
- cell->setParam("\\ARST_POLARITY", clrpol);
+ cell->setPort(ID(ARST), clrctrl);
+ cell->setParam(ID(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");
+ cell->type = ID($adff);
+ cell->unsetPort(ID(SET));
+ cell->unsetPort(ID(CLR));
+ cell->setParam(ID(ARST_VALUE), reset_val);
+ cell->unsetParam(ID(SET_POLARITY));
+ cell->unsetParam(ID(CLR_POLARITY));
return;
}
- if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
- "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_"))
+ if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
+ ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
{
char clkpol = cell->type.c_str()[8];
char setpol = cell->type.c_str()[9];
char clrpol = cell->type.c_str()[10];
- SigBit setbit = sigmap(cell->getPort("\\S"));
- SigBit clrbit = sigmap(cell->getPort("\\R"));
+ SigBit setbit = sigmap(cell->getPort(ID(S)));
+ SigBit clrbit = sigmap(cell->getPort(ID(R)));
SigBit setunused = setpol == 'P' ? State::S0 : State::S1;
SigBit clrunused = clrpol == 'P' ? State::S0 : State::S1;
@@ -112,14 +112,14 @@ void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell)
if (setbit == setunused) {
cell->type = stringf("$_DFF_%c%c0_", clkpol, clrpol);
- cell->unsetPort("\\S");
+ cell->unsetPort(ID(S));
goto converted_gate;
}
if (clrbit == clrunused) {
cell->type = stringf("$_DFF_%c%c1_", clkpol, setpol);
- cell->setPort("\\R", cell->getPort("\\S"));
- cell->unsetPort("\\S");
+ cell->setPort(ID(R), cell->getPort(ID(S)));
+ cell->unsetPort(ID(S));
goto converted_gate;
}
@@ -133,32 +133,32 @@ void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell)
void adff_worker(SigMap &sigmap, Module *module, Cell *cell)
{
- if (cell->type == "$adff")
+ if (cell->type == ID($adff))
{
- bool rstpol = cell->getParam("\\ARST_POLARITY").as_bool();
+ bool rstpol = cell->getParam(ID(ARST_POLARITY)).as_bool();
SigBit rstunused = rstpol ? State::S0 : State::S1;
- SigSpec rstsig = sigmap(cell->getPort("\\ARST"));
+ SigSpec rstsig = sigmap(cell->getPort(ID(ARST)));
if (rstsig != rstunused)
return;
log("Converting %s cell %s.%s to $dff.\n", log_id(cell->type), log_id(module), log_id(cell));
- cell->type = "$dff";
- cell->unsetPort("\\ARST");
- cell->unsetParam("\\ARST_VALUE");
- cell->unsetParam("\\ARST_POLARITY");
+ cell->type = ID($dff);
+ cell->unsetPort(ID(ARST));
+ cell->unsetParam(ID(ARST_VALUE));
+ cell->unsetParam(ID(ARST_POLARITY));
return;
}
- if (cell->type.in("$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
- "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_"))
+ if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
+ ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)))
{
char clkpol = cell->type.c_str()[6];
char rstpol = cell->type.c_str()[7];
- SigBit rstbit = sigmap(cell->getPort("\\R"));
+ SigBit rstbit = sigmap(cell->getPort(ID(R)));
SigBit rstunused = rstpol == 'P' ? State::S0 : State::S1;
if (rstbit != rstunused)
@@ -168,7 +168,7 @@ void adff_worker(SigMap &sigmap, Module *module, Cell *cell)
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");
+ cell->unsetPort(ID(R));
return;
}
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index fff90f13c..f8798eea5 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -54,40 +54,40 @@ public:
RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value)
{
- if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_")
+ if (!cell_type.begins_with("$") || cell_type.begins_with("$_"))
return value;
#define param_bool(_n) if (param == _n) return value.as_bool();
- param_bool("\\ARST_POLARITY");
- param_bool("\\A_SIGNED");
- param_bool("\\B_SIGNED");
- param_bool("\\CLK_ENABLE");
- param_bool("\\CLK_POLARITY");
- param_bool("\\CLR_POLARITY");
- param_bool("\\EN_POLARITY");
- param_bool("\\SET_POLARITY");
- param_bool("\\TRANSPARENT");
+ param_bool(ID(ARST_POLARITY));
+ param_bool(ID(A_SIGNED));
+ param_bool(ID(B_SIGNED));
+ param_bool(ID(CLK_ENABLE));
+ param_bool(ID(CLK_POLARITY));
+ param_bool(ID(CLR_POLARITY));
+ param_bool(ID(EN_POLARITY));
+ param_bool(ID(SET_POLARITY));
+ param_bool(ID(TRANSPARENT));
#undef param_bool
#define param_int(_n) if (param == _n) return value.as_int();
- param_int("\\ABITS")
- param_int("\\A_WIDTH")
- param_int("\\B_WIDTH")
- param_int("\\CTRL_IN_WIDTH")
- param_int("\\CTRL_OUT_WIDTH")
- param_int("\\OFFSET")
- param_int("\\PRIORITY")
- param_int("\\RD_PORTS")
- param_int("\\SIZE")
- param_int("\\STATE_BITS")
- param_int("\\STATE_NUM")
- param_int("\\STATE_NUM_LOG2")
- param_int("\\STATE_RST")
- param_int("\\S_WIDTH")
- param_int("\\TRANS_NUM")
- param_int("\\WIDTH")
- param_int("\\WR_PORTS")
- param_int("\\Y_WIDTH")
+ param_int(ID(ABITS))
+ param_int(ID(A_WIDTH))
+ param_int(ID(B_WIDTH))
+ param_int(ID(CTRL_IN_WIDTH))
+ param_int(ID(CTRL_OUT_WIDTH))
+ param_int(ID(OFFSET))
+ param_int(ID(PRIORITY))
+ param_int(ID(RD_PORTS))
+ param_int(ID(SIZE))
+ param_int(ID(STATE_BITS))
+ param_int(ID(STATE_NUM))
+ param_int(ID(STATE_NUM_LOG2))
+ param_int(ID(STATE_RST))
+ param_int(ID(S_WIDTH))
+ param_int(ID(TRANS_NUM))
+ param_int(ID(WIDTH))
+ param_int(ID(WR_PORTS))
+ param_int(ID(Y_WIDTH))
#undef param_int
return value;
@@ -203,7 +203,7 @@ bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports,
continue;
std::string type = cell->type.str();
- if (sel == NULL && type.substr(0, 2) == "\\$")
+ if (sel == NULL && type.compare(0, 2, "\\$") == 0)
type = type.substr(1);
graph.createNode(cell->name.str(), type, (void*)cell);
@@ -341,10 +341,10 @@ RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit:
bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
{
int left_idx = 0, right_idx = 0;
- if (left->attributes.count("\\extract_order") > 0)
- left_idx = left->attributes.at("\\extract_order").as_int();
- if (right->attributes.count("\\extract_order") > 0)
- right_idx = right->attributes.at("\\extract_order").as_int();
+ if (left->attributes.count(ID(extract_order)) > 0)
+ left_idx = left->attributes.at(ID(extract_order)).as_int();
+ if (right->attributes.count(ID(extract_order)) > 0)
+ right_idx = right->attributes.at(ID(extract_order)).as_int();
if (left_idx != right_idx)
return left_idx < right_idx;
return left->name < right->name;
@@ -594,7 +594,7 @@ struct ExtractPass : public Pass {
map = new RTLIL::Design;
for (auto &filename : map_filenames)
{
- if (filename.substr(0, 1) == "%")
+ if (filename.compare(0, 1, "%") == 0)
{
if (!saved_designs.count(filename.substr(1))) {
delete map;
@@ -613,10 +613,10 @@ struct ExtractPass : public Pass {
delete map;
log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
}
- Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
+ Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog"));
f.close();
- if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") {
+ if (filename.size() <= 3 || filename.compare(filename.size()-3, std::string::npos, ".il") != 0) {
Pass::call(map, "proc");
Pass::call(map, "opt_clean");
}
diff --git a/passes/techmap/extract_counter.cc b/passes/techmap/extract_counter.cc
index a8d0bc834..17a99493d 100644
--- a/passes/techmap/extract_counter.cc
+++ b/passes/techmap/extract_counter.cc
@@ -120,71 +120,71 @@ int counter_tryextract(
//A counter with less than 2 bits makes no sense
//TODO: configurable min threshold
- int a_width = cell->getParam("\\A_WIDTH").as_int();
+ int a_width = cell->getParam(ID(A_WIDTH)).as_int();
extract.width = a_width;
if( (a_width < 2) || (a_width > maxwidth) )
return 1;
//Second input must be a single bit
- int b_width = cell->getParam("\\B_WIDTH").as_int();
+ int b_width = cell->getParam(ID(B_WIDTH)).as_int();
if(b_width != 1)
return 2;
//Both inputs must be unsigned, so don't extract anything with a signed input
- bool a_sign = cell->getParam("\\A_SIGNED").as_bool();
- bool b_sign = cell->getParam("\\B_SIGNED").as_bool();
+ bool a_sign = cell->getParam(ID(A_SIGNED)).as_bool();
+ bool b_sign = cell->getParam(ID(B_SIGNED)).as_bool();
if(a_sign || b_sign)
return 3;
//To be a counter, one input of the ALU must be a constant 1
//TODO: can A or B be swapped in synthesized RTL or is B always the 1?
- const RTLIL::SigSpec b_port = sigmap(cell->getPort("\\B"));
+ const RTLIL::SigSpec b_port = sigmap(cell->getPort(ID::B));
if(!b_port.is_fully_const() || (b_port.as_int() != 1) )
return 4;
//BI and CI must be constant 1 as well
- const RTLIL::SigSpec bi_port = sigmap(cell->getPort("\\BI"));
+ const RTLIL::SigSpec bi_port = sigmap(cell->getPort(ID(BI)));
if(!bi_port.is_fully_const() || (bi_port.as_int() != 1) )
return 5;
- const RTLIL::SigSpec ci_port = sigmap(cell->getPort("\\CI"));
+ const RTLIL::SigSpec ci_port = sigmap(cell->getPort(ID(CI)));
if(!ci_port.is_fully_const() || (ci_port.as_int() != 1) )
return 6;
//CO and X must be unconnected (exactly one connection to each port)
- if(!is_unconnected(sigmap(cell->getPort("\\CO")), index))
+ if(!is_unconnected(sigmap(cell->getPort(ID(CO))), index))
return 7;
- if(!is_unconnected(sigmap(cell->getPort("\\X")), index))
+ if(!is_unconnected(sigmap(cell->getPort(ID(X))), index))
return 8;
//Y must have exactly one connection, and it has to be a $mux cell.
//We must have a direct bus connection from our Y to their A.
- const RTLIL::SigSpec aluy = sigmap(cell->getPort("\\Y"));
+ const RTLIL::SigSpec aluy = sigmap(cell->getPort(ID::Y));
pool<Cell*> y_loads = get_other_cells(aluy, index, cell);
if(y_loads.size() != 1)
return 9;
Cell* count_mux = *y_loads.begin();
extract.count_mux = count_mux;
- if(count_mux->type != "$mux")
+ if(count_mux->type != ID($mux))
return 10;
- if(!is_full_bus(aluy, index, cell, "\\Y", count_mux, "\\A"))
+ if(!is_full_bus(aluy, index, cell, ID::Y, count_mux, ID::A))
return 11;
//B connection of the mux is our underflow value
- const RTLIL::SigSpec underflow = sigmap(count_mux->getPort("\\B"));
+ const RTLIL::SigSpec underflow = sigmap(count_mux->getPort(ID::B));
if(!underflow.is_fully_const())
return 12;
extract.count_value = underflow.as_int();
//S connection of the mux must come from an inverter (need not be the only load)
- const RTLIL::SigSpec muxsel = sigmap(count_mux->getPort("\\S"));
+ const RTLIL::SigSpec muxsel = sigmap(count_mux->getPort(ID(S)));
extract.outsig = muxsel;
pool<Cell*> muxsel_conns = get_other_cells(muxsel, index, count_mux);
Cell* underflow_inv = NULL;
for(auto c : muxsel_conns)
{
- if(c->type != "$logic_not")
+ if(c->type != ID($logic_not))
continue;
- if(!is_full_bus(muxsel, index, c, "\\Y", count_mux, "\\S", true))
+ if(!is_full_bus(muxsel, index, c, ID::Y, count_mux, ID(S), true))
continue;
underflow_inv = c;
@@ -196,7 +196,7 @@ int counter_tryextract(
//Y connection of the mux must have exactly one load, the counter's internal register, if there's no clock enable
//If we have a clock enable, Y drives the B input of a mux. A of that mux must come from our register
- const RTLIL::SigSpec muxy = sigmap(count_mux->getPort("\\Y"));
+ const RTLIL::SigSpec muxy = sigmap(count_mux->getPort(ID::Y));
pool<Cell*> muxy_loads = get_other_cells(muxy, index, count_mux);
if(muxy_loads.size() != 1)
return 14;
@@ -204,12 +204,12 @@ int counter_tryextract(
Cell* count_reg = muxload;
Cell* cemux = NULL;
RTLIL::SigSpec cey;
- if(muxload->type == "$mux")
+ if(muxload->type == ID($mux))
{
//This mux is probably a clock enable mux.
//Find our count register (should be our only load)
cemux = muxload;
- cey = sigmap(cemux->getPort("\\Y"));
+ cey = sigmap(cemux->getPort(ID::Y));
pool<Cell*> cey_loads = get_other_cells(cey, index, cemux);
if(cey_loads.size() != 1)
return 24;
@@ -217,32 +217,32 @@ int counter_tryextract(
//Mux should have A driven by count Q, and B by muxy
//TODO: if A and B are swapped, CE polarity is inverted
- if(sigmap(cemux->getPort("\\B")) != muxy)
+ if(sigmap(cemux->getPort(ID::B)) != muxy)
return 24;
- if(sigmap(cemux->getPort("\\A")) != sigmap(count_reg->getPort("\\Q")))
+ if(sigmap(cemux->getPort(ID::A)) != sigmap(count_reg->getPort(ID(Q))))
return 24;
- if(sigmap(cemux->getPort("\\Y")) != sigmap(count_reg->getPort("\\D")))
+ if(sigmap(cemux->getPort(ID::Y)) != sigmap(count_reg->getPort(ID(D))))
return 24;
//Select of the mux is our clock enable
extract.has_ce = true;
- extract.ce = sigmap(cemux->getPort("\\S"));
+ extract.ce = sigmap(cemux->getPort(ID(S)));
}
else
extract.has_ce = false;
extract.count_reg = count_reg;
- if(count_reg->type == "$dff")
+ if(count_reg->type == ID($dff))
extract.has_reset = false;
- else if(count_reg->type == "$adff")
+ else if(count_reg->type == ID($adff))
{
extract.has_reset = true;
//Check polarity of reset - we may have to add an inverter later on!
- extract.rst_inverted = (count_reg->getParam("\\ARST_POLARITY").as_int() != 1);
+ extract.rst_inverted = (count_reg->getParam(ID(ARST_POLARITY)).as_int() != 1);
//Verify ARST_VALUE is zero or full scale
- int rst_value = count_reg->getParam("\\ARST_VALUE").as_int();
+ int rst_value = count_reg->getParam(ID(ARST_VALUE)).as_int();
if(rst_value == 0)
extract.rst_to_max = false;
else if(rst_value == extract.count_value)
@@ -251,7 +251,7 @@ int counter_tryextract(
return 23;
//Save the reset
- extract.rst = sigmap(count_reg->getPort("\\ARST"));
+ extract.rst = sigmap(count_reg->getPort(ID(ARST)));
}
//TODO: support synchronous reset
else
@@ -260,12 +260,12 @@ int counter_tryextract(
//Sanity check that we use the ALU output properly
if(extract.has_ce)
{
- if(!is_full_bus(muxy, index, count_mux, "\\Y", cemux, "\\B"))
+ if(!is_full_bus(muxy, index, count_mux, ID::Y, cemux, ID::B))
return 16;
- if(!is_full_bus(cey, index, cemux, "\\Y", count_reg, "\\D"))
+ if(!is_full_bus(cey, index, cemux, ID::Y, count_reg, ID(D)))
return 16;
}
- else if(!is_full_bus(muxy, index, count_mux, "\\Y", count_reg, "\\D"))
+ else if(!is_full_bus(muxy, index, count_mux, ID::Y, count_reg, ID(D)))
return 16;
//TODO: Verify count_reg CLK_POLARITY is 1
@@ -273,7 +273,7 @@ int counter_tryextract(
//Register output must have exactly two loads, the inverter and ALU
//(unless we have a parallel output!)
//If we have a clock enable, 3 is OK
- const RTLIL::SigSpec qport = count_reg->getPort("\\Q");
+ const RTLIL::SigSpec qport = count_reg->getPort(ID(Q));
const RTLIL::SigSpec cnout = sigmap(qport);
pool<Cell*> cnout_loads = get_other_cells(cnout, index, count_reg);
unsigned int max_loads = 2;
@@ -312,19 +312,19 @@ int counter_tryextract(
}
}
}
- if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true))
+ if(!is_full_bus(cnout, index, count_reg, ID(Q), underflow_inv, ID::A, true))
return 18;
- if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true))
+ if(!is_full_bus(cnout, index, count_reg, ID(Q), cell, ID::A, true))
return 19;
//Look up the clock from the register
- extract.clk = sigmap(count_reg->getPort("\\CLK"));
+ extract.clk = sigmap(count_reg->getPort(ID(CLK)));
//Register output net must have an INIT attribute equal to the count value
extract.rwire = cnout.as_wire();
- if(extract.rwire->attributes.find("\\init") == extract.rwire->attributes.end())
+ if(extract.rwire->attributes.find(ID(init)) == extract.rwire->attributes.end())
return 20;
- int rinit = extract.rwire->attributes["\\init"].as_int();
+ int rinit = extract.rwire->attributes[ID(init)].as_int();
if(rinit != extract.count_value)
return 21;
@@ -343,21 +343,21 @@ void counter_worker(
SigMap& sigmap = index.sigmap;
//Core of the counter must be an ALU
- if (cell->type != "$alu")
+ if (cell->type != ID($alu))
return;
//A input is the count value. Check if it has COUNT_EXTRACT set.
//If it's not a wire, don't even try
- auto port = sigmap(cell->getPort("\\A"));
+ auto port = sigmap(cell->getPort(ID::A));
if(!port.is_wire())
return;
RTLIL::Wire* a_wire = port.as_wire();
bool force_extract = false;
bool never_extract = false;
- string count_reg_src = a_wire->attributes["\\src"].decode_string().c_str();
- if(a_wire->attributes.find("\\COUNT_EXTRACT") != a_wire->attributes.end())
+ string count_reg_src = a_wire->attributes[ID(src)].decode_string().c_str();
+ if(a_wire->attributes.find(ID(COUNT_EXTRACT)) != a_wire->attributes.end())
{
- pool<string> sa = a_wire->get_strpool_attribute("\\COUNT_EXTRACT");
+ pool<string> sa = a_wire->get_strpool_attribute(ID(COUNT_EXTRACT));
string extract_value;
if(sa.size() >= 1)
{
@@ -434,66 +434,66 @@ void counter_worker(
string countname = string("$COUNTx$") + log_id(extract.rwire->name.str());
//Wipe all of the old connections to the ALU
- cell->unsetPort("\\A");
- cell->unsetPort("\\B");
- cell->unsetPort("\\BI");
- cell->unsetPort("\\CI");
- cell->unsetPort("\\CO");
- cell->unsetPort("\\X");
- cell->unsetPort("\\Y");
- cell->unsetParam("\\A_SIGNED");
- cell->unsetParam("\\A_WIDTH");
- cell->unsetParam("\\B_SIGNED");
- cell->unsetParam("\\B_WIDTH");
- cell->unsetParam("\\Y_WIDTH");
+ cell->unsetPort(ID::A);
+ cell->unsetPort(ID::B);
+ cell->unsetPort(ID(BI));
+ cell->unsetPort(ID(CI));
+ cell->unsetPort(ID(CO));
+ cell->unsetPort(ID(X));
+ cell->unsetPort(ID::Y);
+ cell->unsetParam(ID(A_SIGNED));
+ cell->unsetParam(ID(A_WIDTH));
+ cell->unsetParam(ID(B_SIGNED));
+ cell->unsetParam(ID(B_WIDTH));
+ cell->unsetParam(ID(Y_WIDTH));
//Change the cell type
- cell->type = "$__COUNT_";
+ cell->type = ID($__COUNT_);
//Hook up resets
if(extract.has_reset)
{
//TODO: support other kinds of reset
- cell->setParam("\\RESET_MODE", RTLIL::Const("LEVEL"));
+ cell->setParam(ID(RESET_MODE), RTLIL::Const("LEVEL"));
//If the reset is active low, infer an inverter ($__COUNT_ cells always have active high reset)
if(extract.rst_inverted)
{
auto realreset = cell->module->addWire(NEW_ID);
cell->module->addNot(NEW_ID, extract.rst, RTLIL::SigSpec(realreset));
- cell->setPort("\\RST", realreset);
+ cell->setPort(ID(RST), realreset);
}
else
- cell->setPort("\\RST", extract.rst);
+ cell->setPort(ID(RST), extract.rst);
}
else
{
- cell->setParam("\\RESET_MODE", RTLIL::Const("RISING"));
- cell->setPort("\\RST", RTLIL::SigSpec(false));
+ cell->setParam(ID(RESET_MODE), RTLIL::Const("RISING"));
+ cell->setPort(ID(RST), RTLIL::SigSpec(false));
}
//Hook up other stuff
- //cell->setParam("\\CLKIN_DIVIDE", RTLIL::Const(1));
- cell->setParam("\\COUNT_TO", RTLIL::Const(extract.count_value));
- cell->setParam("\\WIDTH", RTLIL::Const(extract.width));
- cell->setPort("\\CLK", extract.clk);
- cell->setPort("\\OUT", extract.outsig);
+ //cell->setParam(ID(CLKIN_DIVIDE), RTLIL::Const(1));
+ cell->setParam(ID(COUNT_TO), RTLIL::Const(extract.count_value));
+ cell->setParam(ID(WIDTH), RTLIL::Const(extract.width));
+ cell->setPort(ID(CLK), extract.clk);
+ cell->setPort(ID(OUT), extract.outsig);
//Hook up clock enable
if(extract.has_ce)
{
- cell->setParam("\\HAS_CE", RTLIL::Const(1));
- cell->setPort("\\CE", extract.ce);
+ cell->setParam(ID(HAS_CE), RTLIL::Const(1));
+ cell->setPort(ID(CE), extract.ce);
}
else
- cell->setParam("\\HAS_CE", RTLIL::Const(0));
+ cell->setParam(ID(HAS_CE), RTLIL::Const(0));
//Hook up hard-wired ports (for now up/down are not supported), default to no parallel output
- cell->setParam("\\HAS_POUT", RTLIL::Const(0));
- cell->setParam("\\RESET_TO_MAX", RTLIL::Const(0));
- cell->setParam("\\DIRECTION", RTLIL::Const("DOWN"));
- cell->setPort("\\CE", RTLIL::Const(1));
- cell->setPort("\\UP", RTLIL::Const(0));
+ cell->setParam(ID(HAS_POUT), RTLIL::Const(0));
+ cell->setParam(ID(RESET_TO_MAX), RTLIL::Const(0));
+ cell->setParam(ID(DIRECTION), RTLIL::Const("DOWN"));
+ cell->setPort(ID(CE), RTLIL::Const(1));
+ cell->setPort(ID(UP), RTLIL::Const(0));
//Hook up any parallel outputs
for(auto load : extract.pouts)
@@ -505,8 +505,8 @@ void counter_worker(
//Connect it to our parallel output
//(this is OK to do more than once b/c they all go to the same place)
- cell->setPort("\\POUT", sig);
- cell->setParam("\\HAS_POUT", RTLIL::Const(1));
+ cell->setPort(ID(POUT), sig);
+ cell->setParam(ID(HAS_POUT), RTLIL::Const(1));
}
//Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires)
@@ -546,7 +546,7 @@ void counter_worker(
int newbits = ceil(log2(extract.count_value));
if(extract.width != newbits)
{
- cell->setParam("\\WIDTH", RTLIL::Const(newbits));
+ cell->setParam(ID(WIDTH), RTLIL::Const(newbits));
log(" Optimizing out %d unused high-order bits (new width is %d)\n",
extract.width - newbits,
newbits);
diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc
index 9e6dc0d24..29700c37b 100644
--- a/passes/techmap/extract_fa.cc
+++ b/passes/techmap/extract_fa.cc
@@ -85,11 +85,11 @@ struct ExtractFaWorker
{
for (auto cell : module->selected_cells())
{
- if (cell->type.in( "$_BUF_", "$_NOT_", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_",
- "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_",
- "$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
+ if (cell->type.in( ID($_BUF_), ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_),
+ ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($_MUX_), ID($_NMUX_),
+ ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_)))
{
- SigBit y = sigmap(SigBit(cell->getPort("\\Y")));
+ SigBit y = sigmap(SigBit(cell->getPort(ID::Y)));
log_assert(driver.count(y) == 0);
driver[y] = cell;
}
@@ -174,8 +174,10 @@ struct ExtractFaWorker
SigSpec sig = root;
- if (!ce.eval(sig))
- log_abort();
+ if (!ce.eval(sig)) {
+ ce.pop();
+ return;
+ }
if (sig == State::S1)
func |= 1 << i;
@@ -214,8 +216,10 @@ struct ExtractFaWorker
SigSpec sig = root;
- if (!ce.eval(sig))
- log_abort();
+ if (!ce.eval(sig)) {
+ ce.pop();
+ return;
+ }
if (sig == State::S1)
func |= 1 << i;
@@ -258,10 +262,10 @@ struct ExtractFaWorker
pool<SigBit> new_leaves = leaves;
new_leaves.erase(bit);
- if (cell->hasPort("\\A")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\A"))));
- if (cell->hasPort("\\B")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\B"))));
- if (cell->hasPort("\\C")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\C"))));
- if (cell->hasPort("\\D")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\D"))));
+ if (cell->hasPort(ID::A)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::A))));
+ if (cell->hasPort(ID::B)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::B))));
+ if (cell->hasPort(ID(C))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(C)))));
+ if (cell->hasPort(ID(D))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(D)))));
if (GetSize(new_leaves) > maxbreadth)
continue;
@@ -273,8 +277,8 @@ struct ExtractFaWorker
void assign_new_driver(SigBit bit, SigBit new_driver)
{
Cell *cell = driver.at(bit);
- if (sigmap(cell->getPort("\\Y")) == bit) {
- cell->setPort("\\Y", module->addWire(NEW_ID));
+ if (sigmap(cell->getPort(ID::Y)) == bit) {
+ cell->setPort(ID::Y, module->addWire(NEW_ID));
module->connect(bit, new_driver);
}
}
@@ -285,7 +289,7 @@ struct ExtractFaWorker
for (auto it : driver)
{
- if (it.second->type.in("$_BUF_", "$_NOT_"))
+ if (it.second->type.in(ID($_BUF_), ID($_NOT_)))
continue;
SigBit root = it.first;
@@ -386,20 +390,20 @@ struct ExtractFaWorker
}
else
{
- Cell *cell = module->addCell(NEW_ID, "$fa");
- cell->setParam("\\WIDTH", 1);
+ Cell *cell = module->addCell(NEW_ID, ID($fa));
+ cell->setParam(ID(WIDTH), 1);
log(" Created $fa cell %s.\n", log_id(cell));
- cell->setPort("\\A", f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
- cell->setPort("\\B", f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
- cell->setPort("\\C", f3i.inv_c ? module->NotGate(NEW_ID, C) : C);
+ cell->setPort(ID::A, f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
+ cell->setPort(ID::B, f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
+ cell->setPort(ID(C), f3i.inv_c ? module->NotGate(NEW_ID, C) : C);
X = module->addWire(NEW_ID);
Y = module->addWire(NEW_ID);
- cell->setPort("\\X", X);
- cell->setPort("\\Y", Y);
+ cell->setPort(ID(X), X);
+ cell->setPort(ID::Y, Y);
facache[fakey] = make_tuple(X, Y, cell);
}
@@ -492,30 +496,30 @@ struct ExtractFaWorker
}
else
{
- Cell *cell = module->addCell(NEW_ID, "$fa");
- cell->setParam("\\WIDTH", 1);
+ Cell *cell = module->addCell(NEW_ID, ID($fa));
+ cell->setParam(ID(WIDTH), 1);
log(" Created $fa cell %s.\n", log_id(cell));
- cell->setPort("\\A", f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
- cell->setPort("\\B", f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
- cell->setPort("\\C", State::S0);
+ cell->setPort(ID::A, f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
+ cell->setPort(ID::B, f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
+ cell->setPort(ID(C), State::S0);
X = module->addWire(NEW_ID);
Y = module->addWire(NEW_ID);
- cell->setPort("\\X", X);
- cell->setPort("\\Y", Y);
+ cell->setPort(ID(X), X);
+ cell->setPort(ID::Y, Y);
}
if (func2.at(key).count(xor2_func)) {
- SigBit YY = invert_xy ? module->NotGate(NEW_ID, Y) : Y;
+ SigBit YY = invert_xy || (f2i.inv_a && !f2i.inv_b) || (!f2i.inv_a && f2i.inv_b) ? module->NotGate(NEW_ID, Y) : Y;
for (auto bit : func2.at(key).at(xor2_func))
assign_new_driver(bit, YY);
}
if (func2.at(key).count(xnor2_func)) {
- SigBit YY = invert_xy ? Y : module->NotGate(NEW_ID, Y);
+ SigBit YY = invert_xy || (f2i.inv_a && !f2i.inv_b) || (!f2i.inv_a && f2i.inv_b) ? Y : module->NotGate(NEW_ID, Y);
for (auto bit : func2.at(key).at(xnor2_func))
assign_new_driver(bit, YY);
}
diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc
index a77bbc0b7..11cfddcd9 100644
--- a/passes/techmap/extract_reduce.cc
+++ b/passes/techmap/extract_reduce.cc
@@ -58,9 +58,9 @@ struct ExtractReducePass : public Pass
inline bool IsRightType(Cell* cell, GateType gt)
{
- return (cell->type == "$_AND_" && gt == GateType::And) ||
- (cell->type == "$_OR_" && gt == GateType::Or) ||
- (cell->type == "$_XOR_" && gt == GateType::Xor);
+ return (cell->type == ID($_AND_) && gt == GateType::And) ||
+ (cell->type == ID($_OR_) && gt == GateType::Or) ||
+ (cell->type == ID($_XOR_) && gt == GateType::Xor);
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -124,11 +124,11 @@ struct ExtractReducePass : public Pass
GateType gt;
- if (cell->type == "$_AND_")
+ if (cell->type == ID($_AND_))
gt = GateType::And;
- else if (cell->type == "$_OR_")
+ else if (cell->type == ID($_OR_))
gt = GateType::Or;
- else if (cell->type == "$_XOR_")
+ else if (cell->type == ID($_XOR_))
gt = GateType::Xor;
else
continue;
@@ -148,7 +148,7 @@ struct ExtractReducePass : public Pass
head_cell = x;
- auto y = sigmap(x->getPort("\\Y"));
+ auto y = sigmap(x->getPort(ID::Y));
log_assert(y.size() == 1);
// Should only continue if there is one fanout back into a cell (not to a port)
@@ -166,7 +166,7 @@ struct ExtractReducePass : public Pass
{
//BFS, following all chains until they hit a cell of a different type
//Pick the longest one
- auto y = sigmap(cell->getPort("\\Y"));
+ auto y = sigmap(cell->getPort(ID::Y));
pool<Cell*> current_loads = sig_to_sink[y];
pool<Cell*> next_loads;
@@ -233,7 +233,7 @@ struct ExtractReducePass : public Pass
cur_supercell.insert(x);
- auto a = sigmap(x->getPort("\\A"));
+ auto a = sigmap(x->getPort(ID::A));
log_assert(a.size() == 1);
// Must have only one sink unless we're going off chain
@@ -249,7 +249,7 @@ struct ExtractReducePass : public Pass
}
}
- auto b = sigmap(x->getPort("\\B"));
+ auto b = sigmap(x->getPort(ID::B));
log_assert(b.size() == 1);
// Must have only one sink
@@ -279,26 +279,26 @@ struct ExtractReducePass : public Pass
pool<SigBit> input_pool_intermed;
for (auto x : cur_supercell)
{
- input_pool.insert(sigmap(x->getPort("\\A"))[0]);
- input_pool.insert(sigmap(x->getPort("\\B"))[0]);
- input_pool_intermed.insert(sigmap(x->getPort("\\Y"))[0]);
+ input_pool.insert(sigmap(x->getPort(ID::A))[0]);
+ input_pool.insert(sigmap(x->getPort(ID::B))[0]);
+ input_pool_intermed.insert(sigmap(x->getPort(ID::Y))[0]);
}
SigSpec input;
for (auto b : input_pool)
if (input_pool_intermed.count(b) == 0)
input.append_bit(b);
- SigBit output = sigmap(head_cell->getPort("\\Y")[0]);
+ SigBit output = sigmap(head_cell->getPort(ID::Y)[0]);
auto new_reduce_cell = module->addCell(NEW_ID,
- gt == GateType::And ? "$reduce_and" :
- gt == GateType::Or ? "$reduce_or" :
- gt == GateType::Xor ? "$reduce_xor" : "");
- new_reduce_cell->setParam("\\A_SIGNED", 0);
- new_reduce_cell->setParam("\\A_WIDTH", input.size());
- new_reduce_cell->setParam("\\Y_WIDTH", 1);
- new_reduce_cell->setPort("\\A", input);
- new_reduce_cell->setPort("\\Y", output);
+ gt == GateType::And ? ID($reduce_and) :
+ gt == GateType::Or ? ID($reduce_or) :
+ gt == GateType::Xor ? ID($reduce_xor) : "");
+ new_reduce_cell->setParam(ID(A_SIGNED), 0);
+ new_reduce_cell->setParam(ID(A_WIDTH), input.size());
+ new_reduce_cell->setParam(ID(Y_WIDTH), 1);
+ new_reduce_cell->setPort(ID::A, input);
+ new_reduce_cell->setPort(ID::Y, output);
if(allow_off_chain)
consumed_cells.insert(head_cell);
diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc
index f5892a60e..5807178dd 100644
--- a/passes/techmap/flowmap.cc
+++ b/passes/techmap/flowmap.cc
@@ -671,8 +671,8 @@ struct FlowmapWorker
labels[node] = -1;
for (auto input : inputs)
{
- if (input.wire->attributes.count("\\$flowmap_level"))
- labels[input] = input.wire->attributes["\\$flowmap_level"].as_int();
+ if (input.wire->attributes.count(ID($flowmap_level)))
+ labels[input] = input.wire->attributes[ID($flowmap_level)].as_int();
else
labels[input] = 0;
}
@@ -783,7 +783,7 @@ struct FlowmapWorker
int depth = 0;
for (auto label : labels)
depth = max(depth, label.second);
- log("Mapped to %zu LUTs with maximum depth %d.\n", lut_nodes.size(), depth);
+ log("Mapped to %d LUTs with maximum depth %d.\n", GetSize(lut_nodes), depth);
if (debug)
{
@@ -1195,7 +1195,7 @@ struct FlowmapWorker
bool relax_depth_for_bound(bool first, int depth_bound, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs)
{
- size_t initial_count = lut_nodes.size();
+ int initial_count = GetSize(lut_nodes);
for (auto node : lut_nodes)
{
@@ -1215,7 +1215,7 @@ struct FlowmapWorker
if (potentials.empty())
{
- log(" Relaxed to %zu (+%zu) LUTs.\n", lut_nodes.size(), lut_nodes.size() - initial_count);
+ log(" Relaxed to %d (+%d) LUTs.\n", GetSize(lut_nodes), GetSize(lut_nodes) - initial_count);
if (!first && break_num == 1)
{
log(" Design fully relaxed.\n");
@@ -1412,16 +1412,16 @@ struct FlowmapWorker
for (auto gate_node : lut_gates[node])
{
auto gate_origin = node_origins[gate_node];
- lut->add_strpool_attribute("\\src", gate_origin.cell->get_strpool_attribute("\\src"));
+ lut->add_strpool_attribute(ID(src), gate_origin.cell->get_strpool_attribute(ID(src)));
packed_count++;
}
lut_count++;
lut_area += lut_table.size();
if ((int)input_nodes.size() >= minlut)
- log(" Packed into a %zu-LUT %s.%s.\n", input_nodes.size(), log_id(module), log_id(lut));
+ log(" Packed into a %d-LUT %s.%s.\n", GetSize(input_nodes), log_id(module), log_id(lut));
else
- log(" Packed into a %zu-LUT %s.%s (implemented as %d-LUT).\n", input_nodes.size(), log_id(module), log_id(lut), minlut);
+ log(" Packed into a %d-LUT %s.%s (implemented as %d-LUT).\n", GetSize(input_nodes), log_id(module), log_id(lut), minlut);
}
for (auto node : mapped_nodes)
@@ -1586,7 +1586,7 @@ struct FlowmapPass : public Pass {
}
else
{
- cell_types = {"$_NOT_", "$_AND_", "$_OR_", "$_XOR_", "$_MUX_"};
+ cell_types = {ID($_NOT_), ID($_AND_), ID($_OR_), ID($_XOR_), ID($_MUX_)};
}
const char *algo_r = relax ? "-r" : "";
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index efcc082d5..a2551316f 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -179,8 +179,8 @@ struct IopadmapPass : public Pass {
SigMap rewrites;
for (auto cell : module->cells())
- if (cell->type == "$_TBUF_") {
- SigBit bit = sigmap(cell->getPort("\\Y").as_bit());
+ if (cell->type == ID($_TBUF_)) {
+ SigBit bit = sigmap(cell->getPort(ID::Y).as_bit());
tbuf_bits[bit].first = cell->name;
}
@@ -212,8 +212,8 @@ struct IopadmapPass : public Pass {
if (tbuf_cell == nullptr)
continue;
- SigBit en_sig = tbuf_cell->getPort("\\E").as_bit();
- SigBit data_sig = tbuf_cell->getPort("\\A").as_bit();
+ SigBit en_sig = tbuf_cell->getPort(ID(E)).as_bit();
+ SigBit data_sig = tbuf_cell->getPort(ID::A).as_bit();
if (wire->port_input && !tinoutpad_celltype.empty())
{
@@ -226,7 +226,7 @@ struct IopadmapPass : public Pass {
cell->setPort(RTLIL::escape_id(tinoutpad_portname2), owire);
cell->setPort(RTLIL::escape_id(tinoutpad_portname3), data_sig);
cell->setPort(RTLIL::escape_id(tinoutpad_portname4), wire_bit);
- cell->attributes["\\keep"] = RTLIL::Const(1);
+ cell->attributes[ID::keep] = RTLIL::Const(1);
for (auto cn : tbuf_cache.second) {
auto c = module->cell(cn);
@@ -263,7 +263,7 @@ struct IopadmapPass : public Pass {
cell->setPort(RTLIL::escape_id(toutpad_portname), en_sig);
cell->setPort(RTLIL::escape_id(toutpad_portname2), data_sig);
cell->setPort(RTLIL::escape_id(toutpad_portname3), wire_bit);
- cell->attributes["\\keep"] = RTLIL::Const(1);
+ cell->attributes[ID::keep] = RTLIL::Const(1);
for (auto cn : tbuf_cache.second) {
auto c = module->cell(cn);
@@ -390,7 +390,7 @@ struct IopadmapPass : public Pass {
cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(1);
if (!nameparam.empty())
cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(stringf("%s[%d]", RTLIL::id2cstr(wire->name), i));
- cell->attributes["\\keep"] = RTLIL::Const(1);
+ cell->attributes[ID::keep] = RTLIL::Const(1);
}
}
else
@@ -403,7 +403,7 @@ struct IopadmapPass : public Pass {
cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width);
if (!nameparam.empty())
cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name));
- cell->attributes["\\keep"] = RTLIL::Const(1);
+ cell->attributes[ID::keep] = RTLIL::Const(1);
}
wire->port_id = 0;
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index a4ed79550..c6618fc9d 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -25,9 +25,9 @@ PRIVATE_NAMESPACE_BEGIN
int lut2mux(Cell *cell)
{
- SigSpec sig_a = cell->getPort("\\A");
- SigSpec sig_y = cell->getPort("\\Y");
- Const lut = cell->getParam("\\LUT");
+ SigSpec sig_a = cell->getPort(ID::A);
+ SigSpec sig_y = cell->getPort(ID::Y);
+ Const lut = cell->getParam(ID(LUT));
int count = 1;
if (GetSize(sig_a) == 1)
@@ -81,7 +81,7 @@ struct Lut2muxPass : public Pass {
for (auto module : design->selected_modules())
for (auto cell : module->selected_cells()) {
- if (cell->type == "$lut") {
+ if (cell->type == ID($lut)) {
IdString cell_name = cell->name;
int count = lut2mux(cell);
log("Converted %s.%s to %d MUX cells.\n", log_id(module), log_id(cell_name), count);
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index 3e8e59e6b..09f61927c 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -36,7 +36,7 @@ struct MaccmapWorker
void add(RTLIL::SigBit bit, int position)
{
- if (position >= width || bit == RTLIL::S0)
+ if (position >= width || bit == State::S0)
return;
if (bits.at(position).count(bit)) {
@@ -53,7 +53,7 @@ struct MaccmapWorker
if (do_subtract) {
a = module->Not(NEW_ID, a);
- add(RTLIL::S1, 0);
+ add(State::S1, 0);
}
for (int i = 0; i < width; i++)
@@ -80,7 +80,7 @@ struct MaccmapWorker
else
{
add(module->And(NEW_ID, a, RTLIL::SigSpec(b[i], width)), false, do_subtract);
- a = {a.extract(0, width-1), RTLIL::S0};
+ a = {a.extract(0, width-1), State::S0};
}
}
@@ -88,10 +88,10 @@ struct MaccmapWorker
{
int start_index = 0, stop_index = GetSize(in1);
- while (start_index < stop_index && in1[start_index] == RTLIL::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0)
+ while (start_index < stop_index && in1[start_index] == State::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0)
start_index++;
- while (start_index < stop_index && in1[stop_index-1] == RTLIL::S0 && in2[stop_index-1] == RTLIL::S0 && in3[stop_index-1] == RTLIL::S0)
+ while (start_index < stop_index && in1[stop_index-1] == State::S0 && in2[stop_index-1] == RTLIL::S0 && in3[stop_index-1] == RTLIL::S0)
stop_index--;
if (start_index == stop_index)
@@ -111,13 +111,13 @@ struct MaccmapWorker
RTLIL::Wire *w1 = module->addWire(NEW_ID, width);
RTLIL::Wire *w2 = module->addWire(NEW_ID, width);
- RTLIL::Cell *cell = module->addCell(NEW_ID, "$fa");
- cell->setParam("\\WIDTH", width);
- cell->setPort("\\A", in1);
- cell->setPort("\\B", in2);
- cell->setPort("\\C", in3);
- cell->setPort("\\Y", w1);
- cell->setPort("\\X", w2);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, ID($fa));
+ cell->setParam(ID(WIDTH), width);
+ cell->setPort(ID::A, in1);
+ cell->setPort(ID::B, in2);
+ cell->setPort(ID(C), in3);
+ cell->setPort(ID::Y, w1);
+ cell->setPort(ID(X), w2);
out1 = {out_zeros_msb, w1, out_zeros_lsb};
out2 = {out_zeros_msb, w2, out_zeros_lsb};
@@ -222,7 +222,7 @@ struct MaccmapWorker
RTLIL::SigSpec in3 = summands[i+2];
RTLIL::SigSpec out1, out2;
fulladd(in1, in2, in3, out1, out2);
- RTLIL::SigBit extra_bit = RTLIL::S0;
+ RTLIL::SigBit extra_bit = State::S0;
if (!tree_sum_bits.empty()) {
extra_bit = tree_sum_bits.back();
tree_sum_bits.pop_back();
@@ -237,23 +237,23 @@ struct MaccmapWorker
}
- RTLIL::Cell *c = module->addCell(NEW_ID, "$alu");
- c->setPort("\\A", summands.front());
- c->setPort("\\B", summands.back());
- c->setPort("\\CI", RTLIL::S0);
- c->setPort("\\BI", RTLIL::S0);
- c->setPort("\\Y", module->addWire(NEW_ID, width));
- c->setPort("\\X", module->addWire(NEW_ID, width));
- c->setPort("\\CO", module->addWire(NEW_ID, width));
+ RTLIL::Cell *c = module->addCell(NEW_ID, ID($alu));
+ c->setPort(ID::A, summands.front());
+ c->setPort(ID::B, summands.back());
+ c->setPort(ID(CI), State::S0);
+ c->setPort(ID(BI), State::S0);
+ c->setPort(ID::Y, module->addWire(NEW_ID, width));
+ c->setPort(ID(X), module->addWire(NEW_ID, width));
+ c->setPort(ID(CO), module->addWire(NEW_ID, width));
c->fixup_parameters();
if (!tree_sum_bits.empty()) {
- c->setPort("\\CI", tree_sum_bits.back());
+ c->setPort(ID(CI), tree_sum_bits.back());
tree_sum_bits.pop_back();
}
log_assert(tree_sum_bits.empty());
- return c->getPort("\\Y");
+ return c->getPort(ID::Y);
}
};
@@ -264,17 +264,17 @@ extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false
void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
{
- int width = GetSize(cell->getPort("\\Y"));
+ int width = GetSize(cell->getPort(ID::Y));
Macc macc;
macc.from_cell(cell);
RTLIL::SigSpec all_input_bits;
- all_input_bits.append(cell->getPort("\\A"));
- all_input_bits.append(cell->getPort("\\B"));
+ all_input_bits.append(cell->getPort(ID::A));
+ all_input_bits.append(cell->getPort(ID::B));
if (all_input_bits.to_sigbit_set().count(RTLIL::Sx)) {
- module->connect(cell->getPort("\\Y"), RTLIL::SigSpec(RTLIL::Sx, width));
+ module->connect(cell->getPort(ID::Y), RTLIL::SigSpec(RTLIL::Sx, width));
return;
}
@@ -339,9 +339,9 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
}
if (summands.front().second)
- module->addNeg(NEW_ID, summands.front().first, cell->getPort("\\Y"));
+ module->addNeg(NEW_ID, summands.front().first, cell->getPort(ID::Y));
else
- module->connect(cell->getPort("\\Y"), summands.front().first);
+ module->connect(cell->getPort(ID::Y), summands.front().first);
}
else
{
@@ -356,7 +356,7 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
for (auto &bit : macc.bit_ports)
worker.add(bit, 0);
- module->connect(cell->getPort("\\Y"), worker.synth());
+ module->connect(cell->getPort(ID::Y), worker.synth());
}
}
@@ -393,7 +393,7 @@ struct MaccmapPass : public Pass {
for (auto mod : design->selected_modules())
for (auto cell : mod->selected_cells())
- if (cell->type == "$macc") {
+ if (cell->type == ID($macc)) {
log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type));
maccmap(mod, cell, unmap_mode);
mod->remove(cell);
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index 8e44be148..5541b6122 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -23,6 +23,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+#define COST_DMUX 90
#define COST_MUX2 100
#define COST_MUX4 220
#define COST_MUX8 460
@@ -57,7 +58,9 @@ struct MuxcoverWorker
bool use_mux8;
bool use_mux16;
bool nodecode;
+ bool nopartial;
+ int cost_dmux;
int cost_mux2;
int cost_mux4;
int cost_mux8;
@@ -69,6 +72,8 @@ struct MuxcoverWorker
use_mux8 = false;
use_mux16 = false;
nodecode = false;
+ nopartial = false;
+ cost_dmux = COST_DMUX;
cost_mux2 = COST_MUX2;
cost_mux4 = COST_MUX4;
cost_mux8 = COST_MUX8;
@@ -76,6 +81,23 @@ struct MuxcoverWorker
decode_mux_counter = 0;
}
+ bool xcmp(std::initializer_list<SigBit> list)
+ {
+ auto cursor = list.begin(), end = list.end();
+ log_assert(cursor != end);
+ SigBit tmp = *(cursor++);
+ while (cursor != end) {
+ SigBit bit = *(cursor++);
+ if (bit == State::Sx)
+ continue;
+ if (tmp == State::Sx)
+ tmp = bit;
+ if (bit != tmp)
+ return false;
+ }
+ return true;
+ }
+
void treeify()
{
pool<SigBit> roots;
@@ -94,13 +116,13 @@ struct MuxcoverWorker
if (!cell->input(conn.first))
continue;
for (auto bit : sigmap(conn.second)) {
- if (used_once.count(bit) || cell->type != "$_MUX_" || conn.first == "\\S")
+ if (used_once.count(bit) || cell->type != ID($_MUX_) || conn.first == ID(S))
roots.insert(bit);
used_once.insert(bit);
}
}
- if (cell->type == "$_MUX_")
- sig_to_mux[sigmap(cell->getPort("\\Y"))] = cell;
+ if (cell->type == ID($_MUX_))
+ sig_to_mux[sigmap(cell->getPort(ID::Y))] = cell;
}
log(" Treeifying %d MUXes:\n", GetSize(sig_to_mux));
@@ -119,8 +141,8 @@ struct MuxcoverWorker
if (sig_to_mux.count(bit) && (bit == rootsig || !roots.count(bit))) {
Cell *c = sig_to_mux.at(bit);
tree.muxes[bit] = c;
- wavefront.insert(sigmap(c->getPort("\\A")));
- wavefront.insert(sigmap(c->getPort("\\B")));
+ wavefront.insert(sigmap(c->getPort(ID::A)));
+ wavefront.insert(sigmap(c->getPort(ID::B)));
}
}
@@ -133,13 +155,22 @@ struct MuxcoverWorker
log(" Finished treeification: Found %d trees.\n", GetSize(tree_list));
}
- bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path)
+ bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path, bool first_layer = true)
{
if (*path) {
- if (tree.muxes.count(bit) == 0)
- return false;
+ if (tree.muxes.count(bit) == 0) {
+ if (first_layer || nopartial)
+ return false;
+ while (path[0] && path[1])
+ path++;
+ if (path[0] == 'S')
+ ret_bit = State::Sx;
+ else
+ ret_bit = bit;
+ return true;
+ }
char port_name[3] = {'\\', *path, 0};
- return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1);
+ return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1, false);
} else {
ret_bit = bit;
return true;
@@ -148,7 +179,7 @@ struct MuxcoverWorker
int prepare_decode_mux(SigBit &A, SigBit B, SigBit sel, SigBit bit)
{
- if (A == B)
+ if (A == B || sel == State::Sx)
return 0;
tuple<SigBit, SigBit, SigBit> key(A, B, sel);
@@ -166,7 +197,10 @@ struct MuxcoverWorker
if (std::get<2>(entry))
return 0;
- return cost_mux2 / GetSize(std::get<1>(entry));
+ if (A == State::Sx || B == State::Sx)
+ return 0;
+
+ return cost_dmux / GetSize(std::get<1>(entry));
}
void implement_decode_mux(SigBit ctrl_bit)
@@ -183,9 +217,32 @@ struct MuxcoverWorker
implement_decode_mux(std::get<0>(key));
implement_decode_mux(std::get<1>(key));
- module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit);
+ if (std::get<0>(key) == State::Sx) {
+ module->addBufGate(NEW_ID, std::get<1>(key), ctrl_bit);
+ } else if (std::get<1>(key) == State::Sx) {
+ module->addBufGate(NEW_ID, std::get<0>(key), ctrl_bit);
+ } else {
+ module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit);
+ decode_mux_counter++;
+ }
std::get<2>(entry) = true;
- decode_mux_counter++;
+ }
+
+ void find_best_covers(tree_t &tree, const vector<SigBit> &bits)
+ {
+ for (auto bit : bits)
+ find_best_cover(tree, bit);
+ }
+
+ int sum_best_covers(tree_t &tree, const vector<SigBit> &bits)
+ {
+ int sum = 0;
+ for (auto bit : pool<SigBit>(bits.begin(), bits.end())) {
+ int cost = tree.newmuxes.at(bit).cost;
+ log_debug(" Best cost for %s: %d\n", log_signal(bit), cost);
+ sum += cost;
+ }
+ return sum;
}
int find_best_cover(tree_t &tree, SigBit bit)
@@ -218,9 +275,13 @@ struct MuxcoverWorker
mux.inputs.push_back(B);
mux.selects.push_back(S1);
+ find_best_covers(tree, mux.inputs);
+ log_debug(" Decode cost for mux2 at %s: %d\n", log_signal(bit), mux.cost);
+
mux.cost += cost_mux2;
- mux.cost += find_best_cover(tree, A);
- mux.cost += find_best_cover(tree, B);
+ mux.cost += sum_best_covers(tree, mux.inputs);
+
+ log_debug(" Cost of mux2 at %s: %d\n", log_signal(bit), mux.cost);
best_mux = mux;
}
@@ -238,7 +299,7 @@ struct MuxcoverWorker
ok = ok && follow_muxtree(S2, tree, bit, "BS");
if (nodecode)
- ok = ok && S1 == S2;
+ ok = ok && xcmp({S1, S2});
ok = ok && follow_muxtree(T1, tree, bit, "S");
@@ -256,13 +317,15 @@ struct MuxcoverWorker
mux.selects.push_back(S1);
mux.selects.push_back(T1);
+ find_best_covers(tree, mux.inputs);
+ log_debug(" Decode cost for mux4 at %s: %d\n", log_signal(bit), mux.cost);
+
mux.cost += cost_mux4;
- mux.cost += find_best_cover(tree, A);
- mux.cost += find_best_cover(tree, B);
- mux.cost += find_best_cover(tree, C);
- mux.cost += find_best_cover(tree, D);
+ mux.cost += sum_best_covers(tree, mux.inputs);
+
+ log_debug(" Cost of mux4 at %s: %d\n", log_signal(bit), mux.cost);
- if (best_mux.cost > mux.cost)
+ if (best_mux.cost >= mux.cost)
best_mux = mux;
}
}
@@ -286,13 +349,13 @@ struct MuxcoverWorker
ok = ok && follow_muxtree(S4, tree, bit, "BBS");
if (nodecode)
- ok = ok && S1 == S2 && S2 == S3 && S3 == S4;
+ ok = ok && xcmp({S1, S2, S3, S4});
ok = ok && follow_muxtree(T1, tree, bit, "AS");
ok = ok && follow_muxtree(T2, tree, bit, "BS");
if (nodecode)
- ok = ok && T1 == T2;
+ ok = ok && xcmp({T1, T2});
ok = ok && follow_muxtree(U1, tree, bit, "S");
@@ -319,17 +382,15 @@ struct MuxcoverWorker
mux.selects.push_back(T1);
mux.selects.push_back(U1);
+ find_best_covers(tree, mux.inputs);
+ log_debug(" Decode cost for mux8 at %s: %d\n", log_signal(bit), mux.cost);
+
mux.cost += cost_mux8;
- mux.cost += find_best_cover(tree, A);
- mux.cost += find_best_cover(tree, B);
- mux.cost += find_best_cover(tree, C);
- mux.cost += find_best_cover(tree, D);
- mux.cost += find_best_cover(tree, E);
- mux.cost += find_best_cover(tree, F);
- mux.cost += find_best_cover(tree, G);
- mux.cost += find_best_cover(tree, H);
-
- if (best_mux.cost > mux.cost)
+ mux.cost += sum_best_covers(tree, mux.inputs);
+
+ log_debug(" Cost of mux8 at %s: %d\n", log_signal(bit), mux.cost);
+
+ if (best_mux.cost >= mux.cost)
best_mux = mux;
}
}
@@ -365,7 +426,7 @@ struct MuxcoverWorker
ok = ok && follow_muxtree(S8, tree, bit, "BBBS");
if (nodecode)
- ok = ok && S1 == S2 && S2 == S3 && S3 == S4 && S4 == S5 && S5 == S6 && S6 == S7 && S7 == S8;
+ ok = ok && xcmp({S1, S2, S3, S4, S5, S6, S7, S8});
ok = ok && follow_muxtree(T1, tree, bit, "AAS");
ok = ok && follow_muxtree(T2, tree, bit, "ABS");
@@ -373,13 +434,13 @@ struct MuxcoverWorker
ok = ok && follow_muxtree(T4, tree, bit, "BBS");
if (nodecode)
- ok = ok && T1 == T2 && T2 == T3 && T3 == T4;
+ ok = ok && xcmp({T1, T2, T3, T4});
ok = ok && follow_muxtree(U1, tree, bit, "AS");
ok = ok && follow_muxtree(U2, tree, bit, "BS");
if (nodecode)
- ok = ok && U1 == U2;
+ ok = ok && xcmp({U1, U2});
ok = ok && follow_muxtree(V1, tree, bit, "S");
@@ -423,25 +484,15 @@ struct MuxcoverWorker
mux.selects.push_back(U1);
mux.selects.push_back(V1);
+ find_best_covers(tree, mux.inputs);
+ log_debug(" Decode cost for mux16 at %s: %d\n", log_signal(bit), mux.cost);
+
mux.cost += cost_mux16;
- mux.cost += find_best_cover(tree, A);
- mux.cost += find_best_cover(tree, B);
- mux.cost += find_best_cover(tree, C);
- mux.cost += find_best_cover(tree, D);
- mux.cost += find_best_cover(tree, E);
- mux.cost += find_best_cover(tree, F);
- mux.cost += find_best_cover(tree, G);
- mux.cost += find_best_cover(tree, H);
- mux.cost += find_best_cover(tree, I);
- mux.cost += find_best_cover(tree, J);
- mux.cost += find_best_cover(tree, K);
- mux.cost += find_best_cover(tree, L);
- mux.cost += find_best_cover(tree, M);
- mux.cost += find_best_cover(tree, N);
- mux.cost += find_best_cover(tree, O);
- mux.cost += find_best_cover(tree, P);
-
- if (best_mux.cost > mux.cost)
+ mux.cost += sum_best_covers(tree, mux.inputs);
+
+ log_debug(" Cost of mux16 at %s: %d\n", log_signal(bit), mux.cost);
+
+ if (best_mux.cost >= mux.cost)
best_mux = mux;
}
}
@@ -465,69 +516,69 @@ struct MuxcoverWorker
if (GetSize(mux.inputs) == 2) {
count_muxes_by_type[0]++;
- Cell *cell = module->addCell(NEW_ID, "$_MUX_");
- cell->setPort("\\A", mux.inputs[0]);
- cell->setPort("\\B", mux.inputs[1]);
- cell->setPort("\\S", mux.selects[0]);
- cell->setPort("\\Y", bit);
+ Cell *cell = module->addCell(NEW_ID, ID($_MUX_));
+ cell->setPort(ID::A, mux.inputs[0]);
+ cell->setPort(ID::B, mux.inputs[1]);
+ cell->setPort(ID(S), mux.selects[0]);
+ cell->setPort(ID::Y, bit);
return;
}
if (GetSize(mux.inputs) == 4) {
count_muxes_by_type[1]++;
- Cell *cell = module->addCell(NEW_ID, "$_MUX4_");
- cell->setPort("\\A", mux.inputs[0]);
- cell->setPort("\\B", mux.inputs[1]);
- cell->setPort("\\C", mux.inputs[2]);
- cell->setPort("\\D", mux.inputs[3]);
- cell->setPort("\\S", mux.selects[0]);
- cell->setPort("\\T", mux.selects[1]);
- cell->setPort("\\Y", bit);
+ Cell *cell = module->addCell(NEW_ID, ID($_MUX4_));
+ cell->setPort(ID::A, mux.inputs[0]);
+ cell->setPort(ID::B, mux.inputs[1]);
+ cell->setPort(ID(C), mux.inputs[2]);
+ cell->setPort(ID(D), mux.inputs[3]);
+ cell->setPort(ID(S), mux.selects[0]);
+ cell->setPort(ID(T), mux.selects[1]);
+ cell->setPort(ID::Y, bit);
return;
}
if (GetSize(mux.inputs) == 8) {
count_muxes_by_type[2]++;
- Cell *cell = module->addCell(NEW_ID, "$_MUX8_");
- cell->setPort("\\A", mux.inputs[0]);
- cell->setPort("\\B", mux.inputs[1]);
- cell->setPort("\\C", mux.inputs[2]);
- cell->setPort("\\D", mux.inputs[3]);
- cell->setPort("\\E", mux.inputs[4]);
- cell->setPort("\\F", mux.inputs[5]);
- cell->setPort("\\G", mux.inputs[6]);
- cell->setPort("\\H", mux.inputs[7]);
- cell->setPort("\\S", mux.selects[0]);
- cell->setPort("\\T", mux.selects[1]);
- cell->setPort("\\U", mux.selects[2]);
- cell->setPort("\\Y", bit);
+ Cell *cell = module->addCell(NEW_ID, ID($_MUX8_));
+ cell->setPort(ID::A, mux.inputs[0]);
+ cell->setPort(ID::B, mux.inputs[1]);
+ cell->setPort(ID(C), mux.inputs[2]);
+ cell->setPort(ID(D), mux.inputs[3]);
+ cell->setPort(ID(E), mux.inputs[4]);
+ cell->setPort(ID(F), mux.inputs[5]);
+ cell->setPort(ID(G), mux.inputs[6]);
+ cell->setPort(ID(H), mux.inputs[7]);
+ cell->setPort(ID(S), mux.selects[0]);
+ cell->setPort(ID(T), mux.selects[1]);
+ cell->setPort(ID(U), mux.selects[2]);
+ cell->setPort(ID::Y, bit);
return;
}
if (GetSize(mux.inputs) == 16) {
count_muxes_by_type[3]++;
- Cell *cell = module->addCell(NEW_ID, "$_MUX16_");
- cell->setPort("\\A", mux.inputs[0]);
- cell->setPort("\\B", mux.inputs[1]);
- cell->setPort("\\C", mux.inputs[2]);
- cell->setPort("\\D", mux.inputs[3]);
- cell->setPort("\\E", mux.inputs[4]);
- cell->setPort("\\F", mux.inputs[5]);
- cell->setPort("\\G", mux.inputs[6]);
- cell->setPort("\\H", mux.inputs[7]);
- cell->setPort("\\I", mux.inputs[8]);
- cell->setPort("\\J", mux.inputs[9]);
- cell->setPort("\\K", mux.inputs[10]);
- cell->setPort("\\L", mux.inputs[11]);
- cell->setPort("\\M", mux.inputs[12]);
- cell->setPort("\\N", mux.inputs[13]);
- cell->setPort("\\O", mux.inputs[14]);
- cell->setPort("\\P", mux.inputs[15]);
- cell->setPort("\\S", mux.selects[0]);
- cell->setPort("\\T", mux.selects[1]);
- cell->setPort("\\U", mux.selects[2]);
- cell->setPort("\\V", mux.selects[3]);
- cell->setPort("\\Y", bit);
+ Cell *cell = module->addCell(NEW_ID, ID($_MUX16_));
+ cell->setPort(ID::A, mux.inputs[0]);
+ cell->setPort(ID::B, mux.inputs[1]);
+ cell->setPort(ID(C), mux.inputs[2]);
+ cell->setPort(ID(D), mux.inputs[3]);
+ cell->setPort(ID(E), mux.inputs[4]);
+ cell->setPort(ID(F), mux.inputs[5]);
+ cell->setPort(ID(G), mux.inputs[6]);
+ cell->setPort(ID(H), mux.inputs[7]);
+ cell->setPort(ID(I), mux.inputs[8]);
+ cell->setPort(ID(J), mux.inputs[9]);
+ cell->setPort(ID(K), mux.inputs[10]);
+ cell->setPort(ID(L), mux.inputs[11]);
+ cell->setPort(ID(M), mux.inputs[12]);
+ cell->setPort(ID(N), mux.inputs[13]);
+ cell->setPort(ID(O), mux.inputs[14]);
+ cell->setPort(ID(P), mux.inputs[15]);
+ cell->setPort(ID(S), mux.selects[0]);
+ cell->setPort(ID(T), mux.selects[1]);
+ cell->setPort(ID(U), mux.selects[2]);
+ cell->setPort(ID(V), mux.selects[3]);
+ cell->setPort(ID::Y, bit);
return;
}
@@ -537,6 +588,7 @@ struct MuxcoverWorker
void treecover(tree_t &tree)
{
int count_muxes_by_type[4] = {0, 0, 0, 0};
+ log_debug(" Searching for best cover for tree at %s.\n", log_signal(tree.root));
find_best_cover(tree, tree.root);
implement_best_cover(tree, tree.root, count_muxes_by_type);
log(" Replaced tree at %s: %d MUX2, %d MUX4, %d MUX8, %d MUX16\n", log_signal(tree.root),
@@ -553,12 +605,13 @@ struct MuxcoverWorker
log(" Covering trees:\n");
- // pre-fill cache of decoder muxes
- if (!nodecode)
+ if (!nodecode) {
+ log_debug(" Populating cache of decoder muxes.\n");
for (auto &tree : tree_list) {
find_best_cover(tree, tree.root);
tree.newmuxes.clear();
}
+ }
for (auto &tree : tree_list)
treecover(tree);
@@ -579,16 +632,29 @@ struct MuxcoverPass : public Pass {
log("Cover trees of $_MUX_ cells with $_MUX{4,8,16}_ cells\n");
log("\n");
log(" -mux4[=cost], -mux8[=cost], -mux16[=cost]\n");
- log(" Use the specified types of MUXes (with optional integer costs). If none\n");
- log(" of these options are given, the effect is the same as if all of them are.\n");
- log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4);
- log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16);
+ log(" Cover $_MUX_ trees using the specified types of MUXes (with optional\n");
+ log(" integer costs). If none of these options are given, the effect is the\n");
+ log(" same as if all of them are.\n");
+ log(" Default costs: $_MUX4_ = %d, $_MUX8_ = %d, \n", COST_MUX4, COST_MUX8);
+ log(" $_MUX16_ = %d\n", COST_MUX16);
+ log("\n");
+ log(" -mux2=cost\n");
+ log(" Use the specified cost for $_MUX_ cells when making covering decisions.\n");
+ log(" Default cost: $_MUX_ = %d\n", COST_MUX2);
+ log("\n");
+ log(" -dmux=cost\n");
+ log(" Use the specified cost for $_MUX_ cells used in decoders.\n");
+ log(" Default cost: %d\n", COST_DMUX);
log("\n");
log(" -nodecode\n");
log(" Do not insert decoder logic. This reduces the number of possible\n");
log(" substitutions, but guarantees that the resulting circuit is not\n");
log(" less efficient than the original circuit.\n");
log("\n");
+ log(" -nopartial\n");
+ log(" Do not consider mappings that use $_MUX<N>_ to select from less\n");
+ log(" than <N> different signals.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -598,6 +664,9 @@ struct MuxcoverPass : public Pass {
bool use_mux8 = false;
bool use_mux16 = false;
bool nodecode = false;
+ bool nopartial = false;
+ int cost_dmux = COST_DMUX;
+ int cost_mux2 = COST_MUX2;
int cost_mux4 = COST_MUX4;
int cost_mux8 = COST_MUX8;
int cost_mux16 = COST_MUX16;
@@ -606,7 +675,11 @@ struct MuxcoverPass : public Pass {
for (argidx = 1; argidx < args.size(); argidx++)
{
const auto &arg = args[argidx];
- if (arg.size() >= 5 && arg.substr(0,5) == "-mux4") {
+ if (arg.size() >= 6 && arg.compare(0,6,"-mux2=") == 0) {
+ cost_mux2 = atoi(arg.substr(6).c_str());
+ continue;
+ }
+ if (arg.size() >= 5 && arg.compare(0,5,"-mux4") == 0) {
use_mux4 = true;
if (arg.size() > 5) {
if (arg[5] != '=') break;
@@ -614,7 +687,7 @@ struct MuxcoverPass : public Pass {
}
continue;
}
- if (arg.size() >= 5 && arg.substr(0,5) == "-mux8") {
+ if (arg.size() >= 5 && arg.compare(0,5,"-mux8") == 0) {
use_mux8 = true;
if (arg.size() > 5) {
if (arg[5] != '=') break;
@@ -622,7 +695,7 @@ struct MuxcoverPass : public Pass {
}
continue;
}
- if (arg.size() >= 6 && arg.substr(0,6) == "-mux16") {
+ if (arg.size() >= 6 && arg.compare(0,6,"-mux16") == 0) {
use_mux16 = true;
if (arg.size() > 6) {
if (arg[6] != '=') break;
@@ -630,10 +703,18 @@ struct MuxcoverPass : public Pass {
}
continue;
}
+ if (arg.size() >= 6 && arg.compare(0,6,"-dmux=") == 0) {
+ cost_dmux = atoi(arg.substr(6).c_str());
+ continue;
+ }
if (arg == "-nodecode") {
nodecode = true;
continue;
}
+ if (arg == "-nopartial") {
+ nopartial = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -650,10 +731,13 @@ struct MuxcoverPass : public Pass {
worker.use_mux4 = use_mux4;
worker.use_mux8 = use_mux8;
worker.use_mux16 = use_mux16;
+ worker.cost_dmux = cost_dmux;
+ worker.cost_mux2 = cost_mux2;
worker.cost_mux4 = cost_mux4;
worker.cost_mux8 = cost_mux8;
worker.cost_mux16 = cost_mux16;
worker.nodecode = nodecode;
+ worker.nopartial = nopartial;
worker.run();
}
}
diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc
index cc765d89c..798d82248 100644
--- a/passes/techmap/nlutmap.cc
+++ b/passes/techmap/nlutmap.cc
@@ -82,10 +82,10 @@ struct NlutmapWorker
for (auto cell : module->cells())
{
- if (cell->type != "$lut" || mapped_cells.count(cell))
+ if (cell->type != ID($lut) || mapped_cells.count(cell))
continue;
- if (GetSize(cell->getPort("\\A")) == lut_size || lut_size == 2)
+ if (GetSize(cell->getPort(ID::A)) == lut_size || lut_size == 2)
candidate_ratings[cell] = 0;
for (auto &conn : cell->connections())
@@ -119,7 +119,7 @@ struct NlutmapWorker
if (config.assert_mode) {
for (auto cell : module->cells())
- if (cell->type == "$lut" && !mapped_cells.count(cell))
+ if (cell->type == ID($lut) && !mapped_cells.count(cell))
log_error("Insufficient number of LUTs to map all logic cells!\n");
}
diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc
index 6a923f481..31ab13cec 100644
--- a/passes/techmap/pmuxtree.cc
+++ b/passes/techmap/pmuxtree.cc
@@ -89,21 +89,21 @@ struct PmuxtreePass : public Pass {
for (auto module : design->selected_modules())
for (auto cell : module->selected_cells())
{
- if (cell->type != "$pmux")
+ if (cell->type != ID($pmux))
continue;
- SigSpec sig_data = cell->getPort("\\B");
- SigSpec sig_sel = cell->getPort("\\S");
+ SigSpec sig_data = cell->getPort(ID::B);
+ SigSpec sig_sel = cell->getPort(ID(S));
- if (!cell->getPort("\\A").is_fully_undef()) {
- sig_data.append(cell->getPort("\\A"));
+ if (!cell->getPort(ID::A).is_fully_undef()) {
+ sig_data.append(cell->getPort(ID::A));
SigSpec sig_sel_or = module->ReduceOr(NEW_ID, sig_sel);
sig_sel.append(module->Not(NEW_ID, sig_sel_or));
}
SigSpec result, result_or;
result = recursive_mux_generator(module, sig_data, sig_sel, result_or);
- module->connect(cell->getPort("\\Y"), result);
+ module->connect(cell->getPort(ID::Y), result);
module->remove(cell);
}
}
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index 21dfe9619..5e298d8dd 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -73,22 +73,22 @@ struct ShregmapTechGreenpak4 : ShregmapTech
bool fixup(Cell *cell, dict<int, SigBit> &taps)
{
- auto D = cell->getPort("\\D");
- auto C = cell->getPort("\\C");
+ auto D = cell->getPort(ID(D));
+ auto C = cell->getPort(ID(C));
- auto newcell = cell->module->addCell(NEW_ID, "\\GP_SHREG");
- newcell->setPort("\\nRST", State::S1);
- newcell->setPort("\\CLK", C);
- newcell->setPort("\\IN", D);
+ auto newcell = cell->module->addCell(NEW_ID, ID(GP_SHREG));
+ newcell->setPort(ID(nRST), State::S1);
+ newcell->setPort(ID(CLK), C);
+ newcell->setPort(ID(IN), D);
int i = 0;
for (auto tap : taps) {
- newcell->setPort(i ? "\\OUTB" : "\\OUTA", tap.second);
- newcell->setParam(i ? "\\OUTB_TAP" : "\\OUTA_TAP", tap.first + 1);
+ newcell->setPort(i ? ID(OUTB) : ID(OUTA), tap.second);
+ newcell->setParam(i ? ID(OUTB_TAP) : ID(OUTA_TAP), tap.first + 1);
i++;
}
- cell->setParam("\\OUTA_INVERT", 0);
+ cell->setParam(ID(OUTA_INVERT), 0);
return false;
}
};
@@ -104,19 +104,19 @@ struct ShregmapTechXilinx7 : ShregmapTech
{
for (const auto &i : module->cells_) {
auto cell = i.second;
- if (cell->type == "$shiftx") {
- if (cell->getParam("\\Y_WIDTH") != 1) continue;
+ if (cell->type == ID($shiftx)) {
+ if (cell->getParam(ID(Y_WIDTH)) != 1) continue;
int j = 0;
- for (auto bit : sigmap(cell->getPort("\\A")))
+ for (auto bit : sigmap(cell->getPort(ID::A)))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
- log_assert(j == cell->getParam("\\A_WIDTH").as_int());
+ log_assert(j == cell->getParam(ID(A_WIDTH)).as_int());
}
- else if (cell->type == "$mux") {
+ else if (cell->type == ID($mux)) {
int j = 0;
- for (auto bit : sigmap(cell->getPort("\\A")))
+ for (auto bit : sigmap(cell->getPort(ID::A)))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
j = 0;
- for (auto bit : sigmap(cell->getPort("\\B")))
+ for (auto bit : sigmap(cell->getPort(ID::B)))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
}
}
@@ -128,9 +128,9 @@ struct ShregmapTechXilinx7 : ShregmapTech
if (it == sigbit_to_shiftx_offset.end())
return;
if (cell) {
- if (cell->type == "$shiftx" && port == "\\A")
+ if (cell->type == ID($shiftx) && port == ID::A)
return;
- if (cell->type == "$mux" && (port == "\\A" || port == "\\B"))
+ if (cell->type == ID($mux) && port.in(ID::A, ID::B))
return;
}
sigbit_to_shiftx_offset.erase(it);
@@ -177,21 +177,21 @@ struct ShregmapTechXilinx7 : ShregmapTech
log_assert(shiftx);
// Only map if $shiftx exclusively covers the shift register
- if (shiftx->type == "$shiftx") {
- if (GetSize(taps) > shiftx->getParam("\\A_WIDTH").as_int())
+ if (shiftx->type == ID($shiftx)) {
+ if (GetSize(taps) > shiftx->getParam(ID(A_WIDTH)).as_int())
return false;
// Due to padding the most significant bits of A may be 1'bx,
// and if so, discount them
- if (GetSize(taps) < shiftx->getParam("\\A_WIDTH").as_int()) {
- const SigSpec A = shiftx->getPort("\\A");
- const int A_width = shiftx->getParam("\\A_WIDTH").as_int();
+ if (GetSize(taps) < shiftx->getParam(ID(A_WIDTH)).as_int()) {
+ const SigSpec A = shiftx->getPort(ID::A);
+ const int A_width = shiftx->getParam(ID(A_WIDTH)).as_int();
for (int i = GetSize(taps); i < A_width; ++i)
if (A[i] != RTLIL::Sx) return false;
}
- else if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
+ else if (GetSize(taps) != shiftx->getParam(ID(A_WIDTH)).as_int())
return false;
}
- else if (shiftx->type == "$mux") {
+ else if (shiftx->type == ID($mux)) {
if (GetSize(taps) != 2)
return false;
}
@@ -208,34 +208,34 @@ struct ShregmapTechXilinx7 : ShregmapTech
auto it = sigbit_to_shiftx_offset.find(bit);
log_assert(it != sigbit_to_shiftx_offset.end());
- auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_");
+ auto newcell = cell->module->addCell(NEW_ID, ID($__XILINX_SHREG_));
newcell->set_src_attribute(cell->get_src_attribute());
- newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH"));
- newcell->setParam("\\INIT", cell->getParam("\\INIT"));
- newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL"));
- newcell->setParam("\\ENPOL", cell->getParam("\\ENPOL"));
+ newcell->setParam(ID(DEPTH), cell->getParam(ID(DEPTH)));
+ newcell->setParam(ID(INIT), cell->getParam(ID(INIT)));
+ newcell->setParam(ID(CLKPOL), cell->getParam(ID(CLKPOL)));
+ newcell->setParam(ID(ENPOL), cell->getParam(ID(ENPOL)));
- newcell->setPort("\\C", cell->getPort("\\C"));
- newcell->setPort("\\D", cell->getPort("\\D"));
- if (cell->hasPort("\\E"))
- newcell->setPort("\\E", cell->getPort("\\E"));
+ newcell->setPort(ID(C), cell->getPort(ID(C)));
+ newcell->setPort(ID(D), cell->getPort(ID(D)));
+ if (cell->hasPort(ID(E)))
+ newcell->setPort(ID(E), cell->getPort(ID(E)));
Cell* shiftx = std::get<0>(it->second);
RTLIL::SigSpec l_wire, q_wire;
- if (shiftx->type == "$shiftx") {
- l_wire = shiftx->getPort("\\B");
- q_wire = shiftx->getPort("\\Y");
- shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
+ if (shiftx->type == ID($shiftx)) {
+ l_wire = shiftx->getPort(ID::B);
+ q_wire = shiftx->getPort(ID::Y);
+ shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
}
- else if (shiftx->type == "$mux") {
- l_wire = shiftx->getPort("\\S");
- q_wire = shiftx->getPort("\\Y");
- shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
+ else if (shiftx->type == ID($mux)) {
+ l_wire = shiftx->getPort(ID(S));
+ q_wire = shiftx->getPort(ID::Y);
+ shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID));
}
else log_abort();
- newcell->setPort("\\Q", q_wire);
- newcell->setPort("\\L", l_wire);
+ newcell->setPort(ID(Q), q_wire);
+ newcell->setPort(ID(L), l_wire);
return false;
}
@@ -263,16 +263,16 @@ struct ShregmapWorker
{
for (auto wire : module->wires())
{
- if (wire->port_output || wire->get_bool_attribute("\\keep")) {
+ if (wire->port_output || wire->get_bool_attribute(ID::keep)) {
for (auto bit : sigmap(wire)) {
sigbit_with_non_chain_users.insert(bit);
if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
}
}
- if (wire->attributes.count("\\init")) {
+ if (wire->attributes.count(ID(init))) {
SigSpec initsig = sigmap(wire);
- Const initval = wire->attributes.at("\\init");
+ Const initval = wire->attributes.at(ID(init));
for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
if (initval[i] == State::S0 && !opts.zinit)
sigbit_init[initsig[i]] = false;
@@ -283,7 +283,7 @@ struct ShregmapWorker
for (auto cell : module->cells())
{
- if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute("\\keep"))
+ if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute(ID::keep))
{
IdString d_port = opts.ffcells.at(cell->type).first;
IdString q_port = opts.ffcells.at(cell->type).second;
@@ -293,10 +293,22 @@ struct ShregmapWorker
if (opts.init || sigbit_init.count(q_bit) == 0)
{
- if (sigbit_chain_next.count(d_bit)) {
+ auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell));
+ if (!r.second) {
+ // Insertion not successful means that d_bit is already
+ // connected to another register, thus mark it as a
+ // non chain user ...
sigbit_with_non_chain_users.insert(d_bit);
- } else
- sigbit_chain_next[d_bit] = cell;
+ // ... and clone d_bit into another wire, and use that
+ // wire as a different key in the d_bit-to-cell dictionary
+ // so that it can be identified as another chain
+ // (omitting this common flop)
+ // Link: https://github.com/YosysHQ/yosys/pull/1085
+ Wire *wire = module->addWire(NEW_ID);
+ module->connect(wire, d_bit);
+ sigmap.add(wire, d_bit);
+ sigbit_chain_next.insert(std::make_pair(wire, cell));
+ }
sigbit_chain_prev[q_bit] = cell;
continue;
@@ -462,7 +474,7 @@ struct ShregmapWorker
initval.push_back(State::S0);
remove_init.insert(bit);
}
- first_cell->setParam("\\INIT", initval);
+ first_cell->setParam(ID(INIT), initval);
}
if (opts.zinit)
@@ -476,22 +488,22 @@ struct ShregmapWorker
int param_clkpol = -1;
int param_enpol = 2;
- if (first_cell->type == "$_DFF_N_") param_clkpol = 0;
- if (first_cell->type == "$_DFF_P_") param_clkpol = 1;
+ if (first_cell->type == ID($_DFF_N_)) param_clkpol = 0;
+ if (first_cell->type == ID($_DFF_P_)) param_clkpol = 1;
- if (first_cell->type == "$_DFFE_NN_") param_clkpol = 0, param_enpol = 0;
- if (first_cell->type == "$_DFFE_NP_") param_clkpol = 0, param_enpol = 1;
- if (first_cell->type == "$_DFFE_PN_") param_clkpol = 1, param_enpol = 0;
- if (first_cell->type == "$_DFFE_PP_") param_clkpol = 1, param_enpol = 1;
+ if (first_cell->type == ID($_DFFE_NN_)) param_clkpol = 0, param_enpol = 0;
+ if (first_cell->type == ID($_DFFE_NP_)) param_clkpol = 0, param_enpol = 1;
+ if (first_cell->type == ID($_DFFE_PN_)) param_clkpol = 1, param_enpol = 0;
+ if (first_cell->type == ID($_DFFE_PP_)) param_clkpol = 1, param_enpol = 1;
log_assert(param_clkpol >= 0);
- first_cell->setParam("\\CLKPOL", param_clkpol);
- if (opts.ffe) first_cell->setParam("\\ENPOL", param_enpol);
+ first_cell->setParam(ID(CLKPOL), param_clkpol);
+ if (opts.ffe) first_cell->setParam(ID(ENPOL), param_enpol);
}
first_cell->type = shreg_cell_type_str;
first_cell->setPort(q_port, last_cell->getPort(q_port));
- first_cell->setParam("\\DEPTH", depth);
+ first_cell->setParam(ID(DEPTH), depth);
if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict))
remove_cells.insert(first_cell);
@@ -509,18 +521,18 @@ struct ShregmapWorker
for (auto wire : module->wires())
{
- if (wire->attributes.count("\\init") == 0)
+ if (wire->attributes.count(ID(init)) == 0)
continue;
SigSpec initsig = sigmap(wire);
- Const &initval = wire->attributes.at("\\init");
+ Const &initval = wire->attributes.at(ID(init));
for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
if (remove_init.count(initsig[i]))
initval[i] = State::Sx;
if (SigSpec(initval).is_fully_undef())
- wire->attributes.erase("\\init");
+ wire->attributes.erase(ID(init));
}
remove_cells.clear();
@@ -605,9 +617,11 @@ struct ShregmapPass : public Pass {
log("\n");
log(" -tech greenpak4\n");
log(" map to greenpak4 shift registers.\n");
+ log(" this option also implies -clkpol pos -zinit\n");
log("\n");
log(" -tech xilinx\n");
log(" map to xilinx dynamic-length shift registers.\n");
+ log(" this option also implies -params -init\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -703,19 +717,19 @@ struct ShregmapPass : public Pass {
bool en_neg = enpol == "neg" || enpol == "any" || enpol == "any_or_none";
if (clk_pos && en_none)
- opts.ffcells["$_DFF_P_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ opts.ffcells[ID($_DFF_P_)] = make_pair(IdString(ID(D)), IdString(ID(Q)));
if (clk_neg && en_none)
- opts.ffcells["$_DFF_N_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ opts.ffcells[ID($_DFF_N_)] = make_pair(IdString(ID(D)), IdString(ID(Q)));
if (clk_pos && en_pos)
- opts.ffcells["$_DFFE_PP_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ opts.ffcells[ID($_DFFE_PP_)] = make_pair(IdString(ID(D)), IdString(ID(Q)));
if (clk_pos && en_neg)
- opts.ffcells["$_DFFE_PN_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ opts.ffcells[ID($_DFFE_PN_)] = make_pair(IdString(ID(D)), IdString(ID(Q)));
if (clk_neg && en_pos)
- opts.ffcells["$_DFFE_NP_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ opts.ffcells[ID($_DFFE_NP_)] = make_pair(IdString(ID(D)), IdString(ID(Q)));
if (clk_neg && en_neg)
- opts.ffcells["$_DFFE_NN_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ opts.ffcells[ID($_DFFE_NN_)] = make_pair(IdString(ID(D)), IdString(ID(Q)));
if (en_pos || en_neg)
opts.ffe = true;
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index f3da80c66..91574f3c6 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -28,82 +28,82 @@ YOSYS_NAMESPACE_BEGIN
void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
- sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->parameters.at(ID(A_SIGNED)).as_bool());
for (int i = 0; i < GetSize(sig_y); i++) {
- RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", sig_a[i]);
- gate->setPort("\\Y", sig_y[i]);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig_a[i]);
+ gate->setPort(ID::Y, sig_y[i]);
}
}
void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
- sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->parameters.at(ID(A_SIGNED)).as_bool());
module->connect(RTLIL::SigSig(sig_y, sig_a));
}
void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_b = cell->getPort("\\B");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
- sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
- sig_b.extend_u0(GetSize(sig_y), cell->parameters.at("\\B_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->parameters.at(ID(A_SIGNED)).as_bool());
+ sig_b.extend_u0(GetSize(sig_y), cell->parameters.at(ID(B_SIGNED)).as_bool());
- if (cell->type == "$xnor")
+ if (cell->type == ID($xnor))
{
RTLIL::SigSpec sig_t = module->addWire(NEW_ID, GetSize(sig_y));
for (int i = 0; i < GetSize(sig_y); i++) {
- RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", sig_t[i]);
- gate->setPort("\\Y", sig_y[i]);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig_t[i]);
+ gate->setPort(ID::Y, sig_y[i]);
}
sig_y = sig_t;
}
- std::string gate_type;
- if (cell->type == "$and") gate_type = "$_AND_";
- if (cell->type == "$or") gate_type = "$_OR_";
- if (cell->type == "$xor") gate_type = "$_XOR_";
- if (cell->type == "$xnor") gate_type = "$_XOR_";
+ IdString gate_type;
+ if (cell->type == ID($and)) gate_type = ID($_AND_);
+ if (cell->type == ID($or)) gate_type = ID($_OR_);
+ if (cell->type == ID($xor)) gate_type = ID($_XOR_);
+ if (cell->type == ID($xnor)) gate_type = ID($_XOR_);
log_assert(!gate_type.empty());
for (int i = 0; i < GetSize(sig_y); i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", sig_a[i]);
- gate->setPort("\\B", sig_b[i]);
- gate->setPort("\\Y", sig_y[i]);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig_a[i]);
+ gate->setPort(ID::B, sig_b[i]);
+ gate->setPort(ID::Y, sig_y[i]);
}
}
void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
if (sig_y.size() == 0)
return;
if (sig_a.size() == 0) {
- if (cell->type == "$reduce_and") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
- if (cell->type == "$reduce_or") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
- if (cell->type == "$reduce_xor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
- if (cell->type == "$reduce_xnor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
- if (cell->type == "$reduce_bool") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
+ if (cell->type == ID($reduce_and)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
+ if (cell->type == ID($reduce_or)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
+ if (cell->type == ID($reduce_xor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
+ if (cell->type == ID($reduce_xnor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
+ if (cell->type == ID($reduce_bool)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
return;
}
@@ -112,12 +112,12 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
sig_y = sig_y.extract(0, 1);
}
- std::string gate_type;
- if (cell->type == "$reduce_and") gate_type = "$_AND_";
- if (cell->type == "$reduce_or") gate_type = "$_OR_";
- if (cell->type == "$reduce_xor") gate_type = "$_XOR_";
- if (cell->type == "$reduce_xnor") gate_type = "$_XOR_";
- if (cell->type == "$reduce_bool") gate_type = "$_OR_";
+ IdString gate_type;
+ if (cell->type == ID($reduce_and)) gate_type = ID($_AND_);
+ if (cell->type == ID($reduce_or)) gate_type = ID($_OR_);
+ if (cell->type == ID($reduce_xor)) gate_type = ID($_XOR_);
+ if (cell->type == ID($reduce_xnor)) gate_type = ID($_XOR_);
+ if (cell->type == ID($reduce_bool)) gate_type = ID($_OR_);
log_assert(!gate_type.empty());
RTLIL::Cell *last_output_cell = NULL;
@@ -134,22 +134,22 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
}
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", sig_a[i]);
- gate->setPort("\\B", sig_a[i+1]);
- gate->setPort("\\Y", sig_t[i/2]);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig_a[i]);
+ gate->setPort(ID::B, sig_a[i+1]);
+ gate->setPort(ID::Y, sig_t[i/2]);
last_output_cell = gate;
}
sig_a = sig_t;
}
- if (cell->type == "$reduce_xnor") {
+ if (cell->type == ID($reduce_xnor)) {
RTLIL::SigSpec sig_t = module->addWire(NEW_ID);
- RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", sig_a);
- gate->setPort("\\Y", sig_t);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig_a);
+ gate->setPort(ID::Y, sig_t);
last_output_cell = gate;
sig_a = sig_t;
}
@@ -157,7 +157,7 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
if (last_output_cell == NULL) {
module->connect(RTLIL::SigSig(sig_y, sig_a));
} else {
- last_output_cell->setPort("\\Y", sig_y);
+ last_output_cell->setPort(ID::Y, sig_y);
}
}
@@ -174,26 +174,26 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell
continue;
}
- RTLIL::Cell *gate = module->addCell(NEW_ID, "$_OR_");
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", sig[i]);
- gate->setPort("\\B", sig[i+1]);
- gate->setPort("\\Y", sig_t[i/2]);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_OR_));
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig[i]);
+ gate->setPort(ID::B, sig[i+1]);
+ gate->setPort(ID::Y, sig_t[i/2]);
}
sig = sig_t;
}
if (sig.size() == 0)
- sig = RTLIL::SigSpec(0, 1);
+ sig = State::S0;
}
void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
logic_reduce(module, sig_a, cell);
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
if (sig_y.size() == 0)
return;
@@ -203,21 +203,21 @@ void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
sig_y = sig_y.extract(0, 1);
}
- RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", sig_a);
- gate->setPort("\\Y", sig_y);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_));
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig_a);
+ gate->setPort(ID::Y, sig_y);
}
void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
logic_reduce(module, sig_a, cell);
- RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_b = cell->getPort(ID::B);
logic_reduce(module, sig_b, cell);
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
if (sig_y.size() == 0)
return;
@@ -227,41 +227,41 @@ void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
sig_y = sig_y.extract(0, 1);
}
- std::string gate_type;
- if (cell->type == "$logic_and") gate_type = "$_AND_";
- if (cell->type == "$logic_or") gate_type = "$_OR_";
+ IdString gate_type;
+ if (cell->type == ID($logic_and)) gate_type = ID($_AND_);
+ if (cell->type == ID($logic_or)) gate_type = ID($_OR_);
log_assert(!gate_type.empty());
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", sig_a);
- gate->setPort("\\B", sig_b);
- gate->setPort("\\Y", sig_y);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig_a);
+ gate->setPort(ID::B, sig_b);
+ gate->setPort(ID::Y, sig_y);
}
void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_b = cell->getPort("\\B");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
- bool is_ne = cell->type == "$ne" || cell->type == "$nex";
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
+ bool is_signed = cell->parameters.at(ID(A_SIGNED)).as_bool();
+ bool is_ne = cell->type.in(ID($ne), ID($nex));
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"));
+ xor_cell->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
simplemap_bitop(module, xor_cell);
module->remove(xor_cell);
RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID);
RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out);
- reduce_cell->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
+ reduce_cell->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
simplemap_reduce(module, reduce_cell);
module->remove(reduce_cell);
if (!is_ne) {
RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y);
- not_cell->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
+ not_cell->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
simplemap_lognot(module, not_cell);
module->remove(not_cell);
}
@@ -269,65 +269,65 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell)
void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_b = cell->getPort("\\B");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_b = cell->getPort(ID::B);
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
for (int i = 0; i < GetSize(sig_y); i++) {
- RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_");
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", sig_a[i]);
- gate->setPort("\\B", sig_b[i]);
- gate->setPort("\\S", cell->getPort("\\S"));
- gate->setPort("\\Y", sig_y[i]);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig_a[i]);
+ gate->setPort(ID::B, sig_b[i]);
+ gate->setPort(ID(S), cell->getPort(ID(S)));
+ gate->setPort(ID::Y, sig_y[i]);
}
}
void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_e = cell->getPort("\\EN");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_e = cell->getPort(ID(EN));
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
for (int i = 0; i < GetSize(sig_y); i++) {
- 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);
- gate->setPort("\\Y", sig_y[i]);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_TBUF_));
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, sig_a[i]);
+ gate->setPort(ID(E), sig_e);
+ gate->setPort(ID::Y, sig_y[i]);
}
}
void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
{
- SigSpec lut_ctrl = cell->getPort("\\A");
- SigSpec lut_data = cell->getParam("\\LUT");
- lut_data.extend_u0(1 << cell->getParam("\\WIDTH").as_int());
+ SigSpec lut_ctrl = cell->getPort(ID::A);
+ SigSpec lut_data = cell->getParam(ID(LUT));
+ lut_data.extend_u0(1 << cell->getParam(ID(WIDTH)).as_int());
for (int idx = 0; GetSize(lut_data) > 1; idx++) {
SigSpec sig_s = lut_ctrl[idx];
SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2);
for (int i = 0; i < GetSize(lut_data); i += 2) {
- RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_");
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\A", lut_data[i]);
- gate->setPort("\\B", lut_data[i+1]);
- gate->setPort("\\S", lut_ctrl[idx]);
- gate->setPort("\\Y", new_lut_data[i/2]);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID::A, lut_data[i]);
+ gate->setPort(ID::B, lut_data[i+1]);
+ gate->setPort(ID(S), lut_ctrl[idx]);
+ gate->setPort(ID::Y, new_lut_data[i/2]);
}
lut_data = new_lut_data;
}
- module->connect(cell->getPort("\\Y"), lut_data);
+ module->connect(cell->getPort(ID::Y), lut_data);
}
void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell)
{
- SigSpec ctrl = cell->getPort("\\A");
- SigSpec table = cell->getParam("\\TABLE");
+ SigSpec ctrl = cell->getPort(ID::A);
+ SigSpec table = cell->getParam(ID(TABLE));
- int width = cell->getParam("\\WIDTH").as_int();
- int depth = cell->getParam("\\DEPTH").as_int();
+ int width = cell->getParam(ID(WIDTH)).as_int();
+ int depth = cell->getParam(ID(DEPTH)).as_int();
table.extend_u0(2 * width * depth);
SigSpec products;
@@ -348,213 +348,213 @@ void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell)
products.append(GetSize(in) > 0 ? module->Eq(NEW_ID, in, pat) : State::S1);
}
- module->connect(cell->getPort("\\Y"), module->ReduceOr(NEW_ID, products));
+ module->connect(cell->getPort(ID::Y), module->ReduceOr(NEW_ID, products));
}
void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int offset = cell->parameters.at("\\OFFSET").as_int();
- RTLIL::SigSpec sig_a = cell->getPort("\\A");
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ int offset = cell->parameters.at(ID(OFFSET)).as_int();
+ RTLIL::SigSpec sig_a = cell->getPort(ID::A);
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
module->connect(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.size())));
}
void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_ab = cell->getPort("\\A");
- sig_ab.append(cell->getPort("\\B"));
- RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ RTLIL::SigSpec sig_ab = cell->getPort(ID::A);
+ sig_ab.append(cell->getPort(ID::B));
+ RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
module->connect(RTLIL::SigSig(sig_y, sig_ab));
}
void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\WIDTH").as_int();
- char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
- char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
+ int width = cell->parameters.at(ID(WIDTH)).as_int();
+ char set_pol = cell->parameters.at(ID(SET_POLARITY)).as_bool() ? 'P' : 'N';
+ char clr_pol = cell->parameters.at(ID(CLR_POLARITY)).as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_s = cell->getPort("\\SET");
- RTLIL::SigSpec sig_r = cell->getPort("\\CLR");
- RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+ RTLIL::SigSpec sig_s = cell->getPort(ID(SET));
+ RTLIL::SigSpec sig_r = cell->getPort(ID(CLR));
+ RTLIL::SigSpec sig_q = cell->getPort(ID(Q));
std::string gate_type = stringf("$_SR_%c%c_", set_pol, clr_pol);
for (int i = 0; i < width; i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\S", sig_s[i]);
- gate->setPort("\\R", sig_r[i]);
- gate->setPort("\\Q", sig_q[i]);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID(S), sig_s[i]);
+ gate->setPort(ID(R), sig_r[i]);
+ gate->setPort(ID(Q), sig_q[i]);
}
}
void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\WIDTH").as_int();
+ int width = cell->parameters.at(ID(WIDTH)).as_int();
- RTLIL::SigSpec sig_d = cell->getPort("\\D");
- RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+ RTLIL::SigSpec sig_d = cell->getPort(ID(D));
+ RTLIL::SigSpec sig_q = cell->getPort(ID(Q));
- std::string gate_type = "$_FF_";
+ IdString gate_type = ID($_FF_);
for (int i = 0; i < width; i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\D", sig_d[i]);
- gate->setPort("\\Q", sig_q[i]);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID(D), sig_d[i]);
+ gate->setPort(ID(Q), sig_q[i]);
}
}
void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\WIDTH").as_int();
- char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
+ int width = cell->parameters.at(ID(WIDTH)).as_int();
+ char clk_pol = cell->parameters.at(ID(CLK_POLARITY)).as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
- RTLIL::SigSpec sig_d = cell->getPort("\\D");
- RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+ RTLIL::SigSpec sig_clk = cell->getPort(ID(CLK));
+ RTLIL::SigSpec sig_d = cell->getPort(ID(D));
+ RTLIL::SigSpec sig_q = cell->getPort(ID(Q));
- std::string gate_type = stringf("$_DFF_%c_", clk_pol);
+ IdString gate_type = stringf("$_DFF_%c_", clk_pol);
for (int i = 0; i < width; i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\C", sig_clk);
- gate->setPort("\\D", sig_d[i]);
- gate->setPort("\\Q", sig_q[i]);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID(C), sig_clk);
+ gate->setPort(ID(D), sig_d[i]);
+ gate->setPort(ID(Q), sig_q[i]);
}
}
void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\WIDTH").as_int();
- char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
- char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
+ int width = cell->parameters.at(ID(WIDTH)).as_int();
+ char clk_pol = cell->parameters.at(ID(CLK_POLARITY)).as_bool() ? 'P' : 'N';
+ char en_pol = cell->parameters.at(ID(EN_POLARITY)).as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
- RTLIL::SigSpec sig_en = cell->getPort("\\EN");
- RTLIL::SigSpec sig_d = cell->getPort("\\D");
- RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+ RTLIL::SigSpec sig_clk = cell->getPort(ID(CLK));
+ RTLIL::SigSpec sig_en = cell->getPort(ID(EN));
+ RTLIL::SigSpec sig_d = cell->getPort(ID(D));
+ RTLIL::SigSpec sig_q = cell->getPort(ID(Q));
- std::string gate_type = stringf("$_DFFE_%c%c_", clk_pol, en_pol);
+ IdString gate_type = stringf("$_DFFE_%c%c_", clk_pol, en_pol);
for (int i = 0; i < width; i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\C", sig_clk);
- gate->setPort("\\E", sig_en);
- gate->setPort("\\D", sig_d[i]);
- gate->setPort("\\Q", sig_q[i]);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID(C), sig_clk);
+ gate->setPort(ID(E), sig_en);
+ gate->setPort(ID(D), sig_d[i]);
+ gate->setPort(ID(Q), sig_q[i]);
}
}
void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\WIDTH").as_int();
- char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
- char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
- char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
+ int width = cell->parameters.at(ID(WIDTH)).as_int();
+ char clk_pol = cell->parameters.at(ID(CLK_POLARITY)).as_bool() ? 'P' : 'N';
+ char set_pol = cell->parameters.at(ID(SET_POLARITY)).as_bool() ? 'P' : 'N';
+ char clr_pol = cell->parameters.at(ID(CLR_POLARITY)).as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
- RTLIL::SigSpec sig_s = cell->getPort("\\SET");
- RTLIL::SigSpec sig_r = cell->getPort("\\CLR");
- RTLIL::SigSpec sig_d = cell->getPort("\\D");
- RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+ RTLIL::SigSpec sig_clk = cell->getPort(ID(CLK));
+ RTLIL::SigSpec sig_s = cell->getPort(ID(SET));
+ RTLIL::SigSpec sig_r = cell->getPort(ID(CLR));
+ RTLIL::SigSpec sig_d = cell->getPort(ID(D));
+ RTLIL::SigSpec sig_q = cell->getPort(ID(Q));
- std::string gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol);
+ IdString gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol);
for (int i = 0; i < width; i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\C", sig_clk);
- gate->setPort("\\S", sig_s[i]);
- gate->setPort("\\R", sig_r[i]);
- gate->setPort("\\D", sig_d[i]);
- gate->setPort("\\Q", sig_q[i]);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID(C), sig_clk);
+ gate->setPort(ID(S), sig_s[i]);
+ gate->setPort(ID(R), sig_r[i]);
+ gate->setPort(ID(D), sig_d[i]);
+ gate->setPort(ID(Q), sig_q[i]);
}
}
void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\WIDTH").as_int();
- char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
- char rst_pol = cell->parameters.at("\\ARST_POLARITY").as_bool() ? 'P' : 'N';
+ int width = cell->parameters.at(ID(WIDTH)).as_int();
+ char clk_pol = cell->parameters.at(ID(CLK_POLARITY)).as_bool() ? 'P' : 'N';
+ char rst_pol = cell->parameters.at(ID(ARST_POLARITY)).as_bool() ? 'P' : 'N';
- std::vector<RTLIL::State> rst_val = cell->parameters.at("\\ARST_VALUE").bits;
+ std::vector<RTLIL::State> rst_val = cell->parameters.at(ID(ARST_VALUE)).bits;
while (int(rst_val.size()) < width)
rst_val.push_back(RTLIL::State::S0);
- RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
- RTLIL::SigSpec sig_rst = cell->getPort("\\ARST");
- RTLIL::SigSpec sig_d = cell->getPort("\\D");
- RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+ RTLIL::SigSpec sig_clk = cell->getPort(ID(CLK));
+ RTLIL::SigSpec sig_rst = cell->getPort(ID(ARST));
+ RTLIL::SigSpec sig_d = cell->getPort(ID(D));
+ RTLIL::SigSpec sig_q = cell->getPort(ID(Q));
- std::string gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol);
- std::string gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol);
+ IdString gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol);
+ IdString gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol);
for (int i = 0; i < width; i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\C", sig_clk);
- gate->setPort("\\R", sig_rst);
- gate->setPort("\\D", sig_d[i]);
- gate->setPort("\\Q", sig_q[i]);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID(C), sig_clk);
+ gate->setPort(ID(R), sig_rst);
+ gate->setPort(ID(D), sig_d[i]);
+ gate->setPort(ID(Q), sig_q[i]);
}
}
void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\WIDTH").as_int();
- char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
+ int width = cell->parameters.at(ID(WIDTH)).as_int();
+ char en_pol = cell->parameters.at(ID(EN_POLARITY)).as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_en = cell->getPort("\\EN");
- RTLIL::SigSpec sig_d = cell->getPort("\\D");
- RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+ RTLIL::SigSpec sig_en = cell->getPort(ID(EN));
+ RTLIL::SigSpec sig_d = cell->getPort(ID(D));
+ RTLIL::SigSpec sig_q = cell->getPort(ID(Q));
- std::string gate_type = stringf("$_DLATCH_%c_", en_pol);
+ IdString gate_type = stringf("$_DLATCH_%c_", en_pol);
for (int i = 0; i < width; i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
- gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
- gate->setPort("\\E", sig_en);
- gate->setPort("\\D", sig_d[i]);
- gate->setPort("\\Q", sig_q[i]);
+ gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src)));
+ gate->setPort(ID(E), sig_en);
+ gate->setPort(ID(D), sig_d[i]);
+ gate->setPort(ID(Q), sig_q[i]);
}
}
void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
{
- mappers["$not"] = simplemap_not;
- mappers["$pos"] = simplemap_pos;
- mappers["$and"] = simplemap_bitop;
- mappers["$or"] = simplemap_bitop;
- mappers["$xor"] = simplemap_bitop;
- mappers["$xnor"] = simplemap_bitop;
- mappers["$reduce_and"] = simplemap_reduce;
- mappers["$reduce_or"] = simplemap_reduce;
- mappers["$reduce_xor"] = simplemap_reduce;
- mappers["$reduce_xnor"] = simplemap_reduce;
- mappers["$reduce_bool"] = simplemap_reduce;
- mappers["$logic_not"] = simplemap_lognot;
- mappers["$logic_and"] = simplemap_logbin;
- mappers["$logic_or"] = simplemap_logbin;
- mappers["$eq"] = simplemap_eqne;
- mappers["$eqx"] = simplemap_eqne;
- mappers["$ne"] = simplemap_eqne;
- mappers["$nex"] = simplemap_eqne;
- mappers["$mux"] = simplemap_mux;
- mappers["$tribuf"] = simplemap_tribuf;
- mappers["$lut"] = simplemap_lut;
- mappers["$sop"] = simplemap_sop;
- mappers["$slice"] = simplemap_slice;
- mappers["$concat"] = simplemap_concat;
- mappers["$sr"] = simplemap_sr;
- mappers["$ff"] = simplemap_ff;
- mappers["$dff"] = simplemap_dff;
- mappers["$dffe"] = simplemap_dffe;
- mappers["$dffsr"] = simplemap_dffsr;
- mappers["$adff"] = simplemap_adff;
- mappers["$dlatch"] = simplemap_dlatch;
+ mappers[ID($not)] = simplemap_not;
+ mappers[ID($pos)] = simplemap_pos;
+ mappers[ID($and)] = simplemap_bitop;
+ mappers[ID($or)] = simplemap_bitop;
+ mappers[ID($xor)] = simplemap_bitop;
+ mappers[ID($xnor)] = simplemap_bitop;
+ mappers[ID($reduce_and)] = simplemap_reduce;
+ mappers[ID($reduce_or)] = simplemap_reduce;
+ mappers[ID($reduce_xor)] = simplemap_reduce;
+ mappers[ID($reduce_xnor)] = simplemap_reduce;
+ mappers[ID($reduce_bool)] = simplemap_reduce;
+ mappers[ID($logic_not)] = simplemap_lognot;
+ mappers[ID($logic_and)] = simplemap_logbin;
+ mappers[ID($logic_or)] = simplemap_logbin;
+ mappers[ID($eq)] = simplemap_eqne;
+ mappers[ID($eqx)] = simplemap_eqne;
+ mappers[ID($ne)] = simplemap_eqne;
+ mappers[ID($nex)] = simplemap_eqne;
+ mappers[ID($mux)] = simplemap_mux;
+ mappers[ID($tribuf)] = simplemap_tribuf;
+ mappers[ID($lut)] = simplemap_lut;
+ mappers[ID($sop)] = simplemap_sop;
+ mappers[ID($slice)] = simplemap_slice;
+ mappers[ID($concat)] = simplemap_concat;
+ mappers[ID($sr)] = simplemap_sr;
+ mappers[ID($ff)] = simplemap_ff;
+ mappers[ID($dff)] = simplemap_dff;
+ mappers[ID($dffe)] = simplemap_dffe;
+ mappers[ID($dffsr)] = simplemap_dffsr;
+ mappers[ID($adff)] = simplemap_adff;
+ mappers[ID($dlatch)] = simplemap_dlatch;
}
void simplemap(RTLIL::Module *module, RTLIL::Cell *cell)
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index ab0bd3b54..c4496f76f 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -39,20 +39,20 @@ YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-void apply_prefix(std::string prefix, std::string &id)
+void apply_prefix(IdString prefix, IdString &id)
{
if (id[0] == '\\')
- id = prefix + "." + id.substr(1);
+ id = stringf("%s.%s", prefix.c_str(), id.c_str()+1);
else
- id = "$techmap" + prefix + "." + id;
+ id = stringf("$techmap%s.%s", prefix.c_str(), id.c_str());
}
-void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
+void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{
vector<SigChunk> chunks = sig;
for (auto &chunk : chunks)
if (chunk.wire != NULL) {
- std::string wire_name = chunk.wire->name.str();
+ IdString wire_name = chunk.wire->name;
apply_prefix(prefix, wire_name);
log_assert(module->wires_.count(wire_name) > 0);
chunk.wire = module->wires_[wire_name];
@@ -145,8 +145,8 @@ struct TechmapWorker
record.wire = it.second;
record.value = it.second;
result[p].push_back(record);
- it.second->attributes["\\keep"] = RTLIL::Const(1);
- it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1);
+ it.second->attributes[ID::keep] = RTLIL::Const(1);
+ it.second->attributes[ID(_techmap_special_)] = RTLIL::Const(1);
}
}
@@ -175,11 +175,11 @@ struct TechmapWorker
}
std::string orig_cell_name;
- pool<string> extra_src_attrs = cell->get_strpool_attribute("\\src");
+ pool<string> extra_src_attrs = cell->get_strpool_attribute(ID(src));
if (!flatten_mode) {
for (auto &it : tpl->cells_)
- if (it.first == "\\_TECHMAP_REPLACE_") {
+ if (it.first == ID(_TECHMAP_REPLACE_)) {
orig_cell_name = cell->name.str();
module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str());
break;
@@ -189,16 +189,16 @@ struct TechmapWorker
dict<IdString, IdString> memory_renames;
for (auto &it : tpl->memories) {
- std::string m_name = it.first.str();
- apply_prefix(cell->name.str(), m_name);
+ IdString m_name = it.first;
+ apply_prefix(cell->name, m_name);
RTLIL::Memory *m = new RTLIL::Memory;
m->name = m_name;
m->width = it.second->width;
m->start_offset = it.second->start_offset;
m->size = it.second->size;
m->attributes = it.second->attributes;
- if (m->attributes.count("\\src"))
- m->add_strpool_attribute("\\src", extra_src_attrs);
+ if (m->attributes.count(ID(src)))
+ m->add_strpool_attribute(ID(src), extra_src_attrs);
module->memories[m->name] = m;
memory_renames[it.first] = m->name;
design->select(module, m);
@@ -209,16 +209,16 @@ struct TechmapWorker
for (auto &it : tpl->wires_) {
if (it.second->port_id > 0)
positional_ports[stringf("$%d", it.second->port_id)] = it.first;
- std::string w_name = it.second->name.str();
- apply_prefix(cell->name.str(), w_name);
+ IdString w_name = it.second->name;
+ apply_prefix(cell->name, w_name);
RTLIL::Wire *w = module->addWire(w_name, it.second);
w->port_input = false;
w->port_output = false;
w->port_id = 0;
- if (it.second->get_bool_attribute("\\_techmap_special_"))
+ if (it.second->get_bool_attribute(ID(_techmap_special_)))
w->attributes.clear();
- if (w->attributes.count("\\src"))
- w->add_strpool_attribute("\\src", extra_src_attrs);
+ if (w->attributes.count(ID(src)))
+ w->add_strpool_attribute(ID(src), extra_src_attrs);
design->select(module, w);
}
@@ -243,7 +243,7 @@ struct TechmapWorker
if (positional_ports.count(portname) > 0)
portname = positional_ports.at(portname);
if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) {
- if (portname.substr(0, 1) == "$")
+ if (portname.begins_with("$"))
log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
continue;
}
@@ -257,18 +257,18 @@ struct TechmapWorker
if (w->port_output && !w->port_input) {
c.first = it.second;
c.second = RTLIL::SigSpec(w);
- apply_prefix(cell->name.str(), c.second, module);
+ apply_prefix(cell->name, c.second, module);
extra_connect.first = c.second;
extra_connect.second = c.first;
} else if (!w->port_output && w->port_input) {
c.first = RTLIL::SigSpec(w);
c.second = it.second;
- apply_prefix(cell->name.str(), c.first, module);
+ apply_prefix(cell->name, c.first, module);
extra_connect.first = c.first;
extra_connect.second = c.second;
} else {
SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second;
- apply_prefix(cell->name.str(), sig_tpl_pf, module);
+ apply_prefix(cell->name, sig_tpl_pf, module);
for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) {
if (tpl_written_bits.count(tpl_sigmap(sig_tpl[i]))) {
c.first.append(sig_mod[i]);
@@ -320,7 +320,7 @@ struct TechmapWorker
}
for (auto &attr : w->attributes) {
- if (attr.first == "\\src")
+ if (attr.first == ID(src))
continue;
module->connect(extra_connect);
break;
@@ -330,39 +330,39 @@ struct TechmapWorker
for (auto &it : tpl->cells_)
{
- std::string c_name = it.second->name.str();
- bool techmap_replace_cell = (!flatten_mode) && (c_name == "\\_TECHMAP_REPLACE_");
+ IdString c_name = it.second->name.str();
+ bool techmap_replace_cell = (!flatten_mode) && (c_name == ID(_TECHMAP_REPLACE_));
if (techmap_replace_cell)
c_name = orig_cell_name;
else
- apply_prefix(cell->name.str(), c_name);
+ apply_prefix(cell->name, c_name);
RTLIL::Cell *c = module->addCell(c_name, it.second);
design->select(module, c);
- if (!flatten_mode && c->type.substr(0, 2) == "\\$")
+ if (!flatten_mode && c->type.begins_with("\\$"))
c->type = c->type.substr(1);
for (auto &it2 : c->connections_) {
- apply_prefix(cell->name.str(), it2.second, module);
+ apply_prefix(cell->name, it2.second, module);
port_signal_map.apply(it2.second);
}
- if (c->type == "$memrd" || c->type == "$memwr" || c->type == "$meminit") {
- IdString memid = c->getParam("\\MEMID").decode_string();
+ if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) {
+ IdString memid = c->getParam(ID(MEMID)).decode_string();
log_assert(memory_renames.count(memid) != 0);
- c->setParam("\\MEMID", Const(memory_renames[memid].str()));
+ c->setParam(ID(MEMID), Const(memory_renames[memid].str()));
}
- if (c->type == "$mem") {
- string memid = c->getParam("\\MEMID").decode_string();
- apply_prefix(cell->name.str(), memid);
- c->setParam("\\MEMID", Const(memid));
+ if (c->type == ID($mem)) {
+ IdString memid = c->getParam(ID(MEMID)).decode_string();
+ apply_prefix(cell->name, memid);
+ c->setParam(ID(MEMID), Const(memid.c_str()));
}
- if (c->attributes.count("\\src"))
- c->add_strpool_attribute("\\src", extra_src_attrs);
+ if (c->attributes.count(ID(src)))
+ c->add_strpool_attribute(ID(src), extra_src_attrs);
if (techmap_replace_cell)
for (auto attr : cell->attributes)
@@ -406,7 +406,7 @@ struct TechmapWorker
continue;
std::string cell_type = cell->type.str();
- if (in_recursion && cell_type.substr(0, 2) == "\\$")
+ if (in_recursion && cell->type.begins_with("\\$"))
cell_type = cell_type.substr(1);
if (celltypeMap.count(cell_type) == 0) {
@@ -416,9 +416,9 @@ struct TechmapWorker
}
if (flatten_mode) {
- bool keepit = cell->get_bool_attribute("\\keep_hierarchy");
+ bool keepit = cell->get_bool_attribute(ID(keep_hierarchy));
for (auto &tpl_name : celltypeMap.at(cell_type))
- if (map->modules_[tpl_name]->get_bool_attribute("\\keep_hierarchy"))
+ if (map->modules_[tpl_name]->get_bool_attribute(ID(keep_hierarchy)))
keepit = true;
if (keepit) {
if (!flatten_keep_list[cell]) {
@@ -468,7 +468,7 @@ struct TechmapWorker
std::string cell_type = cell->type.str();
- if (in_recursion && cell_type.substr(0, 2) == "\\$")
+ if (in_recursion && cell->type.begins_with("\\$"))
cell_type = cell_type.substr(1);
for (auto &tpl_name : celltypeMap.at(cell_type))
@@ -484,13 +484,13 @@ struct TechmapWorker
{
std::string extmapper_name;
- if (tpl->get_bool_attribute("\\techmap_simplemap"))
+ if (tpl->get_bool_attribute(ID(techmap_simplemap)))
extmapper_name = "simplemap";
- if (tpl->get_bool_attribute("\\techmap_maccmap"))
+ if (tpl->get_bool_attribute(ID(techmap_maccmap)))
extmapper_name = "maccmap";
- if (tpl->attributes.count("\\techmap_wrap"))
+ if (tpl->attributes.count(ID(techmap_wrap)))
extmapper_name = "wrap";
if (!extmapper_name.empty())
@@ -505,7 +505,7 @@ struct TechmapWorker
m_name += stringf(":%s=%s", log_id(c.first), log_signal(c.second));
if (extmapper_name == "wrap")
- m_name += ":" + sha1(tpl->attributes.at("\\techmap_wrap").decode_string());
+ m_name += ":" + sha1(tpl->attributes.at(ID(techmap_wrap)).decode_string());
RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design;
RTLIL::Module *extmapper_module = extmapper_design->module(m_name);
@@ -520,7 +520,7 @@ struct TechmapWorker
int port_counter = 1;
for (auto &c : extmapper_cell->connections_) {
RTLIL::Wire *w = extmapper_module->addWire(c.first, GetSize(c.second));
- if (w->name == "\\Y" || w->name == "\\Q")
+ if (w->name.in(ID::Y, ID(Q)))
w->port_output = true;
else
w->port_input = true;
@@ -541,14 +541,14 @@ struct TechmapWorker
if (extmapper_name == "maccmap") {
log("Creating %s with maccmap.\n", log_id(extmapper_module));
- if (extmapper_cell->type != "$macc")
+ if (extmapper_cell->type != ID($macc))
log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type));
maccmap(extmapper_module, extmapper_cell);
extmapper_module->remove(extmapper_cell);
}
if (extmapper_name == "wrap") {
- std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string();
+ std::string cmd_string = tpl->attributes.at(ID(techmap_wrap)).decode_string();
log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module));
mkdebug.on();
Pass::call_on_module(extmapper_design, extmapper_module, cmd_string);
@@ -587,7 +587,7 @@ struct TechmapWorker
}
if (extmapper_name == "maccmap") {
- if (cell->type != "$macc")
+ if (cell->type != ID($macc))
log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type));
maccmap(module, cell);
}
@@ -602,7 +602,7 @@ struct TechmapWorker
}
for (auto conn : cell->connections()) {
- if (conn.first.substr(0, 1) == "$")
+ if (conn.first.begins_with("$"))
continue;
if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0)
continue;
@@ -616,8 +616,8 @@ struct TechmapWorker
continue;
}
- if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0)
- parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type);
+ if (tpl->avail_parameters.count(ID(_TECHMAP_CELLTYPE_)) != 0)
+ parameters[ID(_TECHMAP_CELLTYPE_)] = RTLIL::unescape_id(cell->type);
for (auto conn : cell->connections()) {
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) {
@@ -649,12 +649,15 @@ struct TechmapWorker
unique_bit_id[bit] = unique_bit_id_counter++;
}
+ // Find highest bit set
int bits = 0;
for (int i = 0; i < 32; i++)
if (((unique_bit_id_counter-1) & (1 << i)) != 0)
bits = i;
- if (tpl->avail_parameters.count("\\_TECHMAP_BITS_CONNMAP_"))
- parameters["\\_TECHMAP_BITS_CONNMAP_"] = bits;
+ // Increment index by one to get number of bits
+ bits++;
+ if (tpl->avail_parameters.count(ID(_TECHMAP_BITS_CONNMAP_)))
+ parameters[ID(_TECHMAP_BITS_CONNMAP_)] = bits;
for (auto conn : cell->connections())
if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
@@ -722,7 +725,7 @@ struct TechmapWorker
for (auto &it : twd)
{
- if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty())
+ if (it.first.compare(0, 12, "_TECHMAP_DO_") != 0 || it.second.empty())
continue;
auto &data = it.second.front();
@@ -871,7 +874,7 @@ struct TechmapWorker
tpl->cloneInto(m);
for (auto cell : m->cells()) {
- if (cell->type.substr(0, 2) == "\\$")
+ if (cell->type.begins_with("\\$"))
cell->type = cell->type.substr(1);
}
@@ -940,7 +943,8 @@ struct TechmapPass : public Pass {
log(" instead of inlining them.\n");
log("\n");
log(" -max_iter <number>\n");
- log(" only run the specified number of iterations.\n");
+ log(" only run the specified number of iterations on each module.\n");
+ log(" default: unlimited\n");
log("\n");
log(" -recursive\n");
log(" instead of the iterative breadth-first algorithm use a recursive\n");
@@ -1110,7 +1114,7 @@ struct TechmapPass : public Pass {
Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend);
} else {
for (auto &fn : map_files)
- if (fn.substr(0, 1) == "%") {
+ if (fn.compare(0, 1, "%") == 0) {
if (!saved_designs.count(fn.substr(1))) {
delete map;
log_cmd_error("Can't saved design `%s'.\n", fn.c_str()+1);
@@ -1125,7 +1129,7 @@ struct TechmapPass : public Pass {
yosys_input_files.insert(fn);
if (f.fail())
log_cmd_error("Can't open map file `%s'\n", fn.c_str());
- Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
+ Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend));
}
}
@@ -1133,14 +1137,14 @@ struct TechmapPass : public Pass {
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
for (auto &it : map->modules_) {
- if (it.second->attributes.count("\\techmap_celltype") && !it.second->attributes.at("\\techmap_celltype").bits.empty()) {
- char *p = strdup(it.second->attributes.at("\\techmap_celltype").decode_string().c_str());
+ if (it.second->attributes.count(ID(techmap_celltype)) && !it.second->attributes.at(ID(techmap_celltype)).bits.empty()) {
+ char *p = strdup(it.second->attributes.at(ID(techmap_celltype)).decode_string().c_str());
for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n"))
celltypeMap[RTLIL::escape_id(q)].insert(it.first);
free(p);
} else {
string module_name = it.first.str();
- if (module_name.substr(0, 2) == "\\$")
+ if (it.first.begins_with("\\$"))
module_name = module_name.substr(1);
celltypeMap[module_name].insert(it.first);
}
@@ -1154,15 +1158,16 @@ struct TechmapPass : public Pass {
RTLIL::Module *module = *worker.module_queue.begin();
worker.module_queue.erase(module);
+ int module_max_iter = max_iter;
bool did_something = true;
std::set<RTLIL::Cell*> handled_cells;
while (did_something) {
did_something = false;
- if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false))
- did_something = true;
+ if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false))
+ did_something = true;
if (did_something)
module->check();
- if (max_iter > 0 && --max_iter == 0)
+ if (module_max_iter > 0 && --module_max_iter == 0)
break;
}
}
@@ -1219,7 +1224,7 @@ struct FlattenPass : public Pass {
RTLIL::Module *top_mod = NULL;
if (design->full_selection())
for (auto mod : design->modules())
- if (mod->get_bool_attribute("\\top"))
+ if (mod->get_bool_attribute(ID(top)))
top_mod = mod;
std::set<RTLIL::Cell*> handled_cells;
diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc
index 587cb9038..41fdc8f3d 100644
--- a/passes/techmap/tribuf.cc
+++ b/passes/techmap/tribuf.cc
@@ -63,38 +63,38 @@ struct TribufWorker {
for (auto cell : module->selected_cells())
{
- if (cell->type == "$tribuf")
- tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell);
+ if (cell->type == ID($tribuf))
+ tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
- if (cell->type == "$_TBUF_")
- tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell);
+ if (cell->type == ID($_TBUF_))
+ tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
- if (cell->type.in("$mux", "$_MUX_"))
+ if (cell->type.in(ID($mux), ID($_MUX_)))
{
- IdString en_port = cell->type == "$mux" ? "\\EN" : "\\E";
- IdString tri_type = cell->type == "$mux" ? "$tribuf" : "$_TBUF_";
+ IdString en_port = cell->type == ID($mux) ? ID(EN) : ID(E);
+ IdString tri_type = cell->type == ID($mux) ? ID($tribuf) : ID($_TBUF_);
- if (is_all_z(cell->getPort("\\A")) && is_all_z(cell->getPort("\\B"))) {
+ if (is_all_z(cell->getPort(ID::A)) && is_all_z(cell->getPort(ID::B))) {
module->remove(cell);
continue;
}
- if (is_all_z(cell->getPort("\\A"))) {
- cell->setPort("\\A", cell->getPort("\\B"));
- cell->setPort(en_port, cell->getPort("\\S"));
- cell->unsetPort("\\B");
- cell->unsetPort("\\S");
+ if (is_all_z(cell->getPort(ID::A))) {
+ cell->setPort(ID::A, cell->getPort(ID::B));
+ cell->setPort(en_port, cell->getPort(ID(S)));
+ cell->unsetPort(ID::B);
+ cell->unsetPort(ID(S));
cell->type = tri_type;
- tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell);
+ tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
continue;
}
- if (is_all_z(cell->getPort("\\B"))) {
- cell->setPort(en_port, module->Not(NEW_ID, cell->getPort("\\S")));
- cell->unsetPort("\\B");
- cell->unsetPort("\\S");
+ if (is_all_z(cell->getPort(ID::B))) {
+ cell->setPort(en_port, module->Not(NEW_ID, cell->getPort(ID(S))));
+ cell->unsetPort(ID::B);
+ cell->unsetPort(ID(S));
cell->type = tri_type;
- tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell);
+ tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell);
continue;
}
}
@@ -118,11 +118,11 @@ struct TribufWorker {
SigSpec pmux_b, pmux_s;
for (auto cell : it.second) {
- if (cell->type == "$tribuf")
- pmux_s.append(cell->getPort("\\EN"));
+ if (cell->type == ID($tribuf))
+ pmux_s.append(cell->getPort(ID(EN)));
else
- pmux_s.append(cell->getPort("\\E"));
- pmux_b.append(cell->getPort("\\A"));
+ pmux_s.append(cell->getPort(ID(E)));
+ pmux_b.append(cell->getPort(ID::A));
module->remove(cell);
}
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
index 2aefc091d..ac3d4ed4a 100644
--- a/passes/techmap/zinit.cc
+++ b/passes/techmap/zinit.cc
@@ -62,12 +62,12 @@ struct ZinitPass : public Pass {
for (auto wire : module->selected_wires())
{
- if (wire->attributes.count("\\init") == 0)
+ if (wire->attributes.count(ID(init)) == 0)
continue;
SigSpec wirebits = sigmap(wire);
- Const initval = wire->attributes.at("\\init");
- wire->attributes.erase("\\init");
+ Const initval = wire->attributes.at(ID(init));
+ wire->attributes.erase(ID(init));
for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
{
@@ -90,12 +90,12 @@ struct ZinitPass : public Pass {
}
pool<IdString> dff_types = {
- "$ff", "$dff", "$dffe", "$dffsr", "$adff",
- "$_FF_", "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_",
- "$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
- "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_",
- "$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
- "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_"
+ ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($adff),
+ ID($_FF_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_),
+ ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
+ ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_),
+ ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
+ ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)
};
for (auto cell : module->selected_cells())
@@ -103,8 +103,8 @@ struct ZinitPass : public Pass {
if (!dff_types.count(cell->type))
continue;
- SigSpec sig_d = sigmap(cell->getPort("\\D"));
- SigSpec sig_q = sigmap(cell->getPort("\\Q"));
+ SigSpec sig_d = sigmap(cell->getPort(ID(D)));
+ SigSpec sig_q = sigmap(cell->getPort(ID(Q)));
if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
continue;
@@ -120,14 +120,14 @@ struct ZinitPass : public Pass {
}
Wire *initwire = module->addWire(NEW_ID, GetSize(initval));
- initwire->attributes["\\init"] = initval;
+ initwire->attributes[ID(init)] = initval;
for (int i = 0; i < GetSize(initwire); i++)
if (initval.bits.at(i) == State::S1)
{
sig_d[i] = module->NotGate(NEW_ID, sig_d[i]);
module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]);
- initwire->attributes["\\init"].bits.at(i) = State::S0;
+ initwire->attributes[ID(init)].bits.at(i) = State::S0;
}
else
{
@@ -137,8 +137,8 @@ struct ZinitPass : public Pass {
log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type),
log_signal(sig_q), log_signal(initval));
- cell->setPort("\\D", sig_d);
- cell->setPort("\\Q", initwire);
+ cell->setPort(ID(D), sig_d);
+ cell->setPort(ID(Q), initwire);
}
for (auto &it : initbits)
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index e360b5edb..88116eeec 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -43,7 +43,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
RTLIL::Cell *cell = module->addCell("\\UUT", cell_type);
RTLIL::Wire *wire;
- if (cell_type == "$mux" || cell_type == "$pmux")
+ if (cell_type.in("$mux", "$pmux"))
{
int width = 1 + xorshift32(8);
int swidth = cell_type == "$mux" ? 1 : 1 + xorshift32(8);
@@ -186,7 +186,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
RTLIL::SigSpec config;
for (int i = 0; i < (1 << width); i++)
- config.append(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
+ config.append(xorshift32(2) ? State::S1 : State::S0);
cell->setParam("\\LUT", config.as_const());
}
@@ -209,16 +209,16 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
for (int i = 0; i < width*depth; i++)
switch (xorshift32(3)) {
case 0:
- config.append(RTLIL::S1);
- config.append(RTLIL::S0);
+ config.append(State::S1);
+ config.append(State::S0);
break;
case 1:
- config.append(RTLIL::S0);
- config.append(RTLIL::S1);
+ config.append(State::S0);
+ config.append(State::S1);
break;
case 2:
- config.append(RTLIL::S0);
- config.append(RTLIL::S0);
+ config.append(State::S0);
+ config.append(State::S0);
break;
}
@@ -264,7 +264,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->setPort("\\Y", wire);
}
- if (muxdiv && (cell_type == "$div" || cell_type == "$mod")) {
+ if (muxdiv && cell_type.in("$div", "$mod")) {
auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort("\\B"));
auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort("\\Y")));
module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(div_out)), div_out, b_not_zero, cell->getPort("\\Y"));
@@ -308,18 +308,18 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
case 0:
n = xorshift32(GetSize(sig) + 1);
for (int i = 0; i < n; i++)
- sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
+ sig[i] = xorshift32(2) == 1 ? State::S1 : State::S0;
break;
case 1:
n = xorshift32(GetSize(sig) + 1);
for (int i = n; i < GetSize(sig); i++)
- sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
+ sig[i] = xorshift32(2) == 1 ? State::S1 : State::S0;
break;
case 2:
n = xorshift32(GetSize(sig));
m = xorshift32(GetSize(sig));
for (int i = min(n, m); i < max(n, m); i++)
- sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
+ sig[i] = xorshift32(2) == 1 ? State::S1 : State::S0;
break;
}
@@ -491,7 +491,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
RTLIL::Const in_value;
for (int i = 0; i < GetSize(gold_wire); i++)
- in_value.bits.push_back(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
+ in_value.bits.push_back(xorshift32(2) ? State::S1 : State::S0);
if (xorshift32(4) == 0) {
int inv_chance = 1 + xorshift32(8);
@@ -591,11 +591,11 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
}
for (int i = 0; i < GetSize(out_sig); i++) {
- if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
+ if (out_val[i] != State::S0 && out_val[i] != State::S1)
continue;
- if (out_val[i] == RTLIL::S0 && sat1_model_value.at(i) == false)
+ if (out_val[i] == State::S0 && sat1_model_value.at(i) == false)
continue;
- if (out_val[i] == RTLIL::S1 && sat1_model_value.at(i) == true)
+ if (out_val[i] == State::S1 && sat1_model_value.at(i) == true)
continue;
log_error("Mismatch in sat model 1 (no undef modeling) output!\n");
}
@@ -627,12 +627,12 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
for (int i = 0; i < GetSize(out_sig); i++) {
if (sat2_model_value.at(GetSize(out_sig) + i)) {
- if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
+ if (out_val[i] != State::S0 && out_val[i] != State::S1)
continue;
} else {
- if (out_val[i] == RTLIL::S0 && sat2_model_value.at(i) == false)
+ if (out_val[i] == State::S0 && sat2_model_value.at(i) == false)
continue;
- if (out_val[i] == RTLIL::S1 && sat2_model_value.at(i) == true)
+ if (out_val[i] == State::S1 && sat2_model_value.at(i) == true)
continue;
}
log_error("Mismatch in sat model 2 (undef modeling) output!\n");
@@ -872,7 +872,7 @@ struct TestCellPass : public Pass {
continue;
}
- if (args[argidx].substr(0, 1) == "/") {
+ if (args[argidx].compare(0, 1, "/") == 0) {
std::vector<std::string> new_selected_cell_types;
for (auto it : selected_cell_types)
if (it != args[argidx].substr(1))
diff --git a/techlibs/anlogic/Makefile.inc b/techlibs/anlogic/Makefile.inc
index 67cf9cf10..9426b5ca5 100644
--- a/techlibs/anlogic/Makefile.inc
+++ b/techlibs/anlogic/Makefile.inc
@@ -1,7 +1,7 @@
OBJS += techlibs/anlogic/synth_anlogic.o
OBJS += techlibs/anlogic/anlogic_eqn.o
-OBJS += techlibs/anlogic/anlogic_determine_init.o
+OBJS += techlibs/anlogic/anlogic_fixcarry.o
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v))
$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v))
diff --git a/techlibs/anlogic/anlogic_determine_init.cc b/techlibs/anlogic/anlogic_determine_init.cc
deleted file mode 100644
index 34b1d4f8a..000000000
--- a/techlibs/anlogic/anlogic_determine_init.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
- *
- * 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 AnlogicDetermineInitPass : public Pass {
- AnlogicDetermineInitPass() : Pass("anlogic_determine_init", "Anlogic: Determine the init value of cells") { }
- void help() YS_OVERRIDE
- {
- log("\n");
- log(" anlogic_determine_init [selection]\n");
- log("\n");
- log("Determine the init value of cells that doesn't allow unknown init value.\n");
- log("\n");
- }
-
- Const determine_init(Const init)
- {
- for (int i = 0; i < GetSize(init); i++) {
- if (init[i] != State::S0 && init[i] != State::S1)
- init[i] = State::S0;
- }
-
- return init;
- }
-
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
- {
- log_header(design, "Executing ANLOGIC_DETERMINE_INIT pass (determine init value for cells).\n");
-
- extra_args(args, args.size(), design);
-
- size_t cnt = 0;
- for (auto module : design->selected_modules())
- {
- for (auto cell : module->selected_cells())
- {
- if (cell->type == "\\EG_LOGIC_DRAM16X4")
- {
- cell->setParam("\\INIT_D0", determine_init(cell->getParam("\\INIT_D0")));
- cell->setParam("\\INIT_D1", determine_init(cell->getParam("\\INIT_D1")));
- cell->setParam("\\INIT_D2", determine_init(cell->getParam("\\INIT_D2")));
- cell->setParam("\\INIT_D3", determine_init(cell->getParam("\\INIT_D3")));
- cnt++;
- }
- }
- }
- log_header(design, "Updated %lu cells with determined init value.\n", cnt);
- }
-} AnlogicDetermineInitPass;
-
-PRIVATE_NAMESPACE_END
diff --git a/techlibs/anlogic/anlogic_eqn.cc b/techlibs/anlogic/anlogic_eqn.cc
index 741bf04cc..070d39a20 100644
--- a/techlibs/anlogic/anlogic_eqn.cc
+++ b/techlibs/anlogic/anlogic_eqn.cc
@@ -69,7 +69,7 @@ struct AnlogicEqnPass : public Pass {
extra_args(args, args.size(), design);
- size_t cnt = 0;
+ int cnt = 0;
for (auto module : design->selected_modules())
{
for (auto cell : module->selected_cells())
@@ -106,7 +106,7 @@ struct AnlogicEqnPass : public Pass {
}
}
}
- log_header(design, "Updated %lu of AL_MAP_LUT* elements with equation.\n", cnt);
+ log_header(design, "Updated %d of AL_MAP_LUT* elements with equation.\n", cnt);
}
} AnlogicEqnPass;
diff --git a/techlibs/anlogic/anlogic_fixcarry.cc b/techlibs/anlogic/anlogic_fixcarry.cc
new file mode 100644
index 000000000..87164d375
--- /dev/null
+++ b/techlibs/anlogic/anlogic_fixcarry.cc
@@ -0,0 +1,130 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+static SigBit get_bit_or_zero(const SigSpec &sig)
+{
+ if (GetSize(sig) == 0)
+ return State::S0;
+ return sig[0];
+}
+
+static void fix_carry_chain(Module *module)
+{
+ SigMap sigmap(module);
+
+ pool<SigBit> ci_bits;
+ dict<SigBit, SigBit> mapping_bits;
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type == "\\AL_MAP_ADDER") {
+ if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue;
+ SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a"));
+ SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b"));
+ if (bit_i0 == State::S0 && bit_i1== State::S0) {
+ SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c"));
+ SigSpec o = cell->getPort("\\o");
+ if (GetSize(o) == 2) {
+ SigBit bit_o = o[0];
+ ci_bits.insert(bit_ci);
+ mapping_bits[bit_ci] = bit_o;
+ }
+ }
+ }
+ }
+ vector<Cell*> adders_to_fix_cells;
+ for (auto cell : module->cells())
+ {
+ if (cell->type == "\\AL_MAP_ADDER") {
+ if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue;
+ SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c"));
+ SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a"));
+ SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b"));
+ SigBit canonical_bit = sigmap(bit_ci);
+ if (!ci_bits.count(canonical_bit))
+ continue;
+ if (bit_i0 == State::S0 && bit_i1== State::S0)
+ continue;
+
+ adders_to_fix_cells.push_back(cell);
+ log("Found %s cell named %s with invalid 'c' signal.\n", log_id(cell->type), log_id(cell));
+ }
+ }
+
+ for (auto cell : adders_to_fix_cells)
+ {
+ SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c"));
+ SigBit canonical_bit = sigmap(bit_ci);
+ auto bit = mapping_bits.at(canonical_bit);
+ log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell));
+ Cell *c = module->addCell(NEW_ID, "\\AL_MAP_ADDER");
+ SigBit new_bit = module->addWire(NEW_ID);
+ SigBit dummy_bit = module->addWire(NEW_ID);
+ SigSpec bits;
+ bits.append(dummy_bit);
+ bits.append(new_bit);
+ c->setParam("\\ALUTYPE", Const("ADD_CARRY"));
+ c->setPort("\\a", bit);
+ c->setPort("\\b", State::S0);
+ c->setPort("\\c", State::S0);
+ c->setPort("\\o", bits);
+
+ cell->setPort("\\c", new_bit);
+ }
+
+}
+
+struct AnlogicCarryFixPass : public Pass {
+ AnlogicCarryFixPass() : Pass("anlogic_fixcarry", "Anlogic: fix carry chain") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" anlogic_fixcarry [options] [selection]\n");
+ log("\n");
+ log("Add Anlogic adders to fix carry chain if needed.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing anlogic_fixcarry pass (fix invalid carry chain).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ Module *module = design->top_module();
+
+ if (module == nullptr)
+ log_cmd_error("No top module found.\n");
+
+ fix_carry_chain(module);
+ }
+} AnlogicCarryFixPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/anlogic/arith_map.v b/techlibs/anlogic/arith_map.v
index 11cd140ec..1186543da 100644
--- a/techlibs/anlogic/arith_map.v
+++ b/techlibs/anlogic/arith_map.v
@@ -31,7 +31,10 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
output [Y_WIDTH-1:0] X, Y;
input CI, BI;
- output CO;
+ output [Y_WIDTH-1:0] CO;
+
+ wire CIx;
+ wire [Y_WIDTH-1:0] COx;
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
@@ -41,44 +44,41 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
wire [Y_WIDTH-1:0] AA = A_buf;
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
- wire [Y_WIDTH+1:0] COx;
- wire [Y_WIDTH+1:0] C = {COx, CI};
+ wire [Y_WIDTH-1:0] C = { COx, CIx };
wire dummy;
- (* keep *)
AL_MAP_ADDER #(
.ALUTYPE("ADD_CARRY"))
adder_cin (
- .a(C[0]),
- .o({COx[0], dummy})
+ .a(CI),
+ .b(1'b0),
+ .c(1'b0),
+ .o({CIx, dummy})
);
genvar i;
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
- if(i==Y_WIDTH-1) begin
- (* keep *)
- AL_MAP_ADDER #(
- .ALUTYPE("ADD"))
- adder_cout (
- .c(C[Y_WIDTH]),
- .o(COx[Y_WIDTH])
- );
- assign CO = COx[Y_WIDTH];
- end
- else
- begin
- (* keep *)
AL_MAP_ADDER #(
.ALUTYPE("ADD")
) adder_i (
.a(AA[i]),
.b(BB[i]),
- .c(C[i+1]),
- .o({COx[i+1],Y[i]})
+ .c(C[i]),
+ .o({COx[i],Y[i]})
);
- end
- end: slice
+
+ wire cout;
+ AL_MAP_ADDER #(
+ .ALUTYPE("ADD"))
+ adder_cout (
+ .a(1'b0),
+ .b(1'b0),
+ .c(COx[i]),
+ .o({cout, CO[i]})
+ );
+ end: slice
endgenerate
- /* End implementation */
- assign X = AA ^ BB;
-endmodule \ No newline at end of file
+
+ /* End implementation */
+ assign X = AA ^ BB;
+endmodule
diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc
index 620bf3965..b87fc8566 100644
--- a/techlibs/anlogic/synth_anlogic.cc
+++ b/techlibs/anlogic/synth_anlogic.cc
@@ -154,7 +154,7 @@ struct SynthAnlogicPass : public ScriptPass
{
run("memory_bram -rules +/anlogic/drams.txt");
run("techmap -map +/anlogic/drams_map.v");
- run("anlogic_determine_init");
+ run("setundef -zero -params t:EG_LOGIC_DRAM16X4");
}
if (check_label("fine"))
@@ -186,6 +186,11 @@ struct SynthAnlogicPass : public ScriptPass
{
run("techmap -map +/anlogic/cells_map.v");
run("clean");
+ }
+
+ if (check_label("map_anlogic"))
+ {
+ run("anlogic_fixcarry");
run("anlogic_eqn");
}
diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v
index 8aa1eb957..0d0757767 100644
--- a/techlibs/common/cmp2lut.v
+++ b/techlibs/common/cmp2lut.v
@@ -27,7 +27,7 @@ parameter _TECHMAP_CONSTVAL_A_ = 0;
parameter _TECHMAP_CONSTMSK_B_ = 0;
parameter _TECHMAP_CONSTVAL_B_ = 0;
-function automatic integer gen_lut;
+function automatic [(1 << `LUT_WIDTH)-1:0] gen_lut;
input integer width;
input integer operation;
input integer swap;
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index 289673e82..64720e598 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -230,6 +230,25 @@ endmodule
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//-
+//- $_NMUX_ (A, B, S, Y)
+//-
+//- A 2-input inverting MUX gate.
+//-
+//- Truth table: A B S | Y
+//- -------+---
+//- 0 - 0 | 1
+//- 1 - 0 | 0
+//- - 0 1 | 1
+//- - 1 1 | 0
+//-
+module \$_NMUX_ (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.
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index a424d3089..7845a3fed 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -532,14 +532,26 @@ endmodule
// --------------------------------------------------------
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $lcu (P, G, CI, CO)
+//-
+//- Lookahead carry unit
+//- A building block dedicated to fast computation of carry-bits used in binary
+//- arithmetic operations. By replacing the ripple carry structure used in full-adder
+//- blocks, the more significant bits of the sum can be expected to be computed more
+//- quickly.
+//- Typically created during `techmap` of $alu cells (see the "_90_alu" rule in
+//- +/techmap.v).
module \$lcu (P, G, CI, CO);
parameter WIDTH = 1;
-input [WIDTH-1:0] P, G;
-input CI;
+input [WIDTH-1:0] P; // Propagate
+input [WIDTH-1:0] G; // Generate
+input CI; // Carry-in
-output reg [WIDTH-1:0] CO;
+output reg [WIDTH-1:0] CO; // Carry-out
integer i;
always @* begin
@@ -555,6 +567,17 @@ endmodule
// --------------------------------------------------------
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $alu (A, B, CI, BI, X, Y, CO)
+//-
+//- Arithmetic logic unit.
+//- A building block supporting both binary addition/subtraction operations, and
+//- indirectly, comparison operations.
+//- Typically created by the `alumacc` pass, which transforms:
+//- $add, $sub, $lt, $le, $ge, $gt, $eq, $eqx, $ne, $nex
+//- cells into this $alu cell.
+//-
module \$alu (A, B, CI, BI, X, Y, CO);
parameter A_SIGNED = 0;
@@ -563,12 +586,16 @@ parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
-input [A_WIDTH-1:0] A;
-input [B_WIDTH-1:0] B;
-output [Y_WIDTH-1:0] X, Y;
+input [A_WIDTH-1:0] A; // Input operand
+input [B_WIDTH-1:0] B; // Input operand
+output [Y_WIDTH-1:0] X; // A xor B (sign-extended, optional B inversion,
+ // used in combination with
+ // reduction-AND for $eq/$ne ops)
+output [Y_WIDTH-1:0] Y; // Sum
-input CI, BI;
-output [Y_WIDTH-1:0] CO;
+input CI; // Carry-in (set for $sub)
+input BI; // Invert-B (set for $sub)
+output [Y_WIDTH-1:0] CO; // Carry-out
wire [Y_WIDTH-1:0] AA, BB;
@@ -584,6 +611,7 @@ endgenerate
wire y_co_undef = ^{A, A, B, B, CI, CI, BI, BI};
assign X = AA ^ BB;
+// Full adder
assign Y = (AA + BB + CI) ^ {Y_WIDTH{y_co_undef}};
function get_carry;
diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc
index e41c0fe97..a176357a7 100644
--- a/techlibs/common/synth.cc
+++ b/techlibs/common/synth.cc
@@ -75,13 +75,16 @@ struct SynthPass : public ScriptPass
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(" -abc9\n");
+ log(" use new ABC9 flow (EXPERIMENTAL)\n");
+ log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
- string top_module, fsm_opts, memory_opts;
+ string top_module, fsm_opts, memory_opts, abc;
bool autotop, flatten, noalumacc, nofsm, noabc, noshare;
int lut;
@@ -98,6 +101,7 @@ struct SynthPass : public ScriptPass
nofsm = false;
noabc = false;
noshare = false;
+ abc = "abc";
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -159,6 +163,10 @@ struct SynthPass : public ScriptPass
noshare = true;
continue;
}
+ if (args[argidx] == "-abc9") {
+ abc = "abc9";
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -166,6 +174,9 @@ struct SynthPass : public ScriptPass
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
+ if (abc == "abc9" && !lut)
+ log_cmd_error("ABC9 flow only supported for FPGA synthesis (using '-lut' option)\n");
+
log_header(design, "Executing SYNTH pass.\n");
log_push();
@@ -241,15 +252,15 @@ struct SynthPass : public ScriptPass
#ifdef YOSYS_ENABLE_ABC
if (help_mode)
{
- run("abc -fast", " (unless -noabc, unless -lut)");
- run("abc -fast -lut k", "(unless -noabc, if -lut)");
+ run(abc + " -fast", " (unless -noabc, unless -lut)");
+ run(abc + " -fast -lut k", "(unless -noabc, if -lut)");
}
else
{
if (lut)
- run(stringf("abc -fast -lut %d", lut));
+ run(stringf("%s -fast -lut %d", abc.c_str(), lut));
else
- run("abc -fast");
+ run(abc + " -fast");
}
run("opt -fast", " (unless -noabc)");
#endif
diff --git a/techlibs/coolrunner2/coolrunner2_sop.cc b/techlibs/coolrunner2/coolrunner2_sop.cc
index 48da0d8ad..de0cbb29d 100644
--- a/techlibs/coolrunner2/coolrunner2_sop.cc
+++ b/techlibs/coolrunner2/coolrunner2_sop.cc
@@ -60,10 +60,8 @@ struct Coolrunner2SopPass : public Pass {
dict<SigBit, pool<tuple<Cell*, std::string>>> special_pterms_inv;
for (auto cell : module->selected_cells())
{
- if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
- cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
- cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE" ||
- cell->type == "\\LDCP" || cell->type == "\\LDCP_N")
+ if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\FTCP", "\\FTCP_N", "\\FTDCP",
+ "\\FDCPE", "\\FDCPE_N", "\\FDDCPE", "\\LDCP", "\\LDCP_N"))
{
if (cell->hasPort("\\PRE"))
special_pterms_no_inv[sigmap(cell->getPort("\\PRE")[0])].insert(
@@ -257,10 +255,8 @@ struct Coolrunner2SopPass : public Pass {
pool<SigBit> sig_fed_by_ff;
for (auto cell : module->selected_cells())
{
- if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
- cell->type == "\\LDCP" || cell->type == "\\LDCP_N" ||
- cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
- cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE")
+ if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N",
+ "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE"))
{
auto output = sigmap(cell->getPort("\\Q")[0]);
sig_fed_by_ff.insert(output);
@@ -270,13 +266,11 @@ struct Coolrunner2SopPass : public Pass {
// Look at all the FF inputs
for (auto cell : module->selected_cells())
{
- if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
- cell->type == "\\LDCP" || cell->type == "\\LDCP_N" ||
- cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
- cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE")
+ if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N",
+ "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE"))
{
SigBit input;
- if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP")
+ if (cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP"))
input = sigmap(cell->getPort("\\T")[0]);
else
input = sigmap(cell->getPort("\\D")[0]);
@@ -300,7 +294,7 @@ struct Coolrunner2SopPass : public Pass {
xor_cell->setPort("\\IN_PTC", and_to_xor_wire);
xor_cell->setPort("\\OUT", xor_to_ff_wire);
- if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP")
+ if (cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP"))
cell->setPort("\\T", xor_to_ff_wire);
else
cell->setPort("\\D", xor_to_ff_wire);
diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc
index 4db087e87..73e18112f 100644
--- a/techlibs/ecp5/Makefile.inc
+++ b/techlibs/ecp5/Makefile.inc
@@ -4,13 +4,17 @@ OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v))
-$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/drams_map.v))
-$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dram.txt))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutrams_map.v))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutram.txt))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g_nowide.lut))
+
EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
diff --git a/techlibs/ecp5/abc_5g.box b/techlibs/ecp5/abc_5g.box
new file mode 100644
index 000000000..c757d137d
--- /dev/null
+++ b/techlibs/ecp5/abc_5g.box
@@ -0,0 +1,43 @@
+# NB: Inputs/Outputs must be ordered alphabetically
+# (with exceptions for carry in/out)
+
+# Box 1 : CCU2C (2xCARRY + 2xLUT4)
+# Outputs: S0, S1, COUT
+# (NB: carry chain input/output must be last
+# input/output and bus has been moved
+# there overriding the otherwise
+# alphabetical ordering)
+# name ID w/b ins outs
+CCU2C 1 1 9 3
+
+#A0 A1 B0 B1 C0 C1 D0 D1 CIN
+379 - 379 - 275 - 141 - 257
+630 379 630 379 526 275 392 141 273
+516 516 516 516 412 412 278 278 43
+
+# Box 2 : TRELLIS_DPR16X4 (16x4 dist ram)
+# Outputs: DO0, DO1, DO2, DO3
+# name ID w/b ins outs
+TRELLIS_DPR16X4 2 0 14 4
+
+#DI0 DI1 DI2 DI3 RAD0 RAD1 RAD2 RAD3 WAD0 WAD1 WAD2 WAD3 WCK WRE
+- - - - 141 379 275 379 - - - - - -
+- - - - 141 379 275 379 - - - - - -
+- - - - 141 379 275 379 - - - - - -
+- - - - 141 379 275 379 - - - - - -
+
+# Box 3 : PFUMX (MUX2)
+# Outputs: Z
+# name ID w/b ins outs
+PFUMX 3 1 3 1
+
+#ALUT BLUT C0
+98 98 151
+
+# Box 4 : L6MUX21 (MUX2)
+# Outputs: Z
+# name ID w/b ins outs
+L6MUX21 4 1 3 1
+
+#D0 D1 SD
+140 141 148
diff --git a/techlibs/ecp5/abc_5g.lut b/techlibs/ecp5/abc_5g.lut
new file mode 100644
index 000000000..e8aa9b35d
--- /dev/null
+++ b/techlibs/ecp5/abc_5g.lut
@@ -0,0 +1,25 @@
+# ECP5-5G LUT library for ABC
+# Note that ECP5 architecture assigns difference
+# in LUT input delay to interconnect, so this is
+# considered too
+
+
+# Simple LUTs
+# area D C B A
+1 1 141
+2 1 141 275
+3 1 141 275 379
+4 1 141 275 379 379
+
+# LUT5 = 2x LUT4 + PFUMX
+# area M0 D C B A
+5 2 151 239 373 477 477
+
+# LUT6 = 2x LUT5 + MUX2
+# area M1 M0 D C B A
+6 4 148 292 380 514 618 618
+
+# LUT7 = 2x LUT6 + MUX2
+# area M2 M1 M0 D C B A
+7 8 148 289 433 521 655 759 759
+
diff --git a/techlibs/ecp5/abc_5g_nowide.lut b/techlibs/ecp5/abc_5g_nowide.lut
new file mode 100644
index 000000000..60352d892
--- /dev/null
+++ b/techlibs/ecp5/abc_5g_nowide.lut
@@ -0,0 +1,12 @@
+# ECP5-5G LUT library for ABC
+# Note that ECP5 architecture assigns difference
+# in LUT input delay to interconnect, so this is
+# considered too
+
+
+# Simple LUTs
+# area D C B A
+1 1 141
+2 1 141 275
+3 1 141 275 379
+4 1 141 275 379 379
diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v
index eb7947601..17bde0497 100644
--- a/techlibs/ecp5/arith_map.v
+++ b/techlibs/ecp5/arith_map.v
@@ -50,20 +50,21 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
wire [Y_WIDTH2-1:0] AA = A_buf;
wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf;
+ wire [Y_WIDTH2-1:0] BX = B_buf;
wire [Y_WIDTH2-1:0] C = {CO, CI};
wire [Y_WIDTH2-1:0] FCO, Y1;
genvar i;
generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice
CCU2C #(
- .INIT0(16'b0110011010101010),
- .INIT1(16'b0110011010101010),
+ .INIT0(16'b1001011010101010),
+ .INIT1(16'b1001011010101010),
.INJECT1_0("NO"),
.INJECT1_1("NO")
) ccu2c_i (
.CIN(C[i]),
- .A0(AA[i]), .B0(BB[i]), .C0(1'b0), .D0(1'b1),
- .A1(AA[i+1]), .B1(BB[i+1]), .C1(1'b0), .D1(1'b1),
+ .A0(AA[i]), .B0(BX[i]), .C0(BI), .D0(1'b1),
+ .A1(AA[i+1]), .B1(BX[i+1]), .C1(BI), .D1(1'b1),
.S0(Y[i]), .S1(Y1[i]),
.COUT(FCO[i])
);
diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
index f6c71a03d..6985fbbc8 100644
--- a/techlibs/ecp5/cells_map.v
+++ b/techlibs/ecp5/cells_map.v
@@ -47,6 +47,28 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"
module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+// TODO: Diamond flip-flops
+// module FD1P3AX(); endmodule
+// module FD1P3AY(); endmodule
+// module FD1P3BX(); endmodule
+// module FD1P3DX(); endmodule
+// module FD1P3IX(); endmodule
+// module FD1P3JX(); endmodule
+// module FD1S3AX(); endmodule
+// module FD1S3AY(); endmodule
+module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+// module FL1P3AY(); endmodule
+// module FL1P3AZ(); endmodule
+// module FL1P3BX(); endmodule
+// module FL1P3DX(); endmodule
+// module FL1P3IY(); endmodule
+// module FL1P3JY(); endmodule
+// module FL1S3AX(); endmodule
+// module FL1S3AY(); endmodule
+
// Diamond I/O buffers
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
@@ -62,8 +84,22 @@ module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
-// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
-module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+// Diamond I/O registers
+module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+// TODO: Diamond I/O latches
+// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
+// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
`ifndef NO_LUT
module \$lut (A, Y);
@@ -73,77 +109,102 @@ module \$lut (A, Y);
input [WIDTH-1:0] A;
output Y;
+ // Need to swap input ordering, and fix init accordingly,
+ // to match ABC's expectation of LUT inputs in non-decreasing
+ // delay order
+ localparam P_WIDTH = WIDTH < 4 ? 4 : WIDTH;
+ function [P_WIDTH-1:0] permute_index;
+ input [P_WIDTH-1:0] i;
+ integer j;
+ begin
+ permute_index = 0;
+ for (j = 0; j < P_WIDTH; j = j + 1)
+ permute_index[P_WIDTH-1 - j] = i[j];
+ end
+ endfunction
+
+ function [2**P_WIDTH-1:0] permute_init;
+ integer i;
+ begin
+ permute_init = 0;
+ for (i = 0; i < 2**P_WIDTH; i = i + 1)
+ permute_init[i] = LUT[permute_index(i)];
+ end
+ endfunction
+
+ parameter [2**P_WIDTH-1:0] P_LUT = permute_init();
+
generate
if (WIDTH == 1) begin
- LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
- .A(A[0]), .B(1'b0), .C(1'b0), .D(1'b0));
+ LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(1'b0), .B(1'b0), .C(1'b0), .D(A[0]));
end else
if (WIDTH == 2) begin
- LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
- .A(A[0]), .B(A[1]), .C(1'b0), .D(1'b0));
+ LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(1'b0), .B(1'b0), .C(A[1]), .D(A[0]));
end else
if (WIDTH == 3) begin
- LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(1'b0));
+ LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(1'b0), .B(A[2]), .C(A[1]), .D(A[0]));
end else
if (WIDTH == 4) begin
- LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[3]), .B(A[2]), .C(A[1]), .D(A[0]));
`ifndef NO_PFUMUX
end else
if (WIDTH == 5) begin
wire f0, f1;
- LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
- LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
- PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y));
+ LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1]));
+ LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
+ .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1]));
+ PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[0]), .Z(Y));
end else
if (WIDTH == 6) begin
wire f0, f1, f2, f3, g0, g1;
- LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
- LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
-
- LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
- LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
-
- PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
- PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
- L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y));
+ LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
+ LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
+ .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
+
+ LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2),
+ .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
+ LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3),
+ .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
+
+ PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[1]), .Z(g0));
+ PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[1]), .Z(g1));
+ L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[0]), .Z(Y));
end else
if (WIDTH == 7) begin
wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1;
- LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
- LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
-
- LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
- LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
-
- LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
- LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
-
- LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
- LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7),
- .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
-
- PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
- PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
- PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2));
- PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3));
- L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0));
- L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1));
- L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y));
+ LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
+ LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
+ .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
+
+ LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2),
+ .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
+ LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3),
+ .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
+
+ LUT4 #(.INIT(P_LUT[79:64])) lut4 (.Z(f4),
+ .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
+ LUT4 #(.INIT(P_LUT[95:80])) lut5 (.Z(f5),
+ .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
+
+ LUT4 #(.INIT(P_LUT[111: 96])) lut6 (.Z(f6),
+ .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
+ LUT4 #(.INIT(P_LUT[127:112])) lut7 (.Z(f7),
+ .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
+
+ PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[2]), .Z(g0));
+ PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[2]), .Z(g1));
+ PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[2]), .Z(g2));
+ PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[2]), .Z(g3));
+ L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[1]), .Z(h0));
+ L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[1]), .Z(h1));
+ L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[0]), .Z(Y));
`endif
end else begin
wire _TECHMAP_FAIL_ = 1;
diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
index 1e4002ee0..dc8334acb 100644
--- a/techlibs/ecp5/cells_sim.v
+++ b/techlibs/ecp5/cells_sim.v
@@ -9,16 +9,21 @@ module LUT4(input A, B, C, D, output Z);
endmodule
// ---------------------------------------
-
+(* abc_box_id=4, lib_whitebox *)
module L6MUX21 (input D0, D1, SD, output Z);
assign Z = SD ? D1 : D0;
endmodule
// ---------------------------------------
-
-module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
- output S0, S1, COUT);
-
+(* abc_box_id=1, lib_whitebox *)
+module CCU2C(
+ (* abc_carry *)
+ input CIN,
+ input A0, B0, C0, D0, A1, B1, C1, D1,
+ output S0, S1,
+ (* abc_carry *)
+ output COUT
+);
parameter [15:0] INIT0 = 16'h0000;
parameter [15:0] INIT1 = 16'h0000;
parameter INJECT1_0 = "YES";
@@ -26,9 +31,13 @@ module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
// First half
wire LUT4_0, LUT2_0;
+`ifdef _ABC
+ assign LUT4_0 = INIT0[{D0, C0, B0, A0}];
+ assign LUT2_0 = INIT0[{2'b00, B0, A0}];
+`else
LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0));
LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0));
-
+`endif
wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN;
assign S0 = LUT4_0 ^ gated_cin_0;
@@ -37,9 +46,13 @@ module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
// Second half
wire LUT4_1, LUT2_1;
+`ifdef _ABC
+ assign LUT4_1 = INIT1[{D1, C1, B1, A1}];
+ assign LUT2_1 = INIT1[{2'b00, B1, A1}];
+`else
LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1));
LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1));
-
+`endif
wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0;
assign S1 = LUT4_1 ^ gated_cin_1;
@@ -90,18 +103,22 @@ module TRELLIS_RAM16X2 (
endmodule
// ---------------------------------------
-
+(* abc_box_id=3, lib_whitebox *)
module PFUMX (input ALUT, BLUT, C0, output Z);
assign Z = C0 ? ALUT : BLUT;
endmodule
// ---------------------------------------
-
+//(* abc_box_id=2 *)
module TRELLIS_DPR16X4 (
- input [3:0] DI,
- input [3:0] WAD,
- input WRE, WCK,
- input [3:0] RAD,
+ (* abc_scc_break *)
+ input [3:0] DI,
+ (* abc_scc_break *)
+ input [3:0] WAD,
+ (* abc_scc_break *)
+ input WRE,
+ input WCK,
+ input [3:0] RAD,
output [3:0] DO
);
parameter WCKMUX = "WCK";
@@ -251,18 +268,6 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
endmodule
// ---------------------------------------
-
-module OBZ(input I, T, output O);
-assign O = T ? 1'bz : I;
-endmodule
-
-// ---------------------------------------
-
-module IB(input I, output O);
-assign O = I;
-endmodule
-
-// ---------------------------------------
(* keep *)
module TRELLIS_IO(
inout B,
@@ -293,19 +298,6 @@ endmodule
// ---------------------------------------
-module OB(input I, output O);
-assign O = I;
-endmodule
-
-// ---------------------------------------
-
-module BB(input I, T, output O, inout B);
-assign B = T ? 1'bz : I;
-assign O = B;
-endmodule
-
-// ---------------------------------------
-
module INV(input A, output Z);
assign Z = !A;
endmodule
@@ -350,6 +342,31 @@ module TRELLIS_SLICE(
parameter [127:0] CCU2_INJECT1_0 = "NO";
parameter [127:0] CCU2_INJECT1_1 = "NO";
parameter WREMUX = "WRE";
+ parameter WCKMUX = "WCK";
+
+ parameter A0MUX = "A0";
+ parameter A1MUX = "A1";
+ parameter B0MUX = "B0";
+ parameter B1MUX = "B1";
+ parameter C0MUX = "C0";
+ parameter C1MUX = "C1";
+ parameter D0MUX = "D0";
+ parameter D1MUX = "D1";
+
+ wire A0m, B0m, C0m, D0m;
+ wire A1m, B1m, C1m, D1m;
+
+ generate
+ if (A0MUX == "1") assign A0m = 1'b1; else assign A0m = A0;
+ if (B0MUX == "1") assign B0m = 1'b1; else assign B0m = B0;
+ if (C0MUX == "1") assign C0m = 1'b1; else assign C0m = C0;
+ if (D0MUX == "1") assign D0m = 1'b1; else assign D0m = D0;
+ if (A1MUX == "1") assign A1m = 1'b1; else assign A1m = A1;
+ if (B1MUX == "1") assign B1m = 1'b1; else assign B1m = B1;
+ if (C1MUX == "1") assign C1m = 1'b1; else assign C1m = C1;
+ if (D1MUX == "1") assign D1m = 1'b1; else assign D1m = D1;
+
+ endgenerate
function [15:0] permute_initval;
input [15:0] initval;
@@ -367,13 +384,13 @@ module TRELLIS_SLICE(
LUT4 #(
.INIT(LUT0_INITVAL)
) lut4_0 (
- .A(A0), .B(B0), .C(C0), .D(D0),
+ .A(A0m), .B(B0m), .C(C0m), .D(D0m),
.Z(F0)
);
LUT4 #(
.INIT(LUT1_INITVAL)
) lut4_1 (
- .A(A1), .B(B1), .C(C1), .D(D1),
+ .A(A1m), .B(B1m), .C(C1m), .D(D1m),
.Z(F1)
);
// LUT expansion muxes
@@ -387,20 +404,20 @@ module TRELLIS_SLICE(
.INJECT1_1(CCU2_INJECT1_1)
) ccu2c_i (
.CIN(FCI),
- .A0(A0), .B0(B0), .C0(C0), .D0(D0),
- .A1(A1), .B1(B1), .C1(C1), .D1(D1),
+ .A0(A0m), .B0(B0m), .C0(C0m), .D0(D0m),
+ .A1(A1m), .B1(B1m), .C1(C1m), .D1(D1m),
.S0(F0), .S1(F1),
.COUT(FCO)
);
end else if (MODE == "RAMW") begin
- assign WDO0 = C1;
- assign WDO1 = A1;
- assign WDO2 = D1;
- assign WDO3 = B1;
- assign WADO0 = D0;
- assign WADO1 = B0;
- assign WADO2 = C0;
- assign WADO3 = A0;
+ assign WDO0 = C1m;
+ assign WDO1 = A1m;
+ assign WDO2 = D1m;
+ assign WDO3 = B1m;
+ assign WADO0 = D0m;
+ assign WADO1 = B0m;
+ assign WADO2 = C0m;
+ assign WADO3 = A0m;
end else if (MODE == "DPRAM") begin
TRELLIS_RAM16X2 #(
.INITVAL_0(permute_initval(LUT0_INITVAL)),
@@ -410,17 +427,19 @@ module TRELLIS_SLICE(
.DI0(WD0), .DI1(WD1),
.WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3),
.WRE(WRE), .WCK(WCK),
- .RAD0(D0), .RAD1(B0), .RAD2(C0), .RAD3(A0),
+ .RAD0(D0m), .RAD1(B0m), .RAD2(C0m), .RAD3(A0m),
.DO0(F0), .DO1(F1)
);
// TODO: confirm RAD and INITVAL ordering
// DPRAM mode contract?
+`ifdef FORMAL
always @(*) begin
- assert(A0==A1);
- assert(B0==B1);
- assert(C0==C1);
- assert(D0==D1);
+ assert(A0m==A1m);
+ assert(B0m==B1m);
+ assert(C0m==C1m);
+ assert(D0m==D1m);
end
+`endif
end else begin
ERROR_UNKNOWN_SLICE_MODE error();
end
@@ -472,105 +491,258 @@ module DP16KD(
input CSB2, CSB1, CSB0,
output DOB17, DOB16, DOB15, DOB14, DOB13, DOB12, DOB11, DOB10, DOB9, DOB8, DOB7, DOB6, DOB5, DOB4, DOB3, DOB2, DOB1, DOB0
);
- parameter DATA_WIDTH_A = 18;
- parameter DATA_WIDTH_B = 18;
-
- parameter REGMODE_A = "NOREG";
- parameter REGMODE_B = "NOREG";
-
- parameter RESETMODE = "SYNC";
- parameter ASYNC_RESET_RELEASE = "SYNC";
-
- parameter CSDECODE_A = "0b000";
- parameter CSDECODE_B = "0b000";
-
- parameter WRITEMODE_A = "NORMAL";
- parameter WRITEMODE_B = "NORMAL";
-
- parameter CLKAMUX = "CLKA";
- parameter CLKBMUX = "CLKB";
-
- parameter GSR = "ENABLED";
-
- parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
- parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-endmodule
+ parameter DATA_WIDTH_A = 18;
+ parameter DATA_WIDTH_B = 18;
+
+ parameter REGMODE_A = "NOREG";
+ parameter REGMODE_B = "NOREG";
+
+ parameter RESETMODE = "SYNC";
+ parameter ASYNC_RESET_RELEASE = "SYNC";
+
+ parameter CSDECODE_A = "0b000";
+ parameter CSDECODE_B = "0b000";
+
+ parameter WRITEMODE_A = "NORMAL";
+ parameter WRITEMODE_B = "NORMAL";
+
+ parameter DIA17MUX = "DIA17";
+ parameter DIA16MUX = "DIA16";
+ parameter DIA15MUX = "DIA15";
+ parameter DIA14MUX = "DIA14";
+ parameter DIA13MUX = "DIA13";
+ parameter DIA12MUX = "DIA12";
+ parameter DIA11MUX = "DIA11";
+ parameter DIA10MUX = "DIA10";
+ parameter DIA9MUX = "DIA9";
+ parameter DIA8MUX = "DIA8";
+ parameter DIA7MUX = "DIA7";
+ parameter DIA6MUX = "DIA6";
+ parameter DIA5MUX = "DIA5";
+ parameter DIA4MUX = "DIA4";
+ parameter DIA3MUX = "DIA3";
+ parameter DIA2MUX = "DIA2";
+ parameter DIA1MUX = "DIA1";
+ parameter DIA0MUX = "DIA0";
+ parameter ADA13MUX = "ADA13";
+ parameter ADA12MUX = "ADA12";
+ parameter ADA11MUX = "ADA11";
+ parameter ADA10MUX = "ADA10";
+ parameter ADA9MUX = "ADA9";
+ parameter ADA8MUX = "ADA8";
+ parameter ADA7MUX = "ADA7";
+ parameter ADA6MUX = "ADA6";
+ parameter ADA5MUX = "ADA5";
+ parameter ADA4MUX = "ADA4";
+ parameter ADA3MUX = "ADA3";
+ parameter ADA2MUX = "ADA2";
+ parameter ADA1MUX = "ADA1";
+ parameter ADA0MUX = "ADA0";
+ parameter CEAMUX = "CEA";
+ parameter OCEAMUX = "OCEA";
+ parameter CLKAMUX = "CLKA";
+ parameter WEAMUX = "WEA";
+ parameter RSTAMUX = "RSTA";
+ parameter CSA2MUX = "CSA2";
+ parameter CSA1MUX = "CSA1";
+ parameter CSA0MUX = "CSA0";
+ parameter DOA17MUX = "DOA17";
+ parameter DOA16MUX = "DOA16";
+ parameter DOA15MUX = "DOA15";
+ parameter DOA14MUX = "DOA14";
+ parameter DOA13MUX = "DOA13";
+ parameter DOA12MUX = "DOA12";
+ parameter DOA11MUX = "DOA11";
+ parameter DOA10MUX = "DOA10";
+ parameter DOA9MUX = "DOA9";
+ parameter DOA8MUX = "DOA8";
+ parameter DOA7MUX = "DOA7";
+ parameter DOA6MUX = "DOA6";
+ parameter DOA5MUX = "DOA5";
+ parameter DOA4MUX = "DOA4";
+ parameter DOA3MUX = "DOA3";
+ parameter DOA2MUX = "DOA2";
+ parameter DOA1MUX = "DOA1";
+ parameter DOA0MUX = "DOA0";
+ parameter DIB17MUX = "DIB17";
+ parameter DIB16MUX = "DIB16";
+ parameter DIB15MUX = "DIB15";
+ parameter DIB14MUX = "DIB14";
+ parameter DIB13MUX = "DIB13";
+ parameter DIB12MUX = "DIB12";
+ parameter DIB11MUX = "DIB11";
+ parameter DIB10MUX = "DIB10";
+ parameter DIB9MUX = "DIB9";
+ parameter DIB8MUX = "DIB8";
+ parameter DIB7MUX = "DIB7";
+ parameter DIB6MUX = "DIB6";
+ parameter DIB5MUX = "DIB5";
+ parameter DIB4MUX = "DIB4";
+ parameter DIB3MUX = "DIB3";
+ parameter DIB2MUX = "DIB2";
+ parameter DIB1MUX = "DIB1";
+ parameter DIB0MUX = "DIB0";
+ parameter ADB13MUX = "ADB13";
+ parameter ADB12MUX = "ADB12";
+ parameter ADB11MUX = "ADB11";
+ parameter ADB10MUX = "ADB10";
+ parameter ADB9MUX = "ADB9";
+ parameter ADB8MUX = "ADB8";
+ parameter ADB7MUX = "ADB7";
+ parameter ADB6MUX = "ADB6";
+ parameter ADB5MUX = "ADB5";
+ parameter ADB4MUX = "ADB4";
+ parameter ADB3MUX = "ADB3";
+ parameter ADB2MUX = "ADB2";
+ parameter ADB1MUX = "ADB1";
+ parameter ADB0MUX = "ADB0";
+ parameter CEBMUX = "CEB";
+ parameter OCEBMUX = "OCEB";
+ parameter CLKBMUX = "CLKB";
+ parameter WEBMUX = "WEB";
+ parameter RSTBMUX = "RSTB";
+ parameter CSB2MUX = "CSB2";
+ parameter CSB1MUX = "CSB1";
+ parameter CSB0MUX = "CSB0";
+ parameter DOB17MUX = "DOB17";
+ parameter DOB16MUX = "DOB16";
+ parameter DOB15MUX = "DOB15";
+ parameter DOB14MUX = "DOB14";
+ parameter DOB13MUX = "DOB13";
+ parameter DOB12MUX = "DOB12";
+ parameter DOB11MUX = "DOB11";
+ parameter DOB10MUX = "DOB10";
+ parameter DOB9MUX = "DOB9";
+ parameter DOB8MUX = "DOB8";
+ parameter DOB7MUX = "DOB7";
+ parameter DOB6MUX = "DOB6";
+ parameter DOB5MUX = "DOB5";
+ parameter DOB4MUX = "DOB4";
+ parameter DOB3MUX = "DOB3";
+ parameter DOB2MUX = "DOB2";
+ parameter DOB1MUX = "DOB1";
+ parameter DOB0MUX = "DOB0";
+
+ parameter WID = 0;
-// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
-module FD1S3BX(input PD, D, CK, output Q);
- TRELLIS_FF #(
- .GSR("DISABLED"),
- .CEMUX("1"),
- .CLKMUX("CLK"),
- .LSRMUX("LSR"),
- .REGSET("SET"),
- .SRMODE("ASYNC")
- ) tff_i (
- .CLK(CK),
- .LSR(PD),
- .DI(D),
- .Q(Q)
- );
+ parameter GSR = "ENABLED";
+
+ parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
endmodule
+
+// TODO: Diamond flip-flops
+// module FD1P3AX(); endmodule
+// module FD1P3AY(); endmodule
+// module FD1P3BX(); endmodule
+// module FD1P3DX(); endmodule
+// module FD1P3IX(); endmodule
+// module FD1P3JX(); endmodule
+// module FD1S3AX(); endmodule
+// module FD1S3AY(); endmodule
+module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+// module FL1P3AY(); endmodule
+// module FL1P3AZ(); endmodule
+// module FL1P3BX(); endmodule
+// module FL1P3DX(); endmodule
+// module FL1P3IY(); endmodule
+// module FL1P3JY(); endmodule
+// module FL1S3AX(); endmodule
+// module FL1S3AY(); endmodule
+
+// Diamond I/O buffers
+module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
+module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
+module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
+module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I)); endmodule
+module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
+module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
+module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
+module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule
+module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
+module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
+module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
+module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) tio (.B(A), .O(Z)); endmodule
+module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(Z), .I(A)); endmodule
+
+// Diamond I/O registers
+module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+// TODO: Diamond I/O latches
+// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
+// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
diff --git a/techlibs/ecp5/dram.txt b/techlibs/ecp5/lutram.txt
index b94357429..b94357429 100644
--- a/techlibs/ecp5/dram.txt
+++ b/techlibs/ecp5/lutram.txt
diff --git a/techlibs/ecp5/drams_map.v b/techlibs/ecp5/lutrams_map.v
index 3b3de831f..3b3de831f 100644
--- a/techlibs/ecp5/drams_map.v
+++ b/techlibs/ecp5/lutrams_map.v
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc
index c6e12248e..143d1f95c 100644
--- a/techlibs/ecp5/synth_ecp5.cc
+++ b/techlibs/ecp5/synth_ecp5.cc
@@ -2,7 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Copyright (C) 2018 Clifford Wolf <dave@ds0.me>
+ * Copyright (C) 2018 David Shah <dave@ds0.me>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -71,17 +71,20 @@ struct SynthEcp5Pass : public ScriptPass
log(" do not use flipflops with CE in output netlist\n");
log("\n");
log(" -nobram\n");
- log(" do not use BRAM cells in output netlist\n");
+ log(" do not use block RAM cells in output netlist\n");
log("\n");
- log(" -nodram\n");
- log(" do not use distributed RAM cells in output netlist\n");
+ log(" -nolutram\n");
+ log(" do not use LUT RAM cells in output netlist\n");
log("\n");
- log(" -nomux\n");
+ log(" -nowidelut\n");
log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
log("\n");
log(" -abc2\n");
log(" run two passes of 'abc' for slightly improved logic density\n");
log("\n");
+ log(" -abc9\n");
+ log(" use new ABC9 flow (EXPERIMENTAL)\n");
+ log("\n");
log(" -vpr\n");
log(" generate an output netlist (and BLIF file) suitable for VPR\n");
log(" (this feature is experimental and incomplete)\n");
@@ -93,7 +96,7 @@ struct SynthEcp5Pass : public ScriptPass
}
string top_opt, blif_file, edif_file, json_file;
- bool noccu2, nodffe, nobram, nodram, nomux, flatten, retime, abc2, vpr;
+ bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, vpr;
void clear_flags() YS_OVERRIDE
{
@@ -104,12 +107,13 @@ struct SynthEcp5Pass : public ScriptPass
noccu2 = false;
nodffe = false;
nobram = false;
- nodram = false;
- nomux = false;
+ nolutram = false;
+ nowidelut = false;
flatten = true;
retime = false;
abc2 = false;
vpr = false;
+ abc9 = false;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -168,12 +172,12 @@ struct SynthEcp5Pass : public ScriptPass
nobram = true;
continue;
}
- if (args[argidx] == "-nodram") {
- nodram = true;
+ if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
+ nolutram = true;
continue;
}
- if (args[argidx] == "-nomux") {
- nomux = true;
+ if (args[argidx] == "-nowidelut" || /*deprecated alias*/ args[argidx] == "-nomux") {
+ nowidelut = true;
continue;
}
if (args[argidx] == "-abc2") {
@@ -184,6 +188,10 @@ struct SynthEcp5Pass : public ScriptPass
vpr = true;
continue;
}
+ if (args[argidx] == "-abc9") {
+ abc9 = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -191,6 +199,9 @@ struct SynthEcp5Pass : public ScriptPass
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
+ if (abc9 && retime)
+ log_cmd_error("-retime option not currently compatible with -abc9!\n");
+
log_header(design, "Executing SYNTH_ECP5 pass.\n");
log_push();
@@ -203,7 +214,7 @@ struct SynthEcp5Pass : public ScriptPass
{
if (check_label("begin"))
{
- run("read_verilog -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v");
+ run("read_verilog -D_ABC -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}
@@ -220,23 +231,27 @@ struct SynthEcp5Pass : public ScriptPass
run("synth -run coarse");
}
- if (!nobram && check_label("bram", "(skip if -nobram)"))
+ if (!nobram && check_label("map_bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/ecp5/bram.txt");
run("techmap -map +/ecp5/brams_map.v");
}
- if (!nodram && check_label("dram", "(skip if -nodram)"))
+ if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
{
- run("memory_bram -rules +/ecp5/dram.txt");
- run("techmap -map +/ecp5/drams_map.v");
+ run("memory_bram -rules +/ecp5/lutram.txt");
+ run("techmap -map +/ecp5/lutrams_map.v");
}
- if (check_label("fine"))
+ if (check_label("map_ffram"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
+ }
+
+ if (check_label("map_gates"))
+ {
if (noccu2)
run("techmap");
else
@@ -264,10 +279,17 @@ struct SynthEcp5Pass : public ScriptPass
run("abc", " (only if -abc2)");
}
run("techmap -map +/ecp5/latches_map.v");
- if (nomux)
- run("abc -lut 4 -dress");
- else
- run("abc -lut 4:7 -dress");
+ if (abc9) {
+ if (nowidelut)
+ run("abc9 -lut +/ecp5/abc_5g_nowide.lut -box +/ecp5/abc_5g.box -W 200");
+ else
+ run("abc9 -lut +/ecp5/abc_5g.lut -box +/ecp5/abc_5g.box -W 200");
+ } else {
+ if (nowidelut)
+ run("abc -lut 4 -dress");
+ else
+ run("abc -lut 4:7 -dress");
+ }
run("clean");
}
diff --git a/techlibs/efinix/Makefile.inc b/techlibs/efinix/Makefile.inc
new file mode 100644
index 000000000..5013f7fc1
--- /dev/null
+++ b/techlibs/efinix/Makefile.inc
@@ -0,0 +1,10 @@
+
+OBJS += techlibs/efinix/synth_efinix.o
+OBJS += techlibs/efinix/efinix_gbuf.o
+OBJS += techlibs/efinix/efinix_fixcarry.o
+
+$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_map.v))
+$(eval $(call add_share_file,share/efinix,techlibs/efinix/arith_map.v))
+$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_sim.v))
+$(eval $(call add_share_file,share/efinix,techlibs/efinix/brams_map.v))
+$(eval $(call add_share_file,share/efinix,techlibs/efinix/bram.txt))
diff --git a/techlibs/efinix/arith_map.v b/techlibs/efinix/arith_map.v
new file mode 100644
index 000000000..178f57bc5
--- /dev/null
+++ b/techlibs/efinix/arith_map.v
@@ -0,0 +1,79 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * 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.
+ *
+ */
+
+(* techmap_celltype = "$alu" *)
+module _80_efinix_alu (A, B, CI, BI, X, Y, CO);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] X, Y;
+
+ input CI, BI;
+ output [Y_WIDTH-1:0] CO;
+
+ wire CIx;
+ wire [Y_WIDTH-1:0] COx;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
+ wire [Y_WIDTH-1:0] C = { COx, CIx };
+
+ EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
+ adder_cin (
+ .I0(CI),
+ .I1(1'b1),
+ .CI(1'b0),
+ .CO(CIx)
+ );
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
+ EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
+ adder_i (
+ .I0(AA[i]),
+ .I1(BB[i]),
+ .CI(C[i]),
+ .O(Y[i]),
+ .CO(COx[i])
+ );
+ EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))
+ adder_cout (
+ .I0(1'b0),
+ .I1(1'b0),
+ .CI(COx[i]),
+ .O(CO[i])
+ );
+ end: slice
+ endgenerate
+
+ /* End implementation */
+ assign X = AA ^ BB;
+endmodule \ No newline at end of file
diff --git a/techlibs/efinix/bram.txt b/techlibs/efinix/bram.txt
new file mode 100644
index 000000000..0b3fd9308
--- /dev/null
+++ b/techlibs/efinix/bram.txt
@@ -0,0 +1,32 @@
+bram $__EFINIX_5K
+ init 1
+
+ abits 8 @a8d16
+ dbits 16 @a8d16
+ abits 9 @a9d8
+ dbits 8 @a9d8
+ abits 10 @a10d4
+ dbits 4 @a10d4
+ abits 11 @a11d2
+ dbits 2 @a11d2
+ abits 12 @a12d1
+ dbits 1 @a12d1
+ abits 8 @a8d20
+ dbits 20 @a8d20
+ abits 9 @a9d10
+ dbits 10 @a9d10
+
+ groups 2
+ ports 1 1
+ wrmode 1 0
+ enable 1 1
+ transp 0 2
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+match $__EFINIX_5K
+ min bits 256
+ min efficiency 5
+ shuffle_enable B
+endmatch
diff --git a/techlibs/efinix/brams_map.v b/techlibs/efinix/brams_map.v
new file mode 100644
index 000000000..6786ae769
--- /dev/null
+++ b/techlibs/efinix/brams_map.v
@@ -0,0 +1,65 @@
+module \$__EFINIX_5K (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 8;
+ parameter CFG_DBITS = 20;
+ parameter CFG_ENABLE_A = 1;
+
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+ parameter [5119:0] INIT = 5119'bx;
+ parameter TRANSP2 = 0;
+
+ input CLK2;
+ input CLK3;
+
+ input [CFG_ABITS-1:0] A1ADDR;
+ input [CFG_DBITS-1:0] A1DATA;
+ input [CFG_ENABLE_A-1:0] A1EN;
+
+ input [CFG_ABITS-1:0] B1ADDR;
+ output [CFG_DBITS-1:0] B1DATA;
+ input B1EN;
+
+ localparam WRITEMODE_A = TRANSP2 ? "WRITE_FIRST" : "READ_FIRST";
+
+ EFX_RAM_5K #(
+ .READ_WIDTH(CFG_DBITS),
+ .WRITE_WIDTH(CFG_DBITS),
+ .OUTPUT_REG(1'b0),
+ .RCLK_POLARITY(1'b1),
+ .RE_POLARITY(1'b1),
+ .WCLK_POLARITY(1'b1),
+ .WE_POLARITY(1'b1),
+ .WCLKE_POLARITY(1'b1),
+ .WRITE_MODE(WRITEMODE_A),
+ .INIT_0(INIT[ 0*256 +: 256]),
+ .INIT_1(INIT[ 1*256 +: 256]),
+ .INIT_2(INIT[ 2*256 +: 256]),
+ .INIT_3(INIT[ 3*256 +: 256]),
+ .INIT_4(INIT[ 4*256 +: 256]),
+ .INIT_5(INIT[ 5*256 +: 256]),
+ .INIT_6(INIT[ 6*256 +: 256]),
+ .INIT_7(INIT[ 7*256 +: 256]),
+ .INIT_8(INIT[ 8*256 +: 256]),
+ .INIT_9(INIT[ 9*256 +: 256]),
+ .INIT_A(INIT[10*256 +: 256]),
+ .INIT_B(INIT[11*256 +: 256]),
+ .INIT_C(INIT[12*256 +: 256]),
+ .INIT_D(INIT[13*256 +: 256]),
+ .INIT_E(INIT[14*256 +: 256]),
+ .INIT_F(INIT[15*256 +: 256]),
+ .INIT_10(INIT[16*256 +: 256]),
+ .INIT_11(INIT[17*256 +: 256]),
+ .INIT_12(INIT[18*256 +: 256]),
+ .INIT_13(INIT[19*256 +: 256])
+ ) _TECHMAP_REPLACE_ (
+ .WDATA(A1DATA),
+ .WADDR(A1ADDR),
+ .WE(A1EN),
+ .WCLK(CLK2),
+ .WCLKE(1'b1),
+ .RDATA(B1DATA),
+ .RADDR(B1ADDR),
+ .RE(B1EN),
+ .RCLK(CLK3)
+ );
+endmodule
diff --git a/techlibs/efinix/cells_map.v b/techlibs/efinix/cells_map.v
new file mode 100644
index 000000000..0aeab1902
--- /dev/null
+++ b/techlibs/efinix/cells_map.v
@@ -0,0 +1,45 @@
+module \$_DFF_N_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
+module \$_DFF_P_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
+
+module \$_DFFE_NN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
+module \$_DFFE_NP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
+
+module \$_DFFE_PN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
+module \$_DFFE_PP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule
+
+module \$_DFF_NN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
+module \$_DFF_NN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
+module \$_DFF_PN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
+module \$_DFF_PN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
+
+module \$_DFF_NP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
+module \$_DFF_NP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
+module \$_DFF_PP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
+module \$_DFF_PP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule
+
+`ifndef NO_LUT
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+
+ input [WIDTH-1:0] A;
+ output Y;
+
+ generate
+ if (WIDTH == 1) begin
+ EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0));
+ end else
+ if (WIDTH == 2) begin
+ EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0));
+ end else
+ if (WIDTH == 3) begin
+ EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0));
+ end else
+ if (WIDTH == 4) begin
+ EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
+ end else begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ endgenerate
+endmodule
+`endif
diff --git a/techlibs/efinix/cells_sim.v b/techlibs/efinix/cells_sim.v
new file mode 100644
index 000000000..8c8f6afaa
--- /dev/null
+++ b/techlibs/efinix/cells_sim.v
@@ -0,0 +1,107 @@
+module EFX_LUT4(
+ output O,
+ input I0,
+ input I1,
+ input I2,
+ input I3
+);
+ parameter LUTMASK = 16'h0000;
+endmodule
+
+module EFX_ADD(
+ output O,
+ output CO,
+ input I0,
+ input I1,
+ input CI
+);
+ parameter I0_POLARITY = 1;
+ parameter I1_POLARITY = 1;
+endmodule
+
+module EFX_FF(
+ output Q,
+ input D,
+ input CE,
+ input CLK,
+ input SR
+);
+ parameter CLK_POLARITY = 1;
+ parameter CE_POLARITY = 1;
+ parameter SR_POLARITY = 1;
+ parameter SR_SYNC = 0;
+ parameter SR_VALUE = 0;
+ parameter SR_SYNC_PRIORITY = 0;
+ parameter D_POLARITY = 1;
+endmodule
+
+module EFX_GBUFCE(
+ input CE,
+ input I,
+ output O
+);
+ parameter CE_POLARITY = 1'b1;
+endmodule
+
+module EFX_RAM_5K(
+ input [WRITE_WIDTH-1:0] WDATA,
+ input [WRITE_ADDR_WIDTH-1:0] WADDR,
+ input WE,
+ input WCLK,
+ input WCLKE,
+ output [READ_WIDTH-1:0] RDATA,
+ input [READ_ADDR_WIDTH-1:0] RADDR,
+ input RE,
+ input RCLK
+);
+ parameter READ_WIDTH = 20;
+ parameter WRITE_WIDTH = 20;
+ parameter OUTPUT_REG = 1'b0;
+ parameter RCLK_POLARITY = 1'b1;
+ parameter RE_POLARITY = 1'b1;
+ parameter WCLK_POLARITY = 1'b1;
+ parameter WE_POLARITY = 1'b1;
+ parameter WCLKE_POLARITY = 1'b1;
+ parameter WRITE_MODE = "READ_FIRST";
+ parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+ localparam READ_ADDR_WIDTH =
+ (READ_WIDTH == 16) ? 8 : // 256x16
+ (READ_WIDTH == 8) ? 9 : // 512x8
+ (READ_WIDTH == 4) ? 10 : // 1024x4
+ (READ_WIDTH == 2) ? 11 : // 2048x2
+ (READ_WIDTH == 1) ? 12 : // 4096x1
+ (READ_WIDTH == 20) ? 8 : // 256x20
+ (READ_WIDTH == 10) ? 9 : // 512x10
+ (READ_WIDTH == 5) ? 10 : -1; // 1024x5
+
+ localparam WRITE_ADDR_WIDTH =
+ (WRITE_WIDTH == 16) ? 8 : // 256x16
+ (WRITE_WIDTH == 8) ? 9 : // 512x8
+ (WRITE_WIDTH == 4) ? 10 : // 1024x4
+ (WRITE_WIDTH == 2) ? 11 : // 2048x2
+ (WRITE_WIDTH == 1) ? 12 : // 4096x1
+ (WRITE_WIDTH == 20) ? 8 : // 256x20
+ (WRITE_WIDTH == 10) ? 9 : // 512x10
+ (WRITE_WIDTH == 5) ? 10 : -1; // 1024x5
+
+endmodule \ No newline at end of file
diff --git a/techlibs/efinix/efinix_fixcarry.cc b/techlibs/efinix/efinix_fixcarry.cc
new file mode 100644
index 000000000..b7cd995b8
--- /dev/null
+++ b/techlibs/efinix/efinix_fixcarry.cc
@@ -0,0 +1,122 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+static SigBit get_bit_or_zero(const SigSpec &sig)
+{
+ if (GetSize(sig) == 0)
+ return State::S0;
+ return sig[0];
+}
+
+static void fix_carry_chain(Module *module)
+{
+ SigMap sigmap(module);
+
+ pool<SigBit> ci_bits;
+ dict<SigBit, SigBit> mapping_bits;
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type == "\\EFX_ADD") {
+ SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0"));
+ SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1"));
+ if (bit_i0 == State::S0 && bit_i1== State::S0) {
+ SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI"));
+ SigBit bit_o = sigmap(cell->getPort("\\O"));
+ ci_bits.insert(bit_ci);
+ mapping_bits[bit_ci] = bit_o;
+ }
+ }
+ }
+
+ vector<Cell*> adders_to_fix_cells;
+ for (auto cell : module->cells())
+ {
+ if (cell->type == "\\EFX_ADD") {
+ SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI"));
+ SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0"));
+ SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1"));
+ SigBit canonical_bit = sigmap(bit_ci);
+ if (!ci_bits.count(canonical_bit))
+ continue;
+ if (bit_i0 == State::S0 && bit_i1== State::S0)
+ continue;
+
+ adders_to_fix_cells.push_back(cell);
+ log("Found %s cell named %s with invalid CI signal.\n", log_id(cell->type), log_id(cell));
+ }
+ }
+
+ for (auto cell : adders_to_fix_cells)
+ {
+ SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI"));
+ SigBit canonical_bit = sigmap(bit_ci);
+ auto bit = mapping_bits.at(canonical_bit);
+ log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell));
+ Cell *c = module->addCell(NEW_ID, "\\EFX_ADD");
+ SigBit new_bit = module->addWire(NEW_ID);
+ c->setParam("\\I0_POLARITY", State::S1);
+ c->setParam("\\I1_POLARITY", State::S1);
+ c->setPort("\\I0", bit);
+ c->setPort("\\I1", State::S1);
+ c->setPort("\\CI", State::S0);
+ c->setPort("\\CO", new_bit);
+
+ cell->setPort("\\CI", new_bit);
+ }
+}
+
+struct EfinixCarryFixPass : public Pass {
+ EfinixCarryFixPass() : Pass("efinix_fixcarry", "Efinix: fix carry chain") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" efinix_fixcarry [options] [selection]\n");
+ log("\n");
+ log("Add Efinix adders to fix carry chain if needed.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing efinix_fixcarry pass (fix invalid carry chain).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ Module *module = design->top_module();
+
+ if (module == nullptr)
+ log_cmd_error("No top module found.\n");
+
+ fix_carry_chain(module);
+ }
+} EfinixCarryFixPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/efinix/efinix_gbuf.cc b/techlibs/efinix/efinix_gbuf.cc
new file mode 100644
index 000000000..e75fb3f4d
--- /dev/null
+++ b/techlibs/efinix/efinix_gbuf.cc
@@ -0,0 +1,119 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * 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
+
+static void handle_gbufs(Module *module)
+{
+ SigMap sigmap(module);
+
+ pool<SigBit> clk_bits;
+ dict<SigBit, SigBit> rewrite_bits;
+ vector<pair<Cell*, SigBit>> pad_bits;
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type == "\\EFX_FF") {
+ for (auto bit : sigmap(cell->getPort("\\CLK")))
+ clk_bits.insert(bit);
+ }
+ if (cell->type == "\\EFX_RAM_5K") {
+ for (auto bit : sigmap(cell->getPort("\\RCLK")))
+ clk_bits.insert(bit);
+ for (auto bit : sigmap(cell->getPort("\\WCLK")))
+ clk_bits.insert(bit);
+ }
+ }
+
+ for (auto wire : vector<Wire*>(module->wires()))
+ {
+ if (!wire->port_input)
+ continue;
+
+ for (int index = 0; index < GetSize(wire); index++)
+ {
+ SigBit bit(wire, index);
+ SigBit canonical_bit = sigmap(bit);
+
+ if (!clk_bits.count(canonical_bit))
+ continue;
+
+ Cell *c = module->addCell(NEW_ID, "\\EFX_GBUFCE");
+ SigBit new_bit = module->addWire(NEW_ID);
+ c->setParam("\\CE_POLARITY", State::S1);
+ c->setPort("\\O", new_bit);
+ c->setPort("\\CE", State::S1);
+ pad_bits.push_back(make_pair(c, bit));
+ rewrite_bits[canonical_bit] = new_bit;
+
+ log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit));
+ }
+ }
+
+ auto rewrite_function = [&](SigSpec &s) {
+ for (auto &bit : s) {
+ SigBit canonical_bit = sigmap(bit);
+ if (rewrite_bits.count(canonical_bit))
+ bit = rewrite_bits.at(canonical_bit);
+ }
+ };
+
+ module->rewrite_sigspecs(rewrite_function);
+
+ for (auto &it : pad_bits)
+ it.first->setPort("\\I", it.second);
+}
+
+struct EfinixGbufPass : public Pass {
+ EfinixGbufPass() : Pass("efinix_gbuf", "Efinix: insert global clock buffers") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" efinix_gbuf [options] [selection]\n");
+ log("\n");
+ log("Add Efinix global clock buffers to top module as needed.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing efinix_gbuf pass (insert global clock buffers).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ Module *module = design->top_module();
+
+ if (module == nullptr)
+ log_cmd_error("No top module found.\n");
+
+ handle_gbufs(module);
+ }
+} EfinixGbufPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc
new file mode 100644
index 000000000..26a8d4eda
--- /dev/null
+++ b/techlibs/efinix/synth_efinix.cc
@@ -0,0 +1,219 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2019 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
+
+struct SynthEfinixPass : public ScriptPass
+{
+ SynthEfinixPass() : ScriptPass("synth_efinix", "synthesis for Efinix FPGAs") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_efinix [options]\n");
+ log("\n");
+ log("This command runs synthesis for Efinix FPGAs.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module\n");
+ log("\n");
+ log(" -edif <file>\n");
+ log(" write the design to the specified EDIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -json <file>\n");
+ log(" write the design to the specified JSON file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log(" -retime\n");
+ log(" run 'abc' with -dff option\n");
+ log("\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
+
+ string top_opt, edif_file, json_file;
+ bool flatten, retime;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ edif_file = "";
+ json_file = "";
+ flatten = true;
+ retime = false;
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_opt = "-top " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-edif" && argidx+1 < args.size()) {
+ edif_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-json" && argidx+1 < args.size()) {
+ json_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This command only operates on fully selected designs!\n");
+
+ log_header(design, "Executing SYNTH_EFINIX pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ void script() YS_OVERRIDE
+ {
+ if (check_label("begin"))
+ {
+ run("read_verilog -lib +/efinix/cells_sim.v");
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
+
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
+ {
+ run("proc");
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
+ }
+
+ if (check_label("coarse"))
+ {
+ run("synth -run coarse");
+ }
+
+ if (check_label("map_bram", "(skip if -nobram)"))
+ {
+ run("memory_bram -rules +/efinix/bram.txt");
+ run("techmap -map +/efinix/brams_map.v");
+ run("setundef -zero -params t:EFX_RAM_5K");
+ }
+
+ if (check_label("fine"))
+ {
+ run("opt -fast -mux_undef -undriven -fine");
+ run("memory_map");
+ run("opt -undriven -fine");
+ run("techmap -map +/techmap.v -map +/efinix/arith_map.v");
+ if (retime || help_mode)
+ run("abc -dff", "(only if -retime)");
+ }
+
+ if (check_label("map_ffs"))
+ {
+ run("dffsr2dff");
+ run("techmap -D NO_LUT -map +/efinix/cells_map.v");
+ run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit");
+ run("opt_expr -mux_undef");
+ run("simplemap");
+ }
+
+ if (check_label("map_luts"))
+ {
+ run("abc -lut 4");
+ run("clean");
+ }
+
+ if (check_label("map_cells"))
+ {
+ run("techmap -map +/efinix/cells_map.v");
+ run("clean");
+ }
+
+ if (check_label("map_gbuf"))
+ {
+ run("efinix_gbuf");
+ run("efinix_fixcarry");
+ run("clean");
+ }
+
+ if (check_label("check"))
+ {
+ run("hierarchy -check");
+ run("stat");
+ run("check -noinit");
+ }
+
+ if (check_label("edif"))
+ {
+ if (!edif_file.empty() || help_mode)
+ run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
+ }
+
+ if (check_label("json"))
+ {
+ if (!json_file.empty() || help_mode)
+ run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
+ }
+ }
+} SynthEfinixPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/gowin/determine_init.cc b/techlibs/gowin/determine_init.cc
index 991e5245a..d9a0880f6 100644
--- a/techlibs/gowin/determine_init.cc
+++ b/techlibs/gowin/determine_init.cc
@@ -50,7 +50,7 @@ struct DetermineInitPass : public Pass {
extra_args(args, args.size(), design);
- size_t cnt = 0;
+ int cnt = 0;
for (auto module : design->selected_modules())
{
for (auto cell : module->selected_cells())
@@ -65,7 +65,7 @@ struct DetermineInitPass : public Pass {
}
}
}
- log_header(design, "Updated %lu cells with determined init value.\n", cnt);
+ log_header(design, "Updated %d cells with determined init value.\n", cnt);
}
} DetermineInitPass;
diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc
index 723b59d6f..76a89b107 100644
--- a/techlibs/ice40/Makefile.inc
+++ b/techlibs/ice40/Makefile.inc
@@ -4,7 +4,6 @@ OBJS += techlibs/ice40/ice40_braminit.o
OBJS += techlibs/ice40/ice40_ffssr.o
OBJS += techlibs/ice40/ice40_ffinit.o
OBJS += techlibs/ice40/ice40_opt.o
-OBJS += techlibs/ice40/ice40_unlut.o
GENFILES += techlibs/ice40/brams_init1.vh
GENFILES += techlibs/ice40/brams_init2.vh
@@ -28,6 +27,12 @@ $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.box))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.lut))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.box))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.lut))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.box))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.lut))
$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init1.vh))
$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init2.vh))
diff --git a/techlibs/ice40/abc_hx.box b/techlibs/ice40/abc_hx.box
new file mode 100644
index 000000000..c0ea742e2
--- /dev/null
+++ b/techlibs/ice40/abc_hx.box
@@ -0,0 +1,13 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt
+
+# NB: Inputs/Outputs must be ordered alphabetically
+# (with exceptions for carry in/out)
+
+# Inputs: A B CI
+# Outputs: O CO
+# (NB: carry chain input/output must be last
+# input/output and have been moved there
+# overriding the alphabetical ordering)
+$__ICE40_FULL_ADDER 1 1 3 2
+400 379 316
+259 231 126
diff --git a/techlibs/ice40/abc_hx.lut b/techlibs/ice40/abc_hx.lut
new file mode 100644
index 000000000..3b3bb11e2
--- /dev/null
+++ b/techlibs/ice40/abc_hx.lut
@@ -0,0 +1,6 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt
+# I3 I2 I1 I0
+1 1 316
+2 1 316 379
+3 1 316 379 400
+4 1 316 379 400 449
diff --git a/techlibs/ice40/abc_lp.box b/techlibs/ice40/abc_lp.box
new file mode 100644
index 000000000..d73b6d649
--- /dev/null
+++ b/techlibs/ice40/abc_lp.box
@@ -0,0 +1,13 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt
+
+# NB: Inputs/Outputs must be ordered alphabetically
+# (with exceptions for carry in/out)
+
+# Inputs: A B CI
+# Outputs: O CO
+# (NB: carry chain input/output must be last
+# input/output and have been moved there
+# overriding the alphabetical ordering)
+$__ICE40_FULL_ADDER 1 1 3 2
+589 558 465
+675 609 186
diff --git a/techlibs/ice40/abc_lp.lut b/techlibs/ice40/abc_lp.lut
new file mode 100644
index 000000000..e72f760a2
--- /dev/null
+++ b/techlibs/ice40/abc_lp.lut
@@ -0,0 +1,6 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt
+# I3 I2 I1 I0
+1 1 465
+2 1 465 558
+3 1 465 558 589
+4 1 465 558 589 661
diff --git a/techlibs/ice40/abc_u.box b/techlibs/ice40/abc_u.box
new file mode 100644
index 000000000..42d666051
--- /dev/null
+++ b/techlibs/ice40/abc_u.box
@@ -0,0 +1,13 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt
+
+# NB: Inputs/Outputs must be ordered alphabetically
+# (with exceptions for carry in/out)
+
+# Inputs: A B CI
+# Outputs: O CO
+# (NB: carry chain input/output must be last
+# input/output and have been moved there
+# overriding the alphabetical ordering)
+$__ICE40_FULL_ADDER 1 1 3 2
+1231 1205 874
+675 609 278
diff --git a/techlibs/ice40/abc_u.lut b/techlibs/ice40/abc_u.lut
new file mode 100644
index 000000000..1e4fcadb6
--- /dev/null
+++ b/techlibs/ice40/abc_u.lut
@@ -0,0 +1,6 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt
+# I3 I2 I1 I0
+1 1 874
+2 1 874 1205
+3 1 874 1205 1231
+4 1 874 1205 1231 1285
diff --git a/techlibs/ice40/arith_map.v b/techlibs/ice40/arith_map.v
index 4449fdc1b..26b24db9e 100644
--- a/techlibs/ice40/arith_map.v
+++ b/techlibs/ice40/arith_map.v
@@ -44,23 +44,19 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO);
genvar i;
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
- SB_CARRY carry (
- .I0(AA[i]),
- .I1(BB[i]),
+ \$__ICE40_CARRY_WRAPPER #(
+ // A[0]: 1010 1010 1010 1010
+ // A[1]: 1100 1100 1100 1100
+ // A[2]: 1111 0000 1111 0000
+ // A[3]: 1111 1111 0000 0000
+ .LUT(16'b 0110_1001_1001_0110)
+ ) fadd (
+ .A(AA[i]),
+ .B(BB[i]),
.CI(C[i]),
- .CO(CO[i])
- );
- SB_LUT4 #(
- // I0: 1010 1010 1010 1010
- // I1: 1100 1100 1100 1100
- // I2: 1111 0000 1111 0000
- // I3: 1111 1111 0000 0000
- .LUT_INIT(16'b 0110_1001_1001_0110)
- ) adder (
.I0(1'b0),
- .I1(AA[i]),
- .I2(BB[i]),
.I3(C[i]),
+ .CO(CO[i]),
.O(Y[i])
);
end endgenerate
diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v
index d0ddfd02e..662423f0a 100644
--- a/techlibs/ice40/cells_map.v
+++ b/techlibs/ice40/cells_map.v
@@ -37,23 +37,46 @@ module \$lut (A, Y);
generate
if (WIDTH == 1) begin
- SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0));
+ localparam [15:0] INIT = {{8{LUT[1]}}, {8{LUT[0]}}};
+ SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(1'b0), .I1(1'b0), .I2(1'b0), .I3(A[0]));
end else
if (WIDTH == 2) begin
- SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0));
+ localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[1]}}, {4{LUT[2]}}, {4{LUT[0]}}};
+ SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(1'b0), .I1(1'b0), .I2(A[1]), .I3(A[0]));
end else
if (WIDTH == 3) begin
- SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0));
+ localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[3]}}, {2{LUT[5]}}, {2{LUT[1]}}, {2{LUT[6]}}, {2{LUT[2]}}, {2{LUT[4]}}, {2{LUT[0]}}};
+ SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(1'b0), .I1(A[2]), .I2(A[1]), .I3(A[0]));
end else
if (WIDTH == 4) begin
- SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
+ localparam [15:0] INIT = {LUT[15], LUT[7], LUT[11], LUT[3], LUT[13], LUT[5], LUT[9], LUT[1], LUT[14], LUT[6], LUT[10], LUT[2], LUT[12], LUT[4], LUT[8], LUT[0]};
+ SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[3]), .I1(A[2]), .I2(A[1]), .I3(A[0]));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
endgenerate
endmodule
`endif
+
+`ifndef NO_ADDER
+module \$__ICE40_CARRY_WRAPPER (output CO, O, input A, B, CI, I0, I3);
+ parameter LUT = 0;
+ SB_CARRY carry (
+ .I0(A),
+ .I1(B),
+ .CI(CI),
+ .CO(CO)
+ );
+ \$lut #(
+ .WIDTH(4),
+ .LUT(LUT)
+ ) lut (
+ .A({I0,A,B,I3}),
+ .Y(O)
+ );
+endmodule
+`endif
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index f9945b2b5..c7f3bdad2 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -127,6 +127,7 @@ endmodule
// SiliconBlue Logic Cells
+(* lib_whitebox *)
module SB_LUT4 (output O, input I0, I1, I2, I3);
parameter [15:0] LUT_INIT = 0;
wire [7:0] s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
@@ -135,10 +136,42 @@ module SB_LUT4 (output O, input I0, I1, I2, I3);
assign O = I0 ? s1[1] : s1[0];
endmodule
+(* lib_whitebox *)
module SB_CARRY (output CO, input I0, I1, CI);
assign CO = (I0 && I1) || ((I0 || I1) && CI);
endmodule
+(* abc_box_id = 1, lib_whitebox *)
+module \$__ICE40_FULL_ADDER (
+ (* abc_carry *)
+ output CO,
+ output O,
+ input A,
+ input B,
+ (* abc_carry *)
+ input CI
+);
+ SB_CARRY carry (
+ .I0(A),
+ .I1(B),
+ .CI(CI),
+ .CO(CO)
+ );
+ SB_LUT4 #(
+ // I0: 1010 1010 1010 1010
+ // I1: 1100 1100 1100 1100
+ // I2: 1111 0000 1111 0000
+ // I3: 1111 1111 0000 0000
+ .LUT_INIT(16'b 0110_1001_1001_0110)
+ ) adder (
+ .I0(1'b0),
+ .I1(A),
+ .I2(B),
+ .I3(CI),
+ .O(O)
+ );
+endmodule
+
// Positive Edge SiliconBlue FF Cells
module SB_DFF (output `SB_DFF_REG, input C, D);
@@ -1338,13 +1371,13 @@ module SB_MAC16 (
wire [15:0] p_Ah_Bh, p_Al_Bh, p_Ah_Bl, p_Al_Bl;
wire [15:0] Ah, Al, Bh, Bl;
assign Ah = {A_SIGNED ? {8{iA[15]}} : 8'b0, iA[15: 8]};
- assign Al = {A_SIGNED ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]};
+ assign Al = {A_SIGNED && MODE_8x8 ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]};
assign Bh = {B_SIGNED ? {8{iB[15]}} : 8'b0, iB[15: 8]};
- assign Bl = {B_SIGNED ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]};
- assign p_Ah_Bh = Ah * Bh;
- assign p_Al_Bh = Al * Bh;
- assign p_Ah_Bl = Ah * Bl;
- assign p_Al_Bl = Al * Bl;
+ assign Bl = {B_SIGNED && MODE_8x8 ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]};
+ assign p_Ah_Bh = Ah * Bh; // F
+ assign p_Al_Bh = {8'b0, Al[7:0]} * Bh; // J
+ assign p_Ah_Bl = Ah * {8'b0, Bl[7:0]}; // K
+ assign p_Al_Bl = Al * Bl; // G
// Regs F and J
reg [15:0] rF, rJ;
@@ -1375,7 +1408,9 @@ module SB_MAC16 (
assign iG = BOT_8x8_MULT_REG ? rG : p_Al_Bl;
// Adder Stage
- assign iL = iG + (iK << 8) + (iJ << 8) + (iF << 16);
+ wire [23:0] iK_e = {A_SIGNED ? {8{iK[15]}} : 8'b0, iK};
+ wire [23:0] iJ_e = {B_SIGNED ? {8{iJ[15]}} : 8'b0, iJ};
+ assign iL = iG + (iK_e << 8) + (iJ_e << 8) + (iF << 16);
// Reg H
reg [31:0] rH;
diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc
index 4fa6b0792..1a139ffea 100644
--- a/techlibs/ice40/ice40_braminit.cc
+++ b/techlibs/ice40/ice40_braminit.cc
@@ -69,13 +69,13 @@ static void run_ice40_braminit(Module *module)
for (int i = 0; i < GetSize(line); i++)
{
- if (in_comment && line.substr(i, 2) == "*/") {
+ if (in_comment && line.compare(i, 2, "*/") == 0) {
line[i] = ' ';
line[i+1] = ' ';
in_comment = false;
continue;
}
- if (!in_comment && line.substr(i, 2) == "/*")
+ if (!in_comment && line.compare(i, 2, "/*") == 0)
in_comment = true;
if (in_comment)
line[i] = ' ';
@@ -87,7 +87,7 @@ static void run_ice40_braminit(Module *module)
long value;
token = next_token(line, " \t\r\n");
- if (token.empty() || token.substr(0, 2) == "//")
+ if (token.empty() || token.compare(0, 2, "//") == 0)
break;
if (token[0] == '@') {
diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc
index f528607d6..d5106b805 100644
--- a/techlibs/ice40/ice40_opt.cc
+++ b/techlibs/ice40/ice40_opt.cc
@@ -83,6 +83,51 @@ static void run_ice40_opts(Module *module)
}
continue;
}
+
+ if (cell->type == "$__ICE40_FULL_ADDER")
+ {
+ SigSpec non_const_inputs, replacement_output;
+ int count_zeros = 0, count_ones = 0;
+
+ SigBit inbit[3] = {
+ cell->getPort("\\A"),
+ cell->getPort("\\B"),
+ cell->getPort("\\CI")
+ };
+ for (int i = 0; i < 3; i++)
+ if (inbit[i].wire == nullptr) {
+ if (inbit[i] == State::S1)
+ count_ones++;
+ else
+ count_zeros++;
+ } else
+ non_const_inputs.append(inbit[i]);
+
+ if (count_zeros >= 2)
+ replacement_output = State::S0;
+ else if (count_ones >= 2)
+ replacement_output = State::S1;
+ else if (GetSize(non_const_inputs) == 1)
+ replacement_output = non_const_inputs;
+
+ if (GetSize(replacement_output)) {
+ optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
+ module->connect(cell->getPort("\\CO")[0], replacement_output);
+ module->design->scratchpad_set_bool("opt.did_something", true);
+ log("Optimized $__ICE40_FULL_ADDER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n",
+ log_id(module), log_id(cell), log_signal(replacement_output));
+ cell->type = "$lut";
+ cell->setPort("\\A", { State::S0, inbit[0], inbit[1], inbit[2] });
+ cell->setPort("\\Y", cell->getPort("\\O"));
+ cell->unsetPort("\\B");
+ cell->unsetPort("\\CI");
+ cell->unsetPort("\\CO");
+ cell->unsetPort("\\O");
+ cell->setParam("\\LUT", RTLIL::Const::from_string("0110100110010110"));
+ cell->setParam("\\WIDTH", 4);
+ }
+ continue;
+ }
}
for (auto cell : sb_lut_cells)
diff --git a/techlibs/ice40/ice40_unlut.cc b/techlibs/ice40/ice40_unlut.cc
deleted file mode 100644
index 2428a8e78..000000000
--- a/techlibs/ice40/ice40_unlut.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#include "kernel/yosys.h"
-#include "kernel/sigtools.h"
-#include <stdlib.h>
-#include <stdio.h>
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-static SigBit get_bit_or_zero(const SigSpec &sig)
-{
- if (GetSize(sig) == 0)
- return State::S0;
- return sig[0];
-}
-
-static void run_ice40_unlut(Module *module)
-{
- SigMap sigmap(module);
-
- for (auto cell : module->selected_cells())
- {
- if (cell->type == "\\SB_LUT4")
- {
- SigSpec inbits;
-
- inbits.append(get_bit_or_zero(cell->getPort("\\I0")));
- inbits.append(get_bit_or_zero(cell->getPort("\\I1")));
- inbits.append(get_bit_or_zero(cell->getPort("\\I2")));
- inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
- sigmap.apply(inbits);
-
- log("Mapping SB_LUT4 cell %s.%s to $lut.\n", log_id(module), log_id(cell));
-
- cell->type ="$lut";
- cell->setParam("\\WIDTH", 4);
- cell->setParam("\\LUT", cell->getParam("\\LUT_INIT"));
- cell->unsetParam("\\LUT_INIT");
-
- cell->setPort("\\A", SigSpec({
- get_bit_or_zero(cell->getPort("\\I3")),
- get_bit_or_zero(cell->getPort("\\I2")),
- get_bit_or_zero(cell->getPort("\\I1")),
- get_bit_or_zero(cell->getPort("\\I0"))
- }));
- cell->setPort("\\Y", cell->getPort("\\O")[0]);
- cell->unsetPort("\\I0");
- cell->unsetPort("\\I1");
- cell->unsetPort("\\I2");
- cell->unsetPort("\\I3");
- cell->unsetPort("\\O");
-
- cell->check();
- }
- }
-}
-
-struct Ice40UnlutPass : public Pass {
- Ice40UnlutPass() : Pass("ice40_unlut", "iCE40: perform simple optimizations") { }
- void help() YS_OVERRIDE
- {
- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
- log("\n");
- log(" ice40_unlut [options] [selection]\n");
- log("\n");
- log("This command transforms all SB_LUT4 cells to generic $lut cells.\n");
- log("\n");
- }
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
- {
- log_header(design, "Executing ICE40_UNLUT pass (convert SB_LUT4 to $lut).\n");
- log_push();
-
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++) {
- // if (args[argidx] == "-???") {
- // continue;
- // }
- break;
- }
- extra_args(args, argidx, design);
-
- for (auto module : design->selected_modules())
- run_ice40_unlut(module);
- }
-} Ice40UnlutPass;
-
-PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index bb96d66d1..c6de81bd9 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -37,6 +37,10 @@ struct SynthIce40Pass : public ScriptPass
log("\n");
log("This command runs synthesis for iCE40 FPGAs.\n");
log("\n");
+ log(" -device < hx | lp | u >\n");
+ log(" relevant only for '-abc9' flow, optimise timing for the specified device.\n");
+ log(" default: hx\n");
+ log("\n");
log(" -top <module>\n");
log(" use the specified module as top module\n");
log("\n");
@@ -63,9 +67,6 @@ struct SynthIce40Pass : public ScriptPass
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log("\n");
- log(" -relut\n");
- log(" combine LUTs after synthesis\n");
- log("\n");
log(" -nocarry\n");
log(" do not use SB_CARRY cells in output netlist\n");
log("\n");
@@ -74,7 +75,7 @@ struct SynthIce40Pass : public ScriptPass
log("\n");
log(" -dffe_min_ce_use <min_ce_use>\n");
log(" do not use SB_DFFE* cells if the resulting CE line would go to less\n");
- log(" than min_ce_use SB_DFFE*in output netlist\n");
+ log(" than min_ce_use SB_DFFE* in output netlist\n");
log("\n");
log(" -nobram\n");
log(" do not use SB_RAM40_4K* cells in output netlist\n");
@@ -92,14 +93,17 @@ struct SynthIce40Pass : public ScriptPass
log(" generate an output netlist (and BLIF file) suitable for VPR\n");
log(" (this feature is experimental and incomplete)\n");
log("\n");
+ log(" -abc9\n");
+ log(" use new ABC9 flow (EXPERIMENTAL)\n");
+ log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
- string top_opt, blif_file, edif_file, json_file;
- bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
+ string top_opt, blif_file, edif_file, json_file, abc, device_opt;
+ bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr;
int min_ce_use;
void clear_flags() YS_OVERRIDE
@@ -115,10 +119,11 @@ struct SynthIce40Pass : public ScriptPass
dsp = false;
flatten = true;
retime = false;
- relut = false;
noabc = false;
abc2 = false;
vpr = false;
+ abc = "abc";
+ device_opt = "hx";
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -166,7 +171,7 @@ struct SynthIce40Pass : public ScriptPass
continue;
}
if (args[argidx] == "-relut") {
- relut = true;
+ // removed, opt_lut is always run
continue;
}
if (args[argidx] == "-nocarry") {
@@ -178,7 +183,7 @@ struct SynthIce40Pass : public ScriptPass
continue;
}
if (args[argidx] == "-dffe_min_ce_use" && argidx+1 < args.size()) {
- min_ce_use = std::stoi(args[++argidx]);
+ min_ce_use = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-nobram") {
@@ -201,12 +206,25 @@ struct SynthIce40Pass : public ScriptPass
vpr = true;
continue;
}
+ if (args[argidx] == "-abc9") {
+ abc = "abc9";
+ continue;
+ }
+ if (args[argidx] == "-device" && argidx+1 < args.size()) {
+ device_opt = args[++argidx];
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
+ if (device_opt != "hx" && device_opt != "lp" && device_opt !="u")
+ log_cmd_error("Invalid or no device specified: '%s'\n", device_opt.c_str());
+
+ if (abc == "abc9" && retime)
+ log_cmd_error("-retime option not currently compatible with -abc9!\n");
log_header(design, "Executing SYNTH_ICE40 pass.\n");
log_push();
@@ -220,7 +238,7 @@ struct SynthIce40Pass : public ScriptPass
{
if (check_label("begin"))
{
- run("read_verilog -lib +/ice40/cells_sim.v");
+ run("read_verilog -icells -lib +/ice40/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
run("proc");
}
@@ -257,14 +275,14 @@ struct SynthIce40Pass : public ScriptPass
run("opt_clean");
}
- if (!nobram && check_label("bram", "(skip if -nobram)"))
+ if (!nobram && check_label("map_bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/ice40/brams.txt");
run("techmap -map +/ice40/brams_map.v");
run("ice40_braminit");
}
- if (check_label("map"))
+ if (check_label("map_ffram"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
@@ -275,10 +293,12 @@ struct SynthIce40Pass : public ScriptPass
{
if (nocarry)
run("techmap");
- else
+ else {
+ run("ice40_wrapcarry");
run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
+ }
if (retime || help_mode)
- run("abc -dff", "(only if -retime)");
+ run(abc + " -dff", "(only if -retime)");
run("ice40_opt");
}
@@ -291,7 +311,7 @@ struct SynthIce40Pass : public ScriptPass
run("opt_merge");
run(stringf("dff2dffe -unmap-mince %d", min_ce_use));
}
- run("techmap -D NO_LUT -map +/ice40/cells_map.v");
+ run("techmap -D NO_LUT -D NO_ADDER -map +/ice40/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
run("ice40_ffinit");
@@ -302,7 +322,7 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("map_luts"))
{
if (abc2 || help_mode) {
- run("abc", " (only if -abc2)");
+ run(abc, " (only if -abc2)");
run("ice40_opt", "(only if -abc2)");
}
run("techmap -map +/ice40/latches_map.v");
@@ -311,13 +331,22 @@ struct SynthIce40Pass : public ScriptPass
run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
}
if (!noabc) {
- run("abc -dress -lut 4", "(skip if -noabc)");
+ if (abc == "abc9") {
+ int wire_delay;
+ if (device_opt == "lp")
+ wire_delay = 400;
+ else if (device_opt == "u")
+ wire_delay = 750;
+ else
+ wire_delay = 250;
+ run(abc + stringf(" -W %d -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", wire_delay, device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
+ }
+ else
+ run(abc + " -dress -lut 4", "(skip if -noabc)");
}
+ run("techmap -D NO_LUT -map +/ice40/cells_map.v");
run("clean");
- if (relut || help_mode) {
- run("ice40_unlut", " (only if -relut)");
- run("opt_lut -dlogic SB_CARRY:I0=1:I1=2:CI=3", "(only if -relut)");
- }
+ run("opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0");
}
if (check_label("map_cells"))
diff --git a/techlibs/ice40/tests/test_arith.ys b/techlibs/ice40/tests/test_arith.ys
index 160c767fb..ddb80b700 100644
--- a/techlibs/ice40/tests/test_arith.ys
+++ b/techlibs/ice40/tests/test_arith.ys
@@ -1,6 +1,5 @@
read_verilog test_arith.v
synth_ice40
-techmap -map ../cells_sim.v
rename test gate
read_verilog test_arith.v
@@ -8,3 +7,11 @@ rename test gold
miter -equiv -flatten -make_outputs gold gate miter
sat -verify -prove trigger 0 -show-ports miter
+
+synth_ice40 -top gate
+
+read_verilog test_arith.v
+rename test gold
+
+miter -equiv -flatten -make_outputs gold gate miter
+sat -verify -prove trigger 0 -show-ports miter
diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh
index 1bc0cc688..1e564d1b2 100644
--- a/techlibs/ice40/tests/test_dsp_model.sh
+++ b/techlibs/ice40/tests/test_dsp_model.sh
@@ -1,10 +1,15 @@
#!/bin/bash
set -ex
sed 's/SB_MAC16/SB_MAC16_UUT/; /SB_MAC16_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v
-cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v
+if [ ! -f "test_dsp_model_ref.v" ]; then
+ cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v
+fi
for tb in testbench \
testbench_comb_8x8_A testbench_comb_8x8_B testbench_comb_16x16 \
- testbench_seq_16x16_A testbench_seq_16x16_B
+ testbench_seq_16x16_A testbench_seq_16x16_B \
+ testbench_comb_8x8_A_signedA testbench_comb_8x8_A_signedB testbench_comb_8x8_A_signedAB \
+ testbench_comb_8x8_B_signedA testbench_comb_8x8_B_signedB testbench_comb_8x8_B_signedAB \
+ testbench_comb_16x16_signedA testbench_comb_16x16_signedB testbench_comb_16x16_signedAB
do
iverilog -s $tb -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v
vvp -N ./test_dsp_model
diff --git a/techlibs/ice40/tests/test_dsp_model.v b/techlibs/ice40/tests/test_dsp_model.v
index 594bd4ad3..f4f6858f0 100644
--- a/techlibs/ice40/tests/test_dsp_model.v
+++ b/techlibs/ice40/tests/test_dsp_model.v
@@ -241,6 +241,81 @@ module testbench_comb_8x8_A;
) testbench ();
endmodule
+module testbench_comb_8x8_A_signedA;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (2), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (0), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (2), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (0), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (1),
+ .B_SIGNED (0)
+ ) testbench ();
+endmodule
+
+module testbench_comb_8x8_A_signedB;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (2), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (0), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (2), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (0), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (0),
+ .B_SIGNED (1)
+ ) testbench ();
+endmodule
+
+module testbench_comb_8x8_A_signedAB;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (2), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (0), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (2), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (0), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (1),
+ .B_SIGNED (1)
+ ) testbench ();
+endmodule
+
module testbench_comb_8x8_B;
testbench #(
.NEG_TRIGGER (0),
@@ -266,6 +341,81 @@ module testbench_comb_8x8_B;
) testbench ();
endmodule
+module testbench_comb_8x8_B_signedA;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (1), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (1), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (1),
+ .B_SIGNED (0)
+ ) testbench ();
+endmodule
+
+module testbench_comb_8x8_B_signedB;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (1), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (1), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (0),
+ .B_SIGNED (1)
+ ) testbench ();
+endmodule
+
+module testbench_comb_8x8_B_signedAB;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (1), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (1), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (1),
+ .B_SIGNED (1)
+ ) testbench ();
+endmodule
+
module testbench_comb_16x16;
testbench #(
.NEG_TRIGGER (0),
@@ -291,6 +441,81 @@ module testbench_comb_16x16;
) testbench ();
endmodule
+module testbench_comb_16x16_signedA;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (1),
+ .B_SIGNED (0)
+ ) testbench ();
+endmodule
+
+module testbench_comb_16x16_signedB;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (0),
+ .B_SIGNED (1)
+ ) testbench ();
+endmodule
+
+module testbench_comb_16x16_signedAB;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (1),
+ .B_SIGNED (1)
+ ) testbench ();
+endmodule
+
module testbench_seq_16x16_A;
testbench #(
.NEG_TRIGGER (0),
diff --git a/techlibs/intel/Makefile.inc b/techlibs/intel/Makefile.inc
index ec7cea379..4e8f423c8 100644
--- a/techlibs/intel/Makefile.inc
+++ b/techlibs/intel/Makefile.inc
@@ -3,22 +3,12 @@ OBJS += techlibs/intel/synth_intel.o
$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/m9k_bb.v))
$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/altpll_bb.v))
-$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams.txt))
-$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map.v))
-$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/cells_sim.v))
-$(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/cells_sim.v))
-$(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_sim.v))
-$(eval $(call add_share_file,share/intel/cyclone10,techlibs/intel/cyclone10/cells_sim.v))
-$(eval $(call add_share_file,share/intel/cycloneiv,techlibs/intel/cycloneiv/cells_sim.v))
-$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/cells_sim.v))
-$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/cells_map.v))
-$(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/cells_map.v))
-$(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_map.v))
-$(eval $(call add_share_file,share/intel/cyclone10,techlibs/intel/cyclone10/cells_map.v))
-$(eval $(call add_share_file,share/intel/cycloneiv,techlibs/intel/cycloneiv/cells_map.v))
-$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/cells_map.v))
-#$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/arith_map.v))
-#$(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/arith_map.v))
-#$(eval $(call add_share_file,share/intel/cycloneiv,techlibs/intel/cycloneiv/arith_map.v))
+$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_m9k.txt))
+$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map_m9k.v))
+
+# Add the cell models and mappings for the VQM backend
+families := max10 a10gx cyclonev cyclone10 cycloneiv cycloneive
+$(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_sim.v)))
+$(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_map.v)))
#$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/arith_map.v))
diff --git a/techlibs/intel/common/brams.txt b/techlibs/intel/common/brams_m9k.txt
index 3bf21afc9..3bf21afc9 100644
--- a/techlibs/intel/common/brams.txt
+++ b/techlibs/intel/common/brams_m9k.txt
diff --git a/techlibs/intel/common/brams_map.v b/techlibs/intel/common/brams_map_m9k.v
index d0f07c1de..d0f07c1de 100644
--- a/techlibs/intel/common/brams_map.v
+++ b/techlibs/intel/common/brams_map_m9k.v
diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc
index 639cba2c2..e5dc1adc7 100644
--- a/techlibs/intel/synth_intel.cc
+++ b/techlibs/intel/synth_intel.cc
@@ -38,9 +38,9 @@ struct SynthIntelPass : public ScriptPass {
log("\n");
log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
log(" generate the synthesis netlist for the specified family.\n");
- log(" MAX10 is the default target if not family argument specified.\n");
+ log(" MAX10 is the default target if no family argument specified.\n");
log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
- log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
+ log(" Cyclone V and Arria 10 GX devices are experimental.\n");
log("\n");
log(" -top <module>\n");
log(" use the specified module as top module (default='top')\n");
@@ -48,6 +48,8 @@ struct SynthIntelPass : public ScriptPass {
log(" -vqm <file>\n");
log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
log(" output file is omitted if this parameter is not specified.\n");
+ log(" Note that this backend has not been tested and is likely incompatible\n");
+ log(" with recent versions of Quartus.\n");
log("\n");
log(" -vpr <file>\n");
log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
@@ -59,11 +61,11 @@ struct SynthIntelPass : public ScriptPass {
log(" from label is synonymous to 'begin', and empty to label is\n");
log(" synonymous to the end of the command list.\n");
log("\n");
- log(" -noiopads\n");
- log(" do not use altsyncram cells in output netlist\n");
+ log(" -iopads\n");
+ log(" use IO pad cells in output netlist\n");
log("\n");
log(" -nobram\n");
- log(" do not use altsyncram cells in output netlist\n");
+ log(" do not use block RAM cells in output netlist\n");
log("\n");
log(" -noflatten\n");
log(" do not flatten design before synthesis\n");
@@ -77,7 +79,7 @@ struct SynthIntelPass : public ScriptPass {
}
string top_opt, family_opt, vout_file, blif_file;
- bool retime, flatten, nobram, noiopads;
+ bool retime, flatten, nobram, iopads;
void clear_flags() YS_OVERRIDE
{
@@ -88,7 +90,7 @@ struct SynthIntelPass : public ScriptPass {
retime = false;
flatten = true;
nobram = false;
- noiopads = false;
+ iopads = false;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -108,6 +110,7 @@ struct SynthIntelPass : public ScriptPass {
}
if (args[argidx] == "-vqm" && argidx + 1 < args.size()) {
vout_file = args[++argidx];
+ log_warning("The Quartus backend has not been tested recently and is likely incompatible with modern versions of Quartus.\n");
continue;
}
if (args[argidx] == "-vpr" && argidx + 1 < args.size()) {
@@ -122,8 +125,8 @@ struct SynthIntelPass : public ScriptPass {
run_to = args[argidx].substr(pos + 1);
continue;
}
- if (args[argidx] == "-noiopads") {
- noiopads = true;
+ if (args[argidx] == "-iopads") {
+ iopads = true;
continue;
}
if (args[argidx] == "-nobram") {
@@ -144,9 +147,13 @@ struct SynthIntelPass : public ScriptPass {
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
- if (family_opt != "max10" && family_opt != "a10gx" && family_opt != "cyclonev" && family_opt != "cycloneiv" &&
- family_opt != "cycloneive" && family_opt != "cyclone10")
- log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());
+ if (family_opt != "max10" &&
+ family_opt != "a10gx" &&
+ family_opt != "cyclonev" &&
+ family_opt != "cycloneiv" &&
+ family_opt != "cycloneive" &&
+ family_opt != "cyclone10")
+ log_cmd_error("Invalid or no family specified: '%s'\n", family_opt.c_str());
log_header(design, "Executing SYNTH_INTEL pass.\n");
log_push();
@@ -159,18 +166,9 @@ struct SynthIntelPass : public ScriptPass {
void script() YS_OVERRIDE
{
if (check_label("begin")) {
- if (check_label("family") && family_opt == "max10")
- run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
- else if (check_label("family") && family_opt == "a10gx")
- run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
- else if (check_label("family") && family_opt == "cyclonev")
- run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
- else if (check_label("family") && family_opt == "cyclone10")
- run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
- else if (check_label("family") && family_opt == "cycloneiv")
- run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
- else
- run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
+ if (check_label("family"))
+ run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str()));
+
// Misc and common cells
run("read_verilog -sv -lib +/intel/common/m9k_bb.v");
run("read_verilog -sv -lib +/intel/common/altpll_bb.v");
@@ -188,12 +186,19 @@ struct SynthIntelPass : public ScriptPass {
run("synth -run coarse");
}
- if (!nobram && check_label("bram", "(skip if -nobram)")) {
- run("memory_bram -rules +/intel/common/brams.txt");
- run("techmap -map +/intel/common/brams_map.v");
+ if (!nobram && check_label("map_bram", "(skip if -nobram)")) {
+ if (family_opt == "cycloneiv" ||
+ family_opt == "cycloneive" ||
+ family_opt == "max10" ||
+ help_mode) {
+ run("memory_bram -rules +/intel/common/brams_m9k.txt", "(if applicable for family)");
+ run("techmap -map +/intel/common/brams_map_m9k.v", "(if applicable for family)");
+ } else {
+ log_warning("BRAM mapping is not currently supported for %s.\n", family_opt.c_str());
+ }
}
- if (check_label("fine")) {
+ if (check_label("map_ffram")) {
run("opt -fast -mux_undef -undriven -fine -full");
run("memory_map");
run("opt -undriven -fine");
@@ -217,20 +222,9 @@ struct SynthIntelPass : public ScriptPass {
}
if (check_label("map_cells")) {
- if (!noiopads)
- run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
- if (family_opt == "max10")
- run("techmap -map +/intel/max10/cells_map.v");
- else if (family_opt == "a10gx")
- run("techmap -map +/intel/a10gx/cells_map.v");
- else if (family_opt == "cyclonev")
- run("techmap -map +/intel/cyclonev/cells_map.v");
- else if (family_opt == "cyclone10")
- run("techmap -map +/intel/cyclone10/cells_map.v");
- else if (family_opt == "cycloneiv")
- run("techmap -map +/intel/cycloneiv/cells_map.v");
- else
- run("techmap -map +/intel/cycloneive/cells_map.v");
+ if (iopads || help_mode)
+ run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(if -iopads)");
+ run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str()));
run("dffinit -highlow -ff dffeas q power_up");
run("clean -purge");
}
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index d68f03bb4..2b1af289c 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -5,6 +5,8 @@ GENFILES += techlibs/xilinx/brams_init_36.vh
GENFILES += techlibs/xilinx/brams_init_32.vh
GENFILES += techlibs/xilinx/brams_init_18.vh
GENFILES += techlibs/xilinx/brams_init_16.vh
+GENFILES += techlibs/xilinx/brams_init_9.vh
+GENFILES += techlibs/xilinx/brams_init_8.vh
EXTRA_OBJS += techlibs/xilinx/brams_init.mk
.SECONDARY: techlibs/xilinx/brams_init.mk
@@ -18,21 +20,33 @@ techlibs/xilinx/brams_init_36.vh: techlibs/xilinx/brams_init.mk
techlibs/xilinx/brams_init_32.vh: techlibs/xilinx/brams_init.mk
techlibs/xilinx/brams_init_18.vh: techlibs/xilinx/brams_init.mk
techlibs/xilinx/brams_init_16.vh: techlibs/xilinx/brams_init.mk
+techlibs/xilinx/brams_init_9.vh: techlibs/xilinx/brams_init.mk
+techlibs/xilinx/brams_init_8.vh: techlibs/xilinx/brams_init.mk
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_xtra.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_bb.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_bb.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v))
+
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7_nowide.lut))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_18.vh))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_16.vh))
+$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_9.vh))
+$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_8.vh))
diff --git a/techlibs/xilinx/abc_xc7.box b/techlibs/xilinx/abc_xc7.box
new file mode 100644
index 000000000..3789ff350
--- /dev/null
+++ b/techlibs/xilinx/abc_xc7.box
@@ -0,0 +1,58 @@
+# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf
+
+# NB: Inputs/Outputs must be ordered alphabetically
+# (with exceptions for carry in/out)
+
+# Average across F7[AB]MUX
+# Inputs: I0 I1 S0
+# Outputs: O
+F7MUX 1 1 3 1
+204 208 286
+
+# Inputs: I0 I1 S0
+# Outputs: O
+MUXF8 2 1 3 1
+104 94 273
+
+# Inputs: I0 I1 I2 I3 S0 S1
+# Outputs: O
+$__MUXF78 3 1 6 1
+294 297 311 317 390 273
+
+# CARRY4 + CARRY4_[ABCD]X
+# Inputs: CYINIT DI0 DI1 DI2 DI3 S0 S1 S2 S3 CI
+# Outputs: O0 O1 O2 O3 CO0 CO1 CO2 CO3
+# (NB: carry chain input/output must be last
+# input/output and the entire bus has been
+# moved there overriding the otherwise
+# alphabetical ordering)
+CARRY4 4 1 10 8
+482 - - - - 223 - - - 222
+598 407 - - - 400 205 - - 334
+584 556 537 - - 523 558 226 - 239
+642 615 596 438 - 582 618 330 227 313
+536 379 - - - 340 - - - 271
+494 465 445 - - 433 469 - - 157
+592 540 520 356 - 512 548 292 - 228
+580 526 507 398 385 508 528 378 380 114
+
+# SLICEM/A6LUT
+# Inputs: A0 A1 A2 A3 A4 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 WCLK WE
+# Outputs: DPO SPO
+RAM32X1D 5 0 13 2
+- - - - - - 631 472 407 238 127 - -
+631 472 407 238 127 - - - - - - - -
+
+# SLICEM/A6LUT
+# Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE
+# Outputs: DPO SPO
+RAM64X1D 6 0 15 2
+- - - - - - - 642 631 472 407 238 127 - -
+642 631 472 407 238 127 - - - - - - - - -
+
+# SLICEM/A6LUT + F7[AB]MUX
+# Inputs: A0 A1 A2 A3 A4 A5 A6 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 DPRA6 WCLK WE
+# Outputs: DPO SPO
+RAM128X1D 7 0 17 2
+- - - - - - - - 1009 998 839 774 605 494 450 - -
+1047 1036 877 812 643 532 478 - - - - - - - - - -
diff --git a/techlibs/xilinx/abc_xc7.lut b/techlibs/xilinx/abc_xc7.lut
new file mode 100644
index 000000000..bcbdec127
--- /dev/null
+++ b/techlibs/xilinx/abc_xc7.lut
@@ -0,0 +1,15 @@
+# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/timings/CLBLL_L.sdf
+# and https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/tile_type_CLBLL_L.json
+
+# K area delay
+1 1 127
+2 2 127 238
+3 3 127 238 407
+4 3 127 238 407 472
+5 3 127 238 407 472 631
+6 5 127 238 407 472 631 642
+ # (F7[AB]MUX.S + [AC]OUTMUX) / 2
+7 10 464 513 624 793 858 1017 1028
+ # F8MUX.S+BOUTMUX
+ # F8MUX.I0+F7MUX.S+BOUTMUX
+8 20 468 585 634 745 914 979 1138 1149
diff --git a/techlibs/xilinx/abc_xc7_nowide.lut b/techlibs/xilinx/abc_xc7_nowide.lut
new file mode 100644
index 000000000..fab48c879
--- /dev/null
+++ b/techlibs/xilinx/abc_xc7_nowide.lut
@@ -0,0 +1,10 @@
+# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/timings/CLBLL_L.sdf
+# and https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/tile_type_CLBLL_L.json
+
+# K area delay
+1 1 127
+2 2 127 238
+3 3 127 238 407
+4 3 127 238 407 472
+5 3 127 238 407 472 631
+6 5 127 238 407 472 631 642
diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v
index 09a5f07e8..5c848d4e6 100644
--- a/techlibs/xilinx/arith_map.v
+++ b/techlibs/xilinx/arith_map.v
@@ -180,7 +180,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
// First one
if (i == 0) begin
- CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_part
+ CARRY4 carry4_1st_part
(
.CYINIT(CI),
.CI (1'd0),
@@ -207,7 +207,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
// First one
if (i == 0) begin
- CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_full
+ CARRY4 carry4_1st_full
(
.CYINIT(CI),
.CI (1'd0),
diff --git a/techlibs/xilinx/brams_init.py b/techlibs/xilinx/brams_init.py
index d46a2b4f7..10057a0cb 100644
--- a/techlibs/xilinx/brams_init.py
+++ b/techlibs/xilinx/brams_init.py
@@ -1,5 +1,17 @@
#!/usr/bin/env python3
+with open("techlibs/xilinx/brams_init_9.vh", "w") as f:
+ for i in range(4):
+ init_snippets = [" INIT[%3d*9+8]" % (k+256*i,) for k in range(255, -1, -1)]
+ for k in range(4, 256, 4):
+ init_snippets[k] = "\n " + init_snippets[k]
+ print(".INITP_%02X({%s})," % (i, ",".join(init_snippets)), file=f)
+ for i in range(32):
+ init_snippets = [" INIT[%3d*9 +: 8]" % (k+32*i,) for k in range(31, -1, -1)]
+ for k in range(4, 32, 4):
+ init_snippets[k] = "\n " + init_snippets[k]
+ print(".INIT_%02X({%s})," % (i, ",".join(init_snippets)), file=f)
+
with open("techlibs/xilinx/brams_init_18.vh", "w") as f:
for i in range(8):
init_snippets = [" INIT[%3d*9+8]" % (k+256*i,) for k in range(255, -1, -1)]
@@ -24,6 +36,10 @@ with open("techlibs/xilinx/brams_init_36.vh", "w") as f:
init_snippets[k] = "\n " + init_snippets[k]
print(".INIT_%02X({%s})," % (i, ",".join(init_snippets)), file=f)
+with open("techlibs/xilinx/brams_init_8.vh", "w") as f:
+ for i in range(32):
+ print(".INIT_%02X(INIT[%3d*256 +: 256])," % (i, i), file=f)
+
with open("techlibs/xilinx/brams_init_16.vh", "w") as f:
for i in range(64):
print(".INIT_%02X(INIT[%3d*256 +: 256])," % (i, i), file=f)
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index 40789ddbe..b8e5bafc7 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -2,6 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,9 +24,9 @@ module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLA
(* techmap_celltype = "$_DFF_PN0_" *)
module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$_DFF_NN1_" *)
-module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$_DFF_PN1_" *)
-module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0;
@@ -55,7 +56,6 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
localparam [DEPTH-1:0] INIT_R = brev(INIT);
parameter _TECHMAP_CONSTMSK_L_ = 0;
- parameter _TECHMAP_CONSTVAL_L_ = 0;
wire CE;
generate
@@ -88,69 +88,280 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
end else
if (DEPTH > 65 && DEPTH <= 96) begin
wire T0, T1, T2, T3, T4, T5, T6;
- SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
+ SRLC32E #(.INIT(INIT_R[32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T4;
- else begin
- MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5]));
- MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5]));
- MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6]));
- end
+ else
+ \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T4), .I3(1'bx), .S0(L[5]), .S1(L[6]), .O(Q));
end else
if (DEPTH > 97 && DEPTH < 128) begin
wire T0, T1, T2, T3, T4, T5, T6, T7, T8;
- SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
+ SRLC32E #(.INIT(INIT_R[32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T6;
- else begin
- MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5]));
- MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5]));
- MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6]));
- end
+ else
+ \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T4), .I3(T6), .S0(L[5]), .S1(L[6]), .O(Q));
end
else if (DEPTH == 128) begin
wire T0, T1, T2, T3, T4, T5, T6;
- SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
- SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
- SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
+ SRLC32E #(.INIT(INIT_R[ 32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1));
+ SRLC32E #(.INIT(INIT_R[ 64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
+ SRLC32E #(.INIT(INIT_R[ 96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T6;
- else begin
- wire T7, T8;
- MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5]));
- MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5]));
- MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6]));
- end
+ else
+ \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T4), .I3(T6), .S0(L[5]), .S1(L[6]), .O(Q));
+ end
+ // For fixed length, if just 1 over a convenient value, decompose
+ else if (DEPTH <= 129 && &_TECHMAP_CONSTMSK_L_) begin
+ wire T;
+ \$__XILINX_SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-1:1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl (.C(C), .D(D), .L({32{1'b1}}), .E(E), .Q(T));
+ \$__XILINX_SHREG_ #(.DEPTH(1), .INIT(INIT[0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_last (.C(C), .D(T), .L(L), .E(E), .Q(Q));
end
- else if (DEPTH <= 129 && ~&_TECHMAP_CONSTMSK_L_) begin
- // Handle cases where fixed-length depth is
- // just 1 over a convenient value
+ // For variable length, if just 1 over a convenient value, then bump up one more
+ else if (DEPTH < 129 && ~&_TECHMAP_CONSTMSK_L_)
\$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q));
+ else begin
+ localparam depth0 = 128;
+ localparam num_srl128 = DEPTH / depth0;
+ localparam depthN = DEPTH % depth0;
+ wire [num_srl128 + (depthN > 0 ? 1 : 0) - 1:0] T;
+ wire [num_srl128 + (depthN > 0 ? 1 : 0) :0] S;
+ assign S[0] = D;
+ genvar i;
+ for (i = 0; i < num_srl128; i++)
+ \$__XILINX_SHREG_ #(.DEPTH(depth0), .INIT(INIT[DEPTH-1-i*depth0-:depth0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl (.C(C), .D(S[i]), .L(L[$clog2(depth0)-1:0]), .E(E), .Q(T[i]), .SO(S[i+1]));
+
+ if (depthN > 0)
+ \$__XILINX_SHREG_ #(.DEPTH(depthN), .INIT(INIT[depthN-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_last (.C(C), .D(S[num_srl128]), .L(L[$clog2(depth0)-1:0]), .E(E), .Q(T[num_srl128]));
+
+ if (&_TECHMAP_CONSTMSK_L_)
+ assign Q = T[num_srl128 + (depthN > 0 ? 1 : 0) - 1];
+ else
+ assign Q = T[L[DEPTH-1:$clog2(depth0)]];
+ end
+ endgenerate
+endmodule
+
+`ifdef MIN_MUX_INPUTS
+module \$__XILINX_SHIFTX (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ parameter [A_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0;
+ parameter [A_WIDTH-1:0] _TECHMAP_CONSTVAL_A_ = 0;
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
+
+ function integer A_WIDTH_trimmed;
+ input integer start;
+ begin
+ A_WIDTH_trimmed = start;
+ while (A_WIDTH_trimmed > 0 && _TECHMAP_CONSTMSK_A_[A_WIDTH_trimmed-1] && _TECHMAP_CONSTVAL_A_[A_WIDTH_trimmed-1] === 1'bx)
+ A_WIDTH_trimmed = A_WIDTH_trimmed - 1;
+ end
+ endfunction
+
+ generate
+ genvar i, j;
+ // Bit-blast
+ if (Y_WIDTH > 1) begin
+ for (i = 0; i < Y_WIDTH; i++)
+ \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH-Y_WIDTH+1), .B_WIDTH(B_WIDTH), .Y_WIDTH(1'd1)) bitblast (.A(A[A_WIDTH-Y_WIDTH+i:i]), .B(B), .Y(Y[i]));
+ end
+ // If the LSB of B is constant zero (and Y_WIDTH is 1) then
+ // we can optimise by removing every other entry from A
+ // and popping the constant zero from B
+ else if (_TECHMAP_CONSTMSK_B_[0] && !_TECHMAP_CONSTVAL_B_[0]) begin
+ wire [(A_WIDTH+1)/2-1:0] A_i;
+ for (i = 0; i < (A_WIDTH+1)/2; i++)
+ assign A_i[i] = A[i*2];
+ \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH((A_WIDTH+1'd1)/2'd2), .B_WIDTH(B_WIDTH-1'd1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A_i), .B(B[B_WIDTH-1:1]), .Y(Y));
+ end
+ // Trim off any leading 1'bx -es in A
+ else if (_TECHMAP_CONSTMSK_A_[A_WIDTH-1] && _TECHMAP_CONSTVAL_A_[A_WIDTH-1] === 1'bx) begin
+ localparam A_WIDTH_new = A_WIDTH_trimmed(A_WIDTH-1);
+ \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH_new), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A[A_WIDTH_new-1:0]), .B(B), .Y(Y));
+ end
+ else if (A_WIDTH < `MIN_MUX_INPUTS) begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ else if (A_WIDTH == 2) begin
+ MUXF7 fpga_hard_mux (.I0(A[0]), .I1(A[1]), .S(B[0]), .O(Y));
+ end
+ else if (A_WIDTH <= 4) begin
+ wire [4-1:0] Ax;
+ if (A_WIDTH == 4)
+ assign Ax = A;
+ else
+ // Rather than extend with 1'bx which gets flattened to 1'b0
+ // causing the "don't care" status to get lost, extend with
+ // the same driver of F7B.I0 so that we can optimise F7B away
+ // later
+ assign Ax = {A[1], A};
+ \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[2]), .I2(Ax[1]), .I3(Ax[3]), .S0(B[1]), .S1(B[0]), .O(Y));
+ end
+ // Note that the following decompositions are 'backwards' in that
+ // the LSBs are placed on the hard resources, and the soft resources
+ // are used for MSBs.
+ // This has the effect of more effectively utilising the hard mux;
+ // take for example a 5:1 multiplexer, currently this would map as:
+ //
+ // A[0] \___ __ A[0] \__ __
+ // A[4] / \| \ whereas the more A[1] / \| \
+ // A[1] _____| | obvious mapping A[2] \___| |
+ // A[2] _____| |-- of MSBs to hard A[3] / | |__
+ // A[3]______| | resources would A[4] ____| |
+ // |__/ lead to: 1'bx ____| |
+ // || |__/
+ // || ||
+ // B[1:0] B[1:2]
+ //
+ // Expectation would be that the 'forward' mapping (right) is more
+ // area efficient (consider a 9:1 multiplexer using 2x4:1 multiplexers
+ // on its I0 and I1 inputs, and A[8] and 1'bx on its I2 and I3 inputs)
+ // but that the 'backwards' mapping (left) is more delay efficient
+ // since smaller LUTs are faster than wider ones.
+ else if (A_WIDTH <= 8) begin
+ wire [8-1:0] Ax = {{{8-A_WIDTH}{1'bx}}, A};
+ wire T0 = B[2] ? Ax[4] : Ax[0];
+ wire T1 = B[2] ? Ax[5] : Ax[1];
+ wire T2 = B[2] ? Ax[6] : Ax[2];
+ wire T3 = B[2] ? Ax[7] : Ax[3];
+ \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T1), .I3(T3), .S0(B[1]), .S1(B[0]), .O(Y));
+ end
+ else if (A_WIDTH <= 16) begin
+ wire [16-1:0] Ax = {{{16-A_WIDTH}{1'bx}}, A};
+ wire T0 = B[2] ? B[3] ? Ax[12] : Ax[4]
+ : B[3] ? Ax[ 8] : Ax[0];
+ wire T1 = B[2] ? B[3] ? Ax[13] : Ax[5]
+ : B[3] ? Ax[ 9] : Ax[1];
+ wire T2 = B[2] ? B[3] ? Ax[14] : Ax[6]
+ : B[3] ? Ax[10] : Ax[2];
+ wire T3 = B[2] ? B[3] ? Ax[15] : Ax[7]
+ : B[3] ? Ax[11] : Ax[3];
+ \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T1), .I3(T3), .S0(B[1]), .S1(B[0]), .O(Y));
end
else begin
- localparam lower_clog2 = $clog2((DEPTH+1)/2);
- localparam lower_depth = 2 ** lower_clog2;
- wire T0, T1, T2, T3;
- if (&_TECHMAP_CONSTMSK_L_) begin
- \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(lower_depth-1), .E(E), .Q(T0));
- \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-lower_depth-1), .E(E), .Q(Q), .SO(T3));
- end
- else begin
- \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1));
- \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3));
- assign Q = L[lower_clog2] ? T2 : T0;
- end
- if (DEPTH == 2 * lower_depth)
- assign SO = T3;
+ localparam num_mux16 = (A_WIDTH+15) / 16;
+ localparam clog2_num_mux16 = $clog2(num_mux16);
+ wire [num_mux16-1:0] T;
+ wire [num_mux16*16-1:0] Ax = {{(num_mux16*16-A_WIDTH){1'bx}}, A};
+ for (i = 0; i < num_mux16; i++)
+ \$__XILINX_SHIFTX #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(16),
+ .B_WIDTH(4),
+ .Y_WIDTH(Y_WIDTH)
+ ) fpga_mux (
+ .A(Ax[i*16+:16]),
+ .B(B[3:0]),
+ .Y(T[i])
+ );
+ \$__XILINX_SHIFTX #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(num_mux16),
+ .B_WIDTH(clog2_num_mux16),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(T),
+ .B(B[B_WIDTH-1-:clog2_num_mux16]),
+ .Y(Y));
end
endgenerate
endmodule
-`ifndef SRL_ONLY
+(* techmap_celltype = "$__XILINX_SHIFTX" *)
+module _90__XILINX_SHIFTX (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y));
+endmodule
+
+module \$_MUX_ (A, B, S, Y);
+ input A, B, S;
+ output Y;
+ generate
+ if (`MIN_MUX_INPUTS == 2)
+ \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(2), .B_WIDTH(1), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({B,A}), .B(S), .Y(Y));
+ else
+ wire _TECHMAP_FAIL_ = 1;
+ endgenerate
+endmodule
+
+module \$_MUX4_ (A, B, C, D, S, T, Y);
+ input A, B, C, D, S, T;
+ output Y;
+ \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({D,C,B,A}), .B({T,S}), .Y(Y));
+endmodule
+
+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;
+ \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(3), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({H,G,F,E,D,C,B,A}), .B({U,T,S}), .Y(Y));
+endmodule
+
+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;
+ \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(16), .B_WIDTH(4), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A}), .B({V,U,T,S}), .Y(Y));
+endmodule
+`endif
+
+`ifndef _ABC
+module \$__XILINX_MUXF78 (O, I0, I1, I2, I3, S0, S1);
+ output O;
+ input I0, I1, I2, I3, S0, S1;
+ wire T0, T1;
+ parameter _TECHMAP_BITS_CONNMAP_ = 0;
+ parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I0_ = 0;
+ parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I1_ = 0;
+ parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I2_ = 0;
+ parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I3_ = 0;
+ parameter _TECHMAP_CONSTMSK_S0_ = 0;
+ parameter _TECHMAP_CONSTVAL_S0_ = 0;
+ parameter _TECHMAP_CONSTMSK_S1_ = 0;
+ parameter _TECHMAP_CONSTVAL_S1_ = 0;
+ if (_TECHMAP_CONSTMSK_S0_ && _TECHMAP_CONSTVAL_S0_ === 1'b1)
+ assign T0 = I1;
+ else if (_TECHMAP_CONSTMSK_S0_ || _TECHMAP_CONNMAP_I0_ === _TECHMAP_CONNMAP_I1_)
+ assign T0 = I0;
+ else
+ MUXF7 mux7a (.I0(I0), .I1(I1), .S(S0), .O(T0));
+ if (_TECHMAP_CONSTMSK_S0_ && _TECHMAP_CONSTVAL_S0_ === 1'b1)
+ assign T1 = I3;
+ else if (_TECHMAP_CONSTMSK_S0_ || _TECHMAP_CONNMAP_I2_ === _TECHMAP_CONNMAP_I3_)
+ assign T1 = I2;
+ else
+ MUXF7 mux7b (.I0(I2), .I1(I3), .S(S0), .O(T1));
+ if (_TECHMAP_CONSTMSK_S1_ && _TECHMAP_CONSTVAL_S1_ === 1'b1)
+ assign O = T1;
+ else if (_TECHMAP_CONSTMSK_S1_ || (_TECHMAP_CONNMAP_I0_ === _TECHMAP_CONNMAP_I1_ && _TECHMAP_CONNMAP_I1_ === _TECHMAP_CONNMAP_I2_ && _TECHMAP_CONNMAP_I2_ === _TECHMAP_CONNMAP_I3_))
+ assign O = T0;
+ else
+ MUXF8 mux8 (.I0(T0), .I1(T1), .S(S1), .O(O));
+endmodule
`endif
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index 3a4540b83..3ad96d7fb 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -159,19 +159,38 @@ module MUXCY(output O, input CI, DI, S);
assign O = S ? CI : DI;
endmodule
+(* abc_box_id = 1, lib_whitebox *)
module MUXF7(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
+(* abc_box_id = 2, lib_whitebox *)
module MUXF8(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
+`ifdef _ABC
+(* abc_box_id = 3, lib_whitebox *)
+module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
+ assign O = S1 ? (S0 ? I3 : I2)
+ : (S0 ? I1 : I0);
+endmodule
+`endif
+
module XORCY(output O, input CI, LI);
assign O = CI ^ LI;
endmodule
-module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
+(* abc_box_id = 4, lib_whitebox *)
+module CARRY4(
+ (* abc_carry *)
+ output [3:0] CO,
+ output [3:0] O,
+ (* abc_carry *)
+ input CI,
+ input CYINIT,
+ input [3:0] DI, S
+);
assign O = S ^ {CO[2:0], CI | CYINIT};
assign CO[0] = S[0] ? CI | CYINIT : DI[0];
assign CO[1] = S[1] ? CO[0] : DI[1];
@@ -215,7 +234,7 @@ module FDRE (output reg Q, input C, CE, D, R);
endmodule
module FDSE (output reg Q, input C, CE, D, S);
- parameter [0:0] INIT = 1'b0;
+ parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
parameter [0:0] IS_S_INVERTED = 1'b0;
@@ -241,7 +260,7 @@ module FDCE (output reg Q, input C, CE, D, CLR);
endmodule
module FDPE (output reg Q, input C, CE, D, PRE);
- parameter [0:0] INIT = 1'b0;
+ parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
parameter [0:0] IS_PRE_INVERTED = 1'b0;
@@ -278,9 +297,36 @@ module FDPE_1 (output reg Q, input C, CE, D, PRE);
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
endmodule
+(* abc_box_id = 5 *)
+module RAM32X1D (
+ output DPO, SPO,
+ (* abc_scc_break *)
+ input D,
+ input WCLK,
+ (* abc_scc_break *)
+ input WE,
+ input A0, A1, A2, A3, A4,
+ input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
+);
+ parameter INIT = 32'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+ wire [4:0] a = {A4, A3, A2, A1, A0};
+ wire [4:0] dpra = {DPRA4, DPRA3, DPRA2, DPRA1, DPRA0};
+ reg [31:0] mem = INIT;
+ assign SPO = mem[a];
+ assign DPO = mem[dpra];
+ wire clk = WCLK ^ IS_WCLK_INVERTED;
+ always @(posedge clk) if (WE) mem[a] <= D;
+endmodule
+
+(* abc_box_id = 6 *)
module RAM64X1D (
output DPO, SPO,
- input D, WCLK, WE,
+ (* abc_scc_break *)
+ input D,
+ input WCLK,
+ (* abc_scc_break *)
+ input WE,
input A0, A1, A2, A3, A4, A5,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
);
@@ -295,9 +341,14 @@ module RAM64X1D (
always @(posedge clk) if (WE) mem[a] <= D;
endmodule
+(* abc_box_id = 7 *)
module RAM128X1D (
output DPO, SPO,
- input D, WCLK, WE,
+ (* abc_scc_break *)
+ input D,
+ input WCLK,
+ (* abc_scc_break *)
+ input WE,
input [6:0] A, DPRA
);
parameter INIT = 128'h0;
diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh
index 8e39b440d..53b528820 100644
--- a/techlibs/xilinx/cells_xtra.sh
+++ b/techlibs/xilinx/cells_xtra.sh
@@ -116,16 +116,16 @@ function xtract_cell_decl()
xtract_cell_decl PS7 "(* keep *)"
xtract_cell_decl PULLDOWN
xtract_cell_decl PULLUP
- xtract_cell_decl RAM128X1D
+ #xtract_cell_decl RAM128X1D
xtract_cell_decl RAM128X1S
xtract_cell_decl RAM256X1S
xtract_cell_decl RAM32M
- xtract_cell_decl RAM32X1D
+ #xtract_cell_decl RAM32X1D
xtract_cell_decl RAM32X1S
xtract_cell_decl RAM32X1S_1
xtract_cell_decl RAM32X2S
xtract_cell_decl RAM64M
- xtract_cell_decl RAM64X1D
+ #xtract_cell_decl RAM64X1D
xtract_cell_decl RAM64X1S
xtract_cell_decl RAM64X1S_1
xtract_cell_decl RAM64X2S
diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v
index fbcc74682..15fa1b63a 100644
--- a/techlibs/xilinx/cells_xtra.v
+++ b/techlibs/xilinx/cells_xtra.v
@@ -3655,17 +3655,6 @@ module PULLUP (...);
output O;
endmodule
-module RAM128X1D (...);
- parameter [127:0] INIT = 128'h00000000000000000000000000000000;
- parameter [0:0] IS_WCLK_INVERTED = 1'b0;
- output DPO, SPO;
- input [6:0] A;
- input [6:0] DPRA;
- input D;
- input WCLK;
- input WE;
-endmodule
-
module RAM128X1S (...);
parameter [127:0] INIT = 128'h00000000000000000000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3705,13 +3694,6 @@ module RAM32M (...);
input WE;
endmodule
-module RAM32X1D (...);
- parameter [31:0] INIT = 32'h00000000;
- parameter [0:0] IS_WCLK_INVERTED = 1'b0;
- output DPO, SPO;
- input A0, A1, A2, A3, A4, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, WCLK, WE;
-endmodule
-
module RAM32X1S (...);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3756,13 +3738,6 @@ module RAM64M (...);
input WE;
endmodule
-module RAM64X1D (...);
- parameter [63:0] INIT = 64'h0000000000000000;
- parameter [0:0] IS_WCLK_INVERTED = 1'b0;
- output DPO, SPO;
- input A0, A1, A2, A3, A4, A5, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5, WCLK, WE;
-endmodule
-
module RAM64X1S (...);
parameter [63:0] INIT = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v
index 13beaa6ae..4571f6d5c 100644
--- a/techlibs/xilinx/ff_map.v
+++ b/techlibs/xilinx/ff_map.v
@@ -33,10 +33,10 @@ module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPL
module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
-module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
-module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
-module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
-module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
+module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
+module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
+module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
+module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
`endif
diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v
index d07c59dee..13d3c3268 100644
--- a/techlibs/xilinx/lut_map.v
+++ b/techlibs/xilinx/lut_map.v
@@ -29,61 +29,86 @@ module \$lut (A, Y);
input [WIDTH-1:0] A;
output Y;
+ // Need to swap input ordering, and fix init accordingly,
+ // to match ABC's expectation of LUT inputs in non-decreasing
+ // delay order
+ function [WIDTH-1:0] permute_index;
+ input [WIDTH-1:0] i;
+ integer j;
+ begin
+ permute_index = 0;
+ for (j = 0; j < WIDTH; j = j + 1)
+ permute_index[WIDTH-1 - j] = i[j];
+ end
+ endfunction
+
+ function [2**WIDTH-1:0] permute_init;
+ input [2**WIDTH-1:0] orig;
+ integer i;
+ begin
+ permute_init = 0;
+ for (i = 0; i < 2**WIDTH; i = i + 1)
+ permute_init[i] = orig[permute_index(i)];
+ end
+ endfunction
+
+ parameter [2**WIDTH-1:0] P_LUT = permute_init(LUT);
+
generate
if (WIDTH == 1) begin
- LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]));
end else
if (WIDTH == 2) begin
- LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(A[1]));
+ LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[1]), .I1(A[0]));
end else
if (WIDTH == 3) begin
- LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]));
+ LUT3 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[2]), .I1(A[1]), .I2(A[0]));
end else
if (WIDTH == 4) begin
- LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]));
+ LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[3]), .I1(A[2]), .I2(A[1]),
+ .I3(A[0]));
end else
if (WIDTH == 5) begin
- LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]));
+ LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[4]), .I1(A[3]), .I2(A[2]),
+ .I3(A[1]), .I4(A[0]));
end else
if (WIDTH == 6) begin
- LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]), .I5(A[5]));
+ LUT6 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[5]), .I1(A[4]), .I2(A[3]),
+ .I3(A[2]), .I4(A[1]), .I5(A[0]));
end else
if (WIDTH == 7) begin
wire T0, T1;
- LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]), .I5(A[5]));
- LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]), .I5(A[5]));
- MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
+ LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
+ .I0(A[6]), .I1(A[5]), .I2(A[4]),
+ .I3(A[3]), .I4(A[2]), .I5(A[1]));
+ LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
+ .I0(A[6]), .I1(A[5]), .I2(A[4]),
+ .I3(A[3]), .I4(A[2]), .I5(A[1]));
+ MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[0]));
end else
if (WIDTH == 8) begin
wire T0, T1, T2, T3, T4, T5;
- LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]), .I5(A[5]));
- LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]), .I5(A[5]));
- LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]), .I5(A[5]));
- LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]), .I5(A[5]));
- MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
- MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
- MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
+ LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
+ .I0(A[7]), .I1(A[6]), .I2(A[5]),
+ .I3(A[4]), .I4(A[3]), .I5(A[2]));
+ LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
+ .I0(A[7]), .I1(A[6]), .I2(A[5]),
+ .I3(A[4]), .I4(A[3]), .I5(A[2]));
+ LUT6 #(.INIT(P_LUT[191:128])) fpga_lut_2 (.O(T2),
+ .I0(A[7]), .I1(A[6]), .I2(A[5]),
+ .I3(A[4]), .I4(A[3]), .I5(A[2]));
+ LUT6 #(.INIT(P_LUT[255:192])) fpga_lut_3 (.O(T3),
+ .I0(A[7]), .I1(A[6]), .I2(A[5]),
+ .I3(A[4]), .I4(A[3]), .I5(A[2]));
+ MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[1]));
+ MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[1]));
+ MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[0]));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
diff --git a/techlibs/xilinx/drams.txt b/techlibs/xilinx/lutrams.txt
index 91632bcee..2613c206c 100644
--- a/techlibs/xilinx/drams.txt
+++ b/techlibs/xilinx/lutrams.txt
@@ -1,4 +1,17 @@
+bram $__XILINX_RAM32X1D
+ init 1
+ abits 5
+ dbits 1
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 2
+endbram
+
bram $__XILINX_RAM64X1D
init 1
abits 6
@@ -25,6 +38,13 @@ bram $__XILINX_RAM128X1D
clkpol 0 2
endbram
+match $__XILINX_RAM32X1D
+ min bits 3
+ min wports 1
+ make_outreg
+ or_next_if_better
+endmatch
+
match $__XILINX_RAM64X1D
min bits 5
min wports 1
diff --git a/techlibs/xilinx/drams_map.v b/techlibs/xilinx/lutrams_map.v
index 47476b592..77041ca86 100644
--- a/techlibs/xilinx/drams_map.v
+++ b/techlibs/xilinx/lutrams_map.v
@@ -1,4 +1,38 @@
+module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter [31:0] INIT = 32'bx;
+ parameter CLKPOL2 = 1;
+ input CLK1;
+
+ input [4:0] A1ADDR;
+ output A1DATA;
+
+ input [4:0] B1ADDR;
+ input B1DATA;
+ input B1EN;
+
+ RAM32X1D #(
+ .INIT(INIT),
+ .IS_WCLK_INVERTED(!CLKPOL2)
+ ) _TECHMAP_REPLACE_ (
+ .DPRA0(A1ADDR[0]),
+ .DPRA1(A1ADDR[1]),
+ .DPRA2(A1ADDR[2]),
+ .DPRA3(A1ADDR[3]),
+ .DPRA4(A1ADDR[4]),
+ .DPO(A1DATA),
+
+ .A0(B1ADDR[0]),
+ .A1(B1ADDR[1]),
+ .A2(B1ADDR[2]),
+ .A3(B1ADDR[3]),
+ .A4(B1ADDR[4]),
+ .D(B1DATA),
+ .WCLK(CLK1),
+ .WE(B1EN)
+ );
+endmodule
+
module \$__XILINX_RAM64X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
parameter [63:0] INIT = 64'bx;
parameter CLKPOL2 = 1;
diff --git a/techlibs/xilinx/mux_map.v b/techlibs/xilinx/mux_map.v
new file mode 100644
index 000000000..91aaf2118
--- /dev/null
+++ b/techlibs/xilinx/mux_map.v
@@ -0,0 +1,71 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// The purpose of these mapping rules is to allow preserve all (sufficiently
+// wide) $shiftx cells during 'techmap' so that they can be mapped to hard
+// resources, rather than being bit-blasted to gates during 'techmap'
+// execution
+
+module \$shiftx (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
+
+ generate
+ if (B_SIGNED) begin
+ if (_TECHMAP_CONSTMSK_B_[B_WIDTH-1] && (_TECHMAP_CONSTVAL_B_[B_WIDTH-1] == 1'b0 || _TECHMAP_CONSTVAL_B_[B_WIDTH-1] === 1'bx))
+ // Optimisation to remove B_SIGNED if sign bit of B is constant-0
+ \$shiftx #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(0),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH-1'd1),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(A), .B(B[B_WIDTH-2:0]), .Y(Y)
+ );
+ else
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ else begin
+ if (((A_WIDTH + Y_WIDTH - 1) / Y_WIDTH) < `MIN_MUX_INPUTS)
+ wire _TECHMAP_FAIL_ = 1;
+ else
+ \$__XILINX_SHIFTX #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(A), .B(B), .Y(Y)
+ );
+ end
+ endgenerate
+endmodule
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index a293081f1..87f4af8f7 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -2,6 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * (C) 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -25,6 +26,9 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+#define XC7_WIRE_DELAY 300 // Number with which ABC will map a 6-input gate
+ // to one LUT6 (instead of a LUT5 + LUT2)
+
struct SynthXilinxPass : public ScriptPass
{
SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
@@ -42,8 +46,9 @@ struct SynthXilinxPass : public ScriptPass
log(" -top <module>\n");
log(" use the specified module as top module\n");
log("\n");
- log(" -arch {xcup|xcu|xc7|xc6s}\n");
+ log(" -family {xcup|xcu|xc7|xc6s}\n");
log(" run synthesis for the specified Xilinx architecture\n");
+ log(" generate the synthesis netlist for the specified family.\n");
log(" default: xc7\n");
log("\n");
log(" -edif <file>\n");
@@ -59,13 +64,24 @@ struct SynthXilinxPass : public ScriptPass
log(" (this feature is experimental and incomplete)\n");
log("\n");
log(" -nobram\n");
- log(" disable inference of block rams\n");
+ log(" do not use block RAM cells in output netlist\n");
log("\n");
- log(" -nodram\n");
- log(" disable inference of distributed rams\n");
+ log(" -nolutram\n");
+ log(" do not use distributed RAM cells in output netlist\n");
log("\n");
log(" -nosrl\n");
- log(" disable inference of shift registers\n");
+ log(" do not use distributed SRL cells in output netlist\n");
+ log("\n");
+ log(" -nocarry\n");
+ log(" do not use XORCY/MUXCY/CARRY4 cells in output netlist\n");
+ log("\n");
+ log(" -nowidelut\n");
+ log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
+ log("\n");
+ log(" -widemux <int>\n");
+ log(" enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n");
+ log(" above this number of inputs (minimum value 2, recommended value >= 5).\n");
+ log(" default: 0 (no inference)\n");
log("\n");
log(" -run <from_label>:<to_label>\n");
log(" only run the commands between the labels (see below). an empty\n");
@@ -78,27 +94,38 @@ struct SynthXilinxPass : public ScriptPass
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log("\n");
+ log(" -abc9\n");
+ log(" use new ABC9 flow (EXPERIMENTAL)\n");
+ log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
- std::string top_opt, edif_file, blif_file, arch;
- bool flatten, retime, vpr, nobram, nodram, nosrl;
+ std::string top_opt, edif_file, blif_file, family;
+ bool flatten, retime, vpr, nobram, nolutram, nosrl, nocarry, nowidelut, abc9;
+ bool flatten_before_abc;
+ int widemux;
void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
edif_file.clear();
blif_file.clear();
+ family = "xc7";
flatten = false;
retime = false;
vpr = false;
+ nocarry = false;
nobram = false;
- nodram = false;
+ nolutram = false;
nosrl = false;
- arch = "xc7";
+ nocarry = false;
+ nowidelut = false;
+ abc9 = false;
+ flatten_before_abc = false;
+ widemux = 0;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -113,8 +140,8 @@ struct SynthXilinxPass : public ScriptPass
top_opt = "-top " + args[++argidx];
continue;
}
- if (args[argidx] == "-arch" && argidx+1 < args.size()) {
- arch = args[++argidx];
+ if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) {
+ family = args[++argidx];
continue;
}
if (args[argidx] == "-edif" && argidx+1 < args.size()) {
@@ -137,36 +164,66 @@ struct SynthXilinxPass : public ScriptPass
flatten = true;
continue;
}
+ if (args[argidx] == "-flatten_before_abc") {
+ flatten_before_abc = true;
+ continue;
+ }
if (args[argidx] == "-retime") {
retime = true;
continue;
}
+ if (args[argidx] == "-nocarry") {
+ nocarry = true;
+ continue;
+ }
+ if (args[argidx] == "-nowidelut") {
+ nowidelut = true;
+ continue;
+ }
if (args[argidx] == "-vpr") {
vpr = true;
continue;
}
+ if (args[argidx] == "-nocarry") {
+ nocarry = true;
+ continue;
+ }
if (args[argidx] == "-nobram") {
nobram = true;
continue;
}
- if (args[argidx] == "-nodram") {
- nodram = true;
+ if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
+ nolutram = true;
continue;
}
if (args[argidx] == "-nosrl") {
nosrl = true;
continue;
}
+ if (args[argidx] == "-widemux" && argidx+1 < args.size()) {
+ widemux = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-abc9") {
+ abc9 = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")
- log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str());
+ if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6s")
+ log_cmd_error("Invalid Xilinx -family setting: '%s'.\n", family.c_str());
+
+ if (widemux != 0 && widemux < 2)
+ log_cmd_error("-widemux value must be 0 or >= 2.\n");
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
+ if (abc9 && retime)
+ log_cmd_error("-retime option not currently compatible with -abc9!\n");
+
log_header(design, "Executing SYNTH_XILINX pass.\n");
log_push();
@@ -179,83 +236,181 @@ struct SynthXilinxPass : public ScriptPass
{
if (check_label("begin")) {
if (vpr)
- run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
+ run("read_verilog -lib -icells -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
else
- run("read_verilog -lib +/xilinx/cells_sim.v");
+ run("read_verilog -lib -icells -D _ABC +/xilinx/cells_sim.v");
run("read_verilog -lib +/xilinx/cells_xtra.v");
- if (!nobram || help_mode)
- run("read_verilog -lib +/xilinx/brams_bb.v", "(skip if '-nobram')");
+ if (help_mode) {
+ run("read_verilog -lib +/xilinx/{family}_brams_bb.v");
+ } else if (family == "xc6s") {
+ run("read_verilog -lib +/xilinx/xc6s_brams_bb.v");
+ } else if (family == "xc7") {
+ run("read_verilog -lib +/xilinx/xc7_brams_bb.v");
+ }
run(stringf("hierarchy -check %s", top_opt.c_str()));
}
- if (check_label("flatten", "(with '-flatten' only)")) {
- if (flatten || help_mode) {
- run("proc");
- run("flatten");
+ if (check_label("coarse")) {
+ run("proc");
+ if (help_mode || flatten)
+ run("flatten", "(if -flatten)");
+ run("opt_expr");
+ run("opt_clean");
+ run("check");
+ run("opt");
+ if (help_mode)
+ run("wreduce [-keepdc]", "(option for '-widemux')");
+ else
+ run("wreduce" + std::string(widemux > 0 ? " -keepdc" : ""));
+ run("peepopt");
+ run("opt_clean");
+
+ if (widemux > 0 || help_mode)
+ run("muxpack", " ('-widemux' only)");
+
+ // shregmap -tech xilinx can cope with $shiftx and $mux
+ // cells for identifying variable-length shift registers,
+ // so attempt to convert $pmux-es to the former
+ // Also: wide multiplexer inference benefits from this too
+ if (!(nosrl && widemux == 0) || help_mode) {
+ run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')");
+ run("clean", " (skip if '-nosrl' and '-widemux=0')");
}
- }
- if (check_label("coarse")) {
- run("synth -run coarse");
+ run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6");
+ run("alumacc");
+ run("share");
+ run("opt");
+ run("fsm");
+ run("opt -fast");
+ run("memory -nomap");
+ run("opt_clean");
}
- if (check_label("bram", "(skip if '-nobram')")) {
- if (!nobram || help_mode) {
- run("memory_bram -rules +/xilinx/brams.txt");
- run("techmap -map +/xilinx/brams_map.v");
+ if (check_label("map_bram", "(skip if '-nobram')")) {
+ if (help_mode) {
+ run("memory_bram -rules +/xilinx/{family}_brams.txt");
+ run("techmap -map +/xilinx/{family}_brams_map.v");
+ } else if (!nobram) {
+ if (family == "xc6s") {
+ run("memory_bram -rules +/xilinx/xc6s_brams.txt");
+ run("techmap -map +/xilinx/xc6s_brams_map.v");
+ } else if (family == "xc7") {
+ run("memory_bram -rules +/xilinx/xc7_brams.txt");
+ run("techmap -map +/xilinx/xc7_brams_map.v");
+ } else {
+ log_warning("Block RAM inference not yet supported for family %s.\n", family.c_str());
+ }
}
}
- if (check_label("dram", "(skip if '-nodram')")) {
- if (!nodram || help_mode) {
- run("memory_bram -rules +/xilinx/drams.txt");
- run("techmap -map +/xilinx/drams_map.v");
+ if (check_label("map_lutram", "(skip if '-nolutram')")) {
+ if (!nolutram || help_mode) {
+ run("memory_bram -rules +/xilinx/lutrams.txt");
+ run("techmap -map +/xilinx/lutrams_map.v");
}
}
- if (check_label("fine")) {
- // shregmap -tech xilinx can cope with $shiftx and $mux
- // cells for identifiying variable-length shift registers,
- // so attempt to convert $pmux-es to the former
- if (!nosrl || help_mode)
- run("pmux2shiftx", "(skip if '-nosrl')");
-
- run("opt -fast -full");
+ if (check_label("map_ffram")) {
+ if (widemux > 0)
+ run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
+ // performs less efficiently
+ else
+ run("opt -fast -full");
run("memory_map");
+ }
+
+ if (check_label("fine")) {
run("dffsr2dff");
run("dff2dffe");
+ if (help_mode) {
+ run("simplemap t:$mux", " ('-widemux' only)");
+ run("muxcover <internal options>, ('-widemux' only)");
+ }
+ else if (widemux > 0) {
+ run("simplemap t:$mux");
+ constexpr int cost_mux2 = 100;
+ std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
+ switch (widemux) {
+ case 2: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2+1, cost_mux2+2, cost_mux2+3); break;
+ case 3:
+ case 4: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-2, cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break;
+ case 5:
+ case 6:
+ case 7:
+ case 8: muxcover_args += stringf(" -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break;
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ default: muxcover_args += stringf(" -mux16=%d", cost_mux2*(widemux-1)-1); break;
+ }
+ run("muxcover " + muxcover_args);
+ }
run("opt -full");
if (!nosrl || help_mode) {
// shregmap operates on bit-level flops, not word-level,
// so break those down here
- run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')");
+ run("simplemap t:$dff t:$dffe", " (skip if '-nosrl')");
// shregmap with '-tech xilinx' infers variable length shift regs
run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
}
- if (!vpr || help_mode)
- run("techmap -map +/techmap.v -map +/xilinx/arith_map.v");
- else
- run("techmap -map +/techmap.v +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
-
+ std::string techmap_args = " -map +/techmap.v";
+ if (help_mode)
+ techmap_args += " [-map +/xilinx/mux_map.v]";
+ else if (widemux > 0)
+ techmap_args += stringf(" -D MIN_MUX_INPUTS=%d -map +/xilinx/mux_map.v", widemux);
+ if (help_mode)
+ techmap_args += " [-map +/xilinx/arith_map.v]";
+ else if (!nocarry) {
+ techmap_args += " -map +/xilinx/arith_map.v";
+ if (vpr)
+ techmap_args += " -D _EXPLICIT_CARRY";
+ else if (abc9)
+ techmap_args += " -D _CLB_CARRY";
+ }
+ run("techmap " + techmap_args);
run("opt -fast");
}
if (check_label("map_cells")) {
- run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
+ std::string techmap_args = "-map +/techmap.v -D _ABC -map +/xilinx/cells_map.v";
+ if (widemux > 0)
+ techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
+ run("techmap " + techmap_args);
run("clean");
}
if (check_label("map_luts")) {
+ run("opt_expr -mux_undef");
+ if (flatten_before_abc)
+ run("flatten");
if (help_mode)
- run("abc -luts 2:2,3,6:5,10,20 [-dff]");
- else
- run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
+ run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut', option for '-retime')");
+ else if (abc9) {
+ if (family != "xc7")
+ log_warning("'synth_xilinx -abc9' currently supports '-family xc7' only.\n");
+ if (nowidelut)
+ run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY));
+ else
+ run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY));
+ }
+ else {
+ if (nowidelut)
+ run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
+ else
+ run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
+ }
run("clean");
+
// This shregmap call infers fixed length shift registers after abc
// has performed any necessary retiming
if (!nosrl || help_mode)
diff --git a/techlibs/xilinx/xc6s_brams.txt b/techlibs/xilinx/xc6s_brams.txt
new file mode 100644
index 000000000..17cd8e355
--- /dev/null
+++ b/techlibs/xilinx/xc6s_brams.txt
@@ -0,0 +1,84 @@
+
+bram $__XILINX_RAMB8BWER_SDP
+ init 1
+ abits 8
+ dbits 36
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 1 4
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+bram $__XILINX_RAMB16BWER_TDP
+ init 1
+ abits 9 @a9d36
+ dbits 36 @a9d36
+ abits 10 @a10d18
+ dbits 18 @a10d18
+ abits 11 @a11d9
+ dbits 9 @a11d9
+ abits 12 @a12d4
+ dbits 4 @a12d4
+ abits 13 @a13d2
+ dbits 2 @a13d2
+ abits 14 @a14d1
+ dbits 1 @a14d1
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 1 4 @a9d36
+ enable 1 2 @a10d18
+ enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+bram $__XILINX_RAMB8BWER_TDP
+ init 1
+ abits 9 @a9d18
+ dbits 18 @a9d18
+ abits 10 @a10d9
+ dbits 9 @a10d9
+ abits 11 @a11d4
+ dbits 4 @a11d4
+ abits 12 @a12d2
+ dbits 2 @a12d2
+ abits 13 @a13d1
+ dbits 1 @a13d1
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 1 2 @a9d18
+ enable 1 1 @a10d9 @a11d4 @a12d2 @a13d1
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+match $__XILINX_RAMB8BWER_SDP
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__XILINX_RAMB16BWER_TDP
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__XILINX_RAMB8BWER_TDP
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+endmatch
+
diff --git a/techlibs/xilinx/xc6s_brams_bb.v b/techlibs/xilinx/xc6s_brams_bb.v
new file mode 100644
index 000000000..eb1a29579
--- /dev/null
+++ b/techlibs/xilinx/xc6s_brams_bb.v
@@ -0,0 +1,211 @@
+module RAMB8BWER (
+ input CLKAWRCLK,
+ input CLKBRDCLK,
+ input ENAWREN,
+ input ENBRDEN,
+ input REGCEA,
+ input REGCEBREGCE,
+ input RSTA,
+ input RSTBRST,
+
+ input [12:0] ADDRAWRADDR,
+ input [12:0] ADDRBRDADDR,
+ input [15:0] DIADI,
+ input [15:0] DIBDI,
+ input [1:0] DIPADIP,
+ input [1:0] DIPBDIP,
+ input [1:0] WEAWEL,
+ input [1:0] WEBWEU,
+
+ output [15:0] DOADO,
+ output [15:0] DOBDO,
+ output [1:0] DOPADOP,
+ output [1:0] DOPBDOP
+);
+ parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+ parameter INIT_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+ parameter RAM_MODE = "TDP";
+ parameter integer DOA_REG = 0;
+ parameter integer DOB_REG = 0;
+
+ parameter integer DATA_WIDTH_A = 0;
+ parameter integer DATA_WIDTH_B = 0;
+
+ parameter WRITE_MODE_A = "WRITE_FIRST";
+ parameter WRITE_MODE_B = "WRITE_FIRST";
+
+ parameter EN_RSTRAM_A = "TRUE";
+ parameter EN_RSTRAM_B = "TRUE";
+
+ parameter INIT_A = 18'h000000000;
+ parameter INIT_B = 18'h000000000;
+ parameter SRVAL_A = 18'h000000000;
+ parameter SRVAL_B = 18'h000000000;
+
+ parameter RST_PRIORITY_A = "CE";
+ parameter RST_PRIORITY_B = "CE";
+
+ parameter RSTTYPE = "SYNC";
+
+ parameter SIM_COLLISION_CHECK = "ALL";
+endmodule
+
+module RAMB16BWER (
+ input CLKA,
+ input CLKB,
+ input ENA,
+ input ENB,
+ input REGCEA,
+ input REGCEB,
+ input RSTA,
+ input RSTB,
+
+ input [13:0] ADDRA,
+ input [13:0] ADDRB,
+ input [31:0] DIA,
+ input [31:0] DIB,
+ input [3:0] DIPA,
+ input [3:0] DIPB,
+ input [3:0] WEA,
+ input [3:0] WEB,
+
+ output [31:0] DOA,
+ output [31:0] DOB,
+ output [3:0] DOPA,
+ output [3:0] DOPB
+);
+ parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INITP_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+ parameter INIT_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+ parameter integer DOA_REG = 0;
+ parameter integer DOB_REG = 0;
+
+ parameter integer DATA_WIDTH_A = 0;
+ parameter integer DATA_WIDTH_B = 0;
+
+ parameter WRITE_MODE_A = "WRITE_FIRST";
+ parameter WRITE_MODE_B = "WRITE_FIRST";
+
+ parameter EN_RSTRAM_A = "TRUE";
+ parameter EN_RSTRAM_B = "TRUE";
+
+ parameter INIT_A = 36'h000000000;
+ parameter INIT_B = 36'h000000000;
+ parameter SRVAL_A = 36'h000000000;
+ parameter SRVAL_B = 36'h000000000;
+
+ parameter RST_PRIORITY_A = "CE";
+ parameter RST_PRIORITY_B = "CE";
+
+ parameter RSTTYPE = "SYNC";
+
+ parameter SIM_COLLISION_CHECK = "ALL";
+endmodule
+
diff --git a/techlibs/xilinx/xc6s_brams_map.v b/techlibs/xilinx/xc6s_brams_map.v
new file mode 100644
index 000000000..16fd15e74
--- /dev/null
+++ b/techlibs/xilinx/xc6s_brams_map.v
@@ -0,0 +1,255 @@
+module \$__XILINX_RAMB8BWER_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+ parameter [9215:0] INIT = 9216'bx;
+
+ input CLK2;
+ input CLK3;
+
+ input [7:0] A1ADDR;
+ output [35:0] A1DATA;
+ input A1EN;
+
+ input [7:0] B1ADDR;
+ input [35:0] B1DATA;
+ input [3:0] B1EN;
+
+ wire [12:0] A1ADDR_13 = {A1ADDR, 5'b0};
+ wire [12:0] B1ADDR_13 = {B1ADDR, 5'b0};
+
+ wire [3:0] DIP, DOP;
+ wire [31:0] DI, DO;
+
+ assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
+ assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
+
+ RAMB8BWER #(
+ .RAM_MODE("SDP"),
+ .DATA_WIDTH_A(36),
+ .DATA_WIDTH_B(36),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ `include "brams_init_9.vh"
+ ) _TECHMAP_REPLACE_ (
+ .DOBDO(DO[31:16]),
+ .DOADO(DO[15:0]),
+ .DOPBDOP(DOP[3:2]),
+ .DOPADOP(DOP[1:0]),
+ .DIBDI(DI[31:16]),
+ .DIADI(DI[15:0]),
+ .DIPBDIP(DIP[3:2]),
+ .DIPADIP(DIP[1:0]),
+ .WEBWEU(B1EN[3:2]),
+ .WEAWEL(B1EN[1:0]),
+
+ .ADDRAWRADDR(B1ADDR_13),
+ .CLKAWRCLK(CLK3 ^ !CLKPOL3),
+ .ENAWREN(|1),
+ .REGCEA(|0),
+ .RSTA(|0),
+
+ .ADDRBRDADDR(A1ADDR_13),
+ .CLKBRDCLK(CLK2 ^ !CLKPOL2),
+ .ENBRDEN(A1EN),
+ .REGCEBREGCE(|1),
+ .RSTBRST(|0)
+ );
+endmodule
+
+// ------------------------------------------------------------------------
+
+module \$__XILINX_RAMB16BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 9;
+ parameter CFG_DBITS = 36;
+ parameter CFG_ENABLE_B = 4;
+
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+ parameter [18431:0] INIT = 18432'bx;
+
+ input CLK2;
+ input CLK3;
+
+ input [CFG_ABITS-1:0] A1ADDR;
+ output [CFG_DBITS-1:0] A1DATA;
+ input A1EN;
+
+ input [CFG_ABITS-1:0] B1ADDR;
+ input [CFG_DBITS-1:0] B1DATA;
+ input [CFG_ENABLE_B-1:0] B1EN;
+
+ wire [13:0] A1ADDR_14 = A1ADDR << (14 - CFG_ABITS);
+ wire [13:0] B1ADDR_14 = B1ADDR << (14 - CFG_ABITS);
+ wire [3:0] B1EN_4 = {4{B1EN}};
+
+ wire [3:0] DIP, DOP;
+ wire [31:0] DI, DO;
+
+ wire [31:0] DOB;
+ wire [3:0] DOPB;
+
+ assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
+ assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
+
+ generate if (CFG_DBITS > 8) begin
+ RAMB16BWER #(
+ .DATA_WIDTH_A(CFG_DBITS),
+ .DATA_WIDTH_B(CFG_DBITS),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ `include "brams_init_18.vh"
+ ) _TECHMAP_REPLACE_ (
+ .DIA(32'd0),
+ .DIPA(4'd0),
+ .DOA(DO[31:0]),
+ .DOPA(DOP[3:0]),
+ .ADDRA(A1ADDR_14),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .REGCEA(|1),
+ .RSTA(|0),
+ .WEA(4'b0),
+
+ .DIB(DI),
+ .DIPB(DIP),
+ .DOB(DOB),
+ .DOPB(DOPB),
+ .ADDRB(B1ADDR_14),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .REGCEB(|0),
+ .RSTB(|0),
+ .WEB(B1EN_4)
+ );
+ end else begin
+ RAMB16BWER #(
+ .DATA_WIDTH_A(CFG_DBITS),
+ .DATA_WIDTH_B(CFG_DBITS),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ `include "brams_init_16.vh"
+ ) _TECHMAP_REPLACE_ (
+ .DIA(32'd0),
+ .DIPA(4'd0),
+ .DOA(DO[31:0]),
+ .DOPA(DOP[3:0]),
+ .ADDRA(A1ADDR_14),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .REGCEA(|1),
+ .RSTA(|0),
+ .WEA(4'b0),
+
+ .DIB(DI),
+ .DIPB(DIP),
+ .DOB(DOB),
+ .DOPB(DOPB),
+ .ADDRB(B1ADDR_14),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .REGCEB(|0),
+ .RSTB(|0),
+ .WEB(B1EN_4)
+ );
+ end endgenerate
+endmodule
+
+// ------------------------------------------------------------------------
+
+module \$__XILINX_RAMB8BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 9;
+ parameter CFG_DBITS = 18;
+ parameter CFG_ENABLE_B = 2;
+
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+ parameter [9215:0] INIT = 9216'bx;
+
+ input CLK2;
+ input CLK3;
+
+ input [CFG_ABITS-1:0] A1ADDR;
+ output [CFG_DBITS-1:0] A1DATA;
+ input A1EN;
+
+ input [CFG_ABITS-1:0] B1ADDR;
+ input [CFG_DBITS-1:0] B1DATA;
+ input [CFG_ENABLE_B-1:0] B1EN;
+
+ wire [12:0] A1ADDR_13 = A1ADDR << (13 - CFG_ABITS);
+ wire [12:0] B1ADDR_13 = B1ADDR << (13 - CFG_ABITS);
+ wire [1:0] B1EN_2 = {2{B1EN}};
+
+ wire [1:0] DIP, DOP;
+ wire [15:0] DI, DO;
+
+ wire [15:0] DOBDO;
+ wire [1:0] DOPBDOP;
+
+ assign A1DATA = { DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
+ assign { DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
+
+ generate if (CFG_DBITS > 8) begin
+ RAMB8BWER #(
+ .RAM_MODE("TDP"),
+ .DATA_WIDTH_A(CFG_DBITS),
+ .DATA_WIDTH_B(CFG_DBITS),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ `include "brams_init_9.vh"
+ ) _TECHMAP_REPLACE_ (
+ .DIADI(16'b0),
+ .DIPADIP(2'b0),
+ .DOADO(DO),
+ .DOPADOP(DOP),
+ .ADDRAWRADDR(A1ADDR_13),
+ .CLKAWRCLK(CLK2 ^ !CLKPOL2),
+ .ENAWREN(A1EN),
+ .REGCEA(|1),
+ .RSTA(|0),
+ .WEAWEL(2'b0),
+
+ .DIBDI(DI),
+ .DIPBDIP(DIP),
+ .DOBDO(DOBDO),
+ .DOPBDOP(DOPBDOP),
+ .ADDRBRDADDR(B1ADDR_13),
+ .CLKBRDCLK(CLK3 ^ !CLKPOL3),
+ .ENBRDEN(|1),
+ .REGCEBREGCE(|0),
+ .RSTBRST(|0),
+ .WEBWEU(B1EN_2)
+ );
+ end else begin
+ RAMB8BWER #(
+ .RAM_MODE("TDP"),
+ .DATA_WIDTH_A(CFG_DBITS),
+ .DATA_WIDTH_B(CFG_DBITS),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ `include "brams_init_8.vh"
+ ) _TECHMAP_REPLACE_ (
+ .DIADI(16'b0),
+ .DIPADIP(2'b0),
+ .DOADO(DO),
+ .DOPADOP(DOP),
+ .ADDRAWRADDR(A1ADDR_13),
+ .CLKAWRCLK(CLK2 ^ !CLKPOL2),
+ .ENAWREN(A1EN),
+ .REGCEA(|1),
+ .RSTA(|0),
+ .WEAWEL(2'b0),
+
+ .DIBDI(DI),
+ .DIPBDIP(DIP),
+ .DOBDO(DOBDO),
+ .DOPBDOP(DOPBDOP),
+ .ADDRBRDADDR(B1ADDR_13),
+ .CLKBRDCLK(CLK3 ^ !CLKPOL3),
+ .ENBRDEN(|1),
+ .REGCEBREGCE(|0),
+ .RSTBRST(|0),
+ .WEBWEU(B1EN_2)
+ );
+ end endgenerate
+endmodule
diff --git a/techlibs/xilinx/brams.txt b/techlibs/xilinx/xc7_brams.txt
index f1161114e..f1161114e 100644
--- a/techlibs/xilinx/brams.txt
+++ b/techlibs/xilinx/xc7_brams.txt
diff --git a/techlibs/xilinx/brams_bb.v b/techlibs/xilinx/xc7_brams_bb.v
index a682ba4a7..a682ba4a7 100644
--- a/techlibs/xilinx/brams_bb.v
+++ b/techlibs/xilinx/xc7_brams_bb.v
diff --git a/techlibs/xilinx/brams_map.v b/techlibs/xilinx/xc7_brams_map.v
index 7ea49158d..7ea49158d 100644
--- a/techlibs/xilinx/brams_map.v
+++ b/techlibs/xilinx/xc7_brams_map.v
diff --git a/tests/aiger/.gitignore b/tests/aiger/.gitignore
index 073f46157..9a26bb8f4 100644
--- a/tests/aiger/.gitignore
+++ b/tests/aiger/.gitignore
@@ -1,2 +1 @@
-*.log
-*.out
+/*_ref.v
diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh
index 5246c1b48..deaf48a3d 100755
--- a/tests/aiger/run-test.sh
+++ b/tests/aiger/run-test.sh
@@ -2,6 +2,16 @@
set -e
+OPTIND=1
+abcprog="../../yosys-abc" # default to built-in version of abc
+while getopts "A:" opt
+do
+ case "$opt" in
+ A) abcprog="$OPTARG" ;;
+ esac
+done
+shift "$((OPTIND-1))"
+
# NB: *.aag and *.aig must contain a symbol table naming the primary
# inputs and outputs, otherwise ABC and Yosys will name them
# arbitrarily (and inconsistently with each other).
@@ -11,7 +21,7 @@ for aag in *.aag; do
# (which would have been created by the reference aig2aig utility,
# available from http://fmv.jku.at/aiger/)
echo "Checking $aag."
- ../../yosys-abc -q "read -c ${aag%.*}.aig; write ${aag%.*}_ref.v"
+ $abcprog -q "read -c ${aag%.*}.aig; write ${aag%.*}_ref.v"
../../yosys -qp "
read_verilog ${aag%.*}_ref.v
prep
@@ -28,7 +38,7 @@ done
for aig in *.aig; do
echo "Checking $aig."
- ../../yosys-abc -q "read -c $aig; write ${aig%.*}_ref.v"
+ $abcprog -q "read -c $aig; write ${aig%.*}_ref.v"
../../yosys -qp "
read_verilog ${aig%.*}_ref.v
prep
diff --git a/tests/arch/run-test.sh b/tests/arch/run-test.sh
new file mode 100755
index 000000000..5292d1615
--- /dev/null
+++ b/tests/arch/run-test.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+echo "Running syntax check on arch sim models"
+for arch in ../../techlibs/*; do
+ find $arch -name cells_sim.v | while read path; do
+ echo -n "Test $path ->"
+ iverilog -t null -I$arch $path
+ echo " ok"
+ done
+done
+
+for path in "../../techlibs/common/simcells.v" "../../techlibs/common/simlib.v"; do
+ echo -n "Test $path ->"
+ iverilog -t null $path
+ echo " ok"
+done
diff --git a/tests/fsm/run-test.sh b/tests/fsm/run-test.sh
index cf506470d..fbdcbf048 100755
--- a/tests/fsm/run-test.sh
+++ b/tests/fsm/run-test.sh
@@ -6,7 +6,7 @@
set -e
OPTIND=1
-count=100
+count=50
seed="" # default to no seed specified
while getopts "c:S:" opt
do
diff --git a/tests/lut/check_map_lut6.ys b/tests/lut/check_map_lut6.ys
new file mode 100644
index 000000000..8a32e4d10
--- /dev/null
+++ b/tests/lut/check_map_lut6.ys
@@ -0,0 +1,7 @@
+chparam -set LUT_WIDTH 6 top
+simplemap
+equiv_opt -assert techmap -D LUT_WIDTH=6 -map +/cmp2lut.v
+design -load postopt
+equiv_opt -assert techmap -D LUT_WIDTH=6 -map +/gate2lut.v
+design -load postopt
+select -assert-count 0 t:* t:$lut %d
diff --git a/tests/lut/map_cmp.v b/tests/lut/map_cmp.v
index 5e413f894..0014eb9ac 100644
--- a/tests/lut/map_cmp.v
+++ b/tests/lut/map_cmp.v
@@ -1,29 +1,30 @@
module top(...);
- input [3:0] a;
+ parameter LUT_WIDTH = 4; // Multiples of 2 only
+ input [LUT_WIDTH-1:0] a;
- output o1_1 = 4'b1010 <= a;
- output o1_2 = 4'b1010 < a;
- output o1_3 = 4'b1010 >= a;
- output o1_4 = 4'b1010 > a;
- output o1_5 = 4'b1010 == a;
- output o1_6 = 4'b1010 != a;
+ output o1_1 = {(LUT_WIDTH/2){2'b10}} <= a;
+ output o1_2 = {(LUT_WIDTH/2){2'b10}} < a;
+ output o1_3 = {(LUT_WIDTH/2){2'b10}} >= a;
+ output o1_4 = {(LUT_WIDTH/2){2'b10}} > a;
+ output o1_5 = {(LUT_WIDTH/2){2'b10}} == a;
+ output o1_6 = {(LUT_WIDTH/2){2'b10}} != a;
- output o2_1 = a <= 4'b1010;
- output o2_2 = a < 4'b1010;
- output o2_3 = a >= 4'b1010;
- output o2_4 = a > 4'b1010;
- output o2_5 = a == 4'b1010;
- output o2_6 = a != 4'b1010;
+ output o2_1 = a <= {(LUT_WIDTH/2){2'b10}};
+ output o2_2 = a < {(LUT_WIDTH/2){2'b10}};
+ output o2_3 = a >= {(LUT_WIDTH/2){2'b10}};
+ output o2_4 = a > {(LUT_WIDTH/2){2'b10}};
+ output o2_5 = a == {(LUT_WIDTH/2){2'b10}};
+ output o2_6 = a != {(LUT_WIDTH/2){2'b10}};
- output o3_1 = 4'sb0101 <= $signed(a);
- output o3_2 = 4'sb0101 < $signed(a);
- output o3_3 = 4'sb0101 >= $signed(a);
- output o3_4 = 4'sb0101 > $signed(a);
- output o3_5 = 4'sb0101 == $signed(a);
- output o3_6 = 4'sb0101 != $signed(a);
+ output o3_1 = {(LUT_WIDTH/2){2'sb01}} <= $signed(a);
+ output o3_2 = {(LUT_WIDTH/2){2'sb01}} < $signed(a);
+ output o3_3 = {(LUT_WIDTH/2){2'sb01}} >= $signed(a);
+ output o3_4 = {(LUT_WIDTH/2){2'sb01}} > $signed(a);
+ output o3_5 = {(LUT_WIDTH/2){2'sb01}} == $signed(a);
+ output o3_6 = {(LUT_WIDTH/2){2'sb01}} != $signed(a);
- output o4_1 = $signed(a) <= 4'sb0000;
- output o4_2 = $signed(a) < 4'sb0000;
- output o4_3 = $signed(a) >= 4'sb0000;
- output o4_4 = $signed(a) > 4'sb0000;
+ output o4_1 = $signed(a) <= {LUT_WIDTH{1'sb0}};
+ output o4_2 = $signed(a) < {LUT_WIDTH{1'sb0}};
+ output o4_3 = $signed(a) >= {LUT_WIDTH{1'sb0}};
+ output o4_4 = $signed(a) > {LUT_WIDTH{1'sb0}};
endmodule
diff --git a/tests/lut/run-test.sh b/tests/lut/run-test.sh
index 207417fa6..f8964f146 100755
--- a/tests/lut/run-test.sh
+++ b/tests/lut/run-test.sh
@@ -4,3 +4,8 @@ for x in *.v; do
echo "Running $x.."
../../yosys -q -s check_map.ys -l ${x%.v}.log $x
done
+
+for x in map_cmp.v; do
+ echo "Running $x.."
+ ../../yosys -q -s check_map_lut6.ys -l ${x%.v}_lut6.log $x
+done
diff --git a/tests/memories/issue00335.v b/tests/memories/issue00335.v
new file mode 100644
index 000000000..f3b6e5dfe
--- /dev/null
+++ b/tests/memories/issue00335.v
@@ -0,0 +1,28 @@
+// expect-wr-ports 1
+// expect-rd-ports 1
+// expect-rd-clk \clk
+
+module ram2 (input clk,
+ input sel,
+ input we,
+ input [SIZE-1:0] adr,
+ input [63:0] dat_i,
+ output reg [63:0] dat_o);
+ parameter SIZE = 5; // Address size
+
+ reg [63:0] mem [0:(1 << SIZE)-1];
+ integer i;
+
+ initial begin
+ for (i = 0; i < (1<<SIZE) - 1; i = i + 1)
+ mem[i] <= 0;
+ end
+
+ always @(posedge clk)
+ if (sel) begin
+ if (~we)
+ dat_o <= mem[adr];
+ else
+ mem[adr] <= dat_i;
+ end
+endmodule
diff --git a/tests/memories/issue00710.v b/tests/memories/issue00710.v
new file mode 100644
index 000000000..7a5fad1c2
--- /dev/null
+++ b/tests/memories/issue00710.v
@@ -0,0 +1,17 @@
+// expect-wr-ports 1
+// expect-rd-ports 1
+// expect-rd-clk \clk
+
+module top(input clk, input we, re, reset, input [7:0] addr, wdata, output reg [7:0] rdata);
+
+reg [7:0] bram[0:255];
+(* keep *) reg dummy;
+
+always @(posedge clk)
+ if (reset)
+ dummy <= 1'b0;
+ else if (re)
+ rdata <= bram[addr];
+ else if (we)
+ bram[addr] <= wdata;
+endmodule
diff --git a/tests/memories/read_two_mux.v b/tests/memories/read_two_mux.v
new file mode 100644
index 000000000..4f2e7e1cd
--- /dev/null
+++ b/tests/memories/read_two_mux.v
@@ -0,0 +1,16 @@
+// expect-wr-ports 1
+// expect-rd-ports 1
+// expect-no-rd-clk
+
+module top(input clk, input we, re, reset, input [7:0] addr, wdata, output reg [7:0] rdata);
+
+reg [7:0] bram[0:255];
+(* keep *) reg dummy;
+
+always @(posedge clk) begin
+ rdata <= re ? (reset ? 8'b0 : bram[addr]) : rdata;
+ if (we)
+ bram[addr] <= wdata;
+end
+
+endmodule
diff --git a/tests/memories/run-test.sh b/tests/memories/run-test.sh
index 734a96682..8d1a8b413 100755
--- a/tests/memories/run-test.sh
+++ b/tests/memories/run-test.sh
@@ -4,17 +4,19 @@ set -e
OPTIND=1
seed="" # default to no seed specified
-while getopts "S:" opt
+abcopt=""
+while getopts "A:S:" opt
do
case "$opt" in
+ A) abcopt="-A $OPTARG" ;;
S) seed="-S $OPTARG" ;;
esac
done
shift "$((OPTIND-1))"
-bash ../tools/autotest.sh $seed -G *.v
+bash ../tools/autotest.sh $abcopt $seed -G *.v
-for f in `egrep -l 'expect-(wr|rd)-ports' *.v`; do
+for f in `egrep -l 'expect-(wr-ports|rd-ports|rd-clk)' *.v`; do
echo -n "Testing expectations for $f .."
../../yosys -qp "proc; opt; memory -nomap;; dump -outfile ${f%.v}.dmp t:\$mem" $f
if grep -q expect-wr-ports $f; then
@@ -25,6 +27,14 @@ for f in `egrep -l 'expect-(wr|rd)-ports' *.v`; do
grep -q "parameter \\\\RD_PORTS $(gawk '/expect-rd-ports/ { print $3; }' $f)\$" ${f%.v}.dmp ||
{ echo " ERROR: Unexpected number of read ports."; false; }
fi
+ if grep -q expect-rd-clk $f; then
+ grep -q "connect \\\\RD_CLK \\$(gawk '/expect-rd-clk/ { print $3; }' $f)\$" ${f%.v}.dmp ||
+ { echo " ERROR: Unexpected read clock."; false; }
+ fi
+ if grep -q expect-no-rd-clk $f; then
+ grep -q "connect \\\\RD_CLK 1'x\$" ${f%.v}.dmp ||
+ { echo " ERROR: Expected no read clock."; false; }
+ fi
echo " ok."
done
diff --git a/tests/opt/opt_expr.ys b/tests/opt/opt_expr.ys
new file mode 100644
index 000000000..ecc2c8da8
--- /dev/null
+++ b/tests/opt/opt_expr.ys
@@ -0,0 +1,293 @@
+
+read_verilog <<EOT
+module opt_expr_add_test(input [3:0] i, input [7:0] j, output [8:0] o);
+ assign o = (i << 4) + j;
+endmodule
+EOT
+
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$add r:A_WIDTH=5 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+##########
+
+# alumacc version of above
+design -reset
+read_verilog <<EOT
+module opt_expr_add_test(input [3:0] i, input [7:0] j, output [8:0] o);
+ assign o = (i << 4) + j;
+endmodule
+EOT
+
+alumacc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i
+
+##########
+
+design -reset
+read_verilog <<EOT
+module opt_expr_add_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
+ assign o = (i << 4) + j;
+endmodule
+EOT
+
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$add r:A_WIDTH=5 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+##########
+
+# alumacc version of above
+design -reset
+read_verilog <<EOT
+module opt_expr_add_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
+ assign o = (i << 4) + j;
+endmodule
+EOT
+
+alumacc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i
+
+##########
+
+design -reset
+read_verilog <<EOT
+module opt_expr_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
+ assign o = j - (i << 4);
+endmodule
+EOT
+
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i
+
+##########
+
+# alumacc version of above
+design -reset
+read_verilog <<EOT
+module opt_expr_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
+ assign o = j - (i << 4);
+endmodule
+EOT
+
+alumacc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+dump
+select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i
+
+##########
+
+design -reset
+read_verilog <<EOT
+module opt_expr_sub_signed_test1(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
+ assign o = j - (i << 4);
+endmodule
+EOT
+
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i
+
+##########
+
+# alumacc version of above
+design -reset
+read_verilog <<EOT
+module opt_expr_sub_signed_test1(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
+ assign o = j - (i << 4);
+endmodule
+EOT
+
+alumacc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i
+
+##########
+
+design -reset
+read_verilog <<EOT
+module opt_expr_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o);
+ assign o = (i << 4) - j;
+endmodule
+EOT
+
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$sub r:A_WIDTH=9 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
+
+##########
+
+# alumacc version of above
+design -reset
+read_verilog <<EOT
+module opt_expr_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o);
+ assign o = (i << 4) - j;
+endmodule
+EOT
+
+alumacc
+opt_expr -fine
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$alu r:A_WIDTH=9 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
+
+##########
+
+design -reset
+read_verilog <<EOT
+module opt_expr_sub_test4(input [3:0] i, output [8:0] o);
+ assign o = 5'b00010 - i;
+endmodule
+EOT
+
+wreduce
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$sub r:A_WIDTH=2 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+##########
+
+# alumacc version of above
+design -reset
+read_verilog <<EOT
+module opt_expr_sub_test4(input [3:0] i, output [8:0] o);
+ assign o = 5'b00010 - i;
+endmodule
+EOT
+
+wreduce
+alumacc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$alu r:A_WIDTH=2 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_alu_test_ci0_bi0(input [7:0] a, input [3:0] b, output [8:0] x, y, co);
+ \$alu #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(8), .Y_WIDTH(9)) alu (.A(a), .B({b, 4'b0000}), .CI(1'b0), .BI(1'b0), .X(x), .Y(y), .CO(co));
+endmodule
+EOT
+check
+
+equiv_opt -assert opt_expr -fine
+design -load postopt
+select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_alu_test_ci1_bi1(input [7:0] a, input [3:0] b, output [8:0] x, y, co);
+ \$alu #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(8), .Y_WIDTH(9)) alu (.A(a), .B({b, 4'b0000}), .CI(1'b1), .BI(1'b1), .X(x), .Y(y), .CO(co));
+endmodule
+EOT
+check
+
+equiv_opt opt_expr -fine
+design -load postopt
+select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_alu_test_ci0_bi1(input [7:0] a, input [3:0] b, output [8:0] x, y, co);
+ \$alu #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(8), .Y_WIDTH(9)) alu (.A(a), .B({b, 4'b0000}), .CI(1'b0), .BI(1'b1), .X(x), .Y(y), .CO(co));
+endmodule
+EOT
+check
+
+equiv_opt opt_expr -fine
+design -load postopt
+select -assert-count 1 t:$alu r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_shiftx_1bit(input [2:0] a, input [1:0] b, output y);
+ \$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shiftx (.A({1'bx,a}), .B(b), .Y(y));
+endmodule
+EOT
+check
+
+equiv_opt opt_expr
+design -load postopt
+select -assert-count 1 t:$shiftx r:A_WIDTH=3 %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_shiftx_3bit(input [9:0] a, input [3:0] b, output [2:0] y);
+ \$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shiftx (.A({4'bxx00,a}), .B(b), .Y(y));
+endmodule
+EOT
+check
+
+equiv_opt opt_expr
+design -load postopt
+select -assert-count 1 t:$shiftx r:A_WIDTH=12 %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_shift_1bit(input [2:0] a, input [1:0] b, output y);
+ \$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shift (.A({1'b0,a}), .B(b), .Y(y));
+endmodule
+EOT
+check
+
+equiv_opt opt_expr
+design -load postopt
+select -assert-count 1 t:$shift r:A_WIDTH=3 %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_shift_3bit(input [9:0] a, input [3:0] b, output [2:0] y);
+ \$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y));
+endmodule
+EOT
+check
+
+equiv_opt opt_expr
+design -load postopt
+select -assert-count 1 t:$shift r:A_WIDTH=10 %i
+
+###########
+
+design -reset
+read_verilog -icells <<EOT
+module opt_expr_shift_3bit_keepdc(input [9:0] a, input [3:0] b, output [2:0] y);
+ \$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y));
+endmodule
+EOT
+check
+
+equiv_opt opt_expr -keepdc
+design -load postopt
+select -assert-count 1 t:$shift r:A_WIDTH=13 %i
diff --git a/tests/opt/opt_ff.v b/tests/opt/opt_ff.v
deleted file mode 100644
index a01b64b61..000000000
--- a/tests/opt/opt_ff.v
+++ /dev/null
@@ -1,21 +0,0 @@
-module top(
- input clk,
- input rst,
- input [2:0] a,
- output [1:0] b
-);
- reg [2:0] b_reg;
- initial begin
- b_reg <= 3'b0;
- end
-
- assign b = b_reg[1:0];
- always @(posedge clk or posedge rst) begin
- if(rst) begin
- b_reg <= 3'b0;
- end else begin
- b_reg <= a;
- end
- end
-endmodule
-
diff --git a/tests/opt/opt_ff.ys b/tests/opt/opt_ff.ys
deleted file mode 100644
index 704c7acf3..000000000
--- a/tests/opt/opt_ff.ys
+++ /dev/null
@@ -1,3 +0,0 @@
-read_verilog opt_ff.v
-synth_ice40
-ice40_unlut
diff --git a/tests/opt/opt_lut.ys b/tests/opt/opt_lut.ys
index 59b12c351..a9fccbb62 100644
--- a/tests/opt/opt_lut.ys
+++ b/tests/opt/opt_lut.ys
@@ -1,4 +1,2 @@
read_verilog opt_lut.v
-synth_ice40
-ice40_unlut
-equiv_opt -map +/ice40/cells_sim.v -assert opt_lut -dlogic SB_CARRY:I0=1:I1=2:CI=3
+equiv_opt -map +/ice40/cells_sim.v -assert synth_ice40
diff --git a/tests/various/opt_rmdff.v b/tests/opt/opt_rmdff.v
index b1c06703c..b1c06703c 100644
--- a/tests/various/opt_rmdff.v
+++ b/tests/opt/opt_rmdff.v
diff --git a/tests/various/opt_rmdff.ys b/tests/opt/opt_rmdff.ys
index 081f81782..83a162f44 100644
--- a/tests/various/opt_rmdff.ys
+++ b/tests/opt/opt_rmdff.ys
@@ -19,8 +19,8 @@ hierarchy -top equiv
equiv_simple -undef
equiv_status -assert
-design -load gold
-stat
-
-design -load gate
-stat
+#design -load gold
+#stat
+#
+#design -load gate
+#stat
diff --git a/tests/opt/opt_rmdff_sat.v b/tests/opt/opt_rmdff_sat.v
new file mode 100644
index 000000000..5a0a6fe37
--- /dev/null
+++ b/tests/opt/opt_rmdff_sat.v
@@ -0,0 +1,12 @@
+module top (
+ input clk,
+ output reg [7:0] cnt
+);
+ initial cnt = 0;
+ always @(posedge clk) begin
+ if (cnt < 20)
+ cnt <= cnt + 1;
+ else
+ cnt <= 0;
+ end
+endmodule
diff --git a/tests/opt/opt_rmdff_sat.ys b/tests/opt/opt_rmdff_sat.ys
new file mode 100644
index 000000000..1c3dd9c05
--- /dev/null
+++ b/tests/opt/opt_rmdff_sat.ys
@@ -0,0 +1,5 @@
+read_verilog opt_rmdff_sat.v
+prep -flatten
+opt_rmdff -sat
+synth
+select -assert-count 5 t:$_DFF_P_
diff --git a/tests/opt/opt_share_add_sub.v b/tests/opt/opt_share_add_sub.v
new file mode 100644
index 000000000..d918f27cc
--- /dev/null
+++ b/tests/opt/opt_share_add_sub.v
@@ -0,0 +1,10 @@
+module opt_share_test(
+ input [15:0] a,
+ input [15:0] b,
+ input sel,
+ output [15:0] res,
+ );
+
+ assign res = {sel ? a + b : a - b};
+
+endmodule
diff --git a/tests/opt/opt_share_add_sub.ys b/tests/opt/opt_share_add_sub.ys
new file mode 100644
index 000000000..4a5406791
--- /dev/null
+++ b/tests/opt/opt_share_add_sub.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_add_sub.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu
diff --git a/tests/opt/opt_share_cat.v b/tests/opt/opt_share_cat.v
new file mode 100644
index 000000000..7fb97fef5
--- /dev/null
+++ b/tests/opt/opt_share_cat.v
@@ -0,0 +1,15 @@
+module opt_share_test(
+ input [15:0] a,
+ input [15:0] b,
+ input [15:0] c,
+ input [15:0] d,
+ input sel,
+ output [63:0] res,
+ );
+
+ reg [31: 0] cat1 = {a+b, c+d};
+ reg [31: 0] cat2 = {a-b, c-d};
+
+ assign res = {b, sel ? cat1 : cat2, a};
+
+endmodule
diff --git a/tests/opt/opt_share_cat.ys b/tests/opt/opt_share_cat.ys
new file mode 100644
index 000000000..7de69bfde
--- /dev/null
+++ b/tests/opt/opt_share_cat.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_cat.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 2 -module merged t:$alu
diff --git a/tests/opt/opt_share_cat_multiuser.v b/tests/opt/opt_share_cat_multiuser.v
new file mode 100644
index 000000000..b250689d9
--- /dev/null
+++ b/tests/opt/opt_share_cat_multiuser.v
@@ -0,0 +1,22 @@
+module opt_share_test(
+ input [15:0] a,
+ input [15:0] b,
+ input [15:0] c,
+ input [15:0] d,
+ input sel,
+ output reg [47:0] res,
+ );
+
+ wire [15:0] add_res = a+b;
+ wire [15:0] sub_res = a-b;
+ wire [31: 0] cat1 = {add_res, c+d};
+ wire [31: 0] cat2 = {sub_res, c-d};
+
+ always @* begin
+ case(sel)
+ 0: res = {cat1, add_res};
+ 1: res = {cat2, add_res};
+ endcase
+ end
+
+endmodule
diff --git a/tests/opt/opt_share_cat_multiuser.ys b/tests/opt/opt_share_cat_multiuser.ys
new file mode 100644
index 000000000..6a82fbd79
--- /dev/null
+++ b/tests/opt/opt_share_cat_multiuser.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_cat_multiuser.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 3 -module merged t:$alu
diff --git a/tests/opt/opt_share_diff_port_widths.v b/tests/opt/opt_share_diff_port_widths.v
new file mode 100644
index 000000000..1a37c80a6
--- /dev/null
+++ b/tests/opt/opt_share_diff_port_widths.v
@@ -0,0 +1,21 @@
+module opt_share_test(
+ input [15:0] a,
+ input [15:0] b,
+ input [15:0] c,
+ input [1:0] sel,
+ output reg [15:0] res
+ );
+
+ wire [15:0] add0_res = a+b;
+ wire [15:0] add1_res = a+c;
+
+ always @* begin
+ case(sel)
+ 0: res = add0_res[10:0];
+ 1: res = add1_res[10:0];
+ 2: res = a - b;
+ default: res = 32'bx;
+ endcase
+ end
+
+endmodule
diff --git a/tests/opt/opt_share_diff_port_widths.ys b/tests/opt/opt_share_diff_port_widths.ys
new file mode 100644
index 000000000..ec5e9f7b0
--- /dev/null
+++ b/tests/opt/opt_share_diff_port_widths.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_diff_port_widths.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 2 -module merged t:$alu
diff --git a/tests/opt/opt_share_extend.v b/tests/opt/opt_share_extend.v
new file mode 100644
index 000000000..d39f19069
--- /dev/null
+++ b/tests/opt/opt_share_extend.v
@@ -0,0 +1,18 @@
+module opt_share_test(
+ input signed [7:0] a,
+ input signed [10:0] b,
+ input signed [15:0] c,
+ input [1:0] sel,
+ output reg signed [15:0] res
+ );
+
+ always @* begin
+ case(sel)
+ 0: res = a + b;
+ 1: res = a - b;
+ 2: res = a + c;
+ default: res = 16'bx;
+ endcase
+ end
+
+endmodule
diff --git a/tests/opt/opt_share_extend.ys b/tests/opt/opt_share_extend.ys
new file mode 100644
index 000000000..c553ee0fb
--- /dev/null
+++ b/tests/opt/opt_share_extend.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_extend.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu
diff --git a/tests/opt/opt_share_large_pmux_cat.v b/tests/opt/opt_share_large_pmux_cat.v
new file mode 100644
index 000000000..416ba3766
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_cat.v
@@ -0,0 +1,21 @@
+module opt_share_test(
+ input [15:0] a,
+ input [15:0] b,
+ input [15:0] c,
+ input [2:0] sel,
+ output reg [31:0] res
+ );
+
+ always @* begin
+ case(sel)
+ 0: res = {a + b, a};
+ 1: res = {a - b, b};
+ 2: res = {a + c, c};
+ 3: res = {a - c, a};
+ 4: res = {b, b};
+ 5: res = {c, c};
+ default: res = 32'bx;
+ endcase
+ end
+
+endmodule
diff --git a/tests/opt/opt_share_large_pmux_cat.ys b/tests/opt/opt_share_large_pmux_cat.ys
new file mode 100644
index 000000000..4186ca52e
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_cat.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_large_pmux_cat.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu
diff --git a/tests/opt/opt_share_large_pmux_cat_multipart.v b/tests/opt/opt_share_large_pmux_cat_multipart.v
new file mode 100644
index 000000000..34d2bd9a8
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_cat_multipart.v
@@ -0,0 +1,25 @@
+module opt_share_test(
+ input [15:0] a,
+ input [15:0] b,
+ input [15:0] c,
+ input [15:0] d,
+ input [2:0] sel,
+ output reg [31:0] res
+ );
+
+ wire [15:0] add0_res = a+d;
+
+ always @* begin
+ case(sel)
+ 0: res = {add0_res, a};
+ 1: res = {a - b, add0_res[7], 15'b0};
+ 2: res = {b-a, b};
+ 3: res = {d, b - c};
+ 4: res = {d, b - a};
+ 5: res = {c, d};
+ 6: res = {a - c, b-d};
+ default: res = 32'bx;
+ endcase
+ end
+
+endmodule
diff --git a/tests/opt/opt_share_large_pmux_cat_multipart.ys b/tests/opt/opt_share_large_pmux_cat_multipart.ys
new file mode 100644
index 000000000..610bb8c6c
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_cat_multipart.ys
@@ -0,0 +1,14 @@
+read_verilog opt_share_large_pmux_cat_multipart.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 4 -module merged t:$alu
diff --git a/tests/opt/opt_share_large_pmux_multipart.v b/tests/opt/opt_share_large_pmux_multipart.v
new file mode 100644
index 000000000..535adf96f
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_multipart.v
@@ -0,0 +1,23 @@
+module opt_share_test(
+ input [15:0] a,
+ input [15:0] b,
+ input [15:0] c,
+ input [15:0] d,
+ input [2:0] sel,
+ output reg [15:0] res
+ );
+
+ always @* begin
+ case(sel)
+ 0: res = a + d;
+ 1: res = a - b;
+ 2: res = b;
+ 3: res = b - c;
+ 4: res = b - a;
+ 5: res = c;
+ 6: res = a - c;
+ default: res = 16'bx;
+ endcase
+ end
+
+endmodule
diff --git a/tests/opt/opt_share_large_pmux_multipart.ys b/tests/opt/opt_share_large_pmux_multipart.ys
new file mode 100644
index 000000000..11182df1a
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_multipart.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_large_pmux_multipart.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 2 -module merged t:$alu
diff --git a/tests/opt/opt_share_large_pmux_part.v b/tests/opt/opt_share_large_pmux_part.v
new file mode 100644
index 000000000..a9008fb5a
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_part.v
@@ -0,0 +1,21 @@
+module opt_share_test(
+ input [15:0] a,
+ input [15:0] b,
+ input [15:0] c,
+ input [2:0] sel,
+ output reg [15:0] res
+ );
+
+ always @* begin
+ case(sel)
+ 0: res = a + b;
+ 1: res = a - b;
+ 2: res = a + c;
+ 3: res = a - c;
+ 4: res = b;
+ 5: res = c;
+ default: res = 16'bx;
+ endcase
+ end
+
+endmodule
diff --git a/tests/opt/opt_share_large_pmux_part.ys b/tests/opt/opt_share_large_pmux_part.ys
new file mode 100644
index 000000000..6b594a3d6
--- /dev/null
+++ b/tests/opt/opt_share_large_pmux_part.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_large_pmux_part.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu
diff --git a/tests/opt/opt_share_mux_tree.v b/tests/opt/opt_share_mux_tree.v
new file mode 100644
index 000000000..cc5ae4eb9
--- /dev/null
+++ b/tests/opt/opt_share_mux_tree.v
@@ -0,0 +1,18 @@
+module opt_share_test(
+ input [15:0] a,
+ input [15:0] b,
+ input [15:0] c,
+ input [1:0] sel,
+ output reg [15:0] res
+ );
+
+ always @* begin
+ case(sel)
+ 0: res = a + b;
+ 1: res = a - b;
+ 2: res = a + c;
+ default: res = 16'bx;
+ endcase
+ end
+
+endmodule
diff --git a/tests/opt/opt_share_mux_tree.ys b/tests/opt/opt_share_mux_tree.ys
new file mode 100644
index 000000000..58473039f
--- /dev/null
+++ b/tests/opt/opt_share_mux_tree.ys
@@ -0,0 +1,13 @@
+read_verilog opt_share_mux_tree.v
+proc;;
+copy opt_share_test merged
+
+alumacc merged
+opt merged
+opt_share merged
+opt_clean merged
+
+miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter
+sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter
+
+select -assert-count 1 -module merged t:$alu
diff --git a/tests/opt_share/.gitignore b/tests/opt_share/.gitignore
new file mode 100644
index 000000000..9c595a6fb
--- /dev/null
+++ b/tests/opt_share/.gitignore
@@ -0,0 +1 @@
+temp
diff --git a/tests/opt_share/generate.py b/tests/opt_share/generate.py
new file mode 100644
index 000000000..2ec92f7de
--- /dev/null
+++ b/tests/opt_share/generate.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+
+import argparse
+import sys
+import random
+from contextlib import contextmanager
+
+
+@contextmanager
+def redirect_stdout(new_target):
+ old_target, sys.stdout = sys.stdout, new_target
+ try:
+ yield new_target
+ finally:
+ sys.stdout = old_target
+
+
+def random_plus_x():
+ return "%s x" % random.choice(['+', '+', '+', '-', '-', '|', '&', '^'])
+
+
+def maybe_plus_x(expr):
+ if random.randint(0, 4) == 0:
+ return "(%s %s)" % (expr, random_plus_x())
+ else:
+ return expr
+
+
+parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+parser.add_argument('-S', '--seed', type=int, help='seed for PRNG')
+parser.add_argument('-c',
+ '--count',
+ type=int,
+ default=100,
+ help='number of test cases to generate')
+args = parser.parse_args()
+
+if args.seed is not None:
+ print("PRNG seed: %d" % args.seed)
+ random.seed(args.seed)
+
+for idx in range(args.count):
+ with open('temp/uut_%05d.v' % idx, 'w') as f:
+ with redirect_stdout(f):
+ print('module uut_%05d(a, b, c, s, y);' % (idx))
+ op = random.choice([
+ random.choice(['+', '-', '*', '/', '%']),
+ random.choice(['<', '<=', '==', '!=', '===', '!==', '>=',
+ '>']),
+ random.choice(['<<', '>>', '<<<', '>>>']),
+ random.choice(['|', '&', '^', '~^', '||', '&&']),
+ ])
+ print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), 8))
+ print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), 8))
+ print(' input%s [%d:0] c;' % (random.choice(['', ' signed']), 8))
+ print(' input s;')
+ print(' output [%d:0] y;' % 8)
+ ops1 = ['a', 'b']
+ ops2 = ['a', 'c']
+ random.shuffle(ops1)
+ random.shuffle(ops2)
+ cast1 = random.choice(['', '$signed', '$unsigned'])
+ cast2 = random.choice(['', '$signed', '$unsigned'])
+ print(' assign y = (s ? %s(%s %s %s) : %s(%s %s %s));' %
+ (cast1, ops1[0], op, ops1[1],
+ cast2, ops2[0], op, ops2[1]))
+ print('endmodule')
+
+ with open('temp/uut_%05d.ys' % idx, 'w') as f:
+ with redirect_stdout(f):
+ print('read_verilog temp/uut_%05d.v' % idx)
+ print('proc;;')
+ print('copy uut_%05d gold' % idx)
+ print('rename uut_%05d gate' % idx)
+ print('tee -a temp/all_share_log.txt log')
+ print('tee -a temp/all_share_log.txt log #job# uut_%05d' % idx)
+ print('tee -a temp/all_share_log.txt opt gate')
+ print('tee -a temp/all_share_log.txt opt_share gate')
+ print('tee -a temp/all_share_log.txt opt_clean gate')
+ print(
+ 'miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter'
+ )
+ print(
+ 'sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter'
+ )
diff --git a/tests/opt_share/run-test.sh b/tests/opt_share/run-test.sh
new file mode 100755
index 000000000..e01552646
--- /dev/null
+++ b/tests/opt_share/run-test.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# run this test many times:
+# time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done'
+
+set -e
+
+OPTIND=1
+count=100
+seed="" # default to no seed specified
+while getopts "c:S:" opt
+do
+ case "$opt" in
+ c) count="$OPTARG" ;;
+ S) seed="-S $OPTARG" ;;
+ esac
+done
+shift "$((OPTIND-1))"
+
+rm -rf temp
+mkdir -p temp
+echo "generating tests.."
+python3 generate.py -c $count $seed
+
+echo "running tests.."
+for i in $( ls temp/*.ys | sed 's,[^0-9],,g; s,^0*\(.\),\1,g;' ); do
+ echo -n "[$i]"
+ idx=$( printf "%05d" $i )
+ ../../yosys -ql temp/uut_${idx}.log temp/uut_${idx}.ys
+done
+echo
+
+failed_share=$( echo $( gawk '/^#job#/ { j=$2; db[j]=0; } /^Removing [246] cells/ { delete db[j]; } END { for (j in db) print(j); }' temp/all_share_log.txt ) )
+if [ -n "$failed_share" ]; then
+ echo "Resource sharing failed for the following test cases: $failed_share"
+ false
+fi
+
+exit 0
diff --git a/tests/proc/.gitignore b/tests/proc/.gitignore
new file mode 100644
index 000000000..397b4a762
--- /dev/null
+++ b/tests/proc/.gitignore
@@ -0,0 +1 @@
+*.log
diff --git a/tests/proc/bug_1268.v b/tests/proc/bug_1268.v
new file mode 100644
index 000000000..698ac937a
--- /dev/null
+++ b/tests/proc/bug_1268.v
@@ -0,0 +1,23 @@
+module gold (input clock, ctrl, din, output reg dout);
+ always @(posedge clock) begin
+ if (1'b1) begin
+ if (1'b0) begin end else begin
+ dout <= 0;
+ end
+ if (ctrl)
+ dout <= din;
+ end
+ end
+endmodule
+
+module gate (input clock, ctrl, din, output reg dout);
+ always @(posedge clock) begin
+ if (1'b1) begin
+ if (1'b0) begin end else begin
+ dout <= 0;
+ end
+ end
+ if (ctrl)
+ dout <= din;
+ end
+endmodule
diff --git a/tests/proc/bug_1268.ys b/tests/proc/bug_1268.ys
new file mode 100644
index 000000000..b73e94449
--- /dev/null
+++ b/tests/proc/bug_1268.ys
@@ -0,0 +1,5 @@
+read_verilog bug_1268.v
+proc
+equiv_make gold gate equiv
+equiv_induct
+equiv_status -assert
diff --git a/tests/proc/run-test.sh b/tests/proc/run-test.sh
new file mode 100755
index 000000000..44ce7e674
--- /dev/null
+++ b/tests/proc/run-test.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -e
+for x in *.ys; do
+ echo "Running $x.."
+ ../../yosys -ql ${x%.ys}.log $x
+done
diff --git a/tests/simple/arrays02.sv b/tests/simple/arrays02.sv
new file mode 100644
index 000000000..76c2a7388
--- /dev/null
+++ b/tests/simple/arrays02.sv
@@ -0,0 +1,16 @@
+module uut_arrays02(clock, we, addr, wr_data, rd_data);
+
+input clock, we;
+input [3:0] addr, wr_data;
+output [3:0] rd_data;
+reg [3:0] rd_data;
+
+reg [3:0] memory [16];
+
+always @(posedge clock) begin
+ if (we)
+ memory[addr] <= wr_data;
+ rd_data <= memory[addr];
+end
+
+endmodule
diff --git a/tests/simple/generate.v b/tests/simple/generate.v
index 3c55682cb..0e353ad9b 100644
--- a/tests/simple/generate.v
+++ b/tests/simple/generate.v
@@ -148,3 +148,14 @@ generate
endgenerate
assign out = steps[WIDTH].outer[0].val;
endmodule
+
+// ------------------------------------------
+
+module gen_test6(output [3:0] o);
+generate
+ genvar i;
+ for (i = 3; i >= 0; i = i-1) begin
+ assign o[i] = 1'b0;
+ end
+endgenerate
+endmodule
diff --git a/tests/simple/realexpr.v b/tests/simple/realexpr.v
index 5b756e6be..74ed8faa5 100644
--- a/tests/simple/realexpr.v
+++ b/tests/simple/realexpr.v
@@ -1,4 +1,3 @@
-
module demo_001(y1, y2, y3, y4);
output [7:0] y1, y2, y3, y4;
@@ -22,3 +21,13 @@ module demo_002(y0, y1, y2, y3);
assign y3 = 1 ? -1 : 'd0;
endmodule
+module demo_003(output A, B);
+ parameter real p = 0;
+ assign A = (p==1.0);
+ assign B = (p!="1.000000");
+endmodule
+
+module demo_004(output A, B, C, D);
+ demo_003 #(1.0) demo_real (A, B);
+ demo_003 #(1) demo_int (C, D);
+endmodule
diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl
index ba61a4476..10063d2c2 100644
--- a/tests/simple/xfirrtl
+++ b/tests/simple/xfirrtl
@@ -1,10 +1,12 @@
# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures.
arraycells.v inst id[0] of
+defvalue.sv Initial value not supported
dff_different_styles.v
dff_init.v Initial value not supported
generate.v combinational loop
hierdefparam.v inst id[0] of
i2c_master_tests.v $adff
+implicit_ports.v not fully initialized
macros.v drops modules
mem2reg.v drops modules
mem_arst.v $adff
@@ -12,7 +14,6 @@ memory.v $adff
multiplier.v inst id[0] of
muxtree.v drops modules
omsp_dbg_uart.v $adff
-operators.v $pow
partsel.v drops modules
process.v drops modules
realexpr.v drops modules
@@ -23,5 +24,6 @@ specify.v no code (empty module generates error
subbytes.v $adff
task_func.v drops modules
values.v combinational loop
+wandwor.v Invalid connect to an expression that is not a reference or a WritePort.
vloghammer.v combinational loop
wreduce.v original verilog issues ( -x where x isn't declared signed)
diff --git a/tests/simple_abc9/.gitignore b/tests/simple_abc9/.gitignore
new file mode 100644
index 000000000..2355aea29
--- /dev/null
+++ b/tests/simple_abc9/.gitignore
@@ -0,0 +1,4 @@
+*.v
+*.sv
+*.log
+*.out
diff --git a/tests/simple_abc9/abc.box b/tests/simple_abc9/abc.box
new file mode 100644
index 000000000..a8801d807
--- /dev/null
+++ b/tests/simple_abc9/abc.box
@@ -0,0 +1,2 @@
+MUXF8 1 0 3 1
+1 1 1
diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v
new file mode 100644
index 000000000..64b625efe
--- /dev/null
+++ b/tests/simple_abc9/abc9.v
@@ -0,0 +1,269 @@
+module abc9_test001(input a, output o);
+assign o = a;
+endmodule
+
+module abc9_test002(input [1:0] a, output o);
+assign o = a[1];
+endmodule
+
+module abc9_test003(input [1:0] a, output [1:0] o);
+assign o = a;
+endmodule
+
+module abc9_test004(input [1:0] a, output o);
+assign o = ^a;
+endmodule
+
+module abc9_test005(input [1:0] a, output o, output p);
+assign o = ^a;
+assign p = ~o;
+endmodule
+
+module abc9_test006(input [1:0] a, output [2:0] o);
+assign o[0] = ^a;
+assign o[1] = ~o[0];
+assign o[2] = o[1];
+endmodule
+
+module abc9_test007(input a, output o);
+wire b, c;
+assign c = ~a;
+assign b = c;
+abc9_test007_sub s(b, o);
+endmodule
+
+module abc9_test007_sub(input a, output b);
+assign b = a;
+endmodule
+
+module abc9_test008(input a, output o);
+wire b, c;
+assign b = ~a;
+assign c = b;
+abc9_test008_sub s(b, o);
+endmodule
+
+module abc9_test008_sub(input a, output b);
+assign b = ~a;
+endmodule
+
+module abc9_test009(inout io, input oe);
+reg latch;
+always @(io or oe)
+ if (!oe)
+ latch <= io;
+assign io = oe ? ~latch : 1'bz;
+endmodule
+
+module abc9_test010(inout [7:0] io, input oe);
+reg [7:0] latch;
+always @(io or oe)
+ if (!oe)
+ latch <= io;
+assign io = oe ? ~latch : 8'bz;
+endmodule
+
+module abc9_test011(inout io, input oe);
+reg latch;
+always @(io or oe)
+ if (!oe)
+ latch <= io;
+//assign io = oe ? ~latch : 8'bz;
+endmodule
+
+module abc9_test012(inout io, input oe);
+reg latch;
+//always @(io or oe)
+// if (!oe)
+// latch <= io;
+assign io = oe ? ~latch : 8'bz;
+endmodule
+
+module abc9_test013(inout [3:0] io, input oe);
+reg [3:0] latch;
+always @(io or oe)
+ if (!oe)
+ latch[3:0] <= io[3:0];
+ else
+ latch[7:4] <= io;
+assign io[3:0] = oe ? ~latch[3:0] : 4'bz;
+assign io[7:4] = !oe ? {latch[4], latch[7:3]} : 4'bz;
+endmodule
+
+module abc9_test014(inout [7:0] io, input oe);
+abc9_test012_sub sub(io, oe);
+endmodule
+
+module abc9_test012_sub(inout [7:0] io, input oe);
+reg [7:0] latch;
+always @(io or oe)
+ if (!oe)
+ latch[3:0] <= io;
+ else
+ latch[7:4] <= io;
+assign io[3:0] = oe ? ~latch[3:0] : 4'bz;
+assign io[7:4] = !oe ? {latch[4], latch[7:3]} : 4'bz;
+endmodule
+
+module abc9_test015(input a, output b, input c);
+assign b = ~a;
+(* keep *) wire d;
+assign d = ~c;
+endmodule
+
+module abc9_test016(input a, output b);
+assign b = ~a;
+(* keep *) reg c;
+always @* c <= ~a;
+endmodule
+
+module abc9_test017(input a, output b);
+assign b = ~a;
+(* keep *) reg c;
+always @* c = b;
+endmodule
+
+module abc9_test018(input a, output b, output c);
+assign b = ~a;
+(* keep *) wire [1:0] d;
+assign c = &d;
+endmodule
+
+module abc9_test019(input a, output b);
+assign b = ~a;
+(* keep *) reg [1:0] c;
+reg d;
+always @* d <= &c;
+endmodule
+
+module abc9_test020(input a, output b);
+assign b = ~a;
+(* keep *) reg [1:0] c;
+(* keep *) reg d;
+always @* d <= &c;
+endmodule
+
+// Citation: https://github.com/alexforencich/verilog-ethernet
+module abc9_test021(clk, rst, s_eth_hdr_valid, s_eth_hdr_ready, s_eth_dest_mac, s_eth_src_mac, s_eth_type, s_eth_payload_axis_tdata, s_eth_payload_axis_tkeep, s_eth_payload_axis_tvalid, s_eth_payload_axis_tready, s_eth_payload_axis_tlast, s_eth_payload_axis_tid, s_eth_payload_axis_tdest, s_eth_payload_axis_tuser, m_eth_hdr_valid, m_eth_hdr_ready, m_eth_dest_mac, m_eth_src_mac, m_eth_type, m_eth_payload_axis_tdata, m_eth_payload_axis_tkeep, m_eth_payload_axis_tvalid, m_eth_payload_axis_tready, m_eth_payload_axis_tlast, m_eth_payload_axis_tid, m_eth_payload_axis_tdest, m_eth_payload_axis_tuser);
+ input clk;
+ output [47:0] m_eth_dest_mac;
+ input m_eth_hdr_ready;
+ output m_eth_hdr_valid;
+ output [7:0] m_eth_payload_axis_tdata;
+ output [7:0] m_eth_payload_axis_tdest;
+ output [7:0] m_eth_payload_axis_tid;
+ output m_eth_payload_axis_tkeep;
+ output m_eth_payload_axis_tlast;
+ input m_eth_payload_axis_tready;
+ output m_eth_payload_axis_tuser;
+ output m_eth_payload_axis_tvalid;
+ output [47:0] m_eth_src_mac;
+ output [15:0] m_eth_type;
+ input rst;
+ input [191:0] s_eth_dest_mac;
+ output [3:0] s_eth_hdr_ready;
+ input [3:0] s_eth_hdr_valid;
+ input [31:0] s_eth_payload_axis_tdata;
+ input [31:0] s_eth_payload_axis_tdest;
+ input [31:0] s_eth_payload_axis_tid;
+ input [3:0] s_eth_payload_axis_tkeep;
+ input [3:0] s_eth_payload_axis_tlast;
+ output [3:0] s_eth_payload_axis_tready;
+ input [3:0] s_eth_payload_axis_tuser;
+ input [3:0] s_eth_payload_axis_tvalid;
+ input [191:0] s_eth_src_mac;
+ input [63:0] s_eth_type;
+ (* keep *)
+ wire [0:0] grant, request;
+ wire a;
+ not u0 (
+ a,
+ grant[0]
+ );
+ and u1 (
+ request[0],
+ s_eth_hdr_valid[0],
+ a
+ );
+ (* keep *)
+ MUXF8 u2 (
+ .I0(1'bx),
+ .I1(1'bx),
+ .O(o),
+ .S(1'bx)
+ );
+ arbiter arb_inst (
+ .acknowledge(acknowledge),
+ .clk(clk),
+ .grant(grant),
+ .grant_encoded(grant_encoded),
+ .grant_valid(grant_valid),
+ .request(request),
+ .rst(rst)
+ );
+endmodule
+
+module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encoded);
+ input [3:0] acknowledge;
+ input clk;
+ output [3:0] grant;
+ output [1:0] grant_encoded;
+ output grant_valid;
+ input [3:0] request;
+ input rst;
+endmodule
+
+(* abc_box_id=1 *)
+module MUXF8(input I0, I1, S, output O);
+endmodule
+
+// Citation: https://github.com/alexforencich/verilog-ethernet
+// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test022" abc9.v -q
+// returns before b4321a31
+// Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [7] is used but has no
+// driver.
+// Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [3] is used but has no
+// driver.
+module abc9_test022
+(
+ input wire clk,
+ input wire i,
+ output wire [7:0] m_eth_payload_axis_tkeep
+);
+ reg [7:0] m_eth_payload_axis_tkeep_reg = 8'd0;
+ assign m_eth_payload_axis_tkeep = m_eth_payload_axis_tkeep_reg;
+ always @(posedge clk)
+ m_eth_payload_axis_tkeep_reg <= i ? 8'hff : 8'h0f;
+endmodule
+
+// Citation: https://github.com/riscv/riscv-bitmanip
+// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test023" abc9.v -q
+// returns before 14233843
+// Warning: Wire abc9_test023.\dout [1] is used but has no driver.
+module abc9_test023 #(
+ parameter integer N = 2,
+ parameter integer M = 2
+) (
+ input [7:0] din,
+ output [M-1:0] dout
+);
+ wire [2*M-1:0] mask = {M{1'b1}};
+ assign dout = (mask << din[N-1:0]) >> M;
+endmodule
+
+module abc9_test024(input [3:0] i, output [3:0] o);
+abc9_test024_sub a(i[1:0], o[1:0]);
+endmodule
+
+module abc9_test024_sub(input [1:0] i, output [1:0] o);
+assign o = i;
+endmodule
+
+module abc9_test025(input [3:0] i, output [3:0] o);
+abc9_test024_sub a(i[2:1], o[2:1]);
+endmodule
+
+module abc9_test026(output [3:0] o, p);
+assign o = { 1'b1, 1'bx };
+assign p = { 1'b1, 1'bx, 1'b0 };
+endmodule
diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh
new file mode 100755
index 000000000..49ae23338
--- /dev/null
+++ b/tests/simple_abc9/run-test.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+OPTIND=1
+seed="" # default to no seed specified
+while getopts "S:" opt
+do
+ case "$opt" in
+ S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space
+ seed="SEED=$arg" ;;
+ esac
+done
+shift "$((OPTIND-1))"
+
+# check for Icarus Verilog
+if ! which iverilog > /dev/null ; then
+ echo "$0: Error: Icarus Verilog 'iverilog' not found."
+ exit 1
+fi
+
+cp ../simple/*.v .
+cp ../simple/*.sv .
+DOLLAR='?'
+exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-n 300 -p 'hierarchy; synth -run coarse; opt -full; techmap; abc9 -lut 4 -box ../abc.box; stat; check -assert; select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
diff --git a/tests/techmap/recursive.v b/tests/techmap/recursive.v
new file mode 100644
index 000000000..d281b21d8
--- /dev/null
+++ b/tests/techmap/recursive.v
@@ -0,0 +1,8 @@
+module top;
+sub s0();
+foo f0();
+endmodule
+
+module foo;
+sub s0();
+endmodule
diff --git a/tests/techmap/recursive_map.v b/tests/techmap/recursive_map.v
new file mode 100644
index 000000000..934256552
--- /dev/null
+++ b/tests/techmap/recursive_map.v
@@ -0,0 +1,4 @@
+module sub;
+ sub _TECHMAP_REPLACE_ ();
+ bar f0();
+endmodule
diff --git a/tests/techmap/recursive_runtest.sh b/tests/techmap/recursive_runtest.sh
new file mode 100644
index 000000000..30c79bf03
--- /dev/null
+++ b/tests/techmap/recursive_runtest.sh
@@ -0,0 +1,3 @@
+set -ev
+
+../../yosys -p 'hierarchy -top top; techmap -map recursive_map.v -max_iter 1; select -assert-count 2 t:sub; select -assert-count 2 t:bar' recursive.v
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index 96d9cdda9..4d3478628 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -23,12 +23,13 @@ warn_iverilog_git=false
# The tests are skipped if firrtl2verilog is the empty string (the default).
firrtl2verilog=""
xfirrtl="../xfirrtl"
+abcprog="$toolsdir/../../yosys-abc"
if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then
( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1
fi
-while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do
+while getopts xmGl:wkjvref:s:p:n:S:I:A:-: opt; do
case "$opt" in
x)
use_xsim=true ;;
@@ -65,6 +66,8 @@ while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do
include_opts="$include_opts -I $OPTARG"
xinclude_opts="$xinclude_opts -i $OPTARG"
minclude_opts="$minclude_opts +incdir+$OPTARG" ;;
+ A)
+ abcprog="$OPTARG" ;;
-)
case "${OPTARG}" in
xfirrtl)
@@ -147,14 +150,14 @@ do
if [[ "$ext" == "v" ]]; then
egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
elif [[ "$ext" == "aig" ]] || [[ "$ext" == "aag" ]]; then
- "$toolsdir"/../../yosys-abc -c "read_aiger ../${fn}; write ${bn}_ref.${refext}"
+ $abcprog -c "read_aiger ../${fn}; write ${bn}_ref.${refext}"
else
refext=$ext
cp ../${fn} ${bn}_ref.${refext}
fi
if [ ! -f ../${bn}_tb.v ]; then
- "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.${refext}
+ "$toolsdir"/../../yosys -f "$frontend $include_opts -D_AUTOTB" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.${refext}
else
cp ../${bn}_tb.v ${bn}_tb.v
fi
diff --git a/tests/various/.gitignore b/tests/various/.gitignore
index 397b4a762..4b286fd61 100644
--- a/tests/various/.gitignore
+++ b/tests/various/.gitignore
@@ -1 +1,5 @@
-*.log
+/*.log
+/*.out
+/write_gzip.v
+/write_gzip.v.gz
+/run-test.mk
diff --git a/tests/various/abc9.v b/tests/various/abc9.v
new file mode 100644
index 000000000..a08b613a8
--- /dev/null
+++ b/tests/various/abc9.v
@@ -0,0 +1,9 @@
+module abc9_test027(output reg o);
+initial o = 1'b0;
+always @*
+ o <= ~o;
+endmodule
+
+module abc9_test028(input i, output o);
+unknown u(~i, o);
+endmodule
diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys
new file mode 100644
index 000000000..5c9a4075d
--- /dev/null
+++ b/tests/various/abc9.ys
@@ -0,0 +1,24 @@
+read_verilog abc9.v
+design -save read
+hierarchy -top abc9_test027
+proc
+design -save gold
+
+abc9 -lut 4
+check
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top abc9_test028
+proc
+
+abc9 -lut 4
+select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i
+select -assert-count 1 t:unknown
+select -assert-none t:$lut t:unknown %% t: %D
diff --git a/tests/various/async.sh b/tests/various/async.sh
new file mode 100644
index 000000000..7c41d6d94
--- /dev/null
+++ b/tests/various/async.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+set -ex
+../../yosys -q -o async_syn.v -p 'synth; rename uut syn' async.v
+../../yosys -q -o async_prp.v -p 'prep; rename uut prp' async.v
+../../yosys -q -o async_a2s.v -p 'prep; async2sync; rename uut a2s' async.v
+../../yosys -q -o async_ffl.v -p 'prep; clk2fflogic; rename uut ffl' async.v
+iverilog -o async_sim -DTESTBENCH async.v async_???.v
+vvp -N async_sim > async.out
+tail async.out
+grep PASS async.out
+rm -f async_???.v async_sim async.out async.vcd
diff --git a/tests/various/async.v b/tests/various/async.v
new file mode 100644
index 000000000..c27e30c4b
--- /dev/null
+++ b/tests/various/async.v
@@ -0,0 +1,108 @@
+`define MAXQ 2
+module uut (
+ input clk,
+ input d, r, e,
+ output [`MAXQ:0] q
+);
+ reg q0;
+ always @(posedge clk) begin
+ if (r)
+ q0 <= 0;
+ else if (e)
+ q0 <= d;
+ end
+
+ reg q1;
+ always @(posedge clk, posedge r) begin
+ if (r)
+ q1 <= 0;
+ else if (e)
+ q1 <= d;
+ end
+
+ reg q2;
+ always @(posedge clk, negedge r) begin
+ if (!r)
+ q2 <= 0;
+ else if (!e)
+ q2 <= d;
+ end
+
+ assign q = {q2, q1, q0};
+endmodule
+
+`ifdef TESTBENCH
+module \$ff #(
+ parameter integer WIDTH = 1
+) (
+ input [WIDTH-1:0] D,
+ output reg [WIDTH-1:0] Q
+);
+ wire sysclk = testbench.sysclk;
+ always @(posedge sysclk)
+ Q <= D;
+endmodule
+
+module testbench;
+ reg sysclk;
+ always #5 sysclk = (sysclk === 1'b0);
+
+ reg clk;
+ always @(posedge sysclk) clk = (clk === 1'b0);
+
+ reg d, r, e;
+
+ wire [`MAXQ:0] q_uut;
+ uut uut (.clk(clk), .d(d), .r(r), .e(e), .q(q_uut));
+
+ wire [`MAXQ:0] q_syn;
+ syn syn (.clk(clk), .d(d), .r(r), .e(e), .q(q_syn));
+
+ wire [`MAXQ:0] q_prp;
+ prp prp (.clk(clk), .d(d), .r(r), .e(e), .q(q_prp));
+
+ wire [`MAXQ:0] q_a2s;
+ a2s a2s (.clk(clk), .d(d), .r(r), .e(e), .q(q_a2s));
+
+ wire [`MAXQ:0] q_ffl;
+ ffl ffl (.clk(clk), .d(d), .r(r), .e(e), .q(q_ffl));
+
+ task printq;
+ reg [5*8-1:0] msg;
+ begin
+ msg = "OK";
+ if (q_uut !== q_syn) msg = "SYN";
+ if (q_uut !== q_prp) msg = "PRP";
+ if (q_uut !== q_a2s) msg = "A2S";
+ if (q_uut !== q_ffl) msg = "FFL";
+ $display("%6t %b %b %b %b %b %s", $time, q_uut, q_syn, q_prp, q_a2s, q_ffl, msg);
+ if (msg != "OK") $finish;
+ end
+ endtask
+
+ initial if(0) begin
+ $dumpfile("async.vcd");
+ $dumpvars(0, testbench);
+ end
+
+ initial begin
+ @(posedge clk);
+ d <= 0;
+ r <= 0;
+ e <= 0;
+ @(posedge clk);
+ e <= 1;
+ @(posedge clk);
+ e <= 0;
+ repeat (10000) begin
+ @(posedge clk);
+ printq;
+ d <= $random;
+ r <= $random;
+ e <= $random;
+ end
+ $display("PASS");
+ $finish;
+ end
+endmodule
+`endif
diff --git a/tests/various/gzip_verilog.v.gz b/tests/various/gzip_verilog.v.gz
new file mode 100644
index 000000000..c52a95358
--- /dev/null
+++ b/tests/various/gzip_verilog.v.gz
Binary files differ
diff --git a/tests/various/gzip_verilog.ys b/tests/various/gzip_verilog.ys
new file mode 100644
index 000000000..870317e80
--- /dev/null
+++ b/tests/various/gzip_verilog.ys
@@ -0,0 +1,2 @@
+read_verilog gzip_verilog.v.gz
+select -assert-any top
diff --git a/tests/various/mem2reg.ys b/tests/various/mem2reg.ys
new file mode 100644
index 000000000..85d6267c5
--- /dev/null
+++ b/tests/various/mem2reg.ys
@@ -0,0 +1,14 @@
+read_verilog <<EOT
+module top;
+parameter DATADEPTH=2;
+parameter DATAWIDTH=1;
+(* keep, nomem2reg *) reg [DATAWIDTH-1:0] data1 [DATADEPTH-1:0];
+(* keep, mem2reg *) reg [DATAWIDTH-1:0] data2 [DATADEPTH-1:0];
+endmodule
+EOT
+
+proc
+cd top
+select -assert-count 1 m:data1 a:src=<<EOT:4 %i
+select -assert-count 2 w:data2[*] a:src=<<EOT:5 %i
+select -assert-none a:mem2reg
diff --git a/tests/various/muxcover.ys b/tests/various/muxcover.ys
index 7ac460f13..67e9625e6 100644
--- a/tests/various/muxcover.ys
+++ b/tests/various/muxcover.ys
@@ -13,7 +13,7 @@ read_verilog -formal <<EOT
EOT
-## Examle usage for "pmuxtree" and "muxcover"
+## Example usage for "pmuxtree" and "muxcover"
proc
pmuxtree
@@ -49,3 +49,462 @@ hierarchy -top equiv
equiv_simple -undef
equiv_status -assert
+## Partial matching MUX4
+
+design -reset
+read_verilog -formal <<EOT
+module mux_if_bal_3_1 #(parameter N=3, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {{W{{1'bx}}}};
+ if (s[0] == 1'b0)
+ if (s[1] == 1'b0)
+ o <= i[0*W+:W];
+ else
+ o <= i[1*W+:W];
+ else
+ if (s[1] == 1'b0)
+ o <= i[2*W+:W];
+end
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux4=150
+select -assert-count 0 t:$_MUX_
+select -assert-count 1 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX4_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## Partial matching MUX8
+
+design -reset
+read_verilog -formal <<EOT
+module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {{W{{1'bx}}}};
+ if (s[0] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ o <= i[0*W+:W];
+ else
+ o <= i[1*W+:W];
+ else
+ if (s[2] == 1'b0)
+ o <= i[2*W+:W];
+ else
+ o <= i[3*W+:W];
+ else
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ o <= i[4*W+:W];
+end
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux4=150 -mux8=200
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 1 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX8_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## Partial matching MUX16
+
+design -reset
+read_verilog -formal <<EOT
+module mux_if_bal_9_1 #(parameter N=9, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {{W{{1'bx}}}};
+ if (s[0] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ if (s[3] == 1'b0)
+ o <= i[0*W+:W];
+ else
+ o <= i[1*W+:W];
+ else
+ if (s[3] == 1'b0)
+ o <= i[2*W+:W];
+ else
+ o <= i[3*W+:W];
+ else
+ if (s[2] == 1'b0)
+ if (s[3] == 1'b0)
+ o <= i[4*W+:W];
+ else
+ o <= i[5*W+:W];
+ else
+ if (s[3] == 1'b0)
+ o <= i[6*W+:W];
+ else
+ o <= i[7*W+:W];
+ else
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ if (s[3] == 1'b0)
+ o <= i[8*W+:W];
+end
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux4=150 -mux8=200 -mux16=250
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX2 in MUX4 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux2in4(input [1:0] i, input s, output o);
+ assign o = s ? i[1] : i[0];
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux4=99 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 1 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX4_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX2 in MUX8 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux2in8(input [1:0] i, input s, output o);
+ assign o = s ? i[1] : i[0];
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux8=99 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 1 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX8_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX4 in MUX8 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux4in8(input [3:0] i, input [1:0] s, output o);
+ assign o = s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0]);
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux8=299 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 1 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX8_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX2 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux2in16(input [1:0] i, input s, output o);
+ assign o = s ? i[1] : i[0];
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux16=99 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX4 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux4in16(input [3:0] i, input [1:0] s, output o);
+ assign o = s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0]);
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux16=299 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX8 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux4in16(input [7:0] i, input [2:0] s, output o);
+ assign o = s[2] ? s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0])
+ : s[1] ? (s[0] ? i[7] : i[6]) : (s[0] ? i[5] : i[4]);
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux16=699 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## mux_if_bal_5_1 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {{W{{1'bx}}}};
+ if (s[0] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ o <= i[0*W+:W];
+ else
+ o <= i[1*W+:W];
+ else
+ if (s[2] == 1'b0)
+ o <= i[2*W+:W];
+ else
+ o <= i[3*W+:W];
+ else
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ o <= i[4*W+:W];
+end
+endmodule
+EOT
+prep
+design -save gold
+
+wreduce
+opt -full
+techmap
+muxcover -mux8=350
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 1 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX8_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## mux_if_bal_5_1 (nodecode) :: https://github.com/YosysHQ/yosys/issues/1132
+design -load gold
+
+wreduce
+opt -full
+techmap
+muxcover -mux8=350 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 1 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX8_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## mux_if_bal_9_1 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux_if_bal_9_1 #(parameter N=9, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {{W{{1'bx}}}};
+ if (s[3] == 1'b0)
+ if (s[2] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[0] == 1'b0)
+ o <= i[0*W+:W];
+ else
+ o <= i[1*W+:W];
+ else
+ if (s[0] == 1'b0)
+ o <= i[2*W+:W];
+ else
+ o <= i[3*W+:W];
+ else
+ if (s[1] == 1'b0)
+ if (s[0] == 1'b0)
+ o <= i[4*W+:W];
+ else
+ o <= i[5*W+:W];
+ else
+ if (s[0] == 1'b0)
+ o <= i[6*W+:W];
+ else
+ o <= i[7*W+:W];
+ else
+ if (s[2] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[0] == 1'b0)
+ o <= i[8*W+:W];
+end
+endmodule
+EOT
+prep
+design -save gold
+
+wreduce
+opt -full
+techmap
+muxcover -mux16=750
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## mux_if_bal_9_1 (nodecode) :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -load gold
+
+wreduce
+opt -full
+techmap
+muxcover -mux16=750 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
+sat -verify -prove-asserts -show-ports miter
diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v
new file mode 100644
index 000000000..33ece1f16
--- /dev/null
+++ b/tests/various/muxpack.v
@@ -0,0 +1,259 @@
+module mux_if_unbal_4_1 #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @*
+ if (s == 0) o <= i[0*W+:W];
+ else if (s == 1) o <= i[1*W+:W];
+ else if (s == 2) o <= i[2*W+:W];
+ else if (s == 3) o <= i[3*W+:W];
+ else o <= {W{1'bx}};
+endmodule
+
+module mux_if_unbal_5_3 #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {W{1'bx}};
+ if (s == 0) o <= i[0*W+:W];
+ if (s == 1) o <= i[1*W+:W];
+ if (s == 2) o <= i[2*W+:W];
+ if (s == 3) o <= i[3*W+:W];
+ if (s == 4) o <= i[4*W+:W];
+end
+endmodule
+
+module mux_if_unbal_5_3_invert #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @*
+ if (s != 0)
+ if (s != 1)
+ if (s != 2)
+ if (s != 3)
+ if (s != 4) o <= i[4*W+:W];
+ else o <= i[0*W+:W];
+ else o <= i[3*W+:W];
+ else o <= i[2*W+:W];
+ else o <= i[1*W+:W];
+ else o <= {W{1'bx}};
+endmodule
+
+module mux_if_unbal_5_3_width_mismatch #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {W{1'bx}};
+ if (s == 0) o <= i[0*W+:W];
+ if (s == 1) o <= i[1*W+:W];
+ if (s == 2) o[W-2:0] <= i[2*W+:W-1];
+ if (s == 3) o <= i[3*W+:W];
+ if (s == 4) o <= i[4*W+:W];
+end
+endmodule
+
+module mux_if_unbal_4_1_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ if (s == 0) o <= i[0*W+:W];
+// else if (s == 1) o <= i[1*W+:W];
+// else if (s == 2) o <= i[2*W+:W];
+ else if (s == 3) o <= i[3*W+:W];
+ else o <= {W{1'bx}};
+end
+endmodule
+
+module mux_if_unbal_5_3_order #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {W{1'bx}};
+ if (s == 3) o <= i[3*W+:W];
+ if (s == 2) o <= i[2*W+:W];
+ if (s == 1) o <= i[1*W+:W];
+ if (s == 4) o <= i[4*W+:W];
+ if (s == 0) o <= i[0*W+:W];
+end
+endmodule
+
+module mux_if_unbal_4_1_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @*
+ if (s == 0) o <= i[0*W+:W];
+ else if (s == 1) o <= i[1*W+:W];
+ else if (s == 2) o <= i[2*W+:W];
+ else if (s == 3) o <= i[3*W+:W];
+ else if (s == 0) o <= {W{1'b0}};
+ else o <= {W{1'bx}};
+endmodule
+
+module mux_if_unbal_5_3_nonexcl #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {W{1'bx}};
+ if (s == 0) o <= i[0*W+:W];
+ if (s == 1) o <= i[1*W+:W];
+ if (s == 2) o <= i[2*W+:W];
+ if (s == 3) o <= i[3*W+:W];
+ if (s == 4) o <= i[4*W+:W];
+ if (s == 0) o <= i[2*W+:W];
+end
+endmodule
+
+module mux_case_unbal_8_7#(parameter N=8, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {W{1'bx}};
+ case (s)
+ 0: o <= i[0*W+:W];
+ default:
+ case (s)
+ 1: o <= i[1*W+:W];
+ 2: o <= i[2*W+:W];
+ default:
+ case (s)
+ 3: o <= i[3*W+:W];
+ 4: o <= i[4*W+:W];
+ 5: o <= i[5*W+:W];
+ default:
+ case (s)
+ 6: o <= i[6*W+:W];
+ default: o <= i[7*W+:W];
+ endcase
+ endcase
+ endcase
+ endcase
+end
+endmodule
+
+module mux_if_bal_8_2 #(parameter N=8, parameter W=2) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @*
+ if (s[0] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ o <= i[0*W+:W];
+ else
+ o <= i[1*W+:W];
+ else
+ if (s[2] == 1'b0)
+ o <= i[2*W+:W];
+ else
+ o <= i[3*W+:W];
+ else
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ o <= i[4*W+:W];
+ else
+ o <= i[5*W+:W];
+ else
+ if (s[2] == 1'b0)
+ o <= i[6*W+:W];
+ else
+ o <= i[7*W+:W];
+endmodule
+
+module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @*
+ if (s[0] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ o <= i[0*W+:W];
+ else
+ o <= i[1*W+:W];
+ else
+ if (s[2] == 1'b0)
+ o <= i[2*W+:W];
+ else
+ o <= i[3*W+:W];
+ else
+ o <= i[4*W+:W];
+endmodule
+
+module cliffordwolf_nonexclusive_select (
+ input wire x, y, z,
+ input wire a, b, c, d,
+ output reg o
+);
+ always @* begin
+ o = a;
+ if (x) o = b;
+ if (y) o = c;
+ if (z) o = d;
+ end
+endmodule
+
+module cliffordwolf_freduce (
+ input wire [1:0] s,
+ input wire a, b, c, d,
+ output reg [3:0] o
+);
+ always @* begin
+ o = {4{a}};
+ if (s == 0) o = {3{b}};
+ if (s == 1) o = {2{c}};
+ if (s == 2) o = d;
+ end
+endmodule
+
+module case_nonexclusive_select (
+ input wire [1:0] x, y,
+ input wire a, b, c, d, e,
+ output reg o
+);
+ always @* begin
+ case (x)
+ 0: o = b;
+ 2: o = b;
+ 1: o = c;
+ default: begin
+ o = a;
+ if (y == 0) o = d;
+ if (y == 1) o = e;
+ end
+ endcase
+ end
+endmodule
+
+module case_nonoverlap (
+ input wire [2:0] x,
+ input wire a, b, c, d, e,
+ output reg o
+);
+ always @* begin
+ case (x)
+ 0, 2: o = b; // Creates $reduce_or
+ 1: o = c;
+ default:
+ case (x)
+ 3: o = d; 4: o = d; // Creates $reduce_or
+ 5: o = e;
+ default: o = 1'b0;
+ endcase
+ endcase
+ end
+endmodule
+
+module case_overlap (
+ input wire [2:0] x,
+ input wire a, b, c, d, e,
+ output reg o
+);
+ always @* begin
+ case (x)
+ 0, 2: o = b; // Creates $reduce_or
+ 1: o = c;
+ default:
+ case (x)
+ 0: o = 1'b1; // OVERLAP!
+ 3, 4: o = d; // Creates $reduce_or
+ 5: o = e;
+ default: o = 1'b0;
+ endcase
+ endcase
+ end
+endmodule
+
+module case_overlap2 (
+ input wire [2:0] x,
+ input wire a, b, c, d, e,
+ output reg o
+);
+ always @* begin
+ case (x)
+ 0: o = b; 2: o = b; // Creates $reduce_or
+ 1: o = c;
+ default:
+ case (x)
+ 0: o = d; 2: o = d; // Creates $reduce_or
+ 3: o = d; 4: o = d; // Creates $reduce_or
+ 5: o = e;
+ default: o = 1'b0;
+ endcase
+ endcase
+ end
+endmodule
diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys
new file mode 100644
index 000000000..3e90419af
--- /dev/null
+++ b/tests/various/muxpack.ys
@@ -0,0 +1,268 @@
+read_verilog muxpack.v
+design -save read
+
+hierarchy -top mux_if_unbal_4_1
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_5_3
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+# TODO: Currently ExclusiveDatabase only analyses $eq cells
+#design -load read
+#hierarchy -top mux_if_unbal_5_3_invert
+#prep
+#design -save gold
+#muxpack
+#opt
+#stat
+#select -assert-count 0 t:$mux
+#select -assert-count 1 t:$pmux
+#design -stash gate
+#design -import gold -as gold
+#design -import gate -as gate
+#miter -equiv -flatten -make_assert -make_outputs gold gate miter
+#sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_5_3_width_mismatch
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 2 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_4_1_missing
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_5_3_order
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_4_1_nonexcl
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_5_3_nonexcl
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_case_unbal_8_7
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_bal_8_2
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 7 t:$mux
+select -assert-count 0 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_bal_5_1
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 4 t:$mux
+select -assert-count 0 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top cliffordwolf_nonexclusive_select
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 3 t:$mux
+select -assert-count 0 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+#design -load read
+#hierarchy -top cliffordwolf_freduce
+#prep
+#design -save gold
+#proc; opt; freduce; opt
+#show
+#muxpack
+#opt
+#stat
+#select -assert-count 0 t:$mux
+#select -assert-count 1 t:$pmux
+#design -stash gate
+#design -import gold -as gold
+#design -import gate -as gate
+#miter -equiv -flatten -make_assert -make_outputs gold gate miter
+#sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top case_nonexclusive_select
+prep
+design -save gold
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 2 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top case_nonoverlap
+#prep # Do not prep otherwise $pmux's overlapping entry will get removed
+proc
+design -save gold
+opt -fast -mux_undef
+select -assert-count 2 t:$pmux
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top case_overlap
+#prep # Do not prep otherwise $pmux's overlapping entry will get removed
+proc
+design -save gold
+opt -fast -mux_undef
+select -assert-count 2 t:$pmux
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 2 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top case_overlap2
+#prep # Do not prep otherwise $pmux's overlapping entry will get removed
+proc
+design -save gold
+opt -fast -mux_undef
+select -assert-count 2 t:$pmux
+muxpack
+opt
+#stat
+select -assert-count 0 t:$mux
+select -assert-count 2 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
diff --git a/tests/various/pmgen_reduce.ys b/tests/various/pmgen_reduce.ys
new file mode 100644
index 000000000..c214d3f25
--- /dev/null
+++ b/tests/various/pmgen_reduce.ys
@@ -0,0 +1,21 @@
+test_pmgen -generate reduce
+hierarchy -top pmtest_test_pmgen_pm_reduce
+flatten; opt_clean
+
+design -save gold
+test_pmgen -reduce_chain
+design -stash gate
+
+design -copy-from gold -as gold pmtest_test_pmgen_pm_reduce
+design -copy-from gate -as gate pmtest_test_pmgen_pm_reduce
+miter -equiv -flatten -make_assert gold gate miter
+sat -verify -prove-asserts miter
+
+design -load gold
+test_pmgen -reduce_tree
+design -stash gate
+
+design -copy-from gold -as gold pmtest_test_pmgen_pm_reduce
+design -copy-from gate -as gate pmtest_test_pmgen_pm_reduce
+miter -equiv -flatten -make_assert gold gate miter
+sat -verify -prove-asserts miter
diff --git a/tests/various/pmux2shiftx.v b/tests/various/pmux2shiftx.v
index fec84187b..563394080 100644
--- a/tests/various/pmux2shiftx.v
+++ b/tests/various/pmux2shiftx.v
@@ -32,3 +32,13 @@ module pmux2shiftx_test (
endcase
end
endmodule
+
+module issue01135(input [7:0] i, output o);
+always @*
+case (i[6:3])
+ 4: o <= i[0];
+ 3: o <= i[2];
+ 7: o <= i[3];
+ default: o <= 1'b0;
+endcase
+endmodule
diff --git a/tests/various/pmux2shiftx.ys b/tests/various/pmux2shiftx.ys
index deb134083..51ee2f7be 100644
--- a/tests/various/pmux2shiftx.ys
+++ b/tests/various/pmux2shiftx.ys
@@ -1,4 +1,7 @@
read_verilog pmux2shiftx.v
+design -save read
+
+hierarchy -top pmux2shiftx_test
prep
design -save gold
@@ -21,8 +24,16 @@ design -import gate -as gate
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -show-ports miter
-design -load gold
-stat
-
-design -load gate
-stat
+#design -load gold
+#stat
+#
+#design -load gate
+#stat
+
+design -load read
+hierarchy -top issue01135
+proc
+pmux2shiftx -norange
+opt -full
+select -assert-count 0 t:$shift*
+select -assert-count 1 t:$pmux
diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh
index d49553ede..ea56b70f0 100755
--- a/tests/various/run-test.sh
+++ b/tests/various/run-test.sh
@@ -1,14 +1,20 @@
#!/usr/bin/env bash
set -e
+{
+echo "all::"
for x in *.ys; do
- echo "Running $x.."
- ../../yosys -ql ${x%.ys}.log $x
+ echo "all:: run-$x"
+ echo "run-$x:"
+ echo " @echo 'Running $x..'"
+ echo " @../../yosys -ql ${x%.ys}.log $x"
done
-# Run any .sh files in this directory (with the exception of the file - run-test.sh
-shell_tests=$(echo *.sh | sed -e 's/run-test.sh//')
-if [ "$shell_tests" ]; then
- for s in $shell_tests; do
- echo "Running $s.."
- bash $s
- done
-fi
+for s in *.sh; do
+ if [ "$s" != "run-test.sh" ]; then
+ echo "all:: run-$s"
+ echo "run-$s:"
+ echo " @echo 'Running $s..'"
+ echo " @bash $s"
+ fi
+done
+} > run-test.mk
+exec ${MAKE:-make} -f run-test.mk
diff --git a/tests/various/script.ys b/tests/various/script.ys
new file mode 100644
index 000000000..66b7b5caa
--- /dev/null
+++ b/tests/various/script.ys
@@ -0,0 +1,20 @@
+read_verilog -formal <<EOT
+ module top;
+ foo bar();
+ foo asdf();
+ winnie the_pooh();
+
+ wire [1023:0] _RUNME0 = "select -assert-count 2 t:foo";
+ wire [1023:0] _RUNME1 = "select -assert-count 1 t:winnie";
+ endmodule
+
+ module other;
+ wire [1023:0] _DELETE = "cd; delete c:bar";
+ endmodule
+EOT
+
+script -scriptwire w:_RUNME*
+
+select w:_DELETE
+script -scriptwire
+select -assert-count 1 t:foo
diff --git a/tests/various/shregmap.v b/tests/various/shregmap.v
new file mode 100644
index 000000000..604c2c976
--- /dev/null
+++ b/tests/various/shregmap.v
@@ -0,0 +1,48 @@
+module shregmap_static_test(input i, clk, output [1:0] q);
+reg head = 1'b0;
+reg [3:0] shift1 = 4'b0000;
+reg [3:0] shift2 = 4'b0000;
+
+always @(posedge clk) begin
+ head <= i;
+ shift1 <= {shift1[2:0], head};
+ shift2 <= {shift2[2:0], head};
+end
+
+assign q = {shift2[3], shift1[3]};
+endmodule
+
+module $__SHREG_DFF_P_(input C, D, output Q);
+parameter DEPTH = 1;
+parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
+reg [DEPTH-1:0] r = INIT;
+always @(posedge C)
+ r <= { r[DEPTH-2:0], D };
+assign Q = r[DEPTH-1];
+endmodule
+
+module shregmap_variable_test(input i, clk, input [1:0] l1, l2, output [1:0] q);
+reg head = 1'b0;
+reg [3:0] shift1 = 4'b0000;
+reg [3:0] shift2 = 4'b0000;
+
+always @(posedge clk) begin
+ head <= i;
+ shift1 <= {shift1[2:0], head};
+ shift2 <= {shift2[2:0], head};
+end
+
+assign q = {shift2[l2], shift1[l1]};
+endmodule
+
+module $__XILINX_SHREG_(input C, D, input [1:0] L, output Q);
+parameter CLKPOL = 1;
+parameter ENPOL = 1;
+parameter DEPTH = 1;
+parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}};
+reg [DEPTH-1:0] r = INIT;
+wire clk = C ^ CLKPOL;
+always @(posedge C)
+ r <= { r[DEPTH-2:0], D };
+assign Q = r[L];
+endmodule
diff --git a/tests/various/shregmap.ys b/tests/various/shregmap.ys
new file mode 100644
index 000000000..0e5fe882b
--- /dev/null
+++ b/tests/various/shregmap.ys
@@ -0,0 +1,66 @@
+read_verilog shregmap.v
+design -save read
+
+design -copy-to model $__SHREG_DFF_P_
+hierarchy -top shregmap_static_test
+prep
+design -save gold
+
+techmap
+shregmap -init
+
+opt
+
+# stat
+# show -width
+select -assert-count 1 t:$_DFF_P_
+select -assert-count 2 t:$__SHREG_DFF_P_
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+design -copy-from model -as $__SHREG_DFF_P_ \$__SHREG_DFF_P_
+prep
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports -seq 5 miter
+
+#design -load gold
+#stat
+
+#design -load gate
+#stat
+
+##########
+
+design -load read
+design -copy-to model $__XILINX_SHREG_
+hierarchy -top shregmap_variable_test
+prep
+design -save gold
+
+simplemap t:$dff t:$dffe
+shregmap -tech xilinx
+
+#stat
+# show -width
+# write_verilog -noexpr -norename
+select -assert-count 1 t:$_DFF_P_
+select -assert-count 2 t:$__XILINX_SHREG_
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_
+prep
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports -seq 5 miter
+
+# design -load gold
+# stat
+
+# design -load gate
+# stat
diff --git a/tests/various/signext.ys b/tests/various/signext.ys
new file mode 100644
index 000000000..0c8d671e7
--- /dev/null
+++ b/tests/various/signext.ys
@@ -0,0 +1,33 @@
+
+read_verilog -formal <<EOT
+module gate(input clk, output [32:0] o, p, q, r, s, t, u);
+assign o = 'bx;
+assign p = 1'bx;
+assign q = 'bz;
+assign r = 1'bz;
+assign s = 1'b0;
+assign t = 'b1;
+assign u = -'sb1;
+endmodule
+EOT
+
+proc
+
+## Equivalence checking
+
+read_verilog -formal <<EOT
+module gold(input clk, output [32:0] o, p, q, r, s, t, u);
+assign o = {33{1'bx}};
+assign p = {{32{1'b0}}, 1'bx};
+assign q = {33{1'bz}};
+assign r = {{32{1'b0}}, 1'bz};
+assign s = {33{1'b0}};
+assign t = {{32{1'b0}}, 1'b1};
+assign u = {33{1'b1}};
+endmodule
+EOT
+
+proc
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports -enable_undef miter
diff --git a/tests/various/specify.v b/tests/various/specify.v
index afc421da8..5d44d78f7 100644
--- a/tests/various/specify.v
+++ b/tests/various/specify.v
@@ -7,9 +7,11 @@ module test (
if (EN) Q <= D;
specify
- if (EN) (CLK *> (Q : D)) = (1, 2:3:4);
+`ifndef SKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS
+ if (EN) (posedge CLK *> (Q : D)) = (1, 2:3:4);
$setup(D, posedge CLK &&& EN, 5);
$hold(posedge CLK, D &&& EN, 6);
+`endif
endspecify
endmodule
@@ -28,3 +30,10 @@ module test2 (
(B => Q) = 1.5;
endspecify
endmodule
+
+module issue01144(input clk, d, output q);
+specify
+ (posedge clk => (q +: d)) = (3,1);
+ (posedge clk *> (q +: d)) = (3,1);
+endspecify
+endmodule
diff --git a/tests/various/specify.ys b/tests/various/specify.ys
index a5ca07219..00597e1e2 100644
--- a/tests/various/specify.ys
+++ b/tests/various/specify.ys
@@ -54,3 +54,5 @@ equiv_struct
equiv_induct -seq 5
equiv_status -assert
design -reset
+
+read_verilog -DSKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS specify.v
diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys
new file mode 100644
index 000000000..2e0812c48
--- /dev/null
+++ b/tests/various/wreduce.ys
@@ -0,0 +1,79 @@
+read_verilog <<EOT
+module wreduce_sub_test(input [3:0] i, input [7:0] j, output [8:0] o);
+ assign o = (j >> 4) - i;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+opt_expr
+wreduce
+
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+##########
+
+read_verilog <<EOT
+module wreduce_sub_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
+ assign o = (j >>> 4) - i;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+opt_expr
+wreduce
+
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+##########
+
+# Testcase from: https://github.com/YosysHQ/yosys/commit/25680f6a078bb32f157bd580705656496717bafb
+design -reset
+read_verilog <<EOT
+module top(
+ input clk,
+ input rst,
+ input [2:0] a,
+ output [1:0] b
+);
+ reg [2:0] b_reg;
+ initial begin
+ b_reg <= 3'b0;
+ end
+
+ assign b = b_reg[1:0];
+ always @(posedge clk or posedge rst) begin
+ if(rst) begin
+ b_reg <= 3'b0;
+ end else begin
+ b_reg <= a;
+ end
+ end
+endmodule
+EOT
+
+proc
+wreduce
+
+select -assert-count 1 t:$adff r:ARST_VALUE=2'b00 %i
diff --git a/tests/various/write_gzip.ys b/tests/various/write_gzip.ys
new file mode 100644
index 000000000..524ecc33e
--- /dev/null
+++ b/tests/various/write_gzip.ys
@@ -0,0 +1,16 @@
+read_verilog <<EOT
+module top(input a, output y);
+assign y = !a;
+endmodule
+EOT
+
+prep -top top
+write_verilog write_gzip.v.gz
+design -reset
+
+! rm -f write_gzip.v
+! gunzip write_gzip.v.gz
+read_verilog write_gzip.v
+! rm -f write_gzip.v
+hierarchy -top top
+select -assert-any top