summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2019-03-28 23:36:07 +0100
committerRuben Undheim <ruben.undheim@gmail.com>2019-03-28 23:36:07 +0100
commitba2a8c73889c487be2400372260e18e8a82877f6 (patch)
treeec26eec3e633e1d68636a63d9588384631ec2ee5
parentb08bbcdcfe7c703ad549866f2a22a0c5ecda3dfe (diff)
parentff5734b20220e6fb4a3913cf5279ed94bb5156ea (diff)
Merge tag 'upstream/0.8+20190328git32bd0f2'
-rw-r--r--.editorconfig7
-rw-r--r--.github/issue_template.md16
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml10
-rwxr-xr-x.travis/build-and-test.sh2
-rwxr-xr-x.travis/setup.sh50
-rw-r--r--CHANGELOG15
-rw-r--r--COPYING2
-rw-r--r--Makefile32
-rw-r--r--README.md53
-rw-r--r--backends/aiger/aiger.cc38
-rw-r--r--backends/btor/btor.cc118
-rw-r--r--backends/edif/edif.cc57
-rw-r--r--backends/firrtl/firrtl.cc284
-rw-r--r--backends/ilang/ilang_backend.cc2
-rw-r--r--backends/protobuf/protobuf.cc6
-rw-r--r--backends/simplec/simplec.cc2
-rw-r--r--backends/simplec/test00_uut.v6
-rw-r--r--backends/smt2/Makefile.inc18
-rw-r--r--backends/smt2/smt2.cc24
-rw-r--r--backends/smt2/smtbmc.py125
-rw-r--r--backends/smt2/smtio.py31
-rw-r--r--backends/smv/smv.cc83
-rw-r--r--backends/table/table.cc2
-rw-r--r--backends/verilog/verilog_backend.cc189
-rw-r--r--examples/anlogic/.gitignore7
-rw-r--r--examples/anlogic/README12
-rwxr-xr-xexamples/anlogic/build.sh4
-rw-r--r--examples/anlogic/build.tcl11
-rw-r--r--examples/anlogic/demo.adc2
-rw-r--r--examples/anlogic/demo.v18
-rw-r--r--examples/anlogic/demo.ys3
-rw-r--r--examples/igloo2/.gitignore4
-rw-r--r--examples/igloo2/example.pdc20
-rw-r--r--examples/igloo2/example.sdc2
-rw-r--r--examples/igloo2/example.v64
-rw-r--r--examples/igloo2/libero.tcl57
-rw-r--r--examples/igloo2/runme.sh6
-rw-r--r--frontends/aiger/Makefile.inc3
-rw-r--r--frontends/aiger/aigerparse.cc414
-rw-r--r--frontends/aiger/aigerparse.h51
-rw-r--r--frontends/ast/ast.cc331
-rw-r--r--frontends/ast/ast.h18
-rw-r--r--frontends/ast/genrtlil.cc205
-rw-r--r--frontends/ast/simplify.cc286
-rw-r--r--frontends/blif/blifparse.cc4
-rw-r--r--frontends/ilang/ilang_frontend.cc30
-rw-r--r--frontends/ilang/ilang_frontend.h2
-rw-r--r--frontends/ilang/ilang_parser.y42
-rw-r--r--frontends/liberty/liberty.cc15
-rw-r--r--frontends/verific/README31
-rw-r--r--frontends/verific/verific.cc534
-rw-r--r--frontends/verific/verific.h1
-rw-r--r--frontends/verific/verificsva.cc23
-rw-r--r--frontends/verilog/verilog_frontend.cc52
-rw-r--r--frontends/verilog/verilog_frontend.h9
-rw-r--r--frontends/verilog/verilog_lexer.l21
-rw-r--r--frontends/verilog/verilog_parser.y387
-rw-r--r--kernel/celltypes.h66
-rw-r--r--kernel/consteval.h9
-rw-r--r--kernel/driver.cc18
-rw-r--r--kernel/hashlib.h6
-rw-r--r--kernel/log.cc4
-rw-r--r--kernel/log.h6
-rw-r--r--kernel/register.cc2
-rw-r--r--kernel/rtlil.cc34
-rw-r--r--kernel/rtlil.h78
-rw-r--r--kernel/yosys.cc49
-rw-r--r--libs/ezsat/ezminisat.h2
-rw-r--r--libs/subcircuit/README6
-rw-r--r--manual/CHAPTER_CellLib.tex67
-rw-r--r--manual/CHAPTER_Overview.tex4
-rw-r--r--misc/launcher.c358
-rw-r--r--misc/yosys.proto12
-rw-r--r--passes/cmds/Makefile.inc2
-rw-r--r--passes/cmds/bugpoint.cc369
-rw-r--r--passes/cmds/chformal.cc4
-rw-r--r--passes/cmds/connect.cc6
-rw-r--r--passes/cmds/rename.cc148
-rw-r--r--passes/cmds/select.cc60
-rw-r--r--passes/cmds/setundef.cc22
-rw-r--r--passes/cmds/show.cc2
-rw-r--r--passes/cmds/tee.cc4
-rw-r--r--passes/equiv/Makefile.inc2
-rw-r--r--passes/equiv/equiv_make.cc86
-rw-r--r--passes/equiv/equiv_opt.cc157
-rw-r--r--passes/fsm/fsm_detect.cc8
-rw-r--r--passes/fsm/fsm_extract.cc4
-rw-r--r--passes/fsm/fsm_opt.cc3
-rw-r--r--passes/hierarchy/hierarchy.cc279
-rw-r--r--passes/hierarchy/uniquify.cc2
-rw-r--r--passes/memory/memory_bram.cc44
-rw-r--r--passes/memory/memory_collect.cc3
-rw-r--r--passes/memory/memory_dff.cc2
-rw-r--r--passes/opt/Makefile.inc1
-rw-r--r--passes/opt/opt_expr.cc240
-rw-r--r--passes/opt/opt_lut.cc607
-rw-r--r--passes/opt/opt_muxtree.cc18
-rw-r--r--passes/opt/opt_rmdff.cc13
-rw-r--r--passes/opt/share.cc8
-rw-r--r--passes/opt/wreduce.cc129
-rw-r--r--passes/pmgen/.gitignore1
-rw-r--r--passes/pmgen/Makefile.inc8
-rw-r--r--passes/pmgen/README.md224
-rw-r--r--passes/pmgen/ice40_dsp.cc237
-rw-r--r--passes/pmgen/ice40_dsp.pmg160
-rw-r--r--passes/pmgen/pmgen.py486
-rw-r--r--passes/proc/proc_clean.cc44
-rw-r--r--passes/sat/Makefile.inc4
-rw-r--r--passes/sat/async2sync.cc53
-rw-r--r--passes/sat/cutpoint.cc168
-rw-r--r--passes/sat/fmcombine.cc341
-rw-r--r--passes/sat/mutate.cc956
-rw-r--r--passes/sat/supercover.cc92
-rw-r--r--passes/techmap/Makefile.inc1
-rw-r--r--passes/techmap/abc.cc93
-rw-r--r--passes/techmap/deminout.cc7
-rw-r--r--passes/techmap/dff2dffe.cc35
-rw-r--r--passes/techmap/dffinit.cc33
-rw-r--r--passes/techmap/dfflibmap.cc16
-rw-r--r--passes/techmap/flowmap.cc1613
-rw-r--r--passes/techmap/libparse.cc176
-rw-r--r--passes/techmap/libparse.h10
-rw-r--r--passes/techmap/lut2mux.cc2
-rw-r--r--passes/tests/flowmap/flow.v22
-rw-r--r--passes/tests/flowmap/flowp.v16
-rw-r--r--passes/tests/flowmap/pack1.v11
-rw-r--r--passes/tests/flowmap/pack1p.v11
-rw-r--r--passes/tests/flowmap/pack2.v15
-rw-r--r--passes/tests/flowmap/pack2p.v15
-rw-r--r--passes/tests/flowmap/pack3.v15
-rw-r--r--passes/tests/flowmap/pack3p.v15
-rwxr-xr-xtechlibs/achronix/speedster22i/cells_map.v16
-rwxr-xr-xtechlibs/achronix/speedster22i/cells_sim.v8
-rwxr-xr-xtechlibs/achronix/synth_achronix.cc6
-rw-r--r--techlibs/anlogic/Makefile.inc12
-rw-r--r--techlibs/anlogic/anlogic_determine_init.cc72
-rw-r--r--techlibs/anlogic/anlogic_eqn.cc113
-rw-r--r--techlibs/anlogic/arith_map.v84
-rw-r--r--techlibs/anlogic/cells_map.v61
-rw-r--r--techlibs/anlogic/cells_sim.v103
-rw-r--r--techlibs/anlogic/dram_init_16x4.vh16
-rw-r--r--techlibs/anlogic/drams.txt16
-rw-r--r--techlibs/anlogic/drams_map.v22
-rw-r--r--techlibs/anlogic/eagle_bb.v1028
-rw-r--r--techlibs/anlogic/synth_anlogic.cc213
-rw-r--r--techlibs/common/Makefile.inc3
-rw-r--r--techlibs/common/cmp2lut.v105
-rw-r--r--techlibs/common/gate2lut.v87
-rw-r--r--techlibs/common/prep.cc2
-rw-r--r--techlibs/common/simcells.v4
-rw-r--r--techlibs/common/synth.cc48
-rw-r--r--techlibs/coolrunner2/synth_coolrunner2.cc4
-rw-r--r--techlibs/easic/synth_easic.cc2
-rw-r--r--techlibs/ecp5/.gitignore9
-rw-r--r--techlibs/ecp5/Makefile.inc38
-rw-r--r--techlibs/ecp5/arith_map.v2
-rw-r--r--techlibs/ecp5/bram.txt29
-rwxr-xr-xtechlibs/ecp5/brams_connect.py46
-rwxr-xr-xtechlibs/ecp5/brams_init.py22
-rw-r--r--techlibs/ecp5/brams_map.v115
-rw-r--r--techlibs/ecp5/cells_bb.v666
-rw-r--r--techlibs/ecp5/cells_map.v35
-rw-r--r--techlibs/ecp5/cells_sim.v154
-rw-r--r--techlibs/ecp5/dram.txt1
-rw-r--r--techlibs/ecp5/ecp5_ffinit.cc203
-rw-r--r--techlibs/ecp5/latches_map.v11
-rw-r--r--techlibs/ecp5/synth_ecp5.cc19
-rw-r--r--techlibs/gowin/Makefile.inc1
-rw-r--r--techlibs/gowin/arith_map.v59
-rw-r--r--techlibs/gowin/cells_sim.v6
-rw-r--r--techlibs/gowin/synth_gowin.cc31
-rw-r--r--techlibs/greenpak4/cells_map.v44
-rw-r--r--techlibs/greenpak4/synth_greenpak4.cc2
-rw-r--r--techlibs/ice40/Makefile.inc2
-rw-r--r--techlibs/ice40/brams_map.v4
-rw-r--r--techlibs/ice40/cells_sim.v279
-rw-r--r--techlibs/ice40/ice40_braminit.cc159
-rw-r--r--techlibs/ice40/ice40_ffssr.cc3
-rw-r--r--techlibs/ice40/ice40_opt.cc15
-rw-r--r--techlibs/ice40/ice40_unlut.cc106
-rw-r--r--techlibs/ice40/synth_ice40.cc81
-rw-r--r--techlibs/ice40/tests/.gitignore13
-rw-r--r--techlibs/ice40/tests/test_dsp_map.sh107
-rw-r--r--techlibs/ice40/tests/test_dsp_model.sh11
-rw-r--r--techlibs/ice40/tests/test_dsp_model.v342
-rw-r--r--techlibs/intel/common/brams_map.v16
-rw-r--r--techlibs/intel/cycloneive/arith_map.v10
-rw-r--r--techlibs/intel/cyclonev/cells_map.v4
-rw-r--r--techlibs/intel/cyclonev/cells_sim.v2
-rw-r--r--techlibs/intel/synth_intel.cc4
-rw-r--r--techlibs/sf2/Makefile.inc8
-rw-r--r--techlibs/sf2/arith_map.v21
-rw-r--r--techlibs/sf2/cells_map.v82
-rw-r--r--techlibs/sf2/cells_sim.v327
-rw-r--r--techlibs/sf2/sf2_iobs.cc197
-rw-r--r--techlibs/sf2/synth_sf2.cc246
-rw-r--r--techlibs/xilinx/Makefile.inc3
-rw-r--r--techlibs/xilinx/arith_map.v282
-rw-r--r--techlibs/xilinx/cells_map.v104
-rw-r--r--techlibs/xilinx/cells_sim.v65
-rw-r--r--techlibs/xilinx/cells_xtra.sh20
-rw-r--r--techlibs/xilinx/cells_xtra.v660
-rw-r--r--techlibs/xilinx/ff_map.v42
-rw-r--r--techlibs/xilinx/lut2lut.v65
-rw-r--r--techlibs/xilinx/lut_map.v94
-rw-r--r--techlibs/xilinx/synth_xilinx.cc77
-rw-r--r--tests/aiger/and.aag5
-rw-r--r--tests/aiger/and.aig3
-rw-r--r--tests/aiger/buffer.aag3
-rw-r--r--tests/aiger/buffer.aig2
-rw-r--r--tests/aiger/cnt1.aag3
-rw-r--r--tests/aiger/cnt1.aig3
-rw-r--r--tests/aiger/cnt1e.aag8
-rw-r--r--tests/aiger/cnt1e.aig4
-rw-r--r--tests/aiger/empty.aag1
-rw-r--r--tests/aiger/empty.aig1
-rw-r--r--tests/aiger/false.aag2
-rw-r--r--tests/aiger/false.aig2
-rw-r--r--tests/aiger/halfadder.aag14
-rw-r--r--tests/aiger/halfadder.aig9
-rw-r--r--tests/aiger/inverter.aag3
-rw-r--r--tests/aiger/inverter.aig2
-rw-r--r--tests/aiger/notcnt1.aag4
-rw-r--r--tests/aiger/notcnt1.aig4
-rw-r--r--tests/aiger/notcnt1e.aag8
-rw-r--r--tests/aiger/notcnt1e.aig4
-rw-r--r--tests/aiger/or.aag5
-rw-r--r--tests/aiger/or.aig3
-rwxr-xr-xtests/aiger/run-test.sh24
-rw-r--r--tests/aiger/toggle-re.aag14
-rw-r--r--tests/aiger/toggle-re.aig8
-rw-r--r--tests/aiger/toggle.aag4
-rw-r--r--tests/aiger/toggle.aig4
-rw-r--r--tests/aiger/true.aag2
-rw-r--r--tests/aiger/true.aig2
-rw-r--r--tests/asicworld/code_hdl_models_misc1.v22
-rw-r--r--tests/asicworld/code_hdl_models_mux21_switch.v22
-rw-r--r--tests/asicworld/code_hdl_models_nand_switch.v14
-rw-r--r--tests/asicworld/code_hdl_models_t_gate_switch.v11
-rwxr-xr-xtests/asicworld/run-test.sh2
-rw-r--r--tests/asicworld/xfirrtl23
-rw-r--r--tests/errors/syntax_err01.v4
-rw-r--r--tests/errors/syntax_err02.v7
-rw-r--r--tests/errors/syntax_err03.v7
-rw-r--r--tests/errors/syntax_err04.v4
-rw-r--r--tests/errors/syntax_err05.v4
-rw-r--r--tests/errors/syntax_err06.v6
-rw-r--r--tests/errors/syntax_err07.v6
-rw-r--r--tests/errors/syntax_err08.v6
-rw-r--r--tests/errors/syntax_err09.v3
-rw-r--r--tests/errors/syntax_err10.v3
-rw-r--r--tests/errors/syntax_err11.v3
-rw-r--r--tests/errors/syntax_err12.v7
-rw-r--r--tests/errors/syntax_err13.v4
-rw-r--r--tests/liberty/.gitignore2
-rw-r--r--tests/liberty/busdef.lib81
-rw-r--r--tests/liberty/normal.lib359
-rw-r--r--tests/liberty/processdefs.lib48
-rwxr-xr-xtests/liberty/run-test.sh10
-rw-r--r--tests/liberty/semicolextra.lib48
-rw-r--r--tests/liberty/semicolmissing.lib72
-rw-r--r--tests/liberty/small.v16
-rw-r--r--tests/lut/.gitignore1
-rw-r--r--tests/lut/check_map.ys6
-rw-r--r--tests/lut/map_and.v5
-rw-r--r--tests/lut/map_cmp.v29
-rw-r--r--tests/lut/map_mux.v5
-rw-r--r--tests/lut/map_not.v5
-rw-r--r--tests/lut/map_or.v5
-rw-r--r--tests/lut/map_xor.v5
-rwxr-xr-xtests/lut/run-test.sh6
-rw-r--r--tests/opt/.gitignore1
-rw-r--r--tests/opt/opt_expr_cmp.v40
-rw-r--r--tests/opt/opt_expr_cmp.ys4
-rw-r--r--tests/opt/opt_ff.v21
-rw-r--r--tests/opt/opt_ff.ys3
-rw-r--r--tests/opt/opt_lut.v18
-rw-r--r--tests/opt/opt_lut.ys4
-rw-r--r--tests/opt/opt_lut_elim.il19
-rw-r--r--tests/opt/opt_lut_elim.ys3
-rw-r--r--tests/opt/opt_lut_port.il18
-rw-r--r--tests/opt/opt_lut_port.ys3
-rwxr-xr-xtests/opt/run-test.sh6
-rw-r--r--tests/simple/dff_init.v42
-rw-r--r--tests/simple/generate.v56
-rw-r--r--tests/simple/hierdefparam.v2
-rw-r--r--tests/simple/task_func.v19
-rw-r--r--tests/simple/xfirrtl26
-rw-r--r--tests/sva/basic01.sv2
-rw-r--r--tests/sva/extnets.sv22
-rw-r--r--tests/svinterfaces/.gitignore8
-rwxr-xr-xtests/svinterfaces/run-test.sh6
-rwxr-xr-xtests/svinterfaces/runone.sh44
-rw-r--r--tests/svinterfaces/svinterface1.sv117
-rw-r--r--tests/svinterfaces/svinterface1_ref.v107
-rw-r--r--tests/svinterfaces/svinterface1_tb.v57
-rw-r--r--tests/svinterfaces/svinterface_at_top.sv125
-rw-r--r--tests/svinterfaces/svinterface_at_top_ref.v120
-rw-r--r--tests/svinterfaces/svinterface_at_top_tb.v68
-rw-r--r--tests/svinterfaces/svinterface_at_top_tb_wrapper.v68
-rw-r--r--tests/svinterfaces/svinterface_at_top_wrapper.v33
-rw-r--r--tests/tools/autotest.mk6
-rwxr-xr-xtests/tools/autotest.sh61
-rw-r--r--tests/various/hierarchy.sh59
-rwxr-xr-xtests/various/run-test.sh10
306 files changed, 19211 insertions, 1635 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..4d6f5ef7
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,7 @@
+root = true
+
+[*]
+indent_style = tab
+indent_size = tab
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/.github/issue_template.md b/.github/issue_template.md
index 24e91a4e..5a0723c3 100644
--- a/.github/issue_template.md
+++ b/.github/issue_template.md
@@ -1,9 +1,20 @@
## Steps to reproduce the issue
*Provide instructions for reproducing the issue. Make sure to include
-all neccessary source files. (You can simply drag&drop a .zip file into
+all necessary source files. (You can simply drag&drop a .zip file into
the issue editor.)*
+Also, make sure that the issue is actually reproducable in current git
+master of Yosys.
+
+See https://stackoverflow.com/help/mcve for some information on how to
+create a Minimal, Complete, and Verifiable example (MCVE).
+
+Please do not waste our time with issues that lack sufficient information
+to reproduce the issue easily. We will simply close those issues.
+
+Contact https://www.symbioticeda.com/ if you need commercial support for Yosys.
+
## Expected behavior
*Please describe the behavior you would have expected from the tool.*
@@ -11,6 +22,3 @@ the issue editor.)*
## Actual behavior
*Please describe how the behavior you see differs from the expected behavior.*
-
-**Important Note:** Nobody will be able to help you and/or fix the issue if you
-do not provide sufficient information for reproducing the problem.
diff --git a/.gitignore b/.gitignore
index 48ce458c..e24f7975 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,8 @@
/yosys-abc.exe
/yosys-config
/yosys-smtbmc
+/yosys-smtbmc.exe
+/yosys-smtbmc-script.py
/yosys-filterlib
/yosys-filterlib.exe
/kernel/version_*.cc
diff --git a/.travis.yml b/.travis.yml
index 321c3325..7c6e4e43 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -132,11 +132,11 @@ matrix:
env:
- MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"
- # Latest clang on Mac OS X
- - os: osx
- osx_image: xcode8
- env:
- - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
+# # Latest clang on Mac OS X
+# - os: osx
+# osx_image: xcode9.4
+# env:
+# - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++"
before_install:
- ./.travis/setup.sh
diff --git a/.travis/build-and-test.sh b/.travis/build-and-test.sh
index 096dde64..b8c35041 100755
--- a/.travis/build-and-test.sh
+++ b/.travis/build-and-test.sh
@@ -36,6 +36,8 @@ echo
##########################################################################
+./yosys tests/simple/fiedler-cooley.v
+
echo
echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r'
echo
diff --git a/.travis/setup.sh b/.travis/setup.sh
index 06851578..4af0b8ee 100755
--- a/.travis/setup.sh
+++ b/.travis/setup.sh
@@ -6,48 +6,15 @@ source .travis/common.sh
##########################################################################
-# Fixing Travis's git clone
-echo
-echo 'Fixing git setup...' && echo -en 'travis_fold:start:before_install.git\\r'
-echo
-git fetch --unshallow && git fetch --tags
-
-# For pull requests, we get more info about the git source.
-if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
- echo "- Fetching from pull request source"
- git remote add source https://github.com/$TRAVIS_PULL_REQUEST_SLUG.git
- git fetch source && git fetch --tags
-
- echo "- Fetching the actual pull request"
- git fetch origin pull/$TRAVIS_PULL_REQUEST/head:pull-$TRAVIS_PULL_REQUEST-head
- git fetch origin pull/$TRAVIS_PULL_REQUEST/merge:pull-$TRAVIS_PULL_REQUEST-merge
-
- git log -n 5 --graph pull-$TRAVIS_PULL_REQUEST-merge
-fi
-
-# For building branches we need to fix the "detached head" state.
-if [ z"$TRAVIS_BRANCH" != z ]; then
- TRAVIS_COMMIT_ACTUAL=$(git log --pretty=format:'%H' -n 1)
- echo "- Fixing detached head (current $TRAVIS_COMMIT_ACTUAL -> $TRAVIS_COMMIT)"
- git remote -v
- git branch -v
- if [ x"$(git show-ref -s HEAD)" = x"$TRAVIS_COMMIT" ]; then
- echo "Checked out at $TRAVIS_COMMIT"
- else
- if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
- git fetch source $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from source"
- fi
- git fetch origin $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from origin"
- fi
- git branch -D $TRAVIS_BRANCH || true
- git checkout $TRAVIS_COMMIT -b $TRAVIS_BRANCH
- git branch -v
-fi
-
# Output status information.
-git status
-git describe --tags
-git log -n 5 --graph
+(
+ set +e
+ set -x
+ git status
+ git branch -v
+ git log -n 5 --graph
+ git log --format=oneline -n 20 --graph
+)
echo
echo -en 'travis_fold:end:before_install.git\\r'
echo
@@ -64,7 +31,6 @@ if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew tap Homebrew/bundle
brew bundle
brew install ccache
- brew install gcc@7
echo
echo -en 'travis_fold:end:before_install.brew\\r'
echo
diff --git a/CHANGELOG b/CHANGELOG
index 5499c309..42e01645 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,21 @@ List of major changes and improvements between releases
=======================================================
+Yosys 0.8 .. Yosys 0.8-dev
+--------------------------
+
+ * Various
+ - Added $changed support to read_verilog
+ - Added "write_edif -attrprop"
+ - Added "ice40_unlut" pass
+ - Added "opt_lut" pass
+ - Added "synth_ice40 -relut"
+ - Added "synth_ice40 -noabc"
+ - Added "gate2lut.v" techmap rule
+ - Added "rename -src"
+ - Added "equiv_opt" pass
+
+
Yosys 0.7 .. Yosys 0.8
----------------------
diff --git a/COPYING b/COPYING
index a01b7b69..a121cdfe 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (C) 2012 - 2017 Clifford Wolf <clifford@clifford.at>
+Copyright (C) 2012 - 2018 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/Makefile b/Makefile
index d759b114..8586e976 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,7 @@ CONFIG := clang
# features (the more the better)
ENABLE_TCL := 1
ENABLE_ABC := 1
+ENABLE_GLOB := 1
ENABLE_PLUGINS := 1
ENABLE_READLINE := 1
ENABLE_EDITLINE := 0
@@ -72,6 +73,7 @@ PKG_CONFIG ?= pkg-config
SED ?= sed
BISON ?= bison
STRIP ?= strip
+AWK ?= awk
ifeq ($(OS), Darwin)
PLUGIN_LDFLAGS += -undefined dynamic_lookup
@@ -99,7 +101,7 @@ LDFLAGS += -rdynamic
LDLIBS += -lrt
endif
-YOSYS_VER := 0.8
+YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. 2> /dev/null | wc -l; })
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
@@ -109,7 +111,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 = ae6716b
+ABCREV = 2ddc57d
ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
@@ -160,7 +162,7 @@ ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
else ifeq ($(CONFIG),gcc-static)
LD = $(CXX)
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -static
-LDLIBS := $(filter-out -lrt,$(LDLIBS))
+LDLIBS := $(filter-out -lrt,$(LDLIBS))
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
CXXFLAGS += -std=c++11 -Os
ABCMKARGS = CC="$(CC)" CXX="$(CXX)" LD="$(LD)" ABC_USE_LIBSTDCXX=1 LIBS="-lm -lpthread -static" OPTFLAGS="-O" \
@@ -297,6 +299,10 @@ LDLIBS += -ldl
endif
endif
+ifeq ($(ENABLE_GLOB),1)
+CXXFLAGS += -DYOSYS_ENABLE_GLOB
+endif
+
ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
ifeq ($(OS), FreeBSD)
@@ -356,11 +362,15 @@ endif
endif
ifeq ($(ENABLE_VERIFIC),1)
-VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
-VERIFIC_COMPONENTS ?= verilog vhdl database util containers sdf hier_tree
+VERIFIC_DIR ?= /usr/local/src/verific_lib
+VERIFIC_COMPONENTS ?= verilog vhdl database util containers hier_tree
CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC
+ifeq ($(OS), Darwin)
+LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-mac.a,$(VERIFIC_COMPONENTS)) -lz
+else
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -lz
endif
+endif
ifeq ($(ENABLE_PROTOBUF),1)
LDLIBS += $(shell pkg-config --cflags --libs protobuf)
@@ -391,8 +401,8 @@ endef
ifeq ($(PRETTY), 1)
P_STATUS = 0
P_OFFSET = 0
-P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
-P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
+P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | $(AWK) 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
+P_SHOW = [$(shell $(AWK) "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@";
Q = @
S = -s
@@ -565,7 +575,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && 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/realmath && bash run-test.sh $(SEEDOPT)
+cd tests/share && bash run-test.sh $(SEEDOPT)
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
+cd tests/techmap && bash run-test.sh
@@ -573,6 +583,9 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+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/opt && bash run-test.sh
+ +cd tests/aiger && bash run-test.sh
@echo ""
@echo " Passed \"make test\"."
@echo ""
@@ -594,7 +607,7 @@ vloghtb: $(TARGETS) $(EXTRA_TARGETS)
ystests: $(TARGETS) $(EXTRA_TARGETS)
rm -rf tests/ystests
git clone https://github.com/YosysHQ/yosys-tests.git tests/ystests
- +PATH="$$PWD:$$PATH" cd tests/ystests && $(MAKE)
+ +$(MAKE) PATH="$$PWD:$$PATH" -C tests/ystests
@echo ""
@echo " Finished \"make ystests\"."
@echo ""
@@ -655,6 +668,7 @@ clean:
rm -rf tests/sat/*.log tests/techmap/*.log tests/various/*.log
rm -rf tests/bram/temp tests/fsm/temp tests/realmath/temp tests/share/temp tests/smv/temp
rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_*
+ rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff
rm -f tests/tools/cmp_tbdata
clean-abc:
diff --git a/README.md b/README.md
index 41ae4ac1..4048ecbc 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
```
yosys -- Yosys Open SYnthesis Suite
-Copyright (C) 2012 - 2017 Clifford Wolf <clifford@clifford.at>
+Copyright (C) 2012 - 2018 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
@@ -34,11 +34,24 @@ compatible license that is similar in terms to the MIT license
or the 2-clause BSD license).
-Web Site
-========
+Web Site and Other Resources
+============================
More information and documentation can be found on the Yosys web site:
-http://www.clifford.at/yosys/
+- http://www.clifford.at/yosys/
+
+The "Documentation" page on the web site contains links to more resources,
+including a manual that even describes some of the Yosys internals:
+- http://www.clifford.at/yosys/documentation.html
+
+The file `CodingReadme` in this directory contains additional information
+for people interested in using the Yosys C++ APIs.
+
+Users interested in formal verification might want to use the formal verification
+front-end for Yosys, SymbiYosys:
+- https://symbiyosys.readthedocs.io/en/latest/
+- https://github.com/YosysHQ/SymbiYosys
+
Setup
======
@@ -92,12 +105,15 @@ Makefile.
To build Yosys simply type 'make' in this directory.
$ make
- $ make test
$ sudo make install
Note that this also downloads, builds and installs ABC (using yosys-abc
as executable name).
+Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via:
+
+ $ make test
+
Getting Started
===============
@@ -117,7 +133,7 @@ reading the design using the Verilog frontend:
yosys> read_verilog tests/simple/fiedler-cooley.v
-writing the design to the console in yosys's internal format:
+writing the design to the console in Yosys's internal format:
yosys> write_ilang
@@ -234,7 +250,7 @@ Unsupported Verilog-2005 Features
=================================
The following Verilog-2005 features are not supported by
-yosys and there are currently no plans to add support
+Yosys and there are currently no plans to add support
for them:
- Non-synthesizable language features as defined in
@@ -285,9 +301,9 @@ Verilog Attributes and non-standard features
storage element. The register itself will always have all bits set
to 'x' (undefined). The variable may only be used as blocking assigned
temporary variable within an always block. This is mostly used internally
- by yosys to synthesize Verilog functions and access arrays.
+ by Yosys to synthesize Verilog functions and access arrays.
-- The ``onehot`` attribute on wires mark them as onehot state register. This
+- The ``onehot`` attribute on wires mark them as one-hot state register. This
is used for example for memory port sharing and set by the fsm_map pass.
- The ``blackbox`` attribute on modules is used to mark empty stub modules
@@ -296,6 +312,12 @@ Verilog Attributes and non-standard features
passes to identify input and output ports of cells. The Verilog backend
also does not output blackbox modules on default.
+- The ``dynports'' attribute is used by the Verilog front-end to mark modules
+ that have ports with a width that depends on a parameter.
+
+- The ``hdlname'' attribute is used by some passes to document the original
+ (HDL) name of a module when renaming a module.
+
- The ``keep`` attribute on cells and wires is used to mark objects that should
never be removed by the optimizer. This is used for example for cells that
have hidden connections that are not part of the netlist, such as IO pads.
@@ -319,13 +341,13 @@ Verilog Attributes and non-standard features
through the synthesis. When entities are combined, a new |-separated
string is created that contains all the string from the original entities.
-- In addition to the ``(* ... *)`` attribute syntax, yosys supports
+- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
the non-standard ``{* ... *}`` attribute syntax to set default attributes
for everything that comes after the ``{* ... *}`` statement. (Reset
by adding an empty ``{* *}`` statement.)
- In module parameter and port declarations, and cell port and parameter
- lists, a trailing comma is ignored. This simplifies writing verilog code
+ lists, a trailing comma is ignored. This simplifies writing Verilog code
generators a bit in some cases.
- Modules can be declared with ``module mod_name(...);`` (with three dots
@@ -410,11 +432,11 @@ Non-standard or SystemVerilog features for formal verification
- The system functions ``$allconst`` and ``$allseq`` can be used to construct
formal exist-forall problems. Assumptions only hold if the trace satisfies
- the assumtion for all ``$allconst/$allseq`` values. For assertions and cover
+ the assumption for all ``$allconst/$allseq`` values. For assertions and cover
statements it is sufficient if just one ``$allconst/$allseq`` value triggers
the property (similar to ``$anyconst/$anyseq``).
-- Wires/registers decalred using the ``anyconst/anyseq/allconst/allseq`` attribute
+- Wires/registers declared using the ``anyconst/anyseq/allconst/allseq`` attribute
(for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if driven
by a ``$anyconst/$anyseq/$allconst/$allseq`` function.
@@ -452,6 +474,9 @@ from SystemVerilog:
into a design with ``read_verilog``, all its packages are available to
SystemVerilog files being read into the same design afterwards.
+- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
+ ports are inputs or outputs are supported.
+
Building the documentation
==========================
@@ -482,6 +507,6 @@ Then execute, from the root of the repository:
Notes:
-- To run `make manual` you need to have installed yosys with `make install`,
+- To run `make manual` you need to have installed Yosys with `make install`,
otherwise it will fail on finding `kernel/yosys.h` while building
`PRESENTATION_Prog`.
diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc
index c323691a..dfe506c6 100644
--- a/backends/aiger/aiger.cc
+++ b/backends/aiger/aiger.cc
@@ -100,7 +100,7 @@ struct AigerWriter
return aig_map.at(bit);
}
- AigerWriter(Module *module, bool zinit_mode) : module(module), zinit_mode(zinit_mode), sigmap(module)
+ AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
{
pool<SigBit> undriven_bits;
pool<SigBit> unused_bits;
@@ -293,6 +293,10 @@ struct AigerWriter
aig_map[bit] = 2*aig_m;
}
+ if (imode && input_bits.empty()) {
+ aig_m++, aig_i++;
+ }
+
if (zinit_mode)
{
for (auto it : ff_map) {
@@ -371,6 +375,11 @@ struct AigerWriter
aig_outputs.push_back(bit2aig(bit));
}
+ if (omode && output_bits.empty()) {
+ aig_o++;
+ aig_outputs.push_back(0);
+ }
+
for (auto it : asserts) {
aig_b++;
int bit_a = bit2aig(it.first);
@@ -378,6 +387,11 @@ struct AigerWriter
aig_outputs.push_back(mkgate(bit_a^1, bit_en));
}
+ if (bmode && asserts.empty()) {
+ aig_b++;
+ aig_outputs.push_back(0);
+ }
+
for (auto it : assumes) {
aig_c++;
int bit_a = bit2aig(it.first);
@@ -689,6 +703,11 @@ struct AigerBackend : public Backend {
log(" -vmap <filename>\n");
log(" like -map, but more verbose\n");
log("\n");
+ log(" -I, -O, -B\n");
+ log(" If the design contains no input/output/assert then create one\n");
+ log(" dummy input/output/bad_state pin to make the tools reading the\n");
+ log(" AIGER file happy.\n");
+ log("\n");
}
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -697,6 +716,9 @@ struct AigerBackend : public Backend {
bool miter_mode = false;
bool symbols_mode = false;
bool verbose_map = false;
+ bool imode = false;
+ bool omode = false;
+ bool bmode = false;
std::string map_filename;
log_header(design, "Executing AIGER backend.\n");
@@ -729,6 +751,18 @@ struct AigerBackend : public Backend {
verbose_map = true;
continue;
}
+ if (args[argidx] == "-I") {
+ imode = true;
+ continue;
+ }
+ if (args[argidx] == "-O") {
+ omode = true;
+ continue;
+ }
+ if (args[argidx] == "-B") {
+ bmode = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
@@ -738,7 +772,7 @@ struct AigerBackend : public Backend {
if (top_module == nullptr)
log_error("Can't find top module in current design!\n");
- AigerWriter writer(top_module, zinit_mode);
+ AigerWriter writer(top_module, zinit_mode, imode, omode, bmode);
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
if (!map_filename.empty()) {
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 58d2a862..55c49499 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -133,12 +133,13 @@ struct BtorWorker
cell_recursion_guard.insert(cell);
btorf_push(log_id(cell));
- if (cell->type.in("$add", "$sub", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx",
- "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
+ if (cell->type.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx",
+ "$concat", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
{
string btor_op;
if (cell->type == "$add") btor_op = "add";
if (cell->type == "$sub") btor_op = "sub";
+ if (cell->type == "$mul") btor_op = "mul";
if (cell->type.in("$shl", "$sshl")) btor_op = "sll";
if (cell->type == "$shr") btor_op = "srl";
if (cell->type == "$sshr") btor_op = "sra";
@@ -146,6 +147,7 @@ struct BtorWorker
if (cell->type.in("$and", "$_AND_")) btor_op = "and";
if (cell->type.in("$or", "$_OR_")) btor_op = "or";
if (cell->type.in("$xor", "$_XOR_")) btor_op = "xor";
+ if (cell->type == "$concat") btor_op = "concat";
if (cell->type == "$_NAND_") btor_op = "nand";
if (cell->type == "$_NOR_") btor_op = "nor";
if (cell->type.in("$xnor", "$_XNOR_")) btor_op = "xnor";
@@ -214,6 +216,40 @@ struct BtorWorker
goto okay;
}
+ if (cell->type.in("$div", "$mod"))
+ {
+ string btor_op;
+ if (cell->type == "$div") btor_op = "div";
+ if (cell->type == "$mod") btor_op = "rem";
+ log_assert(!btor_op.empty());
+
+ int width = GetSize(cell->getPort("\\Y"));
+ width = std::max(width, GetSize(cell->getPort("\\A")));
+ width = std::max(width, GetSize(cell->getPort("\\B")));
+
+ bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false;
+ bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false;
+
+ int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed);
+ int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed);
+
+ int sid = get_bv_sid(width);
+ int nid = next_nid++;
+ btorf("%d %c%s %d %d %d\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b);
+
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
+
+ if (GetSize(sig) < width) {
+ int sid = get_bv_sid(GetSize(sig));
+ int nid2 = next_nid++;
+ btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1);
+ nid = nid2;
+ }
+
+ add_nid_sig(nid, sig);
+ goto okay;
+ }
+
if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
{
int sid = get_bv_sid(1);
@@ -506,6 +542,18 @@ struct BtorWorker
}
}
+ Const initval;
+ for (int i = 0; i < GetSize(sig_q); i++)
+ if (initbits.count(sig_q[i]))
+ initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0);
+ else
+ initval.bits.push_back(State::Sx);
+
+ int nid_init_val = -1;
+
+ if (!initval.is_fully_undef())
+ nid_init_val = get_sig_nid(initval);
+
int sid = get_bv_sid(GetSize(sig_q));
int nid = next_nid++;
@@ -514,15 +562,7 @@ struct BtorWorker
else
btorf("%d state %d %s\n", nid, sid, log_id(symbol));
- Const initval;
- for (int i = 0; i < GetSize(sig_q); i++)
- if (initbits.count(sig_q[i]))
- initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0);
- else
- initval.bits.push_back(State::Sx);
-
- if (!initval.is_fully_undef()) {
- int nid_init_val = get_sig_nid(initval);
+ if (nid_init_val >= 0) {
int nid_init = next_nid++;
if (verbose)
btorf("; initval = %s\n", log_signal(initval));
@@ -575,6 +615,7 @@ struct BtorWorker
{
int abits = cell->getParam("\\ABITS").as_int();
int width = cell->getParam("\\WIDTH").as_int();
+ int nwords = cell->getParam("\\SIZE").as_int();
int rdports = cell->getParam("\\RD_PORTS").as_int();
int wrports = cell->getParam("\\WR_PORTS").as_int();
@@ -601,6 +642,52 @@ struct BtorWorker
int data_sid = get_bv_sid(width);
int bool_sid = get_bv_sid(1);
int sid = get_mem_sid(abits, width);
+
+ Const initdata = cell->getParam("\\INIT");
+ initdata.exts(nwords*width);
+ int nid_init_val = -1;
+
+ if (!initdata.is_fully_undef())
+ {
+ bool constword = true;
+ Const firstword = initdata.extract(0, width);
+
+ for (int i = 1; i < nwords; i++) {
+ Const thisword = initdata.extract(i*width, width);
+ if (thisword != firstword) {
+ constword = false;
+ break;
+ }
+ }
+
+ if (constword)
+ {
+ if (verbose)
+ btorf("; initval = %s\n", log_signal(firstword));
+ nid_init_val = get_sig_nid(firstword);
+ }
+ else
+ {
+ int nid_init_val = next_nid++;
+ btorf("%d state %d\n", nid_init_val, sid);
+
+ for (int i = 0; i < nwords; i++) {
+ Const thisword = initdata.extract(i*width, width);
+ if (thisword.is_fully_undef())
+ continue;
+ Const thisaddr(i, abits);
+ int nid_thisword = get_sig_nid(thisword);
+ int nid_thisaddr = get_sig_nid(thisaddr);
+ int last_nid_init_val = nid_init_val;
+ nid_init_val = next_nid++;
+ if (verbose)
+ btorf("; initval[%d] = %s\n", i, log_signal(thisword));
+ btorf("%d write %d %d %d %d\n", nid_init_val, sid, last_nid_init_val, nid_thisaddr, nid_thisword);
+ }
+ }
+ }
+
+
int nid = next_nid++;
int nid_head = nid;
@@ -609,6 +696,12 @@ struct BtorWorker
else
btorf("%d state %d %s\n", nid, sid, log_id(cell));
+ if (nid_init_val >= 0)
+ {
+ int nid_init = next_nid++;
+ btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val);
+ }
+
if (asyncwr)
{
for (int port = 0; port < wrports; port++)
@@ -892,9 +985,8 @@ struct BtorWorker
btorf_push(stringf("output %s", log_id(wire)));
- int sid = get_bv_sid(GetSize(wire));
int nid = get_sig_nid(wire);
- btorf("%d output %d %d %s\n", next_nid++, sid, nid, log_id(wire));
+ btorf("%d output %d %s\n", next_nid++, nid, log_id(wire));
btorf_pop(stringf("output %s", log_id(wire)));
}
diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc
index 5f9ec54f..7e30b67a 100644
--- a/backends/edif/edif.cc
+++ b/backends/edif/edif.cc
@@ -106,6 +106,13 @@ struct EdifBackend : public Backend {
log(" if the design contains constant nets. use \"hilomap\" to map to custom\n");
log(" constant drivers first)\n");
log("\n");
+ log(" -gndvccy\n");
+ log(" create \"GND\" and \"VCC\" cells with \"Y\" outputs. (the default is \"G\"\n");
+ log(" for \"GND\" and \"P\" for \"VCC\".)\n");
+ log("\n");
+ log(" -attrprop\n");
+ log(" create EDIF properties for cell attributes\n");
+ log("\n");
log(" -pvector {par|bra|ang}\n");
log(" sets the delimiting character for module port rename clauses to\n");
log(" parentheses, square brackets, or angle brackets.\n");
@@ -121,8 +128,9 @@ struct EdifBackend : public Backend {
log_header(design, "Executing EDIF backend.\n");
std::string top_module_name;
bool port_rename = false;
+ bool attr_properties = false;
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
- bool nogndvcc = false;
+ bool nogndvcc = false, gndvccy = false;
CellTypes ct(design);
EdifNames edif_names;
@@ -137,6 +145,14 @@ struct EdifBackend : public Backend {
nogndvcc = true;
continue;
}
+ if (args[argidx] == "-gndvccy") {
+ gndvccy = true;
+ continue;
+ }
+ if (args[argidx] == "-attrprop") {
+ attr_properties = true;
+ continue;
+ }
if (args[argidx] == "-pvector" && argidx+1 < args.size()) {
std::string parray;
port_rename = true;
@@ -203,7 +219,7 @@ struct EdifBackend : public Backend {
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
- *f << stringf(" (interface (port G (direction OUTPUT)))\n");
+ *f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'G');
*f << stringf(" )\n");
*f << stringf(" )\n");
@@ -211,7 +227,7 @@ struct EdifBackend : public Backend {
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
- *f << stringf(" (interface (port P (direction OUTPUT)))\n");
+ *f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'P');
*f << stringf(" )\n");
*f << stringf(" )\n");
}
@@ -332,24 +348,33 @@ struct EdifBackend : public Backend {
*f << stringf(" (instance %s\n", EDIF_DEF(cell->name));
*f << stringf(" (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell->type),
lib_cell_ports.count(cell->type) > 0 ? " (libraryRef LIB)" : "");
- for (auto &p : cell->parameters)
- if ((p.second.flags & RTLIL::CONST_FLAG_STRING) != 0)
- *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), p.second.decode_string().c_str());
- else if (p.second.bits.size() <= 32 && RTLIL::SigSpec(p.second).is_fully_def())
- *f << stringf("\n (property %s (integer %u))", EDIF_DEF(p.first), p.second.as_int());
+
+ auto add_prop = [&](IdString name, Const val) {
+ if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0)
+ *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str());
+ else if (val.bits.size() <= 32 && RTLIL::SigSpec(val).is_fully_def())
+ *f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int());
else {
std::string hex_string = "";
- for (size_t i = 0; i < p.second.bits.size(); i += 4) {
+ for (size_t i = 0; i < val.bits.size(); i += 4) {
int digit_value = 0;
- if (i+0 < p.second.bits.size() && p.second.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
- if (i+1 < p.second.bits.size() && p.second.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
- if (i+2 < p.second.bits.size() && p.second.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
- if (i+3 < p.second.bits.size() && p.second.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
+ if (i+0 < val.bits.size() && val.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
+ if (i+1 < val.bits.size() && val.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
+ if (i+2 < val.bits.size() && val.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
+ if (i+3 < val.bits.size() && val.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
hex_string = std::string(digit_str) + hex_string;
}
- *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(p.first), GetSize(p.second.bits), hex_string.c_str());
+ *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val.bits), hex_string.c_str());
}
+ };
+
+ for (auto &p : cell->parameters)
+ add_prop(p.first, p.second);
+ if (attr_properties)
+ for (auto &p : cell->attributes)
+ add_prop(p.first, p.second);
+
*f << stringf(")\n");
for (auto &p : cell->connections()) {
RTLIL::SigSpec sig = sigmap(p.second);
@@ -403,9 +428,9 @@ struct EdifBackend : public Backend {
if (nogndvcc)
log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
if (sig == RTLIL::State::S0)
- *f << stringf(" (portRef G (instanceRef GND))\n");
+ *f << stringf(" (portRef %c (instanceRef GND))\n", gndvccy ? 'Y' : 'G');
if (sig == RTLIL::State::S1)
- *f << stringf(" (portRef P (instanceRef VCC))\n");
+ *f << stringf(" (portRef %c (instanceRef VCC))\n", gndvccy ? 'Y' : 'P');
}
*f << stringf(" ))\n");
}
diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index 32410a65..eef6401b 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -23,7 +23,11 @@
#include "kernel/celltypes.h"
#include "kernel/cellaigs.h"
#include "kernel/log.h"
+#include <algorithm>
#include <string>
+#include <regex>
+#include <vector>
+#include <cmath>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -37,6 +41,7 @@ static const FDirection FD_NODIRECTION = 0x0;
static const FDirection FD_IN = 0x1;
static const FDirection FD_OUT = 0x2;
static const FDirection FD_INOUT = 0x3;
+static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width
// Get a port direction with respect to a specific module.
FDirection getPortFDirection(IdString id, Module *module)
@@ -160,11 +165,9 @@ struct FirrtlWorker
std::string fid(RTLIL::IdString internal_id)
{
- const char *str = internal_id.c_str();
- return *str == '\\' ? str + 1 : str;
+ return make_id(internal_id);
}
-
std::string cellname(RTLIL::Cell *cell)
{
return fid(cell->name).c_str();
@@ -173,6 +176,26 @@ struct FirrtlWorker
void process_instance(RTLIL::Cell *cell, vector<string> &wire_exprs)
{
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")
+ {
+ std::string::iterator it;
+ for (it = cell_type.begin(); it < cell_type.end(); it++)
+ {
+ switch (*it) {
+ case '\\': /* FALL_THROUGH */
+ case '=': /* FALL_THROUGH */
+ case '\'': /* FALL_THROUGH */
+ case '$': instanceOf.append("_"); break;
+ default: instanceOf.append(1, *it); break;
+ }
+ }
+ }
+ else
+ {
+ instanceOf = cell_type;
+ }
std::string cell_name = cellname(cell);
std::string cell_name_comment;
@@ -182,41 +205,74 @@ struct FirrtlWorker
cell_name_comment = "";
// Find the module corresponding to this instance.
auto instModule = design->module(cell->type);
- wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), cell_type.c_str()));
+ // If there is no instance for this, just return.
+ if (instModule == NULL)
+ {
+ log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
+ return;
+ }
+ wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str()));
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (it->second.size() > 0) {
const SigSpec &secondSig = it->second;
const std::string firstName = cell_name + "." + make_id(it->first);
- const std::string secondName = make_expr(secondSig);
+ const std::string secondExpr = make_expr(secondSig);
// Find the direction for this port.
FDirection dir = getPortFDirection(it->first, instModule);
- std::string source, sink;
+ std::string sourceExpr, sinkExpr;
+ const SigSpec *sinkSig = nullptr;
switch (dir) {
case FD_INOUT:
- log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", log_id(cell_type), log_signal(it->second));
+ log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
case FD_OUT:
- source = firstName;
- sink = secondName;
+ sourceExpr = firstName;
+ sinkExpr = secondExpr;
+ sinkSig = &secondSig;
break;
case FD_NODIRECTION:
- log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", log_id(cell_type), log_signal(it->second));
+ log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
/* FALL_THROUGH */
case FD_IN:
- source = secondName;
- sink = firstName;
+ sourceExpr = secondExpr;
+ sinkExpr = firstName;
break;
default:
- log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", log_id(cell_type), log_signal(it->second), dir);
+ log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir);
break;
}
- wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str()));
+ // Check for subfield assignment.
+ std::string bitsString = "bits(";
+ if (sinkExpr.substr(0, bitsString.length()) == bitsString ) {
+ if (sinkSig == nullptr)
+ log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str());
+ // Don't generate the assignment here.
+ // Add the source and sink to the "reverse_wire_map" and we'll output the assignment
+ // as part of the coalesced subfield assignments for this wire.
+ register_reverse_wire_map(sourceExpr, *sinkSig);
+ } else {
+ wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str()));
+ }
}
}
wire_exprs.push_back(stringf("\n"));
}
+ // 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)
+ {
+ string result = b_expr;
+ if (b_padded_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
+ result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1);
+ }
+ return result;
+ }
+
void run()
{
f << stringf(" module %s:\n", make_id(module->name));
@@ -225,6 +281,12 @@ struct FirrtlWorker
for (auto wire : module->wires())
{
const auto wireName = make_id(wire->name);
+ // If a wire has initial data, issue a warning since FIRRTL doesn't currently support it.
+ if (wire->attributes.count("\\init")) {
+ log_warning("Initial value (%s) for (%s.%s) not supported\n",
+ wire->attributes.at("\\init").as_string().c_str(),
+ log_id(module), log_id(wire));
+ }
if (wire->port_id)
{
if (wire->port_input && wire->port_output)
@@ -240,7 +302,8 @@ struct FirrtlWorker
for (auto cell : module->cells())
{
- // Is this cell is a module instance?
+ bool extract_y_bits = false; // Assume no extraction of final bits will be required.
+ // Is this cell is a module instance?
if (cell->type[0] != '$')
{
process_instance(cell, wire_exprs);
@@ -264,21 +327,21 @@ struct FirrtlWorker
}
string primop;
- bool always_uint = false;
+ bool always_uint = false;
if (cell->type == "$not") primop = "not";
- if (cell->type == "$neg") primop = "neg";
- if (cell->type == "$logic_not") {
+ else if (cell->type == "$neg") primop = "neg";
+ else if (cell->type == "$logic_not") {
primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
}
- if (cell->type == "$reduce_and") primop = "andr";
- if (cell->type == "$reduce_or") primop = "orr";
- if (cell->type == "$reduce_xor") primop = "xorr";
- if (cell->type == "$reduce_xnor") {
+ else if (cell->type == "$reduce_and") primop = "andr";
+ else if (cell->type == "$reduce_or") primop = "orr";
+ else if (cell->type == "$reduce_xor") primop = "xorr";
+ else if (cell->type == "$reduce_xnor") {
primop = "not";
a_expr = stringf("xorr(%s)", a_expr.c_str());
}
- if (cell->type == "$reduce_bool") {
+ 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();
@@ -297,14 +360,15 @@ struct FirrtlWorker
continue;
}
if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx",
- "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
- "$logic_and", "$logic_or"))
+ "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
+ "$logic_and", "$logic_or"))
{
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()) {
@@ -315,67 +379,93 @@ struct FirrtlWorker
if (cell->parameters.at("\\B_SIGNED").as_bool()) {
b_expr = "asSInt(" + b_expr + ")";
}
- b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
+ if (b_padded_width < y_width) {
+ auto b_sig = cell->getPort("\\B");
+ b_padded_width = y_width;
+ }
}
- a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+ auto a_sig = cell->getPort("\\A");
if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) {
a_expr = "asUInt(" + a_expr + ")";
}
string primop;
- bool always_uint = false;
+ bool always_uint = false;
if (cell->type == "$add") primop = "add";
- if (cell->type == "$sub") primop = "sub";
- if (cell->type == "$mul") primop = "mul";
- if (cell->type == "$div") primop = "div";
- if (cell->type == "$mod") primop = "rem";
- if (cell->type == "$and") {
+ 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;
}
- if (cell->type == "$or" ) {
+ else if (cell->type == "$or" ) {
primop = "or";
always_uint = true;
}
- if (cell->type == "$xor") {
+ else if (cell->type == "$xor") {
primop = "xor";
always_uint = true;
}
- if ((cell->type == "$eq") | (cell->type == "$eqx")) {
+ else if ((cell->type == "$eq") | (cell->type == "$eqx")) {
primop = "eq";
always_uint = true;
}
- if ((cell->type == "$ne") | (cell->type == "$nex")) {
+ else if ((cell->type == "$ne") | (cell->type == "$nex")) {
primop = "neq";
always_uint = true;
}
- if (cell->type == "$gt") {
+ else if (cell->type == "$gt") {
primop = "gt";
always_uint = true;
}
- if (cell->type == "$ge") {
+ else if (cell->type == "$ge") {
primop = "geq";
always_uint = true;
}
- if (cell->type == "$lt") {
+ else if (cell->type == "$lt") {
primop = "lt";
always_uint = true;
}
- if (cell->type == "$le") {
+ else if (cell->type == "$le") {
primop = "leq";
always_uint = true;
}
- if ((cell->type == "$shl") | (cell->type == "$sshl")) primop = "dshl";
- if ((cell->type == "$shr") | (cell->type == "$sshr")) primop = "dshr";
- if ((cell->type == "$logic_and")) {
+ 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.
+ extract_y_bits = true;
+ // Is the shift amount constant?
+ auto b_sig = cell->getPort("\\B");
+ if (b_sig.is_fully_const()) {
+ primop = "shl";
+ } else {
+ primop = "dshl";
+ // Convert from FIRRTL left shift semantics.
+ b_expr = gen_dshl(b_expr, b_padded_width);
+ }
+ }
+ else if ((cell->type == "$shr") | (cell->type == "$sshr")) {
+ // We don't need to extract a specific range of bits.
+ extract_y_bits = false;
+ // Is the shift amount constant?
+ auto b_sig = cell->getPort("\\B");
+ if (b_sig.is_fully_const()) {
+ primop = "shr";
+ } else {
+ primop = "dshr";
+ }
+ }
+ 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;
}
- if ((cell->type == "$logic_or")) {
+ else if ((cell->type == "$logic_or")) {
primop = "or";
a_expr = "neq(" + a_expr + ", UInt(0))";
b_expr = "neq(" + b_expr + ", UInt(0))";
@@ -388,6 +478,11 @@ struct FirrtlWorker
string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
+ // Deal with FIRRTL's "shift widens" semantics
+ if (extract_y_bits) {
+ expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
+ }
+
if ((is_signed && !always_uint) || cell->type.in("$sub"))
expr = stringf("asUInt(%s)", expr.c_str());
@@ -513,7 +608,65 @@ struct FirrtlWorker
continue;
}
- log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
+ // This may be a parameterized module - paramod.
+ if (cell->type.substr(0, 8) == "$paramod")
+ {
+ process_instance(cell, wire_exprs);
+ continue;
+ }
+ if (cell->type == "$shiftx") {
+ // 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"));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+
+ if (cell->getParam("\\B_SIGNED").as_bool()) {
+ // Use validif to constrain the selection (test the sign bit)
+ auto b_string = b_expr.c_str();
+ int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1;
+ b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string);
+ }
+ string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str());
+
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+ continue;
+ }
+ if (cell->type == "$shift") {
+ // 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 dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
+ expr = stringf("mux(%s < 0, %s, %s)",
+ b_string,
+ dshl.c_str(),
+ dshr.c_str()
+ );
+ } else {
+ expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
+ }
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ 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));
}
for (auto conn : module->connections())
@@ -629,38 +782,53 @@ struct FirrtlBackend : public Backend {
log(" write_firrtl [options] [filename]\n");
log("\n");
log("Write a FIRRTL netlist of the current design.\n");
+ log("The following commands are executed by this command:\n");
+ log(" pmuxtree\n");
log("\n");
}
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++)
- {
- // if (args[argidx] == "-aig") {
- // aig_mode = true;
- // continue;
- // }
- break;
+ size_t argidx = args.size(); // We aren't expecting any arguments.
+
+ // If we weren't explicitly passed a filename, use the last argument (if it isn't a flag).
+ if (filename == "") {
+ if (argidx > 0 && args[argidx - 1][0] != '-') {
+ // extra_args and friends need to see this argument.
+ argidx -= 1;
+ filename = args[argidx];
+ }
}
extra_args(f, filename, args, argidx);
- log_header(design, "Executing FIRRTL backend.\n");
+ if (!design->full_selection())
+ log_cmd_error("This command only operates on fully selected designs!\n");
- Module *top = design->top_module();
+ log_header(design, "Executing FIRRTL backend.\n");
+ log_push();
- if (top == nullptr)
- log_error("No top module found!\n");
+ Pass::call(design, stringf("pmuxtree"));
namecache.clear();
autoid_counter = 0;
+ // Get the top module, or a reasonable facsimile - we need something for the circuit name.
+ Module *top = design->top_module();
+ Module *last = nullptr;
+ // Generate module and wire names.
for (auto module : design->modules()) {
make_id(module->name);
+ last = module;
+ if (top == nullptr && module->get_bool_attribute("\\top")) {
+ top = module;
+ }
for (auto wire : module->wires())
if (wire->port_id)
make_id(wire->name);
}
+ if (top == nullptr)
+ top = last;
+
*f << stringf("circuit %s:\n", make_id(top->name));
for (auto module : design->modules())
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
index 4c58ea08..dc39e5e0 100644
--- a/backends/ilang/ilang_backend.cc
+++ b/backends/ilang/ilang_backend.cc
@@ -204,7 +204,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0)
- f << stringf(", ");
+ f << stringf(" , ");
dump_sigspec(f, (*it)->compare[i]);
}
f << stringf("\n");
diff --git a/backends/protobuf/protobuf.cc b/backends/protobuf/protobuf.cc
index f56147ce..549fc73a 100644
--- a/backends/protobuf/protobuf.cc
+++ b/backends/protobuf/protobuf.cc
@@ -48,7 +48,7 @@ struct ProtobufDesignSerializer
ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
aig_mode_(aig_mode), use_selection_(use_selection) { }
-
+
string get_name(IdString name)
{
return RTLIL::unescape_id(name);
@@ -60,7 +60,7 @@ struct ProtobufDesignSerializer
{
for (auto &param : parameters) {
std::string key = get_name(param.first);
-
+
yosys::pb::Parameter pb_param;
@@ -207,7 +207,7 @@ struct ProtobufDesignSerializer
(*models)[aig.name] = pb_model;
}
}
-
+
void serialize_design(yosys::pb::Design *pb, Design *design)
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc
index 349bc5a6..6f2ccbe2 100644
--- a/backends/simplec/simplec.cc
+++ b/backends/simplec/simplec.cc
@@ -748,7 +748,7 @@ struct SimplecBackend : public Backend {
log("\n");
log(" write_simplec [options] [filename]\n");
log("\n");
- log("Write simple C code for simulating the design. The C code writen can be used to\n");
+ log("Write simple C code for simulating the design. The C code written can be used to\n");
log("simulate the design in a C environment, but the purpose of this command is to\n");
log("generate code that works well with C-based formal verification.\n");
log("\n");
diff --git a/backends/simplec/test00_uut.v b/backends/simplec/test00_uut.v
index 744dbe9e..92329a6f 100644
--- a/backends/simplec/test00_uut.v
+++ b/backends/simplec/test00_uut.v
@@ -3,12 +3,12 @@ module test(input [31:0] a, b, c, output [31:0] x, y, z, w);
unit_y unit_y_inst (.a(a), .b(b), .c(c), .y(y));
assign z = a ^ b ^ c, w = z;
endmodule
-
+
module unit_x(input [31:0] a, b, c, output [31:0] x);
assign x = (a & b) | c;
endmodule
-
+
module unit_y(input [31:0] a, b, c, output [31:0] y);
assign y = a & (b | c);
endmodule
-
+
diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc
index dce82f01..92941d4c 100644
--- a/backends/smt2/Makefile.inc
+++ b/backends/smt2/Makefile.inc
@@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o
ifneq ($(CONFIG),mxe)
ifneq ($(CONFIG),emcc)
+
+# MSYS targets support yosys-smtbmc, but require a launcher script
+ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
+TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py
+# Needed to find the Python interpreter for yosys-smtbmc scripts.
+# Override if necessary, it is only used for msys2 targets.
+PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
+
+yosys-smtbmc-script.py: backends/smt2/smtbmc.py
+ $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \
+ -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
+
+yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
+ $(P) gcc -DGUI=0 -O -s -o $@ $<
+# Other targets
+else
TARGETS += yosys-smtbmc
yosys-smtbmc: backends/smt2/smtbmc.py
$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
$(Q) chmod +x $@.new
$(Q) mv $@.new $@
+endif
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
endif
endif
-
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index e2777ae0..688535f3 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -416,6 +416,7 @@ struct Smt2Worker
for (char ch : expr) {
if (ch == 'A') processed_expr += get_bv(sig_a);
else if (ch == 'B') processed_expr += get_bv(sig_b);
+ else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B"));
else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
else processed_expr += ch;
@@ -554,7 +555,9 @@ struct Smt2Worker
if (cell->type.in("$shift", "$shiftx")) {
if (cell->getParam("\\B_SIGNED").as_bool()) {
- /* FIXME */
+ return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) "
+ "(bvlshr A B) (bvlshr A (bvneg B)))",
+ GetSize(cell->getPort("\\B")), 0), 's');
} else {
return export_bvop(cell, "(bvlshr A B)", 's');
}
@@ -885,8 +888,8 @@ struct Smt2Worker
string name_a = get_bool(cell->getPort("\\A"));
string name_en = get_bool(cell->getPort("\\EN"));
- decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id,
- cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
+ string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell);
+ decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str()));
if (cell->type == "$cover")
decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
@@ -1101,20 +1104,27 @@ struct Smt2Worker
break;
Const initword = init_data.extract(i*width, width, State::Sx);
+ Const initmask = initword;
bool gen_init_constr = false;
- for (auto bit : initword.bits)
- if (bit == State::S0 || bit == State::S1)
+ for (int k = 0; k < GetSize(initword); k++) {
+ if (initword[k] == State::S0 || initword[k] == State::S1) {
gen_init_constr = true;
+ initmask[k] = State::S1;
+ } else {
+ initmask[k] = State::S0;
+ initword[k] = State::S0;
+ }
+ }
if (gen_init_constr)
{
if (statebv)
/* FIXME */;
else
- init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]",
+ init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]",
get_id(module), arrayid, Const(i, abits).as_string().c_str(),
- initword.as_string().c_str(), get_id(cell), i));
+ initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i));
}
}
}
diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py
index 6af2a5ac..445a42e0 100644
--- a/backends/smt2/smtbmc.py
+++ b/backends/smt2/smtbmc.py
@@ -32,6 +32,7 @@ cexfile = None
aimfile = None
aiwfile = None
aigheader = True
+btorwitfile = None
vlogtbfile = None
vlogtbtop = None
inconstr = list()
@@ -86,12 +87,15 @@ yosys-smtbmc [options] <yosys_smt2_output>
--aig <aim_filename>:<aiw_filename>
like above, but for map files and witness files that do not
- share a filename prefix (or use differen file extensions).
+ share a filename prefix (or use different file extensions).
--aig-noheader
the AIGER witness file does not include the status and
properties lines.
+ --btorwit <btor_witness_filename>
+ read a BTOR witness.
+
--noinfo
only run the core proof, do not collect and print any
additional information (e.g. which assert failed)
@@ -99,8 +103,8 @@ yosys-smtbmc [options] <yosys_smt2_output>
--presat
check if the design with assumptions but without assertions
is SAT before checking if assertions are UNSAT. This will
- detect if there are contradicting assumtions. In some cases
- this will also help to "warmup" the solver, potentially
+ detect if there are contradicting assumptions. In some cases
+ this will also help to "warm up" the solver, potentially
yielding a speedup.
--final-only
@@ -145,14 +149,14 @@ yosys-smtbmc [options] <yosys_smt2_output>
--append <num_steps>
add <num_steps> time steps at the end of the trace
when creating a counter example (this additional time
- steps will still be constrained by assumtions)
+ steps will still be constrained by assumptions)
""" + so.helpmsg())
sys.exit(1)
try:
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts +
- ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "presat",
+ ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat",
"dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=",
"smtc-init", "smtc-top=", "noinit"])
except:
@@ -189,6 +193,8 @@ for o, a in opts:
aiwfile = a + ".aiw"
elif o == "--aig-noheader":
aigheader = False
+ elif o == "--btorwit":
+ btorwitfile = a
elif o == "--dump-vcd":
vcdfile = a
elif o == "--dump-vlogtb":
@@ -575,6 +581,103 @@ if aimfile is not None:
num_steps = max(num_steps, step+1)
step += 1
+if btorwitfile is not None:
+ with open(btorwitfile, "r") as f:
+ step = None
+ suffix = None
+ altsuffix = None
+ header_okay = False
+
+ for line in f:
+ line = line.strip()
+
+ if line == "sat":
+ header_okay = True
+ continue
+
+ if not header_okay:
+ continue
+
+ if line == "" or line[0] == "b" or line[0] == "j":
+ continue
+
+ if line == ".":
+ break
+
+ if line[0] == '#' or line[0] == '@':
+ step = int(line[1:])
+ suffix = line
+ altsuffix = suffix
+ if suffix[0] == "@":
+ altsuffix = "#" + suffix[1:]
+ else:
+ altsuffix = "@" + suffix[1:]
+ continue
+
+ line = line.split()
+
+ if len(line) == 0:
+ continue
+
+ if line[-1].endswith(suffix):
+ line[-1] = line[-1][0:len(line[-1]) - len(suffix)]
+
+ if line[-1].endswith(altsuffix):
+ line[-1] = line[-1][0:len(line[-1]) - len(altsuffix)]
+
+ if line[-1][0] == "$":
+ continue
+
+ # BV assignments
+ if len(line) == 3 and line[1][0] != "[":
+ value = line[1]
+ name = line[2]
+
+ path = smt.get_path(topmod, name)
+
+ if not smt.net_exists(topmod, path):
+ continue
+
+ width = smt.net_width(topmod, path)
+
+ if width == 1:
+ assert value in ["0", "1"]
+ value = "true" if value == "1" else "false"
+ else:
+ value = "#b" + value
+
+ smtexpr = "(= [%s] %s)" % (name, value)
+ constr_assumes[step].append((btorwitfile, smtexpr))
+
+ # Array assignments
+ if len(line) == 4 and line[1][0] == "[":
+ index = line[1]
+ value = line[2]
+ name = line[3]
+
+ path = smt.get_path(topmod, name)
+
+ if not smt.mem_exists(topmod, path):
+ continue
+
+ meminfo = smt.mem_info(topmod, path)
+
+ if meminfo[1] == 1:
+ assert value in ["0", "1"]
+ value = "true" if value == "1" else "false"
+ else:
+ value = "#b" + value
+
+ assert index[0] == "["
+ assert index[-1] == "]"
+ index = "#b" + index[1:-1]
+
+ smtexpr = "(= (select [%s] %s) %s)" % (name, index, value)
+ constr_assumes[step].append((btorwitfile, smtexpr))
+
+ skip_steps = step
+ num_steps = step+1
+
def write_vcd_trace(steps_start, steps_stop, index):
filename = vcdfile.replace("%", index)
print_msg("Writing trace to VCD file: %s" % (filename))
@@ -1259,7 +1362,11 @@ elif covermode:
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
smt_assert_consequent(get_constr_expr(constr_assumes, i))
print_msg("Re-solving with appended steps..")
- assert smt_check_sat() == "sat"
+ if smt_check_sat() == "unsat":
+ print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
+ found_failed_assert = True
+ retstatus = False
+ break
reached_covers = smt.bv2bin(smt.get("(covers_%d s%d)" % (coveridx, step)))
assert len(reached_covers) == len(cover_desc)
@@ -1377,7 +1484,11 @@ else: # not tempind, covermode
smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
smt_assert_consequent(get_constr_expr(constr_assumes, i))
- assert smt_check_sat() == "sat"
+ print_msg("Re-solving with appended steps..")
+ if smt_check_sat() == "unsat":
+ print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
+ retstatus = False
+ break
print_anyconsts(step)
for i in range(step, last_check_step+1):
print_failed_asserts(i)
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
index 3fc823e3..ab20a4af 100644
--- a/backends/smt2/smtio.py
+++ b/backends/smt2/smtio.py
@@ -31,11 +31,19 @@ from threading import Thread
# does not run out of stack frames when parsing large expressions
if os.name == "posix":
smtio_reclimit = 64 * 1024
- smtio_stacksize = 128 * 1024 * 1024
if sys.getrecursionlimit() < smtio_reclimit:
sys.setrecursionlimit(smtio_reclimit)
- if resource.getrlimit(resource.RLIMIT_STACK)[0] < smtio_stacksize:
- resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, -1))
+
+ current_rlimit_stack = resource.getrlimit(resource.RLIMIT_STACK)
+ if current_rlimit_stack[0] != resource.RLIM_INFINITY:
+ smtio_stacksize = 128 * 1024 * 1024
+ if os.uname().sysname == "Darwin":
+ # MacOS has rather conservative stack limits
+ smtio_stacksize = 16 * 1024 * 1024
+ 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]))
# currently running solvers (so we can kill them)
@@ -158,19 +166,28 @@ class SmtIo:
self.unroll = False
if self.solver == "yices":
- self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts
+ if self.noincr:
+ self.popen_vargs = ['yices-smt2'] + self.solver_opts
+ else:
+ self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts
if self.solver == "z3":
self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts
if self.solver == "cvc4":
- self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
+ if self.noincr:
+ self.popen_vargs = ['cvc4', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
+ else:
+ self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
if self.solver == "mathsat":
self.popen_vargs = ['mathsat'] + self.solver_opts
if self.solver == "boolector":
- self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
+ if self.noincr:
+ self.popen_vargs = ['boolector', '--smt2'] + self.solver_opts
+ else:
+ self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
self.unroll = True
if self.solver == "abc":
@@ -767,7 +784,7 @@ class SmtIo:
def get_path(self, mod, path):
assert mod in self.modinfo
- path = path.split(".")
+ path = path.replace("\\", "/").split(".")
for i in range(len(path)-1):
first = ".".join(path[0:i+1])
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index b8383412..f379c9c4 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -42,7 +42,7 @@ struct SmvWorker
pool<Wire*> partial_assignment_wires;
dict<SigBit, std::pair<const char*, int>> partial_assignment_bits;
- vector<string> assignments, invarspecs;
+ vector<string> inputvars, vars, definitions, assignments, invarspecs;
const char *cid()
{
@@ -195,7 +195,7 @@ struct SmvWorker
return rvalue(sig);
const char *temp_id = cid();
- f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig));
+// f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig));
int offset = 0;
for (auto bit : sig) {
@@ -210,14 +210,14 @@ struct SmvWorker
void run()
{
f << stringf("MODULE %s\n", cid(module->name));
- f << stringf(" VAR\n");
for (auto wire : module->wires())
{
if (SigSpec(wire) != sigmap(wire))
partial_assignment_wires.insert(wire);
- f << stringf(" %s : unsigned word[%d]; -- %s\n", cid(wire->name), wire->width, log_id(wire));
+ if (wire->port_input)
+ inputvars.push_back(stringf("%s : unsigned word[%d]; -- %s", cid(wire->name), wire->width, log_id(wire)));
if (wire->attributes.count("\\init"))
assignments.push_back(stringf("init(%s) := %s;", lvalue(wire), rvalue(wire->attributes.at("\\init"))));
@@ -275,8 +275,8 @@ struct SmvWorker
const char *b_shr = rvalue_u(sig_b);
const char *b_shl = cid();
- f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b));
- assignments.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b)));
+// f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b));
+ definitions.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b)));
string expr_shl = stringf("resize(%s << %s[%d:0], %d)", expr_a.c_str(), b_shl, shift_b_width-1, width_y);
string expr_shr = stringf("resize(%s >> %s[%d:0], %d)", expr_a.c_str(), b_shr, shift_b_width-1, width_y);
@@ -303,7 +303,7 @@ struct SmvWorker
GetSize(sig_b)-shift_b_width, width_y, expr.c_str());
}
- assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
+ definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
continue;
}
@@ -319,12 +319,12 @@ struct SmvWorker
if (cell->getParam("\\A_SIGNED").as_bool())
{
- assignments.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")),
op.c_str(), rvalue_s(cell->getPort("\\A"), width)));
}
else
{
- assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")),
op.c_str(), rvalue_u(cell->getPort("\\A"), width)));
}
@@ -346,12 +346,12 @@ struct SmvWorker
if (cell->getParam("\\A_SIGNED").as_bool())
{
- assignments.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")),
rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width)));
}
else
{
- assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width)));
}
@@ -370,12 +370,12 @@ struct SmvWorker
if (cell->getParam("\\A_SIGNED").as_bool())
{
- assignments.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width), width_y));
}
else
{
- assignments.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")),
rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width), width_y));
}
@@ -407,7 +407,7 @@ struct SmvWorker
expr_b = stringf("resize(%s, %d)", rvalue(cell->getPort("\\B")), width);
}
- assignments.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
expr_a.c_str(), op.c_str(), expr_b.c_str(), GetSize(cell->getPort("\\Y"))));
continue;
@@ -425,7 +425,7 @@ struct SmvWorker
if (cell->type == "$reduce_or") expr = stringf("%s != 0ub%d_0", expr_a, width_a);
if (cell->type == "$reduce_bool") expr = stringf("%s != 0ub%d_0", expr_a, width_a);
- assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
+ definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
continue;
}
@@ -444,7 +444,7 @@ struct SmvWorker
if (cell->type == "$reduce_xnor")
expr = "!(" + expr + ")";
- assignments.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y));
+ definitions.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y));
continue;
}
@@ -462,7 +462,7 @@ struct SmvWorker
if (cell->type == "$logic_and") expr = expr_a + " & " + expr_b;
if (cell->type == "$logic_or") expr = expr_a + " | " + expr_b;
- assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
+ definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
continue;
}
@@ -474,7 +474,7 @@ struct SmvWorker
string expr_a = stringf("(%s = 0ub%d_0)", rvalue(cell->getPort("\\A")), width_a);
const char *expr_y = lvalue(cell->getPort("\\Y"));
- assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y));
+ definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y));
continue;
}
@@ -490,12 +490,13 @@ struct SmvWorker
expr += stringf("bool(%s) ? %s : ", rvalue(sig_s[i]), rvalue(sig_b.extract(i*width, width)));
expr += rvalue(sig_a);
- assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
+ definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
continue;
}
if (cell->type == "$dff")
{
+ vars.push_back(stringf("%s : unsigned word[%d]; -- %s", lvalue(cell->getPort("\\Q")), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))));
assignments.push_back(stringf("next(%s) := %s;", lvalue(cell->getPort("\\Q")), rvalue(cell->getPort("\\D"))));
continue;
}
@@ -503,7 +504,7 @@ struct SmvWorker
if (cell->type.in("$_BUF_", "$_NOT_"))
{
string op = cell->type == "$_NOT_" ? "!" : "";
- assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A"))));
+ definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A"))));
continue;
}
@@ -517,49 +518,49 @@ struct SmvWorker
if (cell->type.in("$_XNOR_")) op = "xnor";
if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
- assignments.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
else
if (cell->type.in("$_NAND_", "$_NOR_"))
- assignments.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
else
- assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
continue;
}
if (cell->type == "$_MUX_")
{
- assignments.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort("\\Y")),
+ 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_")
{
- assignments.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C"))));
continue;
}
if (cell->type == "$_OAI3_")
{
- assignments.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C"))));
continue;
}
if (cell->type == "$_AOI4_")
{
- assignments.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D"))));
continue;
}
if (cell->type == "$_OAI4_")
{
- assignments.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")),
+ definitions.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D"))));
continue;
}
@@ -567,13 +568,13 @@ struct SmvWorker
if (cell->type[0] == '$')
log_error("Found currently unsupported cell type %s (%s.%s).\n", log_id(cell->type), log_id(module), log_id(cell));
- f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type));
+// f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type));
for (auto &conn : cell->connections())
if (cell->output(conn.first))
- assignments.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first)));
+ definitions.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first)));
else
- assignments.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second)));
+ definitions.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second)));
}
for (Wire *wire : partial_assignment_wires)
@@ -657,7 +658,25 @@ struct SmvWorker
}
}
- assignments.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str()));
+ definitions.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str()));
+ }
+
+ if (!inputvars.empty()) {
+ f << stringf(" IVAR\n");
+ for (const string &line : inputvars)
+ f << stringf(" %s\n", line.c_str());
+ }
+
+ if (!vars.empty()) {
+ f << stringf(" VAR\n");
+ for (const string &line : vars)
+ f << stringf(" %s\n", line.c_str());
+ }
+
+ if (!definitions.empty()) {
+ f << stringf(" DEFINE\n");
+ for (const string &line : definitions)
+ f << stringf(" %s\n", line.c_str());
}
if (!assignments.empty()) {
diff --git a/backends/table/table.cc b/backends/table/table.cc
index 979273dd..b75169ea 100644
--- a/backends/table/table.cc
+++ b/backends/table/table.cc
@@ -109,7 +109,7 @@ struct TableBackend : public Backend {
else if (cell->output(conn.first))
*f << "out" << "\t";
else
- *f << "unkown" << "\t";
+ *f << "unknown" << "\t";
*f << log_signal(sigmap(conn.second)) << "\n";
}
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index ae903151..83d83f48 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -33,7 +33,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal;
+bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit;
int auto_name_counter, auto_name_offset, auto_name_digits;
std::map<RTLIL::IdString, int> auto_name_map;
std::set<RTLIL::IdString> reg_wires, reg_ct;
@@ -126,6 +126,33 @@ std::string id(RTLIL::IdString internal_id, bool may_rename = true)
break;
}
+ const pool<string> keywords = {
+ // IEEE 1800-2017 Annex B
+ "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
+ "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
+ "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
+ "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
+ "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
+ "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
+ "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
+ "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
+ "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
+ "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
+ "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
+ "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
+ "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
+ "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
+ "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
+ "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
+ "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
+ "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
+ "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
+ "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
+ "wildcard", "wire", "with", "within", "wor", "xnor", "xor",
+ };
+ if (keywords.count(str))
+ do_escape = true;
+
if (do_escape)
return "\\" + std::string(str) + " ";
return std::string(str);
@@ -388,7 +415,7 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory)
{
dump_attributes(f, indent, memory->attributes);
- f << stringf("%s" "reg [%d:0] %s [%d:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
+ f << stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size+memory->start_offset-1, memory->start_offset);
}
void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
@@ -678,13 +705,45 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
#undef HANDLE_UNIOP
#undef HANDLE_BINOP
- if (cell->type == "$shiftx")
+ if (cell->type == "$shift")
{
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort("\\Y"));
f << stringf(" = ");
+ if (cell->getParam("\\B_SIGNED").as_bool())
+ {
+ f << stringf("$signed(");
+ dump_sigspec(f, cell->getPort("\\B"));
+ f << stringf(")");
+ f << stringf(" < 0 ? ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" << - ");
+ dump_sigspec(f, cell->getPort("\\B"));
+ f << stringf(" : ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" >> ");
+ dump_sigspec(f, cell->getPort("\\B"));
+ }
+ else
+ {
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" >> ");
+ dump_sigspec(f, cell->getPort("\\B"));
+ }
+ f << stringf(";\n");
+ return true;
+ }
+
+ if (cell->type == "$shiftx")
+ {
+ std::string temp_id = next_auto_id();
+ f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort("\\A"))-1, temp_id.c_str());
dump_sigspec(f, cell->getPort("\\A"));
- f << stringf("[");
+ f << stringf(";\n");
+
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = %s[", temp_id.c_str());
if (cell->getParam("\\B_SIGNED").as_bool())
f << stringf("$signed(");
dump_sigspec(f, cell->getPort("\\B"));
@@ -757,6 +816,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
+ if (cell->type == "$tribuf")
+ {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
+ dump_sigspec(f, cell->getPort("\\EN"));
+ f << stringf(" ? ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf(" : %d'bz;\n", cell->parameters.at("\\WIDTH").as_int());
+ return true;
+ }
+
if (cell->type == "$slice")
{
f << stringf("%s" "assign ", indent.c_str());
@@ -952,6 +1023,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
int abits = cell->parameters["\\ABITS"].as_int();
int size = cell->parameters["\\SIZE"].as_int();
+ int offset = cell->parameters["\\OFFSET"].as_int();
int width = cell->parameters["\\WIDTH"].as_int();
bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef());
@@ -960,7 +1032,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
// initial begin
// memid[0] = ...
// end
- f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size-1, 0);
+ f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size+offset-1, offset);
if (use_init)
{
f << stringf("%s" "initial begin\n", indent.c_str());
@@ -993,43 +1065,46 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
+ if (use_rd_clk)
{
- std::ostringstream os;
- dump_sigspec(os, sig_rd_clk);
- clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
- if( clk_to_lof_body.count(clk_domain_str) == 0 )
- clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
- }
- if (use_rd_clk && !rd_transparent)
- {
- // for clocked read ports make something like:
- // reg [..] temp_id;
- // always @(posedge clk)
- // if (rd_en) temp_id <= array_reg[r_addr];
- // assign r_data = temp_id;
- std::string temp_id = next_auto_id();
- lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
{
std::ostringstream os;
- if (sig_rd_en != RTLIL::SigBit(true))
+ dump_sigspec(os, sig_rd_clk);
+ clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
+ if( clk_to_lof_body.count(clk_domain_str) == 0 )
+ clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
+ }
+ if (!rd_transparent)
+ {
+ // for clocked read ports make something like:
+ // reg [..] temp_id;
+ // always @(posedge clk)
+ // if (rd_en) temp_id <= array_reg[r_addr];
+ // assign r_data = temp_id;
+ std::string temp_id = next_auto_id();
+ lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
{
- os << stringf("if (");
- dump_sigspec(os, sig_rd_en);
- os << stringf(") ");
+ std::ostringstream os;
+ if (sig_rd_en != RTLIL::SigBit(true))
+ {
+ os << stringf("if (");
+ dump_sigspec(os, sig_rd_en);
+ os << stringf(") ");
+ }
+ os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
+ dump_sigspec(os, sig_rd_addr);
+ os << stringf("];\n");
+ clk_to_lof_body[clk_domain_str].push_back(os.str());
+ }
+ {
+ std::ostringstream os;
+ dump_sigspec(os, sig_rd_data);
+ std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
+ clk_to_lof_body[""].push_back(line);
}
- os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
- dump_sigspec(os, sig_rd_addr);
- os << stringf("];\n");
- clk_to_lof_body[clk_domain_str].push_back(os.str());
}
+ else
{
- std::ostringstream os;
- dump_sigspec(os, sig_rd_data);
- std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
- clk_to_lof_body[""].push_back(line);
- }
- } else {
- if (rd_transparent) {
// for rd-transparent read-ports make something like:
// reg [..] temp_id;
// always @(posedge clk)
@@ -1049,15 +1124,15 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str());
clk_to_lof_body[""].push_back(line);
}
- } else {
- // for non-clocked read-ports make something like:
- // assign r_data = array_reg[r_addr];
- std::ostringstream os, os2;
- dump_sigspec(os, sig_rd_data);
- dump_sigspec(os2, sig_rd_addr);
- std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
- clk_to_lof_body[""].push_back(line);
}
+ } else {
+ // for non-clocked read-ports make something like:
+ // assign r_data = array_reg[r_addr];
+ std::ostringstream os, os2;
+ dump_sigspec(os, sig_rd_data);
+ dump_sigspec(os2, sig_rd_addr);
+ std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
+ clk_to_lof_body[""].push_back(line);
}
}
@@ -1235,6 +1310,15 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
}
}
+ if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) {
+ std::stringstream ss;
+ dump_reg_init(ss, cell->getPort("\\Q"));
+ if (!ss.str().empty()) {
+ f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str());
+ f << ss.str();
+ f << ";\n";
+ }
+ }
}
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
@@ -1351,6 +1435,8 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
if (sync->type == RTLIL::STa) {
f << stringf("%s" "always @* begin\n", indent.c_str());
+ } else if (sync->type == RTLIL::STi) {
+ f << stringf("%s" "initial begin\n", indent.c_str());
} else {
f << stringf("%s" "always @(", indent.c_str());
if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
@@ -1415,10 +1501,10 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
}
if (!module->processes.empty())
- log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
+ log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
"can't always be mapped directly to Verilog always blocks. Unintended\n"
"changes in simulation behavior are possible! Use \"proc\" to convert\n"
- "processes to logic networks and registers.", log_id(module));
+ "processes to logic networks and registers.\n", log_id(module));
f << stringf("\n");
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
@@ -1521,6 +1607,10 @@ struct VerilogBackend : public Backend {
log(" without this option all internal cells are converted to Verilog\n");
log(" expressions.\n");
log("\n");
+ log(" -siminit\n");
+ log(" add initial statements with hierarchical refs to initialize FFs when\n");
+ log(" in -noexpr mode.\n");
+ log("\n");
log(" -nodec\n");
log(" 32-bit constant values are by default dumped as decimal numbers,\n");
log(" not bit pattern. This option deactivates this feature and instead\n");
@@ -1577,11 +1667,14 @@ struct VerilogBackend : public Backend {
nostr = false;
defparam = false;
decimal = false;
+ siminit = false;
auto_prefix = "";
bool blackboxes = false;
bool selected = false;
+ auto_name_map.clear();
+ reg_wires.clear();
reg_ct.clear();
reg_ct.insert("$dff");
@@ -1653,6 +1746,10 @@ struct VerilogBackend : public Backend {
decimal = true;
continue;
}
+ if (arg == "-siminit") {
+ siminit = true;
+ continue;
+ }
if (arg == "-blackboxes") {
blackboxes = true;
continue;
@@ -1684,6 +1781,8 @@ struct VerilogBackend : public Backend {
dump_module(*f, "", it->second);
}
+ auto_name_map.clear();
+ reg_wires.clear();
reg_ct.clear();
}
} VerilogBackend;
diff --git a/examples/anlogic/.gitignore b/examples/anlogic/.gitignore
new file mode 100644
index 00000000..97c978a1
--- /dev/null
+++ b/examples/anlogic/.gitignore
@@ -0,0 +1,7 @@
+demo.bit
+demo_phy.area
+full.v
+*.log
+*.h
+*.tde
+*.svf
diff --git a/examples/anlogic/README b/examples/anlogic/README
new file mode 100644
index 00000000..35d8e9cb
--- /dev/null
+++ b/examples/anlogic/README
@@ -0,0 +1,12 @@
+LED Blink project for Anlogic Lichee Tang board.
+
+Follow the install instructions for the Tang Dynasty IDE from given link below.
+
+https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/
+
+
+set TD_HOME env variable to the full path to the TD <TD Install Directory> as follow.
+
+export TD_HOME=<TD Install Directory>
+
+then run "bash build.sh" in this directory.
diff --git a/examples/anlogic/build.sh b/examples/anlogic/build.sh
new file mode 100755
index 00000000..e0f6b4cf
--- /dev/null
+++ b/examples/anlogic/build.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+set -ex
+yosys demo.ys
+$TD_HOME/bin/td build.tcl
diff --git a/examples/anlogic/build.tcl b/examples/anlogic/build.tcl
new file mode 100644
index 00000000..06db525c
--- /dev/null
+++ b/examples/anlogic/build.tcl
@@ -0,0 +1,11 @@
+import_device eagle_s20.db -package BG256
+read_verilog full.v -top demo
+read_adc demo.adc
+optimize_rtl
+map_macro
+map
+pack
+place
+route
+report_area -io_info -file demo_phy.area
+bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000
diff --git a/examples/anlogic/demo.adc b/examples/anlogic/demo.adc
new file mode 100644
index 00000000..ec802502
--- /dev/null
+++ b/examples/anlogic/demo.adc
@@ -0,0 +1,2 @@
+set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ
+set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED
diff --git a/examples/anlogic/demo.v b/examples/anlogic/demo.v
new file mode 100644
index 00000000..e17db771
--- /dev/null
+++ b/examples/anlogic/demo.v
@@ -0,0 +1,18 @@
+module demo (
+ input wire CLK_IN,
+ output wire R_LED
+);
+ parameter time1 = 30'd12_000_000;
+ reg led_state;
+ reg [29:0] count;
+
+ always @(posedge CLK_IN)begin
+ if(count == time1)begin
+ count<= 30'd0;
+ led_state <= ~led_state;
+ end
+ else
+ count <= count + 1'b1;
+ end
+ assign R_LED = led_state;
+endmodule
diff --git a/examples/anlogic/demo.ys b/examples/anlogic/demo.ys
new file mode 100644
index 00000000..cb396cc2
--- /dev/null
+++ b/examples/anlogic/demo.ys
@@ -0,0 +1,3 @@
+read_verilog demo.v
+synth_anlogic -top demo
+write_verilog full.v
diff --git a/examples/igloo2/.gitignore b/examples/igloo2/.gitignore
new file mode 100644
index 00000000..33b7182d
--- /dev/null
+++ b/examples/igloo2/.gitignore
@@ -0,0 +1,4 @@
+/netlist.edn
+/netlist.vm
+/example.stp
+/proj
diff --git a/examples/igloo2/example.pdc b/examples/igloo2/example.pdc
new file mode 100644
index 00000000..298d9e93
--- /dev/null
+++ b/examples/igloo2/example.pdc
@@ -0,0 +1,20 @@
+# Add placement constraints here
+
+set_io clk -pinname H16 -fixed yes -DIRECTION INPUT
+
+set_io SW1 -pinname H12 -fixed yes -DIRECTION INPUT
+set_io SW2 -pinname H13 -fixed yes -DIRECTION INPUT
+
+set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT
+set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT
+set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT
+set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT
+
+set_io AA -pinname L12 -fixed yes -DIRECTION OUTPUT
+set_io AB -pinname L13 -fixed yes -DIRECTION OUTPUT
+set_io AC -pinname M13 -fixed yes -DIRECTION OUTPUT
+set_io AD -pinname N15 -fixed yes -DIRECTION OUTPUT
+set_io AE -pinname L11 -fixed yes -DIRECTION OUTPUT
+set_io AF -pinname L14 -fixed yes -DIRECTION OUTPUT
+set_io AG -pinname N14 -fixed yes -DIRECTION OUTPUT
+set_io CA -pinname M15 -fixed yes -DIRECTION OUTPUT
diff --git a/examples/igloo2/example.sdc b/examples/igloo2/example.sdc
new file mode 100644
index 00000000..f8b48731
--- /dev/null
+++ b/examples/igloo2/example.sdc
@@ -0,0 +1,2 @@
+# Add timing constraints here
+create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]
diff --git a/examples/igloo2/example.v b/examples/igloo2/example.v
new file mode 100644
index 00000000..4a9486e5
--- /dev/null
+++ b/examples/igloo2/example.v
@@ -0,0 +1,64 @@
+module example (
+ input clk,
+ input SW1,
+ input SW2,
+ output LED1,
+ output LED2,
+ output LED3,
+ output LED4,
+
+ output AA, AB, AC, AD,
+ output AE, AF, AG, CA
+);
+
+ localparam BITS = 8;
+ localparam LOG2DELAY = 22;
+
+ reg [BITS+LOG2DELAY-1:0] counter = 0;
+ reg [BITS-1:0] outcnt;
+
+ always @(posedge clk) begin
+ counter <= counter + SW1 + SW2 + 1;
+ outcnt <= counter >> LOG2DELAY;
+ end
+
+ assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1);
+
+ // assign CA = counter[10];
+ // seg7enc seg7encinst (
+ // .seg({AA, AB, AC, AD, AE, AF, AG}),
+ // .dat(CA ? outcnt[3:0] : outcnt[7:4])
+ // );
+
+ assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]);
+ assign CA = outcnt[7];
+endmodule
+
+module seg7enc (
+ input [3:0] dat,
+ output [6:0] seg
+);
+ reg [6:0] seg_inv;
+ always @* begin
+ seg_inv = 0;
+ case (dat)
+ 4'h0: seg_inv = 7'b 0111111;
+ 4'h1: seg_inv = 7'b 0000110;
+ 4'h2: seg_inv = 7'b 1011011;
+ 4'h3: seg_inv = 7'b 1001111;
+ 4'h4: seg_inv = 7'b 1100110;
+ 4'h5: seg_inv = 7'b 1101101;
+ 4'h6: seg_inv = 7'b 1111101;
+ 4'h7: seg_inv = 7'b 0000111;
+ 4'h8: seg_inv = 7'b 1111111;
+ 4'h9: seg_inv = 7'b 1101111;
+ 4'hA: seg_inv = 7'b 1110111;
+ 4'hB: seg_inv = 7'b 1111100;
+ 4'hC: seg_inv = 7'b 0111001;
+ 4'hD: seg_inv = 7'b 1011110;
+ 4'hE: seg_inv = 7'b 1111001;
+ 4'hF: seg_inv = 7'b 1110001;
+ endcase
+ end
+ assign seg = ~seg_inv;
+endmodule
diff --git a/examples/igloo2/libero.tcl b/examples/igloo2/libero.tcl
new file mode 100644
index 00000000..abc94e47
--- /dev/null
+++ b/examples/igloo2/libero.tcl
@@ -0,0 +1,57 @@
+# Run with "libero SCRIPT:libero.tcl"
+
+file delete -force proj
+
+new_project \
+ -name example \
+ -location proj \
+ -block_mode 0 \
+ -hdl "VERILOG" \
+ -family IGLOO2 \
+ -die PA4MGL2500 \
+ -package vf256 \
+ -speed -1
+
+import_files -hdl_source {netlist.vm}
+import_files -sdc {example.sdc}
+import_files -io_pdc {example.pdc}
+build_design_hierarchy
+set_option -synth 0
+
+organize_tool_files -tool PLACEROUTE \
+ -file {proj/constraint/example.sdc} \
+ -file {proj/constraint/io/example.pdc} \
+ -input_type constraint
+
+organize_tool_files -tool VERIFYTIMING \
+ -file {proj/constraint/example.sdc} \
+ -input_type constraint
+
+configure_tool -name PLACEROUTE \
+ -params TDPR:true \
+ -params PDPR:false \
+ -params EFFORT_LEVEL:false \
+ -params REPAIR_MIN_DELAY:false
+
+puts ""
+puts "**> COMPILE"
+run_tool -name {COMPILE}
+puts "<** COMPILE"
+
+puts ""
+puts "**> PLACEROUTE"
+run_tool -name {PLACEROUTE}
+puts "<** PLACEROUTE"
+
+puts ""
+puts "**> VERIFYTIMING"
+run_tool -name {VERIFYTIMING}
+puts "<** VERIFYTIMING"
+
+puts ""
+puts "**> BITSTREAM"
+export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC}
+puts "<** BITSTREAM"
+
+puts ""
+exit 0
diff --git a/examples/igloo2/runme.sh b/examples/igloo2/runme.sh
new file mode 100644
index 00000000..a08894e0
--- /dev/null
+++ b/examples/igloo2/runme.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -ex
+yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v
+export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost}
+/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl
+cp proj/designer/example/export/example.stp .
diff --git a/frontends/aiger/Makefile.inc b/frontends/aiger/Makefile.inc
new file mode 100644
index 00000000..bc111245
--- /dev/null
+++ b/frontends/aiger/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += frontends/aiger/aigerparse.o
+
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
new file mode 100644
index 00000000..cf7950c8
--- /dev/null
+++ b/frontends/aiger/aigerparse.cc
@@ -0,0 +1,414 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 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]] The AIGER And-Inverter Graph (AIG) Format Version 20071012
+// 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>
+#endif
+#include <array>
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "aigerparse.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+#define log_debug log
+
+AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
+ : design(design), f(f), clk_name(clk_name)
+{
+ module = new RTLIL::Module;
+ module->name = module_name;
+ if (design->module(module->name))
+ log_error("Duplicate definition of module %s!\n", log_id(module->name));
+}
+
+void AigerReader::parse_aiger()
+{
+ 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;
+ for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) {
+ if (f.peek() != ' ') break;
+ if (!(f >> i))
+ log_error("Invalid AIGER header\n");
+ }
+
+ 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 B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
+
+ line_count = 1;
+
+ if (header == "aag")
+ parse_aiger_ascii();
+ else if (header == "aig")
+ parse_aiger_binary();
+ else
+ log_abort();
+
+ // Parse footer (symbol table, comments, etc.)
+ unsigned l1;
+ std::string s;
+ for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
+ if (c == 'i' || c == 'l' || c == 'o') {
+ f.ignore(1);
+ if (!(f >> l1 >> s))
+ log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
+
+ if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
+ log_error("Line %u has invalid symbol position!\n", line_count);
+
+ RTLIL::Wire* wire;
+ if (c == 'i') wire = inputs[l1];
+ else if (c == 'l') wire = latches[l1];
+ else if (c == 'o') wire = outputs[l1];
+ else log_abort();
+
+ module->rename(wire, stringf("\\%s", s.c_str()));
+ }
+ else if (c == 'b' || c == 'j' || c == 'f') {
+ // TODO
+ }
+ else if (c == 'c') {
+ f.ignore(1);
+ if (f.peek() == '\n')
+ break;
+ // Else constraint (TODO)
+ }
+ else
+ log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
+ std::getline(f, line); // Ignore up to start of next line
+ }
+
+ module->fixup_ports();
+ design->add(module);
+}
+
+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::Wire *wire = module->wire(wire_name);
+ if (wire) return wire;
+ log_debug("Creating %s\n", wire_name.c_str());
+ wire = module->addWire(wire_name);
+ if (!invert) return wire;
+ RTLIL::IdString wire_inv_name(stringf("\\n%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());
+ wire_inv = module->addWire(wire_inv_name);
+ }
+
+ 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?
+
+ return wire;
+}
+
+void AigerReader::parse_aiger_ascii()
+{
+ std::string line;
+ std::stringstream ss;
+
+ unsigned l1, l2, l3;
+
+ // Parse inputs
+ for (unsigned i = 0; 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?
+ RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+ wire->port_input = true;
+ inputs.push_back(wire);
+ }
+
+ // Parse latches
+ RTLIL::Wire *clk_wire = nullptr;
+ if (L > 0) {
+ clk_wire = module->wire(clk_name);
+ log_assert(!clk_wire);
+ log_debug("Creating %s\n", clk_name.c_str());
+ clk_wire = module->addWire(clk_name);
+ clk_wire->port_input = true;
+ }
+ 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?
+ RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
+ RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
+
+ module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
+
+ // Reset logic is optional in AIGER 1.9
+ if (f.peek() == ' ') {
+ if (!(f >> l3))
+ log_error("Line %u cannot be interpreted as a latch!\n", line_count);
+
+ if (l3 == 0 || l3 == 1)
+ q_wire->attributes["\\init"] = RTLIL::Const(l3);
+ else if (l3 == l1) {
+ //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::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::Const(0);
+ }
+ latches.push_back(q_wire);
+ }
+
+ // Parse outputs
+ for (unsigned i = 0; i < O; ++i, ++line_count) {
+ 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);
+ wire->port_output = true;
+ outputs.push_back(wire);
+ }
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse bad state properties
+ for (unsigned i = 0; i < B; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse invariant constraints
+ for (unsigned i = 0; i < C; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse justice properties
+ for (unsigned i = 0; i < J; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse fairness constraints
+ for (unsigned i = 0; i < F; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // Parse AND
+ for (unsigned i = 0; i < A; ++i) {
+ 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?
+ 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);
+ }
+ std::getline(f, line); // Ignore up to start of next line
+}
+
+static unsigned parse_next_delta_literal(std::istream &f, unsigned ref)
+{
+ unsigned x = 0, i = 0;
+ unsigned char ch;
+ while ((ch = f.get()) & 0x80)
+ x |= (ch & 0x7f) << (7 * i++);
+ return ref - (x | (ch << (7 * i)));
+}
+
+void AigerReader::parse_aiger_binary()
+{
+ unsigned l1, l2, l3;
+ std::string line;
+
+ // Parse inputs
+ for (unsigned i = 1; i <= I; ++i) {
+ RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
+ wire->port_input = true;
+ inputs.push_back(wire);
+ }
+
+ // Parse latches
+ RTLIL::Wire *clk_wire = nullptr;
+ if (L > 0) {
+ clk_wire = module->wire(clk_name);
+ log_assert(!clk_wire);
+ log_debug("Creating %s\n", clk_name.c_str());
+ clk_wire = module->addWire(clk_name);
+ clk_wire->port_input = true;
+ }
+ l1 = (I+1) * 2;
+ for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
+ if (!(f >> l2))
+ log_error("Line %u cannot be interpreted as a latch!\n", line_count);
+ log_debug("%d %d is a latch\n", l1, l2);
+ RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
+ RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
+
+ module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
+
+ // Reset logic is optional in AIGER 1.9
+ if (f.peek() == ' ') {
+ if (!(f >> l3))
+ log_error("Line %u cannot be interpreted as a latch!\n", line_count);
+
+ if (l3 == 0 || l3 == 1)
+ q_wire->attributes["\\init"] = RTLIL::Const(l3);
+ else if (l3 == l1) {
+ //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::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::Const(0);
+ }
+ latches.push_back(q_wire);
+ }
+
+ // Parse outputs
+ for (unsigned i = 0; i < O; ++i, ++line_count) {
+ 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);
+ wire->port_output = true;
+ outputs.push_back(wire);
+ }
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse bad state properties
+ for (unsigned i = 0; i < B; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse invariant constraints
+ for (unsigned i = 0; i < C; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse justice properties
+ for (unsigned i = 0; i < J; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // TODO: Parse fairness constraints
+ for (unsigned i = 0; i < F; ++i, ++line_count)
+ std::getline(f, line); // Ignore up to start of next line
+
+ // Parse AND
+ l1 = (I+L+1) << 1;
+ for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) {
+ 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?
+ RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
+ RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
+ RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
+
+ 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);
+ }
+}
+
+struct AigerFrontend : public Frontend {
+ AigerFrontend() : Frontend("aiger", "read AIGER file") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" read_aiger [options] [filename]\n");
+ log("\n");
+ 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: <filename>)"
+#ifdef _WIN32
+ "top" // FIXME
+#else
+ "<filename>"
+#endif
+ ")\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");
+ }
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing AIGER frontend.\n");
+
+ RTLIL::IdString clk_name = "\\clk";
+ RTLIL::IdString module_name;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-module_name" && argidx+1 < args.size()) {
+ module_name = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ if (arg == "-clk_name" && argidx+1 < args.size()) {
+ clk_name = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ if (module_name.empty()) {
+#ifdef _WIN32
+ module_name = "top"; // FIXME: basename equivalent on Win32?
+#else
+ char* bn = strdup(filename.c_str());
+ module_name = RTLIL::escape_id(bn);
+ free(bn);
+#endif
+ }
+
+ AigerReader reader(design, *f, module_name, clk_name);
+ reader.parse_aiger();
+ }
+} AigerFrontend;
+
+YOSYS_NAMESPACE_END
diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h
new file mode 100644
index 00000000..c49cd152
--- /dev/null
+++ b/frontends/aiger/aigerparse.h
@@ -0,0 +1,51 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 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.
+ *
+ */
+
+#ifndef ABC_AIGERPARSE
+#define ABC_AIGERPARSE
+
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct AigerReader
+{
+ RTLIL::Design *design;
+ std::istream &f;
+ RTLIL::IdString clk_name;
+ RTLIL::Module *module;
+
+ unsigned M, I, L, O, A;
+ unsigned B, C, J, F; // Optional in AIGER 1.9
+ unsigned line_count;
+
+ std::vector<RTLIL::Wire*> inputs;
+ std::vector<RTLIL::Wire*> latches;
+ std::vector<RTLIL::Wire*> outputs;
+
+ AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name);
+ void parse_aiger();
+ void parse_aiger_ascii();
+ void parse_aiger_binary();
+};
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index e79be953..d4899616 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -2,6 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 Ruben Undheim <ruben.undheim@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
@@ -35,16 +36,16 @@ YOSYS_NAMESPACE_BEGIN
using namespace AST;
using namespace AST_INTERNAL;
-// instanciate global variables (public API)
+// instantiate global variables (public API)
namespace AST {
std::string current_filename;
void (*set_line_num)(int) = NULL;
int (*get_line_num)() = NULL;
}
-// instanciate global variables (private API)
+// instantiate global variables (private API)
namespace AST_INTERNAL {
- bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
+ bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
@@ -171,8 +172,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
AstNode *attr = attributes.at(id);
if (attr->type != AST_CONSTANT)
- log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n",
- id.c_str());
+ log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n", id.c_str());
return attr->integer != 0;
}
@@ -431,9 +431,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
break;
case AST_RANGE:
- if (range_valid)
- fprintf(f, "[%d:%d]", range_left, range_right);
- else {
+ if (range_valid) {
+ if (range_swapped)
+ fprintf(f, "[%d:%d]", range_right, range_left);
+ else
+ fprintf(f, "[%d:%d]", range_left, range_right);
+ } else {
for (auto child : children) {
fprintf(f, "%c", first ? '[' : ':');
child->dumpVlog(f, "");
@@ -562,7 +565,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_CONCAT:
fprintf(f, "{");
- for (auto child : children) {
+ for (int i = GetSize(children)-1; i >= 0; i--) {
+ auto child = children[i];
if (!first)
fprintf(f, ", ");
child->dumpVlog(f, "");
@@ -903,9 +907,9 @@ RTLIL::Const AstNode::realAsConst(int width)
}
// create a new AstModule from an AST_MODULE AST node
-static AstModule* process_module(AstNode *ast, bool defer)
+static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL)
{
- log_assert(ast->type == AST_MODULE);
+ log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
if (defer)
log("Storing AST representation for module `%s'.\n", ast->str.c_str());
@@ -916,28 +920,38 @@ static AstModule* process_module(AstNode *ast, bool defer)
current_module->ast = NULL;
current_module->name = ast->str;
current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
+ current_module->set_bool_attribute("\\cells_not_processed");
current_ast_mod = ast;
- AstNode *ast_before_simplify = ast->clone();
+ AstNode *ast_before_simplify;
+ if (original_ast != NULL)
+ ast_before_simplify = original_ast;
+ else
+ ast_before_simplify = ast->clone();
if (flag_dump_ast1) {
- log("Dumping Verilog AST before simplification:\n");
+ log("Dumping AST before simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
+ if (flag_dump_vlog1) {
+ log("Dumping Verilog AST before simplification:\n");
+ ast->dumpVlog(NULL, " ");
+ log("--- END OF AST DUMP ---\n");
+ }
if (!defer)
{
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) {
- log("Dumping Verilog AST after simplification:\n");
+ log("Dumping AST after simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
- if (flag_dump_vlog) {
- log("Dumping Verilog AST (as requested by dump_vlog option):\n");
+ if (flag_dump_vlog2) {
+ log("Dumping Verilog AST after simplification:\n");
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
@@ -963,8 +977,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
current_module->attributes[attr.first] = attr.second->asAttrConst();
}
for (size_t i = 0; i < ast->children.size(); i++) {
@@ -989,6 +1002,8 @@ static AstModule* process_module(AstNode *ast, bool defer)
ignoreThisSignalsInInitial = RTLIL::SigSpec();
}
+ if (ast->type == AST_INTERFACE)
+ current_module->set_bool_attribute("\\is_interface");
current_module->ast = ast_before_simplify;
current_module->nolatches = flag_nolatches;
current_module->nomeminit = flag_nomeminit;
@@ -1010,14 +1025,15 @@ static AstModule* process_module(AstNode *ast, bool defer)
}
// create AstModule instances for all modules in the AST tree and add them to 'design'
-void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog, bool dump_rtlil,
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
flag_no_dump_ptr = no_dump_ptr;
- flag_dump_vlog = dump_vlog;
+ flag_dump_vlog1 = dump_vlog1;
+ flag_dump_vlog2 = dump_vlog2;
flag_dump_rtlil = dump_rtlil;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
@@ -1031,7 +1047,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
log_assert(current_ast->type == AST_DESIGN);
for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)
{
- if ((*it)->type == AST_MODULE)
+ if ((*it)->type == AST_MODULE || (*it)->type == AST_INTERFACE)
{
for (auto n : design->verilog_globals)
(*it)->children.push_back(n->clone());
@@ -1053,8 +1069,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")) {
- log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n",
- (*it)->str.c_str());
+ 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",
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
@@ -1083,8 +1098,264 @@ AstModule::~AstModule()
delete ast;
}
+
+// An interface port with modport is specified like this:
+// <interface_name>.<modport_name>
+// This function splits the interface_name from the modport_name, and fails if it is not a valid combination
+std::pair<std::string,std::string> AST::split_modport_from_type(std::string name_type)
+{
+ std::string interface_type = "";
+ std::string interface_modport = "";
+ size_t ndots = std::count(name_type.begin(), name_type.end(), '.');
+ // Separate the interface instance name from any modports:
+ if (ndots == 0) { // Does not have modport
+ interface_type = name_type;
+ }
+ else {
+ std::stringstream name_type_stream(name_type);
+ std::string segment;
+ std::vector<std::string> seglist;
+ while(std::getline(name_type_stream, segment, '.')) {
+ seglist.push_back(segment);
+ }
+ if (ndots == 1) { // Has modport
+ interface_type = seglist[0];
+ interface_modport = seglist[1];
+ }
+ else { // Erroneous port type
+ log_error("More than two '.' in signal port type (%s)\n", name_type.c_str());
+ }
+ }
+ return std::pair<std::string,std::string>(interface_type, interface_modport);
+
+}
+
+AstNode * AST::find_modport(AstNode *intf, std::string name)
+{
+ for (auto &ch : intf->children)
+ if (ch->type == AST_MODPORT)
+ if (ch->str == name) // Modport found
+ return ch;
+ return NULL;
+}
+
+// Iterate over all wires in an interface and add them as wires in the AST module:
+void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport)
+{
+ for (auto &wire_it : intfmodule->wires_){
+ AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
+ std::string origname = log_id(wire_it.first);
+ std::string newname = intfname + "." + origname;
+ wire->str = newname;
+ if (modport != NULL) {
+ bool found_in_modport = false;
+ // Search for the current wire in the wire list for the current modport
+ for (auto &ch : modport->children) {
+ if (ch->type == AST_MODPORTMEMBER) {
+ std::string compare_name = "\\" + origname;
+ if (ch->str == compare_name) { // Found signal. The modport decides whether it is input or output
+ found_in_modport = true;
+ wire->is_input = ch->is_input;
+ wire->is_output = ch->is_output;
+ break;
+ }
+ }
+ }
+ if (found_in_modport) {
+ module_ast->children.push_back(wire);
+ }
+ else { // If not found in modport, do not create port
+ delete wire;
+ }
+ }
+ else { // If no modport, set inout
+ wire->is_input = true;
+ wire->is_output = true;
+ module_ast->children.push_back(wire);
+ }
+ }
+}
+
+// When an interface instance is found in a module, the whole RTLIL for the module will be rederived again
+// from AST. The interface members are copied into the AST module with the prefix of the interface.
+void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module*> local_interfaces)
+{
+ bool is_top = false;
+ AstNode *new_ast = ast->clone();
+ for (auto &intf : local_interfaces) {
+ std::string intfname = intf.first.str();
+ RTLIL::Module *intfmodule = intf.second;
+ for (auto &wire_it : intfmodule->wires_){
+ AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
+ std::string newname = log_id(wire_it.first);
+ newname = intfname + "." + newname;
+ wire->str = newname;
+ new_ast->children.push_back(wire);
+ }
+ }
+
+ AstNode *ast_before_replacing_interface_ports = new_ast->clone();
+
+ // Explode all interface ports. Note this will only have an effect on 'top
+ // level' modules. Other sub-modules will have their interface ports
+ // exploded via the derive(..) function
+ for (size_t i =0; i<new_ast->children.size(); i++)
+ {
+ AstNode *ch2 = new_ast->children[i];
+ if (ch2->type == AST_INTERFACEPORT) { // Is an interface port
+ std::string name_port = ch2->str; // Name of the interface port
+ if (ch2->children.size() > 0) {
+ for(size_t j=0; j<ch2->children.size();j++) {
+ AstNode *ch = ch2->children[j];
+ if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface
+ std::pair<std::string,std::string> res = split_modport_from_type(ch->str);
+ std::string interface_type = res.first;
+ std::string interface_modport = res.second; // Is "", if no modport
+ if (design->modules_.count(interface_type) > 0) {
+ // Add a cell to the module corresponding to the interface port such that
+ // it can further propagated down if needed:
+ AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE);
+ celltype_for_intf->str = interface_type;
+ AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf);
+ cell_for_intf->str = name_port + "_inst_from_top_dummy";
+ new_ast->children.push_back(cell_for_intf);
+
+ // Get all members of this non-overridden dummy interface instance:
+ RTLIL::Module *intfmodule = design->modules_[interface_type]; // All interfaces should at this point in time (assuming
+ // reprocess_module is called from the hierarchy pass) be
+ // present in design->modules_
+ AstModule *ast_module_of_interface = (AstModule*)intfmodule;
+ std::string interface_modport_compare_str = "\\" + interface_modport;
+ AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport
+ // Iterate over all wires in the interface and add them to the module:
+ explode_interface_port(new_ast, intfmodule, name_port, modport);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // The old module will be deleted. Rename and mark for deletion:
+ std::string original_name = this->name.str();
+ std::string changed_name = original_name + "_before_replacing_local_interfaces";
+ design->rename(this, changed_name);
+ this->set_bool_attribute("\\to_delete");
+
+ // Check if the module was the top module. If it was, we need to remove the top attribute and put it on the
+ // new module.
+ if (this->get_bool_attribute("\\initial_top")) {
+ this->attributes.erase("\\initial_top");
+ is_top = true;
+ }
+
+ // Generate RTLIL from AST for the new module and add to the design:
+ AstModule *newmod = process_module(new_ast, false, ast_before_replacing_interface_ports);
+ delete(new_ast);
+ design->add(newmod);
+ RTLIL::Module* mod = design->module(original_name);
+ if (is_top)
+ mod->set_bool_attribute("\\top");
+
+ // Set the attribute "interfaces_replaced_in_module" so that it does not happen again.
+ mod->set_bool_attribute("\\interfaces_replaced_in_module");
+}
+
+// create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces
+// This method is used to explode the interface when the interface is a port of the module (not instantiated inside)
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail)
+{
+ AstNode *new_ast = NULL;
+ std::string modname = derive_common(design, parameters, &new_ast, mayfail);
+
+ // Since interfaces themselves may be instantiated with different parameters,
+ // "modname" must also take those into account, so that unique modules
+ // are derived for any variant of interface connections:
+ std::string interf_info = "";
+
+ bool has_interfaces = false;
+ for(auto &intf : interfaces) {
+ interf_info += log_id(intf.second->name);
+ has_interfaces = true;
+ }
+
+ if (has_interfaces)
+ modname += "$interfaces$" + interf_info;
+
+
+ if (!design->has(modname)) {
+ new_ast->str = modname;
+
+ // Iterate over all interfaces which are ports in this module:
+ for(auto &intf : interfaces) {
+ RTLIL::Module * intfmodule = intf.second;
+ std::string intfname = intf.first.str();
+ // Check if a modport applies for the interface port:
+ AstNode *modport = NULL;
+ if (modports.count(intfname) > 0) {
+ std::string interface_modport = modports.at(intfname).str();
+ AstModule *ast_module_of_interface = (AstModule*)intfmodule;
+ AstNode *ast_node_of_interface = ast_module_of_interface->ast;
+ modport = find_modport(ast_node_of_interface, interface_modport);
+ }
+ // Iterate over all wires in the interface and add them to the module:
+ explode_interface_port(new_ast, intfmodule, intfname, modport);
+ }
+
+ design->add(process_module(new_ast, false));
+ design->module(modname)->check();
+
+ RTLIL::Module* mod = design->module(modname);
+
+ // Now that the interfaces have been exploded, we can delete the dummy port related to every interface.
+ for(auto &intf : interfaces) {
+ if(mod->wires_.count(intf.first)) {
+ mod->wires_.erase(intf.first);
+ mod->fixup_ports();
+ // We copy the cell of the interface to the sub-module such that it can further be found if it is propagated
+ // down to sub-sub-modules etc.
+ RTLIL::Cell * new_subcell = mod->addCell(intf.first, intf.second->name);
+ new_subcell->set_bool_attribute("\\is_interface");
+ }
+ else {
+ log_error("No port with matching name found (%s) in %s. Stopping\n", log_id(intf.first), modname.c_str());
+ }
+ }
+
+ // If any interfaces were replaced, set the attribute 'interfaces_replaced_in_module':
+ if (interfaces.size() > 0) {
+ mod->set_bool_attribute("\\interfaces_replaced_in_module");
+ }
+
+ } else {
+ log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
+ }
+
+ delete new_ast;
+ return modname;
+}
+
+// create a new parametric module (when needed) and return the name of the generated module - without support for interfaces
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail)
+{
+ AstNode *new_ast = NULL;
+ std::string modname = derive_common(design, parameters, &new_ast, mayfail);
+
+ if (!design->has(modname)) {
+ new_ast->str = modname;
+ design->add(process_module(new_ast, false));
+ design->module(modname)->check();
+ } else {
+ log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
+ }
+
+ delete new_ast;
+ return modname;
+}
+
// create a new parametric module (when needed) and return the name of the generated module
-RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool)
+std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool)
{
std::string stripped_name = name.str();
@@ -1096,7 +1367,8 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
current_ast = NULL;
flag_dump_ast1 = false;
flag_dump_ast2 = false;
- flag_dump_vlog = false;
+ flag_dump_vlog1 = false;
+ flag_dump_vlog2 = false;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
@@ -1156,15 +1428,8 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
else
modname = "$paramod" + stripped_name + para_info;
- if (!design->has(modname)) {
- new_ast->str = modname;
- design->add(process_module(new_ast, false));
- design->module(modname)->check();
- } else {
- log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
- }
- delete new_ast;
+ (*new_ast_out) = new_ast;
return modname;
}
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 7e97bdb3..ddd59d4b 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -142,6 +142,11 @@ namespace AST
AST_NEGEDGE,
AST_EDGE,
+ AST_INTERFACE,
+ AST_INTERFACEPORT,
+ AST_INTERFACEPORTTYPE,
+ AST_MODPORT,
+ AST_MODPORTMEMBER,
AST_PACKAGE
};
@@ -209,6 +214,8 @@ namespace AST
MEM2REG_FL_SET_ASYNC = 0x00000800,
MEM2REG_FL_EQ2 = 0x00001000,
MEM2REG_FL_CMPLX_LHS = 0x00002000,
+ MEM2REG_FL_CONST_LHS = 0x00004000,
+ MEM2REG_FL_VAR_LHS = 0x00008000,
/* proc flags */
MEM2REG_FL_EQ1 = 0x01000000,
@@ -232,6 +239,7 @@ namespace AST
bool has_const_only_constructs(bool &recommend_const_eval);
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
AstNode *eval_const_function(AstNode *fcall);
+ bool is_simple_const_expr();
// create a human-readable text representation of the AST (for debugging)
void dumpAst(FILE *f, std::string indent) const;
@@ -274,7 +282,7 @@ namespace AST
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
- void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit,
+ void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
@@ -284,6 +292,9 @@ namespace AST
bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
~AstModule() YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
+ RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;
+ std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail);
+ void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE;
RTLIL::Module *clone() const YS_OVERRIDE;
};
@@ -300,6 +311,11 @@ namespace AST
// call a DPI function
AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args);
+
+ // Helper functions related to handling SystemVerilog interfaces
+ std::pair<std::string,std::string> split_modport_from_type(std::string name_type);
+ AstNode * find_modport(AstNode *intf, std::string name);
+ void explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport);
}
namespace AST_INTERNAL
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 0f7e910f..b3a2a84b 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -55,8 +55,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
if (gen_attributes)
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -89,8 +88,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
if (that != NULL)
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -117,8 +115,7 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_wi
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -152,8 +149,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -480,8 +476,7 @@ struct AST_INTERNAL::ProcessGenerator
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
sw->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -530,7 +525,16 @@ struct AST_INTERNAL::ProcessGenerator
}
if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
+ #if 0
+ // this is a valid transformation, but as optimization it is premature.
+ // better: add a default case that assigns 'x' to everything, and let later
+ // optimizations take care of the rest
last_generated_case->compare.clear();
+ #else
+ default_case = new RTLIL::CaseRule;
+ addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)));
+ sw->cases.push_back(default_case);
+ #endif
} else {
if (default_case == NULL) {
default_case = new RTLIL::CaseRule;
@@ -549,7 +553,11 @@ struct AST_INTERNAL::ProcessGenerator
break;
case AST_WIRE:
- log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n");
+ log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n");
+ break;
+
+ case AST_ASSIGN:
+ log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n");
break;
case AST_PARAMETER:
@@ -648,9 +656,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
- str.c_str());
- this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
+ this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
delete left_at_zero_ast;
delete right_at_zero_ast;
} else
@@ -778,7 +785,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
if (children[0]->type != AST_CONSTANT)
log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
width_hint = max(width_hint, int(children[0]->asInt(true)));
}
break;
@@ -798,9 +805,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
// everything should have been handled above -> print error if not.
default:
for (auto f : log_files)
- current_ast->dumpAst(f, "verilog-ast> ");
- log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n",
- type2str(type).c_str());
+ current_ast_mod->dumpAst(f, "verilog-ast> ");
+ log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
}
if (*found_real)
@@ -853,6 +859,35 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_GENIF:
case AST_GENCASE:
case AST_PACKAGE:
+ case AST_MODPORT:
+ case AST_MODPORTMEMBER:
+ break;
+ case AST_INTERFACEPORT: {
+ // If a port in a module with unknown type is found, mark it with the attribute 'is_interface'
+ // This is used by the hierarchy pass to know when it can replace interface connection with the individual
+ // signals.
+ RTLIL::Wire *wire = current_module->addWire(str, 1);
+ wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ wire->start_offset = 0;
+ wire->port_id = port_id;
+ wire->port_input = true;
+ wire->port_output = true;
+ wire->set_bool_attribute("\\is_interface");
+ if (children.size() > 0) {
+ for(size_t i=0; i<children.size();i++) {
+ if(children[i]->type == AST_INTERFACEPORTTYPE) {
+ std::pair<std::string,std::string> res = AST::split_modport_from_type(children[i]->str);
+ wire->attributes["\\interface_type"] = res.first;
+ if (res.second != "")
+ wire->attributes["\\interface_modport"] = res.second;
+ break;
+ }
+ }
+ }
+ wire->upto = 0;
+ }
+ break;
+ case AST_INTERFACEPORTTYPE:
break;
// remember the parameter, needed for example in techmap
@@ -863,11 +898,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// create an RTLIL::Wire for an AST_WIRE node
case AST_WIRE: {
if (current_module->wires_.count(str) != 0)
- log_file_error(filename, linenum, "Re-definition of signal `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Re-definition of signal `%s'!\n", str.c_str());
if (!range_valid)
- log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str());
log_assert(range_left >= range_right || (range_left == -1 && range_right == 0));
@@ -881,8 +914,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
wire->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -891,16 +923,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// create an RTLIL::Memory for an AST_MEMORY node
case AST_MEMORY: {
if (current_module->memories.count(str) != 0)
- log_file_error(filename, linenum, "Re-definition of memory `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Re-definition of memory `%s'!\n", str.c_str());
log_assert(children.size() >= 2);
log_assert(children[0]->type == AST_RANGE);
log_assert(children[1]->type == AST_RANGE);
if (!children[0]->range_valid || !children[1]->range_valid)
- log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n", str.c_str());
RTLIL::Memory *memory = new RTLIL::Memory;
memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -917,8 +947,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
memory->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -926,19 +955,17 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node
case AST_CONSTANT:
+ case AST_REALVALUE:
{
if (width_hint < 0)
detectSignWidth(width_hint, sign_hint);
-
is_signed = sign_hint;
- return RTLIL::SigSpec(bitsAsConst());
- }
- case AST_REALVALUE:
- {
+ if (type == AST_CONSTANT)
+ return RTLIL::SigSpec(bitsAsConst());
+
RTLIL::SigSpec sig = realAsConst(width_hint);
- log_file_warning(filename, linenum, "converting real value %e to binary %s.\n",
- realvalue, log_signal(sig));
+ log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
return sig;
}
@@ -949,6 +976,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
{
RTLIL::Wire *wire = NULL;
RTLIL::SigChunk chunk;
+ bool is_interface = false;
int add_undef_bits_msb = 0;
int add_undef_bits_lsb = 0;
@@ -964,19 +992,42 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) {
if (id2ast->children[0]->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", str.c_str());
chunk = RTLIL::Const(id2ast->children[0]->bits);
goto use_const_chunk;
}
- else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE &&
- id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0)
- log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n",
- str.c_str());
+ else if (id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) {
+ RTLIL::Wire *current_wire = current_module->wire(str);
+ if (current_wire->get_bool_attribute("\\is_interface"))
+ is_interface = true;
+ // Ignore
+ }
+ // If an identifier is found that is not already known, assume that it is an interface:
+ else if (1) { // FIXME: Check if sv_mode first?
+ is_interface = true;
+ }
+ else {
+ log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n", str.c_str());
+ }
if (id2ast->type == AST_MEMORY)
- log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n", str.c_str());
+
+ // If identifier is an interface, create a RTLIL::SigSpec with a dummy wire with a attribute called 'is_interface'
+ // This makes it possible for the hierarchy pass to see what are interface connections and then replace them
+ // with the individual signals:
+ if (is_interface) {
+ RTLIL::Wire *dummy_wire;
+ std::string dummy_wire_name = "$dummywireforinterface" + str;
+ if (current_module->wires_.count(dummy_wire_name))
+ dummy_wire = current_module->wires_[dummy_wire_name];
+ else {
+ dummy_wire = current_module->addWire(dummy_wire_name);
+ dummy_wire->set_bool_attribute("\\is_interface");
+ }
+ RTLIL::SigSpec tmp = RTLIL::SigSpec(dummy_wire);
+ return tmp;
+ }
wire = current_module->wires_[str];
chunk.wire = wire;
@@ -985,7 +1036,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
use_const_chunk:
if (children.size() != 0) {
- log_assert(children[0]->type == AST_RANGE);
+ if (children[0]->type != AST_RANGE)
+ log_file_error(filename, linenum, "Single range expected.\n");
int source_width = id2ast->range_left - id2ast->range_right + 1;
int source_offset = id2ast->range_right;
if (!children[0]->range_valid) {
@@ -994,9 +1046,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
- str.c_str());
- int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
+ int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
children[0]->children[1]->clone() : children[0]->children[0]->clone());
fake_ast->children[0]->delete_children();
@@ -1024,10 +1075,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {
if (chunk.width == 1)
log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
- str.c_str());
+ str.c_str());
else
- log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting all %d result bits to undef.\n",
- str.c_str(), chunk.width);
+ log_file_warning(filename, linenum, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
+ children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
if (chunk.width + chunk.offset > source_width) {
@@ -1040,11 +1091,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset += add_undef_bits_lsb;
}
if (add_undef_bits_lsb)
- log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
- str.c_str(), add_undef_bits_lsb);
+ log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
+ children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
if (add_undef_bits_msb)
- log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
- str.c_str(), add_undef_bits_msb);
+ log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
+ children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
}
}
}
@@ -1371,16 +1422,21 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (GetSize(en) != 1)
en = current_module->ReduceBool(NEW_ID, en);
- std::stringstream sstr;
- sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
+ IdString cellname;
+ if (str.empty()) {
+ std::stringstream sstr;
+ sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
+ cellname = sstr.str();
+ } else {
+ cellname = str;
+ }
- RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype);
+ RTLIL::Cell *cell = current_module->addCell(cellname, celltype);
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -1402,9 +1458,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
new_right.append(right[i]);
}
log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n"
- " old assignment: %s = %s\n new assignment: %s = %s.\n",
- log_signal(left), log_signal(right),
- log_signal(new_left), log_signal(new_right));
+ " old assignment: %s = %s\n new assignment: %s = %s.\n",
+ log_signal(left), log_signal(right),
+ log_signal(new_left), log_signal(new_right));
left = new_left;
right = new_right;
}
@@ -1422,6 +1478,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::Cell *cell = current_module->addCell(str, "");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ // Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass
+ cell->set_bool_attribute("\\module_not_derived");
for (auto it = children.begin(); it != children.end(); it++) {
AstNode *child = *it;
@@ -1435,14 +1493,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) {
log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
- log_id(cell), log_id(paraname), child->children[0]->realvalue);
+ log_id(cell), log_id(paraname), child->children[0]->realvalue);
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]);
delete strnode;
}
if (child->children[0]->type != AST_CONSTANT)
log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
- log_id(cell), log_id(paraname));
+ log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst();
continue;
}
@@ -1463,8 +1521,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
- attr.first.c_str());
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -1492,18 +1549,17 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (GetSize(children) > 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n",
- RTLIL::unescape_id(str).c_str(), GetSize(children));
+ RTLIL::unescape_id(str).c_str(), GetSize(children));
if (GetSize(children) == 1) {
if (children[0]->type != AST_CONSTANT)
log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
width = children[0]->asInt(true);
}
if (width <= 0)
- log_file_error(filename, linenum, "Failed to detect width of %s!\n",
- RTLIL::unescape_id(str).c_str());
+ log_file_error(filename, linenum, "Failed to detect width of %s!\n", RTLIL::unescape_id(str).c_str());
Cell *cell = current_module->addCell(myid, str.substr(1));
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -1528,10 +1584,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// everything should have been handled above -> print error if not.
default:
for (auto f : log_files)
- current_ast->dumpAst(f, "verilog-ast> ");
+ current_ast_mod->dumpAst(f, "verilog-ast> ");
type_name = type2str(type);
- log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n",
- type_name.c_str());
+ log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str());
}
return RTLIL::SigSpec();
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index aa3b982d..63b71b80 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -50,7 +50,6 @@ using namespace AST_INTERNAL;
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
{
static int recursion_counter = 0;
- static pair<string, int> last_blocking_assignment_warn;
static bool deep_recursion_warning = false;
if (recursion_counter++ == 1000 && deep_recursion_warning) {
@@ -71,8 +70,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (stage == 0)
{
- log_assert(type == AST_MODULE);
- last_blocking_assignment_warn = pair<string, int>();
+ log_assert(type == AST_MODULE || type == AST_INTERFACE);
deep_recursion_warning = true;
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
@@ -113,6 +111,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
goto verbose_activate;
+ if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS))
+ goto verbose_activate;
+
// log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
continue;
@@ -137,9 +138,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int mem_width, mem_size, addr_bits;
node->meminfo(mem_width, mem_size, addr_bits);
+ int data_range_left = node->children[0]->range_left;
+ int data_range_right = node->children[0]->range_right;
+
+ if (node->children[0]->range_swapped)
+ std::swap(data_range_left, data_range_right);
+
for (int i = 0; i < mem_size; i++) {
AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
- mkconst_int(mem_width-1, true), mkconst_int(0, true)));
+ mkconst_int(data_range_left, true), mkconst_int(data_range_right, true)));
reg->str = stringf("%s[%d]", node->str.c_str(), i);
reg->is_reg = true;
reg->is_signed = node->is_signed;
@@ -196,7 +203,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int nargs = GetSize(children);
if (nargs < 1)
log_file_error(filename, linenum, "System task `%s' got %d arguments, expected >= 1.\n",
- str.c_str(), int(children.size()));
+ str.c_str(), int(children.size()));
// First argument is the format string
AstNode *node_string = children[0];
@@ -240,7 +247,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
case 'X':
if (next_arg >= GetSize(children))
log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n",
- cformat, str.c_str());
+ cformat, str.c_str());
node_arg = children[next_arg++];
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
@@ -325,6 +332,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i];
if (node->type == AST_WIRE) {
+ if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
+ for (auto c : node->children[0]->children) {
+ if (!c->is_simple_const_expr()) {
+ if (attributes.count("\\dynports"))
+ delete attributes.at("\\dynports");
+ attributes["\\dynports"] = AstNode::mkconst_int(1, true);
+ }
+ }
+ }
if (this_wire_scope.count(node->str) > 0) {
AstNode *first_node = this_wire_scope[node->str];
if (first_node->is_input && node->is_reg)
@@ -450,8 +466,21 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment
if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg)
log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum);
- if (type == AST_ASSIGN && children[0]->id2ast->is_reg)
- log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum);
+ if (type == AST_ASSIGN && children[0]->id2ast->is_reg) {
+ bool is_rand_reg = false;
+ if (children[1]->type == AST_FCALL) {
+ if (children[1]->str == "\\$anyconst")
+ is_rand_reg = true;
+ if (children[1]->str == "\\$anyseq")
+ is_rand_reg = true;
+ if (children[1]->str == "\\$allconst")
+ is_rand_reg = true;
+ if (children[1]->str == "\\$allseq")
+ is_rand_reg = true;
+ }
+ if (!is_rand_reg)
+ log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum);
+ }
children[0]->was_checked = true;
}
break;
@@ -629,6 +658,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// (iterate by index as e.g. auto wires can add new children in the process)
for (size_t i = 0; i < children.size(); i++) {
bool did_something_here = true;
+ bool backup_flag_autowire = flag_autowire;
if ((type == AST_GENFOR || type == AST_FOR) && i >= 3)
break;
if ((type == AST_GENIF || type == AST_GENCASE) && i >= 1)
@@ -639,6 +669,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
break;
if (type == AST_PREFIX && i >= 1)
break;
+ if (type == AST_DEFPARAM && i == 0)
+ flag_autowire = true;
while (did_something_here && i < children.size()) {
bool const_fold_here = const_fold, in_lvalue_here = in_lvalue;
int width_hint_here = width_hint;
@@ -673,6 +705,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
children.erase(children.begin() + (i--));
did_something = true;
}
+ flag_autowire = backup_flag_autowire;
}
for (auto &attr : attributes) {
while (attr.second->simplify(true, false, false, stage, -1, false, true))
@@ -732,7 +765,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (current_scope.at(modname)->type != AST_CELL)
log_file_error(filename, linenum, "Defparam argument `%s . %s` does not match a cell!\n",
- RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str());
+ RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str());
AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL);
paraset->str = paramname;
@@ -880,7 +913,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (children[0]->type == AST_REALVALUE) {
RTLIL::Const constvalue = children[0]->realAsConst(width);
log_file_warning(filename, linenum, "converting real value %e to binary %s.\n",
- children[0]->realvalue, log_signal(constvalue));
+ children[0]->realvalue, log_signal(constvalue));
delete children[0];
children[0] = mkconst_bits(constvalue.bits, sign_hint);
did_something = true;
@@ -921,12 +954,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
if (current_scope.count(str) == 0) {
- // log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
- AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
- auto_wire->str = str;
- current_ast_mod->children.push_back(auto_wire);
- current_scope[str] = auto_wire;
- did_something = true;
+ if (flag_autowire || str == "\\$global_clock") {
+ AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
+ auto_wire->str = str;
+ current_ast_mod->children.push_back(auto_wire);
+ current_scope[str] = auto_wire;
+ did_something = true;
+ } else {
+ log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
+ }
}
if (id2ast != current_scope[str]) {
id2ast = current_scope[str];
@@ -946,6 +982,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int data_range_left = id2ast->children[0]->range_left;
int data_range_right = id2ast->children[0]->range_right;
+ if (id2ast->children[0]->range_swapped)
+ std::swap(data_range_left, data_range_right);
+
std::stringstream sstr;
sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string wire_id = sstr.str();
@@ -1299,8 +1338,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_PRIMITIVE)
{
if (children.size() < 2)
- log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n", str.c_str());
std::vector<AstNode*> children_list;
for (auto child : children) {
@@ -1315,8 +1353,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (str == "bufif0" || str == "bufif1" || str == "notif0" || str == "notif1")
{
if (children_list.size() != 3)
- log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n", str.c_str());
std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz);
@@ -1336,6 +1373,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
str.clear();
type = AST_ASSIGN;
children.push_back(children_list.at(0));
+ children.back()->was_checked = true;
children.push_back(node);
did_something = true;
}
@@ -1372,6 +1410,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
str.clear();
type = AST_ASSIGN;
children.push_back(children_list[0]);
+ children.back()->was_checked = true;
children.push_back(node);
did_something = true;
}
@@ -1401,8 +1440,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
- str.c_str());
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
}
did_something = true;
@@ -1480,6 +1518,7 @@ skip_dynamic_range_lvalue_expansion:;
newNode->children.push_back(assign_en);
AstNode *assertnode = new AstNode(type);
+ assertnode->str = str;
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children[0]->str = id_check;
@@ -1530,6 +1569,7 @@ skip_dynamic_range_lvalue_expansion:;
wire_tmp_id->str = wire_tmp->str;
newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone()));
+ newNode->children.back()->was_checked = true;
int cursor = 0;
for (auto child : children[0]->children)
@@ -1559,14 +1599,6 @@ skip_dynamic_range_lvalue_expansion:;
sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
- if (type == AST_ASSIGN_EQ) {
- pair<string, int> this_blocking_assignment_warn(filename, linenum);
- if (this_blocking_assignment_warn != last_blocking_assignment_warn)
- log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
- filename.c_str(), linenum);
- last_blocking_assignment_warn = this_blocking_assignment_warn;
- }
-
int mem_width, mem_size, addr_bits;
bool mem_signed = children[0]->id2ast->is_signed;
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
@@ -1676,7 +1708,7 @@ skip_dynamic_range_lvalue_expansion:;
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
- int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
+ int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
@@ -1765,18 +1797,18 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$past")
{
- if (width_hint <= 0)
+ if (width_hint < 0)
goto replace_fcall_later;
int num_steps = 1;
if (GetSize(children) != 1 && GetSize(children) != 2)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (!current_always_clocked)
log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
if (GetSize(children) == 2)
{
@@ -1797,6 +1829,11 @@ skip_dynamic_range_lvalue_expansion:;
log_assert(block != nullptr);
+ if (num_steps == 0) {
+ newNode = children[0]->clone();
+ goto apply_newNode;
+ }
+
int myidx = autoidx++;
AstNode *outreg = nullptr;
@@ -1815,6 +1852,7 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *regid = new AstNode(AST_IDENTIFIER);
regid->str = reg->str;
regid->id2ast = reg;
+ regid->was_checked = true;
AstNode *rhs = nullptr;
@@ -1836,15 +1874,15 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
- if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell")
+ if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell" || str == "\\$changed")
{
if (GetSize(children) != 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (!current_always_clocked)
log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
AstNode *present = children.at(0)->clone();
AstNode *past = clone();
@@ -1853,11 +1891,18 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$stable")
newNode = new AstNode(AST_EQ, past, present);
+ else if (str == "\\$changed")
+ newNode = new AstNode(AST_NE, past, present);
+
else if (str == "\\$rose")
- newNode = new AstNode(AST_LOGIC_AND, new AstNode(AST_LOGIC_NOT, past), present);
+ newNode = new AstNode(AST_LOGIC_AND,
+ new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, past, mkconst_int(1,false))),
+ new AstNode(AST_BIT_AND, present, mkconst_int(1,false)));
else if (str == "\\$fell")
- newNode = new AstNode(AST_LOGIC_AND, past, new AstNode(AST_LOGIC_NOT, present));
+ newNode = new AstNode(AST_LOGIC_AND,
+ new AstNode(AST_BIT_AND, past, mkconst_int(1,false)),
+ new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, present, mkconst_int(1,false))));
else
log_abort();
@@ -1875,7 +1920,7 @@ skip_dynamic_range_lvalue_expansion:;
{
if (children.size() != 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
AstNode *buf = children[0]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
@@ -1892,7 +1937,7 @@ skip_dynamic_range_lvalue_expansion:;
if (arg_value.bits.at(i) == RTLIL::State::S1)
result = i + 1;
- newNode = mkconst_int(result, false);
+ newNode = mkconst_int(result, true);
goto apply_newNode;
}
@@ -1900,11 +1945,11 @@ skip_dynamic_range_lvalue_expansion:;
{
if (str == "\\$bits" && children.size() != 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (str == "\\$size" && children.size() != 1 && children.size() != 2)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
int dim = 1;
if (str == "\\$size" && children.size() == 2) {
@@ -1978,18 +2023,18 @@ skip_dynamic_range_lvalue_expansion:;
if (func_with_two_arguments) {
if (children.size() != 2)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 2.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
} else {
if (children.size() != 1)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
}
if (children.size() >= 1) {
while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (!children[0]->isConst())
log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
int child_width_hint = width_hint;
bool child_sign_hint = sign_hint;
children[0]->detectSignWidth(child_width_hint, child_sign_hint);
@@ -2000,7 +2045,7 @@ skip_dynamic_range_lvalue_expansion:;
while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (!children[1]->isConst())
log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n",
- RTLIL::unescape_id(str).c_str());
+ RTLIL::unescape_id(str).c_str());
int child_width_hint = width_hint;
bool child_sign_hint = sign_hint;
children[1]->detectSignWidth(child_width_hint, child_sign_hint);
@@ -2088,7 +2133,7 @@ skip_dynamic_range_lvalue_expansion:;
{
if (GetSize(children) < 2 || GetSize(children) > 4)
log_file_error(filename, linenum, "System function %s got %d arguments, expected 2-4.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()));
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
AstNode *node_filename = children[0]->clone();
while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
@@ -2136,6 +2181,8 @@ skip_dynamic_range_lvalue_expansion:;
}
newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);
+ delete node_filename;
+ delete node_memory;
goto apply_newNode;
}
@@ -2177,6 +2224,8 @@ skip_dynamic_range_lvalue_expansion:;
std::map<std::string, std::string> replace_rules;
vector<AstNode*> added_mod_children;
dict<std::string, AstNode*> wire_cache;
+ vector<AstNode*> new_stmts;
+ vector<AstNode*> output_assignments;
if (current_block == NULL)
{
@@ -2201,6 +2250,8 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *always = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK,
new AstNode(AST_ASSIGN_EQ, lvalue, clone())));
+ always->children[0]->children[0]->was_checked = true;
+
current_ast_mod->children.push_back(always);
goto replace_fcall_with_id;
@@ -2250,6 +2301,7 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign = child->is_input ?
new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg) :
new AstNode(AST_ASSIGN_EQ, arg, wire_id->clone());
+ assign->children[0]->was_checked = true;
for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
if (*it != current_block_child)
@@ -2298,8 +2350,8 @@ skip_dynamic_range_lvalue_expansion:;
wire->port_id = 0;
wire->is_input = false;
wire->is_output = false;
- if (!child->is_output)
- wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+ wire->is_reg = true;
+ wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
wire_cache[child->str] = wire;
current_ast_mod->children.push_back(wire);
@@ -2320,13 +2372,11 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign = child->is_input ?
new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
new AstNode(AST_ASSIGN_EQ, arg, wire_id);
-
- for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
- if (*it != current_block_child)
- continue;
- current_block->children.insert(it, assign);
- break;
- }
+ assign->children[0]->was_checked = true;
+ if (child->is_input)
+ new_stmts.push_back(assign);
+ else
+ output_assignments.push_back(assign);
}
}
@@ -2340,14 +2390,18 @@ skip_dynamic_range_lvalue_expansion:;
{
AstNode *stmt = child->clone();
stmt->replace_ids(prefix, replace_rules);
+ new_stmts.push_back(stmt);
+ }
- for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
- if (*it != current_block_child)
- continue;
- current_block->children.insert(it, stmt);
- break;
- }
+ new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end());
+
+ for (auto it = current_block->children.begin(); ; it++) {
+ log_assert(it != current_block->children.end());
+ if (*it == current_block_child) {
+ current_block->children.insert(it, new_stmts.begin(), new_stmts.end());
+ break;
}
+ }
replace_fcall_with_id:
if (type == AST_FCALL) {
@@ -2759,6 +2813,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value));
block->children.back()->children[0]->str = memory->str;
block->children.back()->children[0]->id2ast = memory;
+ block->children.back()->children[0]->was_checked = true;
}
cursor += increment;
@@ -2817,7 +2872,11 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
for (size_t i = 0; i < children.size(); i++) {
AstNode *child = children[i];
- if (child->type != AST_FUNCTION && child->type != AST_TASK && child->type != AST_PREFIX)
+ // AST_PREFIX member names should not be prefixed; a nested AST_PREFIX
+ // still needs to recursed-into
+ if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)
+ continue;
+ if (child->type != AST_FUNCTION && child->type != AST_TASK)
child->expand_genblock(index_var, prefix, name_map);
}
@@ -2872,7 +2931,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
{
uint32_t children_flags = 0;
- int ignore_children_counter = 0;
+ int lhs_children_counter = 0;
if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
{
@@ -2898,6 +2957,16 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
}
+ // for proper (non-init) writes: remember if this is a constant index or not
+ if ((flags & MEM2REG_FL_INIT) == 0) {
+ if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) {
+ if (children[0]->children[0]->children[0]->type == AST_CONSTANT)
+ mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS;
+ else
+ mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS;
+ }
+ }
+
// remember where this is
if (flags & MEM2REG_FL_INIT) {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT))
@@ -2910,7 +2979,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
}
}
- ignore_children_counter = 1;
+ lhs_children_counter = 1;
}
if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY)
@@ -2953,12 +3022,23 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
log_assert((flags & ~0x000000ff) == 0);
for (auto child : children)
- if (ignore_children_counter > 0)
- ignore_children_counter--;
- else if (proc_flags_p)
+ {
+ if (lhs_children_counter > 0) {
+ lhs_children_counter--;
+ if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) {
+ for (auto c : child->children[0]->children) {
+ if (proc_flags_p)
+ c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
+ else
+ c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
+ }
+ }
+ } else
+ if (proc_flags_p)
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
else
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
+ }
flags &= ~children_flags | backup_flags;
@@ -3010,6 +3090,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
if (type == AST_FUNCTION || type == AST_TASK)
return false;
+ if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast))
+ {
+ log_assert(children[0]->type == AST_CONSTANT);
+ log_assert(children[1]->type == AST_CONSTANT);
+ log_assert(children[2]->type == AST_CONSTANT);
+
+ int cursor = children[0]->asInt(false);
+ Const data = children[1]->bitsAsConst();
+ int length = children[2]->asInt(false);
+
+ if (length != 0)
+ {
+ AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK));
+ mod->children.push_back(block);
+ block = block->children[0];
+
+ int wordsz = GetSize(data) / length;
+
+ for (int i = 0; i < length; i++) {
+ block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false)));
+ block->children.back()->children[0]->str = str;
+ block->children.back()->children[0]->id2ast = id2ast;
+ block->children.back()->children[0]->was_checked = true;
+ }
+ }
+
+ AstNode *newNode = new AstNode(AST_NONE);
+ newNode->cloneInto(this);
+ delete newNode;
+
+ did_something = true;
+ }
+
if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set))
{
if (async_block == NULL) {
@@ -3019,6 +3132,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *newNode = clone();
newNode->type = AST_ASSIGN_EQ;
+ newNode->children[0]->was_checked = true;
async_block->children[0]->children.push_back(newNode);
newNode = new AstNode(AST_NONE);
@@ -3064,6 +3178,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
assign_addr->children[0]->str = id_addr;
+ assign_addr->children[0]->was_checked = true;
block->children.insert(block->children.begin()+assign_idx+1, assign_addr);
AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER));
@@ -3087,6 +3202,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
children[0]->id2ast = NULL;
children[0]->str = id_data;
type = AST_ASSIGN_EQ;
+ children[0]->was_checked = true;
did_something = true;
}
@@ -3236,6 +3352,16 @@ bool AstNode::has_const_only_constructs(bool &recommend_const_eval)
return false;
}
+bool AstNode::is_simple_const_expr()
+{
+ if (type == AST_IDENTIFIER)
+ return false;
+ for (auto child : children)
+ if (!child->is_simple_const_expr())
+ return false;
+ return true;
+}
+
// helper function for AstNode::eval_const_function()
void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
{
@@ -3244,12 +3370,12 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia
if (!children.empty()) {
if (children.size() != 1 || children.at(0)->type != AST_RANGE)
log_file_error(filename, linenum, "Memory access in constant function is not supported\n%s:%d: ...called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
children.at(0)->replace_variables(variables, fcall);
while (simplify(true, false, false, 1, -1, false, true)) { }
if (!children.at(0)->range_valid)
log_file_error(filename, linenum, "Non-constant range\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
offset = min(children.at(0)->range_left, children.at(0)->range_right);
width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
}
@@ -3289,7 +3415,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
while (child->simplify(true, false, false, 1, -1, false, true)) { }
if (!child->range_valid)
log_file_error(child->filename, child->linenum, "Can't determine size of variable %s\n%s:%d: ... called from here.\n",
- child->str.c_str(), fcall->filename.c_str(), fcall->linenum);
+ child->str.c_str(), fcall->filename.c_str(), fcall->linenum);
variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1);
variables[child->str].offset = min(child->range_left, child->range_right);
variables[child->str].is_signed = child->is_signed;
@@ -3333,15 +3459,15 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (stmt->children.at(1)->type != AST_CONSTANT)
log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here. X\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
if (stmt->children.at(0)->type != AST_IDENTIFIER)
log_file_error(stmt->filename, stmt->linenum, "Unsupported composite left hand side in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
if (!variables.count(stmt->children.at(0)->str))
log_file_error(stmt->filename, stmt->linenum, "Assignment to non-local variable in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
if (stmt->children.at(0)->children.empty()) {
variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
@@ -3349,7 +3475,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
AstNode *range = stmt->children.at(0)->children.at(0);
if (!range->range_valid)
log_file_error(range->filename, range->linenum, "Non-constant range\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
int offset = min(range->range_left, range->range_right);
int width = std::abs(range->range_left - range->range_right) + 1;
varinfo_t &v = variables[stmt->children.at(0)->str];
@@ -3381,7 +3507,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (cond->type != AST_CONSTANT)
log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
if (cond->asBool()) {
block->children.insert(block->children.begin(), stmt->children.at(1)->clone());
@@ -3402,7 +3528,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (num->type != AST_CONSTANT)
log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
block->children.erase(block->children.begin());
for (int i = 0; i < num->bitsAsConst().as_int(); i++)
@@ -3440,7 +3566,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
if (cond->type != AST_CONSTANT)
log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
found_match = cond->asBool();
delete cond;
@@ -3470,7 +3596,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
}
log_file_error(stmt->filename, stmt->linenum, "Unsupported language construct in constant function\n%s:%d: ... called from here.\n",
- fcall->filename.c_str(), fcall->linenum);
+ fcall->filename.c_str(), fcall->linenum);
log_abort();
}
diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc
index 034b3e70..a6a07863 100644
--- a/frontends/blif/blifparse.cc
+++ b/frontends/blif/blifparse.cc
@@ -276,7 +276,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
if(lastcell == nullptr || module == nullptr)
{
- err_reason = stringf("No primative object to attach .cname %s.", p);
+ err_reason = stringf("No primitive object to attach .cname %s.", p);
goto error_with_reason;
}
@@ -584,7 +584,7 @@ struct BlifFrontend : public Frontend {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" read_blif [filename]\n");
+ log(" read_blif [options] [filename]\n");
log("\n");
log("Load modules from a BLIF file into the current design.\n");
log("\n");
diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc
index d8783ac1..6b302a79 100644
--- a/frontends/ilang/ilang_frontend.cc
+++ b/frontends/ilang/ilang_frontend.cc
@@ -44,11 +44,39 @@ struct IlangFrontend : public Frontend {
log("Load modules from an ilang file to the current design. (ilang is a text\n");
log("representation of a design in yosys's internal format.)\n");
log("\n");
+ log(" -nooverwrite\n");
+ log(" ignore re-definitions of modules. (the default behavior is to\n");
+ log(" create an error message if the existing module is not a blackbox\n");
+ log(" module, and overwrite the existing module if it is a blackbox module.)\n");
+ log("\n");
+ log(" -overwrite\n");
+ log(" overwrite existing modules with the same name\n");
+ log("\n");
}
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
+ ILANG_FRONTEND::flag_nooverwrite = false;
+ ILANG_FRONTEND::flag_overwrite = false;
+
log_header(design, "Executing ILANG frontend.\n");
- extra_args(f, filename, args, 1);
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-nooverwrite") {
+ ILANG_FRONTEND::flag_nooverwrite = true;
+ ILANG_FRONTEND::flag_overwrite = false;
+ continue;
+ }
+ if (arg == "-overwrite") {
+ ILANG_FRONTEND::flag_nooverwrite = false;
+ ILANG_FRONTEND::flag_overwrite = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
log("Input filename: %s\n", filename.c_str());
ILANG_FRONTEND::lexin = f;
diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h
index ad3ffec9..052dd4cb 100644
--- a/frontends/ilang/ilang_frontend.h
+++ b/frontends/ilang/ilang_frontend.h
@@ -32,6 +32,8 @@ YOSYS_NAMESPACE_BEGIN
namespace ILANG_FRONTEND {
extern std::istream *lexin;
extern RTLIL::Design *current_design;
+ extern bool flag_nooverwrite;
+ extern bool flag_overwrite;
}
YOSYS_NAMESPACE_END
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y
index bfc062fe..5bcc01f4 100644
--- a/frontends/ilang/ilang_parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -37,6 +37,8 @@ namespace ILANG_FRONTEND {
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
+ bool flag_nooverwrite, flag_overwrite;
+ bool delete_current_module;
}
using namespace ILANG_FRONTEND;
YOSYS_NAMESPACE_END
@@ -93,18 +95,36 @@ design:
module:
TOK_MODULE TOK_ID EOL {
- if (current_design->has($2))
- rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
+ delete_current_module = false;
+ if (current_design->has($2)) {
+ RTLIL::Module *existing_mod = current_design->module($2);
+ if (!flag_overwrite && attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()) {
+ log("Ignoring blackbox re-definition of module %s.\n", $2);
+ delete_current_module = true;
+ } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
+ rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
+ } else if (flag_nooverwrite) {
+ log("Ignoring re-definition of module %s.\n", $2);
+ delete_current_module = true;
+ } else {
+ log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", $2);
+ current_design->remove(existing_mod);
+ }
+ }
current_module = new RTLIL::Module;
current_module->name = $2;
current_module->attributes = attrbuf;
- current_design->add(current_module);
+ if (!delete_current_module)
+ current_design->add(current_module);
attrbuf.clear();
free($2);
} module_body TOK_END {
if (attrbuf.size() != 0)
rtlil_frontend_ilang_yyerror("dangling attribute");
current_module->fixup_ports();
+ if (delete_current_module)
+ delete current_module;
+ current_module = nullptr;
} EOL;
module_body:
@@ -387,17 +407,13 @@ sigspec:
$$ = new RTLIL::SigSpec(current_module->wires_[$1]);
free($1);
} |
- TOK_ID '[' TOK_INT ']' {
- if (current_module->wires_.count($1) == 0)
- rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
- $$ = new RTLIL::SigSpec(current_module->wires_[$1], $3);
- free($1);
+ sigspec '[' TOK_INT ']' {
+ $$ = new RTLIL::SigSpec($1->extract($3));
+ delete $1;
} |
- TOK_ID '[' TOK_INT ':' TOK_INT ']' {
- if (current_module->wires_.count($1) == 0)
- rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
- $$ = new RTLIL::SigSpec(current_module->wires_[$1], $5, $3 - $5 + 1);
- free($1);
+ sigspec '[' TOK_INT ':' TOK_INT ']' {
+ $$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1));
+ delete $1;
} |
'{' sigspec_list '}' {
$$ = $2;
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index 0a5bd84d..6e3cffac 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -36,7 +36,8 @@ static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&
int id_len = 0;
while (('a' <= expr[id_len] && expr[id_len] <= 'z') || ('A' <= expr[id_len] && expr[id_len] <= 'Z') ||
- ('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' || expr[id_len] == '_') id_len++;
+ ('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' ||
+ expr[id_len] == '_' || expr[id_len] == '[' || expr[id_len] == ']') id_len++;
if (id_len == 0)
log_error("Expected identifier at `%s'.\n", expr);
@@ -615,7 +616,7 @@ struct LibertyFrontend : public Frontend {
LibertyAst *bus_type_node = node->find("bus_type");
if (!bus_type_node || !type_map.count(bus_type_node->value))
- log_error("Unkown or unsupported type for bus interface %s on cell %s.\n",
+ log_error("Unknown or unsupported type for bus interface %s on cell %s.\n",
node->args.at(0).c_str(), log_id(cell_name));
int bus_type_width = std::get<0>(type_map.at(bus_type_node->value));
@@ -634,9 +635,12 @@ struct LibertyFrontend : public Frontend {
}
}
- for (auto node : cell->children)
+ if (!flag_lib)
{
- if (!flag_lib) {
+ // some liberty files do not put ff/latch at the beginning of a cell
+ // try to find "ff" or "latch" and create FF/latch _before_ processing all other nodes
+ for (auto node : cell->children)
+ {
if (node->id == "ff" && node->args.size() == 2)
create_ff(module, node);
if (node->id == "latch" && node->args.size() == 2)
@@ -645,7 +649,10 @@ struct LibertyFrontend : public Frontend {
goto skip_cell;
}
}
+ }
+ for (auto node : cell->children)
+ {
if (node->id == "pin" && node->args.size() == 1)
{
LibertyAst *dir = node->find("direction");
diff --git a/frontends/verific/README b/frontends/verific/README
index b4c436a3..89584f2e 100644
--- a/frontends/verific/README
+++ b/frontends/verific/README
@@ -4,35 +4,6 @@ This directory contains Verific bindings for Yosys.
See http://www.verific.com/ for details.
-Building Yosys with the 32 bit Verific eval library on amd64:
-=============================================================
-
-1.) Use a Makefile.conf like the following one:
-
---snip--
-CONFIG := gcc
-ENABLE_TCL := 0
-ENABLE_PLUGINS := 0
-ENABLE_VERIFIC := 1
-CXXFLAGS += -m32
-LDFLAGS += -m32
-VERIFIC_DIR = /usr/local/src/verific_lib_eval
---snap--
-
-
-2.) Install the necessary multilib packages
-
-Hint: On debian/ubuntu the multilib packages have names such as
-libreadline-dev:i386 or lib32readline6-dev, depending on the
-exact version of debian/ubuntu you are working with.
-
-
-3.) Build and test
-
-make -j8
-./yosys -p 'verific -sv frontends/verific/example.sv; verific -import top'
-
-
Verific Features that should be enabled in your Verific library
===============================================================
@@ -50,7 +21,7 @@ Then run in the following command in this directory:
sby -f example.sby
-This will generate approximately one page of text outpout. The last lines
+This will generate approximately one page of text output. The last lines
should be something like this:
SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index c5fa5831..ed9727b8 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -118,6 +118,27 @@ RTLIL::SigBit VerificImporter::net_map_at(Net *net)
return net_map.at(net);
}
+bool is_blackbox(Netlist *nl)
+{
+ if (nl->IsBlackBox())
+ return true;
+
+ const char *attr = nl->GetAttValue("blackbox");
+ if (attr != nullptr && strcmp(attr, "0"))
+ return true;
+
+ return false;
+}
+
+RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj)
+{
+ std::string s = stringf("$verific$%s", obj->Name());
+ if (obj->Linefile())
+ s += stringf("$%s:%d", Verific::LineFile::GetFileName(obj->Linefile()), Verific::LineFile::GetLineNo(obj->Linefile()));
+ s += stringf("$%d", autoidx++);
+ return s;
+}
+
void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj)
{
MapIter mi;
@@ -203,7 +224,7 @@ RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*,
dummy_wire = NULL;
} else {
if (dummy_wire == NULL)
- dummy_wire = module->addWire(NEW_ID);
+ dummy_wire = module->addWire(new_verific_id(inst));
else
dummy_wire->width++;
sig.append(RTLIL::SigSpec(dummy_wire, dummy_wire->width - 1));
@@ -219,8 +240,8 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr
}
if (inst->Type() == PRIM_NAND) {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addAndGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst));
+ module->addAndGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput()));
return true;
}
@@ -231,8 +252,8 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr
}
if (inst->Type() == PRIM_NOR) {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addOrGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst));
+ module->addOrGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput()));
return true;
}
@@ -272,16 +293,16 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr
if (inst->Type() == PRIM_FADD)
{
RTLIL::SigSpec a = net_map_at(inst->GetInput1()), b = net_map_at(inst->GetInput2()), c = net_map_at(inst->GetCin());
- RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(NEW_ID);
- RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID);
- RTLIL::SigSpec tmp1 = module->addWire(NEW_ID);
- RTLIL::SigSpec tmp2 = module->addWire(NEW_ID);
- RTLIL::SigSpec tmp3 = module->addWire(NEW_ID);
- module->addXorGate(NEW_ID, a, b, tmp1);
+ RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(new_verific_id(inst));
+ RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst));
+ RTLIL::SigSpec tmp1 = module->addWire(new_verific_id(inst));
+ RTLIL::SigSpec tmp2 = module->addWire(new_verific_id(inst));
+ RTLIL::SigSpec tmp3 = module->addWire(new_verific_id(inst));
+ module->addXorGate(new_verific_id(inst), a, b, tmp1);
module->addXorGate(inst_name, tmp1, c, y);
- module->addAndGate(NEW_ID, tmp1, c, tmp2);
- module->addAndGate(NEW_ID, a, b, tmp3);
- module->addOrGate(NEW_ID, tmp2, tmp3, x);
+ module->addAndGate(new_verific_id(inst), tmp1, c, tmp2);
+ module->addAndGate(new_verific_id(inst), a, b, tmp3);
+ module->addOrGate(new_verific_id(inst), tmp2, tmp3, x);
return true;
}
@@ -308,63 +329,78 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr
bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdString inst_name)
{
+ RTLIL::Cell *cell = nullptr;
+
if (inst->Type() == PRIM_AND) {
- module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ cell = module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_NAND) {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addAnd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
- module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst));
+ cell = module->addAnd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ import_attributes(cell->attributes, inst);
+ cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_OR) {
- module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ cell = module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_NOR) {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addOr(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
- module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst));
+ cell = module->addOr(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ import_attributes(cell->attributes, inst);
+ cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_XOR) {
- module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ cell = module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_XNOR) {
- module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ cell = module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_INV) {
- module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ cell = module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_MUX) {
- module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
+ cell = module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_TRI) {
- module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
+ cell = module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_FADD)
{
- RTLIL::SigSpec a_plus_b = module->addWire(NEW_ID, 2);
- RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID);
+ RTLIL::SigSpec a_plus_b = module->addWire(new_verific_id(inst), 2);
+ RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst));
if (inst->GetCout())
y.append(net_map_at(inst->GetCout()));
- module->addAdd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b);
- module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y);
+ cell = module->addAdd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b);
+ import_attributes(cell->attributes, inst);
+ cell = module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -375,24 +411,26 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
log_assert(clocking.body_net == nullptr);
if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
- clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ cell = clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
else if (inst->GetSet()->IsGnd())
- clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0);
+ cell = clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0);
else if (inst->GetReset()->IsGnd())
- clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1);
+ cell = clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1);
else
- clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
+ cell = clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == PRIM_DLATCHRS)
{
if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
- module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ cell = module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
else
- module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
+ cell = module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -408,37 +446,45 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
if (inst->GetCout() != NULL)
out.append(net_map_at(inst->GetCout()));
if (inst->GetCin()->IsGnd()) {
- module->addAdd(inst_name, IN1, IN2, out, SIGNED);
+ cell = module->addAdd(inst_name, IN1, IN2, out, SIGNED);
+ import_attributes(cell->attributes, inst);
} else {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID, GetSize(out));
- module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED);
- module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false);
+ RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst), GetSize(out));
+ cell = module->addAdd(new_verific_id(inst), IN1, IN2, tmp, SIGNED);
+ import_attributes(cell->attributes, inst);
+ cell = module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false);
+ import_attributes(cell->attributes, inst);
}
return true;
}
if (inst->Type() == OPER_MULTIPLIER) {
- module->addMul(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addMul(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_DIVIDER) {
- module->addDiv(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addDiv(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_MODULO) {
- module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REMAINDER) {
- module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_SHIFT_LEFT) {
- module->addShl(inst_name, IN1, IN2, OUT, false);
+ cell = module->addShl(inst_name, IN1, IN2, OUT, false);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -448,7 +494,8 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
for (unsigned i = 1; i < inst->OutputSize(); i++) {
vec.append(RTLIL::State::S0);
}
- module->addShl(inst_name, vec, IN, OUT, false);
+ cell = module->addShl(inst_name, vec, IN, OUT, false);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -458,7 +505,8 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
for (unsigned i = 1; i < inst->OutputSize(); i++) {
vec.append(RTLIL::State::S0);
}
- module->addShl(inst_name, vec, IN, OUT, false);
+ cell = module->addShl(inst_name, vec, IN, OUT, false);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -466,108 +514,127 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
Net *net_cin = inst->GetCin();
Net *net_a_msb = inst->GetInput1Bit(0);
if (net_cin->IsGnd())
- module->addShr(inst_name, IN1, IN2, OUT, false);
+ cell = module->addShr(inst_name, IN1, IN2, OUT, false);
else if (net_cin == net_a_msb)
- module->addSshr(inst_name, IN1, IN2, OUT, true);
+ cell = module->addSshr(inst_name, IN1, IN2, OUT, true);
else
log_error("Can't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", inst->Name());
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_AND) {
- module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_OR) {
- module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_XOR) {
- module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_XNOR) {
- module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_REDUCE_NOR) {
- SigSpec t = module->ReduceOr(NEW_ID, IN, SIGNED);
- module->addNot(inst_name, t, net_map_at(inst->GetOutput()));
+ SigSpec t = module->ReduceOr(new_verific_id(inst), IN, SIGNED);
+ cell = module->addNot(inst_name, t, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_LESSTHAN) {
Net *net_cin = inst->GetCin();
if (net_cin->IsGnd())
- module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
else if (net_cin->IsPwr())
- module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
else
log_error("Can't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", inst->Name());
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_AND) {
- module->addAnd(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addAnd(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_OR) {
- module->addOr(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addOr(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_XOR) {
- module->addXor(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addXor(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_XNOR) {
- module->addXnor(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addXnor(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_BUF) {
- module->addPos(inst_name, IN, FILTERED_OUT, SIGNED);
+ cell = module->addPos(inst_name, IN, FILTERED_OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_INV) {
- module->addNot(inst_name, IN, OUT, SIGNED);
+ cell = module->addNot(inst_name, IN, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_MINUS) {
- module->addSub(inst_name, IN1, IN2, OUT, SIGNED);
+ cell = module->addSub(inst_name, IN1, IN2, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_UMINUS) {
- module->addNeg(inst_name, IN, OUT, SIGNED);
+ cell = module->addNeg(inst_name, IN, OUT, SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_EQUAL) {
- module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_NEQUAL) {
- module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ cell = module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_MUX) {
- module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT);
+ cell = module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_NTO1MUX) {
- module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput()));
+ cell = module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -587,25 +654,29 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
padded_data.append(d);
}
- module->addShr(inst_name, padded_data, sel, out);
+ cell = module->addShr(inst_name, padded_data, sel, out);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_SELECTOR)
{
- module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput()));
+ cell = module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput()));
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_SELECTOR)
{
SigSpec out = OUT;
- module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out);
+ cell = module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out);
+ import_attributes(cell->attributes, inst);
return true;
}
if (inst->Type() == OPER_WIDE_TRI) {
- module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT);
+ cell = module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -619,9 +690,10 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
RTLIL::SigSpec sig_reset = operatorInport(inst, "reset");
if (sig_set.is_fully_const() && !sig_set.as_bool() && sig_reset.is_fully_const() && !sig_reset.as_bool())
- clocking.addDff(inst_name, IN, OUT);
+ cell = clocking.addDff(inst_name, IN, OUT);
else
- clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT);
+ cell = clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT);
+ import_attributes(cell->attributes, inst);
return true;
}
@@ -709,7 +781,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
netlist = nl;
if (design->has(module_name)) {
- if (!nl->IsOperator())
+ if (!nl->IsOperator() && !is_blackbox(nl))
log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name());
return;
}
@@ -718,7 +790,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
module->name = module_name;
design->add(module);
- if (nl->IsBlackBox()) {
+ if (is_blackbox(nl)) {
log("Importing blackbox module %s.\n", RTLIL::id2cstr(module->name));
module->set_bool_attribute("\\blackbox");
} else {
@@ -850,7 +922,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
ascii_initdata++;
}
if (initval_valid) {
- RTLIL::Cell *cell = module->addCell(NEW_ID, "$meminit");
+ RTLIL::Cell *cell = module->addCell(new_verific_id(net), "$meminit");
cell->parameters["\\WORDS"] = 1;
if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound())
cell->setPort("\\ADDR", word_idx);
@@ -913,7 +985,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (net->Bus())
continue;
- RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : NEW_ID);
+ RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : new_verific_id(net));
if (verific_verbose)
log(" importing net %s as %s.\n", net->Name(), log_id(wire_name));
@@ -937,7 +1009,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (found_new_net)
{
- RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : NEW_ID);
+ RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : new_verific_id(netbus));
if (verific_verbose)
log(" importing netbus %s as %s.\n", netbus->Name(), log_id(wire_name));
@@ -1013,16 +1085,16 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
}
if (GetSize(anyconst_sig))
- module->connect(anyconst_sig, module->Anyconst(NEW_ID, GetSize(anyconst_sig)));
+ module->connect(anyconst_sig, module->Anyconst(new_verific_id(netbus), GetSize(anyconst_sig)));
if (GetSize(anyseq_sig))
- module->connect(anyseq_sig, module->Anyseq(NEW_ID, GetSize(anyseq_sig)));
+ module->connect(anyseq_sig, module->Anyseq(new_verific_id(netbus), GetSize(anyseq_sig)));
if (GetSize(allconst_sig))
- module->connect(allconst_sig, module->Allconst(NEW_ID, GetSize(allconst_sig)));
+ module->connect(allconst_sig, module->Allconst(new_verific_id(netbus), GetSize(allconst_sig)));
if (GetSize(allseq_sig))
- module->connect(allseq_sig, module->Allseq(NEW_ID, GetSize(allseq_sig)));
+ module->connect(allseq_sig, module->Allseq(new_verific_id(netbus), GetSize(allseq_sig)));
}
for (auto it : init_nets)
@@ -1046,10 +1118,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
}
for (auto net : anyconst_nets)
- module->connect(net_map_at(net), module->Anyconst(NEW_ID));
+ module->connect(net_map_at(net), module->Anyconst(new_verific_id(net)));
for (auto net : anyseq_nets)
- module->connect(net_map_at(net), module->Anyseq(NEW_ID));
+ module->connect(net_map_at(net), module->Anyseq(new_verific_id(net)));
pool<Instance*, hash_ptr_ops> sva_asserts;
pool<Instance*, hash_ptr_ops> sva_assumes;
@@ -1060,7 +1132,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst)
{
- RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : NEW_ID);
+ RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : new_verific_id(inst));
if (verific_verbose)
log(" importing cell %s (%s) as %s.\n", inst->Name(), inst->View()->Owner()->Name(), log_id(inst_name));
@@ -1128,27 +1200,34 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (inst->Type() == OPER_WRITE_PORT || inst->Type() == OPER_CLOCKED_WRITE_PORT)
{
RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name()));
- if (memory->width != int(inst->Input2Size()))
- log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
+ int numchunks = int(inst->Input2Size()) / memory->width;
+ int chunksbits = ceil_log2(numchunks);
+
+ if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0)
+ log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name());
+
+ for (int i = 0; i < numchunks; i++)
+ {
+ RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)};
+ RTLIL::SigSpec data = operatorInput2(inst).extract(i * memory->width, memory->width);
+
+ RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name :
+ RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), "$memwr");
+ cell->parameters["\\MEMID"] = memory->name.str();
+ cell->parameters["\\CLK_ENABLE"] = false;
+ cell->parameters["\\CLK_POLARITY"] = true;
+ cell->parameters["\\PRIORITY"] = 0;
+ cell->parameters["\\ABITS"] = GetSize(addr);
+ cell->parameters["\\WIDTH"] = GetSize(data);
+ cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data)));
+ cell->setPort("\\CLK", RTLIL::State::S0);
+ cell->setPort("\\ADDR", addr);
+ cell->setPort("\\DATA", data);
- RTLIL::SigSpec addr = operatorInput1(inst);
- RTLIL::SigSpec data = operatorInput2(inst);
-
- RTLIL::Cell *cell = module->addCell(inst_name, "$memwr");
- cell->parameters["\\MEMID"] = memory->name.str();
- cell->parameters["\\CLK_ENABLE"] = false;
- cell->parameters["\\CLK_POLARITY"] = true;
- cell->parameters["\\PRIORITY"] = 0;
- cell->parameters["\\ABITS"] = GetSize(addr);
- cell->parameters["\\WIDTH"] = GetSize(data);
- cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data)));
- cell->setPort("\\CLK", RTLIL::State::S0);
- cell->setPort("\\ADDR", addr);
- cell->setPort("\\DATA", data);
-
- if (inst->Type() == OPER_CLOCKED_WRITE_PORT) {
- cell->parameters["\\CLK_ENABLE"] = true;
- cell->setPort("\\CLK", net_map_at(inst->GetClock()));
+ if (inst->Type() == OPER_CLOCKED_WRITE_PORT) {
+ cell->parameters["\\CLK_ENABLE"] = true;
+ cell->setPort("\\CLK", net_map_at(inst->GetClock()));
+ }
}
continue;
}
@@ -1184,7 +1263,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
log_assert(inst->Input1Size() == inst->OutputSize());
SigSpec sig_d, sig_q, sig_o;
- sig_q = module->addWire(NEW_ID, inst->Input1Size());
+ sig_q = module->addWire(new_verific_id(inst), inst->Input1Size());
for (int i = int(inst->Input1Size())-1; i >= 0; i--){
sig_d.append(net_map_at(inst->GetInput1Bit(i)));
@@ -1198,8 +1277,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
log_signal(sig_d), log_signal(sig_q), log_signal(sig_o));
}
- clocking.addDff(NEW_ID, sig_d, sig_q);
- module->addXnor(NEW_ID, sig_d, sig_q, sig_o);
+ clocking.addDff(new_verific_id(inst), sig_d, sig_q);
+ module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o);
if (!mode_keep)
continue;
@@ -1213,7 +1292,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
SigSpec sig_d = net_map_at(inst->GetInput1());
SigSpec sig_o = net_map_at(inst->GetOutput());
- SigSpec sig_q = module->addWire(NEW_ID);
+ SigSpec sig_q = module->addWire(new_verific_id(inst));
if (verific_verbose) {
log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
@@ -1222,8 +1301,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
log_signal(sig_d), log_signal(sig_q), log_signal(sig_o));
}
- clocking.addDff(NEW_ID, sig_d, sig_q);
- module->addXnor(NEW_ID, sig_d, sig_q, sig_o);
+ clocking.addDff(new_verific_id(inst), sig_d, sig_q);
+ module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o);
if (!mode_keep)
continue;
@@ -1242,7 +1321,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
- past_ffs.insert(clocking.addDff(NEW_ID, sig_d, sig_q));
+ past_ffs.insert(clocking.addDff(new_verific_id(inst), sig_d, sig_q));
if (!mode_keep)
continue;
@@ -1256,14 +1335,14 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
SigBit sig_d = net_map_at(inst->GetInput1());
SigBit sig_o = net_map_at(inst->GetOutput());
- SigBit sig_q = module->addWire(NEW_ID);
+ SigBit sig_q = module->addWire(new_verific_id(inst));
if (verific_verbose)
log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
- clocking.addDff(NEW_ID, sig_d, sig_q);
- module->addEq(NEW_ID, {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o);
+ clocking.addDff(new_verific_id(inst), sig_d, sig_q);
+ module->addEq(new_verific_id(inst), {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o);
if (!mode_keep)
continue;
@@ -1286,9 +1365,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
Cell *cell = nullptr;
if (assume_attr != nullptr && !strcmp(assume_attr, "1"))
- cell = module->addAssume(NEW_ID, cond, State::S1);
+ cell = module->addAssume(new_verific_id(inst), cond, State::S1);
else
- cell = module->addAssert(NEW_ID, cond, State::S1);
+ cell = module->addAssert(new_verific_id(inst), cond, State::S1);
import_attributes(cell->attributes, inst);
continue;
@@ -1330,7 +1409,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
IdString port_name_id = RTLIL::escape_id(port_name);
auto &sigvec = cell_port_conns[port_name_id];
if (GetSize(sigvec) <= port_offset) {
- SigSpec zwires = module->addWire(NEW_ID, port_offset+1-GetSize(sigvec));
+ SigSpec zwires = module->addWire(new_verific_id(inst), port_offset+1-GetSize(sigvec));
for (auto bit : zwires)
sigvec.push_back(bit);
}
@@ -1540,30 +1619,35 @@ struct VerificExtNets
int portname_cnt = 0;
// a map from Net to the same Net one level up in the design hierarchy
- std::map<Net*, Net*> net_level_up;
+ std::map<Net*, Net*> net_level_up_drive_up;
+ std::map<Net*, Net*> net_level_up_drive_down;
- Net *get_net_level_up(Net *net)
+ Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr)
{
+ auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down;
+
if (net_level_up.count(net) == 0)
{
Netlist *nl = net->Owner();
// Simply return if Netlist is not unique
- if (nl->NumOfRefs() != 1)
- return net;
+ log_assert(nl->NumOfRefs() == 1);
Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
Netlist *up_nl = up_inst->Owner();
// create new Port
string name = stringf("___extnets_%d", portname_cnt++);
- Port *new_port = new Port(name.c_str(), DIR_OUT);
+ Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN);
nl->Add(new_port);
net->Connect(new_port);
// create new Net in up Netlist
- Net *new_net = new Net(name.c_str());
- up_nl->Add(new_net);
+ Net *new_net = final_net;
+ if (new_net == nullptr || new_net->Owner() != up_nl) {
+ new_net = new Net(name.c_str());
+ up_nl->Add(new_net);
+ }
up_inst->Connect(new_port, new_net);
net_level_up[net] = new_net;
@@ -1572,6 +1656,39 @@ struct VerificExtNets
return net_level_up.at(net);
}
+ Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr)
+ {
+ while (net->Owner() != dest)
+ net = route_up(net, drive_up, final_net);
+ if (final_net != nullptr)
+ log_assert(net == final_net);
+ return net;
+ }
+
+ Netlist *find_common_ancestor(Netlist *A, Netlist *B)
+ {
+ std::set<Netlist*> ancestors_of_A;
+
+ Netlist *cursor = A;
+ while (1) {
+ ancestors_of_A.insert(cursor);
+ if (cursor->NumOfRefs() != 1)
+ break;
+ cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
+ }
+
+ cursor = B;
+ while (1) {
+ if (ancestors_of_A.count(cursor))
+ return cursor;
+ if (cursor->NumOfRefs() != 1)
+ break;
+ cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
+ }
+
+ log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str());
+ }
+
void run(Netlist *nl)
{
MapIter mi, mi2;
@@ -1595,19 +1712,37 @@ struct VerificExtNets
if (verific_verbose)
log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
- while (net->IsExternalTo(nl))
- {
- Net *newnet = get_net_level_up(net);
- if (newnet == net) break;
+ Netlist *ext_nl = net->Owner();
+
+ if (verific_verbose)
+ log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str());
+
+ Netlist *ca_nl = find_common_ancestor(nl, ext_nl);
+
+ if (verific_verbose)
+ log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str());
+ Net *ca_net = route_up(net, !port->IsOutput(), ca_nl);
+ Net *new_net = ca_net;
+
+ if (ca_nl != nl)
+ {
if (verific_verbose)
- log(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name());
- net = newnet;
+ log(" net in common ancestor: %s\n", ca_net->Name());
+
+ string name = stringf("___extnets_%d", portname_cnt++);
+ new_net = new Net(name.c_str());
+ nl->Add(new_net);
+
+ Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
+ log_assert(n == ca_net);
}
if (verific_verbose)
- log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : "");
- todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net));
+ log(" new local net: %s\n", new_net->Name());
+
+ log_assert(!new_net->IsExternalTo(nl));
+ todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net));
}
for (auto it : todo_connect) {
@@ -1676,6 +1811,7 @@ YOSYS_NAMESPACE_END
PRIVATE_NAMESPACE_BEGIN
+#ifdef YOSYS_ENABLE_VERIFIC
bool check_noverific_env()
{
const char *e = getenv("YOSYS_NOVERIFIC");
@@ -1685,6 +1821,7 @@ bool check_noverific_env()
return false;
return true;
}
+#endif
struct VerificPass : public Pass {
VerificPass() : Pass("verific", "load Verilog and VHDL designs using Verific") { }
@@ -1774,6 +1911,13 @@ struct VerificPass : public Pass {
log(" -autocover\n");
log(" Generate automatic cover statements for all asserts\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");
+ log(" cause Verific to produce a VERI-1928 or VHDL-1676 message. This option\n");
+ log(" can be specified multiple times to override multiple parameters.\n");
+ log(" String values must be passed in double quotes (\").\n");
+ log("\n");
log(" -v, -vv\n");
log(" Verbose log messages. (-vv is even more verbose than -v.)\n");
log("\n");
@@ -1819,12 +1963,19 @@ struct VerificPass : public Pass {
{
Message::SetConsoleOutput(0);
Message::RegisterCallBackMsg(msg_func);
+
RuntimeFlags::SetVar("db_preserve_user_nets", 1);
RuntimeFlags::SetVar("db_allow_external_nets", 1);
- RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0);
+ RuntimeFlags::SetVar("db_infer_wide_operators", 1);
+
RuntimeFlags::SetVar("veri_extract_dualport_rams", 0);
RuntimeFlags::SetVar("veri_extract_multiport_rams", 1);
- RuntimeFlags::SetVar("db_infer_wide_operators", 1);
+
+ RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0);
+ RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1);
+
+ RuntimeFlags::SetVar("vhdl_support_variable_slice", 1);
+ RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0);
// Workaround for VIPER #13851
RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1);
@@ -1832,6 +1983,10 @@ struct VerificPass : public Pass {
// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
+#ifndef DB_PRESERVE_INITIAL_VALUE
+# warning Verific was built without DB_PRESERVE_INITIAL_VALUE.
+#endif
+
set_verific_global_flags = false;
}
@@ -2017,6 +2172,7 @@ struct VerificPass : public Pass {
bool mode_autocover = false;
bool flatten = false, extnets = false;
string dumpfile;
+ Map parameters(STRING_HASH);
for (argidx++; argidx < GetSize(args); argidx++) {
if (args[argidx] == "-all") {
@@ -2055,6 +2211,15 @@ struct VerificPass : public Pass {
mode_autocover = true;
continue;
}
+ if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
+ const std::string &key = args[++argidx];
+ const std::string &value = args[++argidx];
+ unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
+ 1 /* force_overwrite */);
+ if (!new_insertion)
+ log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str());
+ continue;
+ }
if (args[argidx] == "-V") {
mode_verific = true;
continue;
@@ -2079,42 +2244,6 @@ struct VerificPass : public Pass {
if (mode_all)
{
-#if 0
- log("Running veri_file::ElaborateAll().\n");
- if (!veri_file::ElaborateAll())
- log_cmd_error("Elaboration of Verilog modules failed.\n");
-
- log("Running vhdl_file::ElaborateAll().\n");
- if (!vhdl_file::ElaborateAll())
- log_cmd_error("Elaboration of VHDL modules failed.\n");
-
- Library *lib = Netlist::PresentDesign()->Owner()->Owner();
-
- if (argidx == GetSize(args))
- {
- MapIter iter;
- char *iter_name;
- Verific::Cell *iter_cell;
-
- FOREACH_MAP_ITEM(lib->GetCells(), iter, &iter_name, &iter_cell) {
- if (*iter_name != '$')
- nl_todo.insert(iter_cell->GetFirstNetlist());
- }
- }
- else
- {
- for (; argidx < GetSize(args); argidx++)
- {
- Verific::Cell *cell = lib->GetCell(args[argidx].c_str());
-
- if (cell == nullptr)
- log_cmd_error("Module not found: %s\n", args[argidx].c_str());
-
- nl_todo.insert(cell->GetFirstNetlist());
- cell->GetFirstNetlist()->SetPresentDesign();
- }
- }
-#else
log("Running hier_tree::ElaborateAll().\n");
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
@@ -2124,35 +2253,19 @@ struct VerificPass : public Pass {
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
if (veri_lib) veri_libs.InsertLast(veri_lib);
- Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
+ Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &parameters);
Netlist *nl;
int i;
FOREACH_ARRAY_ITEM(netlists, i, nl)
nl_todo.insert(nl);
delete netlists;
-#endif
}
else
{
if (argidx == GetSize(args))
log_cmd_error("No top module specified.\n");
-#if 0
- for (; argidx < GetSize(args); argidx++) {
- if (veri_file::GetModule(args[argidx].c_str())) {
- log("Running veri_file::Elaborate(\"%s\").\n", args[argidx].c_str());
- if (!veri_file::Elaborate(args[argidx].c_str()))
- log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
- nl_todo.insert(Netlist::PresentDesign());
- } else {
- log("Running vhdl_file::Elaborate(\"%s\").\n", args[argidx].c_str());
- if (!vhdl_file::Elaborate(args[argidx].c_str()))
- log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
- nl_todo.insert(Netlist::PresentDesign());
- }
- }
-#else
Array veri_modules, vhdl_units;
for (; argidx < GetSize(args); argidx++)
{
@@ -2177,14 +2290,13 @@ struct VerificPass : public Pass {
}
log("Running hier_tree::Elaborate().\n");
- Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units);
+ Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &parameters);
Netlist *nl;
int i;
FOREACH_ARRAY_ITEM(netlists, i, nl)
nl_todo.insert(nl);
delete netlists;
-#endif
}
if (!verific_error_msg.empty())
@@ -2274,21 +2386,43 @@ struct ReadPass : public Pass {
log("\n");
log("Add directory to global Verilog/SystemVerilog include directories.\n");
log("\n");
+ log("\n");
+ log(" read -verific\n");
+ log(" read -noverific\n");
+ log("\n");
+ log("Subsequent calls to 'read' will either use or not use Verific. Calling 'read'\n");
+ log("with -verific will result in an error on Yosys binaries that are built without\n");
+ log("Verific support. The default is to use Verific if it is available.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- if (args.size() < 2)
+#ifdef YOSYS_ENABLE_VERIFIC
+ static bool verific_available = !check_noverific_env();
+#else
+ static bool verific_available = false;
+#endif
+ static bool use_verific = verific_available;
+
+ if (args.size() < 2 || args[1][0] != '-')
log_cmd_error("Missing mode parameter.\n");
+ if (args[1] == "-verific" || args[1] == "-noverific") {
+ if (args.size() != 2)
+ log_cmd_error("Additional arguments to -verific/-noverific.\n");
+ if (args[1] == "-verific") {
+ if (!verific_available)
+ log_cmd_error("This version of Yosys is built without Verific support.\n");
+ use_verific = true;
+ } else {
+ use_verific = false;
+ }
+ return;
+ }
+
if (args.size() < 3)
log_cmd_error("Missing file name parameter.\n");
-#ifdef YOSYS_ENABLE_VERIFIC
- bool use_verific = !check_noverific_env();
-#else
- bool use_verific = false;
-#endif
-
if (args[1] == "-vlog95" || args[1] == "-vlog2k") {
if (use_verific) {
args[0] = "verific";
diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h
index 334a436a..b331dd4b 100644
--- a/frontends/verific/verific.h
+++ b/frontends/verific/verific.h
@@ -78,6 +78,7 @@ struct VerificImporter
RTLIL::SigBit net_map_at(Verific::Net *net);
+ RTLIL::IdString new_verific_id(Verific::DesignObj *obj);
void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj);
RTLIL::SigSpec operatorInput(Verific::Instance *inst);
diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc
index cdc9ece8..8ea8372d 100644
--- a/frontends/verific/verificsva.cc
+++ b/frontends/verific/verificsva.cc
@@ -827,9 +827,9 @@ struct SvaFsm
for (auto &it : nodes[i].edges) {
if (it.second != State::S1)
- log(" egde %s -> %d\n", log_signal(it.second), it.first);
+ log(" edge %s -> %d\n", log_signal(it.second), it.first);
else
- log(" egde -> %d\n", it.first);
+ log(" edge -> %d\n", it.first);
}
for (auto &it : nodes[i].links) {
@@ -856,9 +856,9 @@ struct SvaFsm
for (auto &it : unodes[i].edges) {
if (!it.second.empty())
- log(" egde %s -> %d\n", log_signal(it.second), it.first);
+ log(" edge %s -> %d\n", log_signal(it.second), it.first);
else
- log(" egde -> %d\n", it.first);
+ log(" edge -> %d\n", it.first);
}
for (auto &ctrl : unodes[i].accept) {
@@ -1666,7 +1666,20 @@ struct VerificSvaImporter
log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
- RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID);
+ bool is_user_declared = root->IsUserDeclared();
+
+ // FIXME
+ if (!is_user_declared) {
+ const char *name = root->Name();
+ for (int i = 0; name[i]; i++) {
+ if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) {
+ is_user_declared = true;
+ break;
+ }
+ }
+ }
+
+ RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID);
// parse SVA sequence into trigger signal
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index 8dcc7c5a..504f8b3f 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -66,12 +66,24 @@ struct VerilogFrontend : public Frontend {
log(" enable support for SystemVerilog assertions and some Yosys extensions\n");
log(" replace the implicit -D SYNTHESIS with -D FORMAL\n");
log("\n");
+ log(" -noassert\n");
+ log(" ignore assert() statements\n");
+ log("\n");
+ log(" -noassume\n");
+ log(" ignore assume() statements\n");
+ log("\n");
log(" -norestrict\n");
- log(" ignore restrict() assertions\n");
+ log(" ignore restrict() statements\n");
log("\n");
log(" -assume-asserts\n");
log(" treat all assert() statements like assume() statements\n");
log("\n");
+ log(" -assert-assumes\n");
+ log(" treat all assume() statements like assert() statements\n");
+ log("\n");
+ log(" -debug\n");
+ log(" alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n");
+ log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@@ -81,7 +93,10 @@ struct VerilogFrontend : public Frontend {
log(" -no_dump_ptr\n");
log(" do not include hex memory addresses in dump (easier to diff dumps)\n");
log("\n");
- log(" -dump_vlog\n");
+ log(" -dump_vlog1\n");
+ log(" dump ast as Verilog code (before simplification)\n");
+ log("\n");
+ log(" -dump_vlog2\n");
log(" dump ast as Verilog code (after simplification)\n");
log("\n");
log(" -dump_rtlil\n");
@@ -188,7 +203,8 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_ast1 = false;
bool flag_dump_ast2 = false;
bool flag_no_dump_ptr = false;
- bool flag_dump_vlog = false;
+ bool flag_dump_vlog1 = false;
+ bool flag_dump_vlog2 = false;
bool flag_dump_rtlil = false;
bool flag_nolatches = false;
bool flag_nomeminit = false;
@@ -229,6 +245,14 @@ struct VerilogFrontend : public Frontend {
formal_mode = true;
continue;
}
+ if (arg == "-noassert") {
+ noassert_mode = true;
+ continue;
+ }
+ if (arg == "-noassume") {
+ noassume_mode = true;
+ continue;
+ }
if (arg == "-norestrict") {
norestrict_mode = true;
continue;
@@ -237,6 +261,18 @@ struct VerilogFrontend : public Frontend {
assume_asserts_mode = true;
continue;
}
+ if (arg == "-assert-assumes") {
+ assert_assumes_mode = true;
+ continue;
+ }
+ if (arg == "-debug") {
+ flag_dump_ast1 = true;
+ flag_dump_ast2 = true;
+ flag_dump_vlog1 = true;
+ flag_dump_vlog2 = true;
+ frontend_verilog_yydebug = true;
+ continue;
+ }
if (arg == "-dump_ast1") {
flag_dump_ast1 = true;
continue;
@@ -249,8 +285,12 @@ struct VerilogFrontend : public Frontend {
flag_no_dump_ptr = true;
continue;
}
- if (arg == "-dump_vlog") {
- flag_dump_vlog = true;
+ if (arg == "-dump_vlog1") {
+ flag_dump_vlog1 = true;
+ continue;
+ }
+ if (arg == "-dump_vlog2") {
+ flag_dump_vlog2 = true;
continue;
}
if (arg == "-dump_rtlil") {
@@ -389,7 +429,7 @@ struct VerilogFrontend : public Frontend {
if (flag_nodpi)
error_on_dpi_function(current_ast);
- AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
+ AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index 16edc798..523bbc89 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -54,12 +54,21 @@ namespace VERILOG_FRONTEND
// running in -formal mode
extern bool formal_mode;
+ // running in -noassert mode
+ extern bool noassert_mode;
+
+ // running in -noassume mode
+ extern bool noassume_mode;
+
// running in -norestrict mode
extern bool norestrict_mode;
// running in -assume-asserts mode
extern bool assume_asserts_mode;
+ // running in -assert-assumes mode
+ extern bool assert_assumes_mode;
+
// running in -lib mode
extern bool lib_mode;
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 83921bf0..6ef38252 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -135,6 +135,9 @@ YOSYS_NAMESPACE_END
frontend_verilog_yyerror("Unsupported default nettype: %s", p);
}
+"`protect"[^\n]* /* ignore `protect*/
+"`endprotect"[^\n]* /* ignore `endprotect*/
+
"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
}
@@ -150,6 +153,9 @@ YOSYS_NAMESPACE_END
"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
+"interface" { SV_KEYWORD(TOK_INTERFACE); }
+"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); }
+"modport" { SV_KEYWORD(TOK_MODPORT); }
"parameter" { return TOK_PARAMETER; }
"localparam" { return TOK_LOCALPARAM; }
"defparam" { return TOK_DEFPARAM; }
@@ -183,6 +189,14 @@ YOSYS_NAMESPACE_END
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
+ /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
+ 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_$\.] {
+ frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
+ return TOK_SVA_LABEL;
+}
+
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
@@ -268,7 +282,7 @@ YOSYS_NAMESPACE_END
yystr[j++] = yystr[i++];
}
yystr[j] = 0;
- frontend_verilog_yylval.string = new std::string(yystr);
+ frontend_verilog_yylval.string = new std::string(yystr, j);
free(yystr);
return TOK_STRING;
}
@@ -295,6 +309,11 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID;
}
+[a-zA-Z_$][a-zA-Z0-9_$\.]* {
+ frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
+ return TOK_ID;
+}
+
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
static bool printed_warning = false;
if (!printed_warning) {
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 2389d7d3..52685f63 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -35,6 +35,7 @@
%{
#include <list>
+#include <stack>
#include <string.h>
#include "frontends/verilog/verilog_frontend.h"
#include "kernel/log.h"
@@ -47,7 +48,8 @@ YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
int port_counter;
std::map<std::string, int> port_stubs;
- std::map<std::string, AstNode*> attr_list, default_attr_list;
+ std::map<std::string, AstNode*> *attr_list, default_attr_list;
+ std::stack<std::map<std::string, AstNode*> *> attr_list_stack;
std::map<std::string, AstNode*> *albuf;
std::vector<AstNode*> ast_stack;
struct AstNode *astbuf1, *astbuf2, *astbuf3;
@@ -58,8 +60,10 @@ namespace VERILOG_FRONTEND {
bool do_not_require_port_stubs;
bool default_nettype_wire;
bool sv_mode, formal_mode, lib_mode;
- bool norestrict_mode, assume_asserts_mode;
+ bool noassert_mode, noassume_mode, norestrict_mode;
+ bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const;
+ bool current_modport_input, current_modport_output;
std::istream *lexin;
}
YOSYS_NAMESPACE_END
@@ -101,10 +105,12 @@ static void free_attr(std::map<std::string, AstNode*> *al)
bool boolean;
}
-%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
+%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
+%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
+%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
@@ -114,15 +120,14 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
-%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
-%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
+%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
-%type <string> opt_label tok_prim_wrapper hierarchical_id
-%type <boolean> opt_signed unique_case_attr
+%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id
+%type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr
// operator precedence from low to high
@@ -167,19 +172,23 @@ design:
param_decl design |
localparam_decl design |
package design |
+ interface design |
/* empty */;
attr:
{
- for (auto &it : attr_list)
- delete it.second;
- attr_list.clear();
+ if (attr_list != nullptr)
+ attr_list_stack.push(attr_list);
+ attr_list = new std::map<std::string, AstNode*>;
for (auto &it : default_attr_list)
- attr_list[it.first] = it.second->clone();
+ (*attr_list)[it.first] = it.second->clone();
} attr_opt {
- std::map<std::string, AstNode*> *al = new std::map<std::string, AstNode*>;
- al->swap(attr_list);
- $$ = al;
+ $$ = attr_list;
+ if (!attr_list_stack.empty()) {
+ attr_list = attr_list_stack.top();
+ attr_list_stack.pop();
+ } else
+ attr_list = nullptr;
};
attr_opt:
@@ -188,15 +197,20 @@ attr_opt:
defattr:
DEFATTR_BEGIN {
+ if (attr_list != nullptr)
+ attr_list_stack.push(attr_list);
+ attr_list = new std::map<std::string, AstNode*>;
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
- for (auto &it : attr_list)
- delete it.second;
- attr_list.clear();
} opt_attr_list {
- default_attr_list = attr_list;
- attr_list.clear();
+ attr_list->swap(default_attr_list);
+ delete attr_list;
+ if (!attr_list_stack.empty()) {
+ attr_list = attr_list_stack.top();
+ attr_list_stack.pop();
+ } else
+ attr_list = nullptr;
} DEFATTR_END;
opt_attr_list:
@@ -208,15 +222,15 @@ attr_list:
attr_assign:
hierarchical_id {
- if (attr_list.count(*$1) != 0)
- delete attr_list[*$1];
- attr_list[*$1] = AstNode::mkconst_int(1, false);
+ if (attr_list->count(*$1) != 0)
+ delete (*attr_list)[*$1];
+ (*attr_list)[*$1] = AstNode::mkconst_int(1, false);
delete $1;
} |
hierarchical_id '=' expr {
- if (attr_list.count(*$1) != 0)
- delete attr_list[*$1];
- attr_list[*$1] = $3;
+ if (attr_list->count(*$1) != 0)
+ delete (*attr_list)[*$1];
+ (*attr_list)[*$1] = $3;
delete $1;
};
@@ -301,7 +315,7 @@ module_arg_opt_assignment:
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
} else
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value.");
} |
/* empty */;
@@ -319,6 +333,21 @@ module_arg:
}
delete $1;
} module_arg_opt_assignment |
+ TOK_ID {
+ astbuf1 = new AstNode(AST_INTERFACEPORT);
+ astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE));
+ astbuf1->children[0]->str = *$1;
+ delete $1;
+ } TOK_ID { /* SV interfaces */
+ if (!sv_mode)
+ frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str());
+ astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type.
+ astbuf2->str = *$3;
+ delete $3;
+ astbuf2->port_id = ++port_counter;
+ ast_stack.back()->children.push_back(astbuf2);
+ delete astbuf1; // really only needed if multiple instances of same type.
+ } module_arg_opt_assignment |
attr wire_type range TOK_ID {
AstNode *node = $2;
node->str = *$4;
@@ -356,6 +385,33 @@ package_body:
package_body_stmt:
localparam_decl;
+interface:
+ TOK_INTERFACE TOK_ID {
+ do_not_require_port_stubs = false;
+ AstNode *intf = new AstNode(AST_INTERFACE);
+ ast_stack.back()->children.push_back(intf);
+ ast_stack.push_back(intf);
+ current_ast_mod = intf;
+ port_stubs.clear();
+ port_counter = 0;
+ intf->str = *$2;
+ delete $2;
+ } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE {
+ if (port_stubs.size() != 0)
+ frontend_verilog_yyerror("Missing details for module port `%s'.",
+ port_stubs.begin()->first.c_str());
+ ast_stack.pop_back();
+ log_assert(ast_stack.size() == 1);
+ current_ast_mod = NULL;
+ };
+
+interface_body:
+ interface_body interface_body_stmt |;
+
+interface_body_stmt:
+ param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
+ modport_stmt;
+
non_opt_delay:
'#' TOK_ID { delete $2; } |
'#' TOK_CONSTVAL { delete $2; } |
@@ -626,7 +682,7 @@ task_func_port:
astbuf2 = $3;
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
if (astbuf2) {
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions (task/function arguments)");
} else {
astbuf2 = new AstNode(AST_RANGE);
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
@@ -634,7 +690,7 @@ task_func_port:
}
}
if (astbuf2 && astbuf2->children.size() != 2)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("task/function argument range must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
} wire_name | wire_name;
task_func_body:
@@ -738,7 +794,7 @@ more_path_inputs :
list_of_path_outputs :
specify_output_terminal_descriptor |
list_of_path_outputs ',' specify_output_terminal_descriptor ;
-
+
opt_polarity_operator :
'+'
| '-'
@@ -763,7 +819,7 @@ system_timing_arg :
system_timing_args :
system_timing_arg |
system_timing_args ',' system_timing_arg ;
-
+
/*
t_path_delay_expression :
path_delay_expression;
@@ -825,7 +881,7 @@ constant_mintypmax_expression :
// for the time being this is OK, but we may write our own expr here.
// as I'm not sure it is legal to use a full expr here (probably not)
// On the other hand, other rules requiring constant expressions also use 'expr'
-// (such as param assignment), so we may leave this as-is, perhaps assing runtime checks for constant-ness
+// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
constant_expression:
expr ;
@@ -837,7 +893,7 @@ param_signed:
param_integer:
TOK_INTEGER {
if (astbuf1->children.size() != 1)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Internal error in param_integer - should not happen?");
astbuf1->children.push_back(new AstNode(AST_RANGE));
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true));
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true));
@@ -847,7 +903,7 @@ param_integer:
param_real:
TOK_REAL {
if (astbuf1->children.size() != 1)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real.");
astbuf1->children.push_back(new AstNode(AST_REALVALUE));
} | /* empty */;
@@ -855,7 +911,7 @@ param_range:
range {
if ($1 != NULL) {
if (astbuf1->children.size() != 1)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("integer/real parameters should not have a range.");
astbuf1->children.push_back($1);
}
};
@@ -881,9 +937,15 @@ param_decl_list:
single_param_decl:
TOK_ID '=' expr {
- if (astbuf1 == nullptr)
- frontend_verilog_yyerror("syntax error");
- AstNode *node = astbuf1->clone();
+ AstNode *node;
+ if (astbuf1 == nullptr) {
+ if (!sv_mode)
+ frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword");
+ node = new AstNode(AST_PARAMETER);
+ node->children.push_back(AstNode::mkconst_int(0, true));
+ } else {
+ node = astbuf1->clone();
+ }
node->str = *$1;
delete node->children[0];
node->children[0] = $3;
@@ -914,7 +976,7 @@ wire_decl:
astbuf2 = $3;
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
if (astbuf2) {
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions.");
} else {
astbuf2 = new AstNode(AST_RANGE);
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
@@ -922,7 +984,7 @@ wire_decl:
}
}
if (astbuf2 && astbuf2->children.size() != 2)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
} wire_name_list {
delete astbuf1;
if (astbuf2 != NULL)
@@ -1016,7 +1078,7 @@ wire_name_and_opt_assign:
wire_name:
TOK_ID range_or_multirange {
if (astbuf1 == nullptr)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node.");
AstNode *node = astbuf1->clone();
node->str = *$1;
append_attr_clone(node, albuf);
@@ -1024,7 +1086,7 @@ wire_name:
node->children.push_back(astbuf2->clone());
if ($2 != NULL) {
if (node->is_input || node->is_output)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions.");
if (!astbuf2) {
AstNode *rng = new AstNode(AST_RANGE);
rng->children.push_back(AstNode::mkconst_int(0, true));
@@ -1267,74 +1329,216 @@ opt_label:
$$ = NULL;
};
+opt_sva_label:
+ TOK_SVA_LABEL ':' {
+ $$ = $1;
+ } |
+ /* empty */ {
+ $$ = NULL;
+ };
+
opt_property:
- TOK_PROPERTY | /* empty */;
+ TOK_PROPERTY {
+ $$ = true;
+ } |
+ /* empty */ {
+ $$ = false;
+ };
-opt_stmt_label:
- TOK_ID ':' | /* empty */;
+modport_stmt:
+ TOK_MODPORT TOK_ID {
+ AstNode *modport = new AstNode(AST_MODPORT);
+ ast_stack.back()->children.push_back(modport);
+ ast_stack.push_back(modport);
+ modport->str = *$2;
+ delete $2;
+ } modport_args_opt {
+ ast_stack.pop_back();
+ log_assert(ast_stack.size() == 2);
+ } ';'
+
+modport_args_opt:
+ '(' ')' | '(' modport_args optional_comma ')';
+
+modport_args:
+ modport_arg | modport_args ',' modport_arg;
+
+modport_arg:
+ modport_type_token modport_member |
+ modport_member
+
+modport_member:
+ TOK_ID {
+ AstNode *modport_member = new AstNode(AST_MODPORTMEMBER);
+ ast_stack.back()->children.push_back(modport_member);
+ modport_member->str = *$1;
+ modport_member->is_input = current_modport_input;
+ modport_member->is_output = current_modport_output;
+ delete $1;
+ }
+
+modport_type_token:
+ TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
assert:
- opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
+ opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {
+ if (noassert_mode) {
+ delete $5;
+ } else {
+ AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {
+ if (noassume_mode) {
+ delete $5;
+ } else {
+ AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
+ opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ if (noassert_mode) {
+ delete $6;
+ } else {
+ AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
+ opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ if (noassume_mode) {
+ delete $6;
+ } else {
+ AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
+ opt_sva_label TOK_COVER opt_property '(' expr ')' ';' {
+ AstNode *node = new AstNode(AST_COVER, $5);
+ if ($1 != nullptr) {
+ node->str = *$1;
+ delete $1;
+ }
+ ast_stack.back()->children.push_back(node);
} |
- opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
+ opt_sva_label TOK_COVER opt_property '(' ')' ';' {
+ AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
+ if ($1 != nullptr) {
+ node->str = *$1;
+ delete $1;
+ }
+ ast_stack.back()->children.push_back(node);
} |
- opt_stmt_label TOK_COVER ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
+ opt_sva_label TOK_COVER ';' {
+ AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
+ if ($1 != nullptr) {
+ node->str = *$1;
+ delete $1;
+ }
+ ast_stack.back()->children.push_back(node);
} |
- opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
- if (norestrict_mode)
+ opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' {
+ if (norestrict_mode) {
delete $5;
- else
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ } else {
+ AstNode *node = new AstNode(AST_ASSUME, $5);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if (!$3)
+ log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
+ if ($1 != nullptr)
+ delete $1;
} |
- opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
- if (norestrict_mode)
+ opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ if (norestrict_mode) {
delete $6;
- else
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
+ } else {
+ AstNode *node = new AstNode(AST_FAIR, $6);
+ if ($1 != nullptr)
+ node->str = *$1;
+ ast_stack.back()->children.push_back(node);
+ }
+ if (!$3)
+ log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
+ if ($1 != nullptr)
+ delete $1;
};
assert_property:
- TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4));
- } |
- TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
+ opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5));
+ opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
+ opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
+ opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
- if (norestrict_mode)
- delete $4;
- else
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
+ opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
} |
- TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
- if (norestrict_mode)
+ opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
+ if (norestrict_mode) {
delete $5;
- else
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
+ } else {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
+ }
+ } |
+ opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
+ if (norestrict_mode) {
+ delete $6;
+ } else {
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
+ if ($1 != nullptr) {
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ }
+ }
};
simple_behavioral_stmt:
@@ -1379,7 +1583,7 @@ behavioral_stmt:
node->str = *$3;
} behavioral_stmt_list TOK_END opt_label {
if ($3 != NULL && $7 != NULL && *$3 != *$7)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1);
if ($3 != NULL)
delete $3;
if ($7 != NULL)
@@ -1552,6 +1756,11 @@ case_expr_list:
TOK_DEFAULT {
ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
} |
+ TOK_SVA_LABEL {
+ ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER));
+ ast_stack.back()->children.back()->str = *$1;
+ delete $1;
+ } |
expr {
ast_stack.back()->children.push_back($1);
} |
@@ -1695,7 +1904,7 @@ basic_expr:
} |
'(' expr ')' TOK_CONSTVAL {
if ($4->substr(0, 1) != "'")
- frontend_verilog_yyerror("Syntax error.");
+ 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);
if (val == NULL)
@@ -1705,7 +1914,7 @@ basic_expr:
} |
hierarchical_id TOK_CONSTVAL {
if ($2->substr(0, 1) != "'")
- frontend_verilog_yyerror("Syntax error.");
+ 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;
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index fcc4fcc4..ae88f4aa 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -82,6 +82,27 @@ struct CellTypes
void setup_internals()
{
+ setup_internals_eval();
+
+ IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
+
+ 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);
+ }
+
+ void setup_internals_eval()
+ {
std::vector<RTLIL::IdString> unary_ops = {
"$not", "$pos", "$neg",
"$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
@@ -111,20 +132,6 @@ struct CellTypes
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("$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);
}
void setup_internals_mem()
@@ -154,10 +161,19 @@ struct CellTypes
void setup_stdcells()
{
+ setup_stdcells_eval();
+
+ IdString A = "\\A", E = "\\E", Y = "\\Y";
+
+ setup_type("$_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 = "\\I", N = "\\N", O = "\\O", P = "\\P";
+ IdString M = "\\M", N = "\\N", O = "\\O", P = "\\P";
IdString S = "\\S", T = "\\T", U = "\\U", V = "\\V";
IdString Y = "\\Y";
@@ -179,7 +195,6 @@ struct CellTypes
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);
- setup_type("$_TBUF_", {A, E}, {Y}, true);
}
void setup_stdcells_mem()
@@ -257,7 +272,7 @@ struct CellTypes
return v;
}
- static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+ 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";
@@ -329,10 +344,15 @@ struct CellTypes
if (type == "$_ORNOT_")
return const_or(arg1, eval_not(arg2), false, false, 1);
+ if (errp != nullptr) {
+ *errp = true;
+ return State::Sm;
+ }
+
log_abort();
}
- static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2)
+ static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)
{
if (cell->type == "$slice") {
RTLIL::Const ret;
@@ -415,10 +435,10 @@ struct CellTypes
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;
- return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len);
+ 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)
+ 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_")) {
RTLIL::Const ret = arg1;
@@ -436,10 +456,10 @@ struct CellTypes
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1));
log_assert(arg3.bits.size() == 0);
- return eval(cell, arg1, arg2);
+ return eval(cell, arg1, arg2, errp);
}
- static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4)
+ 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_")
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
@@ -447,7 +467,7 @@ struct CellTypes
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
log_assert(arg4.bits.size() == 0);
- return eval(cell, arg1, arg2, arg3);
+ return eval(cell, arg1, arg2, arg3, errp);
}
};
diff --git a/kernel/consteval.h b/kernel/consteval.h
index 0229f504..154373a8 100644
--- a/kernel/consteval.h
+++ b/kernel/consteval.h
@@ -321,8 +321,13 @@ struct ConstEval
if (sig_d.size() > 0 && !eval(sig_d, undef, cell))
return false;
- set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(),
- sig_c.as_const(), sig_d.as_const()));
+ bool eval_err = false;
+ RTLIL::Const eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err);
+
+ if (eval_err)
+ return false;
+
+ set(sig_y, eval_ret);
}
return true;
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 17864110..a0bb7e60 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -179,6 +179,7 @@ int main(int argc, char **argv)
{
std::string frontend_command = "auto";
std::string backend_command = "auto";
+ std::vector<std::string> vlog_defines;
std::vector<std::string> passes_commands;
std::vector<std::string> plugin_filenames;
std::string output_filename = "";
@@ -268,7 +269,10 @@ int main(int argc, char **argv)
printf(" -A\n");
printf(" will call abort() at the end of the script. for debugging\n");
printf("\n");
- printf(" -D <header_id>[:<filename>]\n");
+ printf(" -D <macro>[=<value>]\n");
+ printf(" set the specified Verilog define (via \"read -define\")\n");
+ printf("\n");
+ printf(" -P <header_id>[:<filename>]\n");
printf(" dump the design when printing the specified log header to a file.\n");
printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n");
printf(" Use 'ALL' as <header_id> to dump at every header.\n");
@@ -307,7 +311,7 @@ int main(int argc, char **argv)
}
int opt;
- while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:E:")) != -1)
+ while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1)
{
switch (opt)
{
@@ -408,6 +412,9 @@ int main(int argc, char **argv)
std::regex_constants::egrep));
break;
case 'D':
+ vlog_defines.push_back(optarg);
+ break;
+ case 'P':
{
auto args = split_tokens(optarg, ":");
if (!args.empty() && args[0] == "ALL") {
@@ -473,6 +480,13 @@ int main(int argc, char **argv)
shell(yosys_design);
}
+ if (!vlog_defines.empty()) {
+ std::string vdef_cmd = "read -define";
+ for (auto vdef : vlog_defines)
+ vdef_cmd += " " + vdef;
+ run_pass(vdef_cmd);
+ }
+
while (optind < argc)
run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
index df534ec1..e7cb312e 100644
--- a/kernel/hashlib.h
+++ b/kernel/hashlib.h
@@ -557,9 +557,11 @@ public:
void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); }
+ iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
+ const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
const_iterator end() const { return const_iterator(nullptr, -1); }
};
@@ -881,9 +883,11 @@ public:
void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); }
+ iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
+ const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
const_iterator end() const { return const_iterator(nullptr, -1); }
};
@@ -952,6 +956,7 @@ public:
void clear() { database.clear(); }
const_iterator begin() const { return database.begin(); }
+ const_iterator element(int n) const { return database.element(n); }
const_iterator end() const { return database.end(); }
};
@@ -1051,6 +1056,7 @@ public:
void clear() { database.clear(); parents.clear(); }
const_iterator begin() const { return database.begin(); }
+ const_iterator element(int n) const { return database.element(n); }
const_iterator end() const { return database.end(); }
};
diff --git a/kernel/log.cc b/kernel/log.cc
index 0ee2170a..400a549d 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -196,7 +196,11 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap)
if (log_hdump.count(header_id) && design != nullptr)
for (auto &filename : log_hdump.at(header_id)) {
log("Dumping current design to '%s'.\n", filename.c_str());
+ if (yosys_xtrace)
+ IdString::xtrace_db_dump();
Pass::call(design, {"dump", "-o", filename});
+ if (yosys_xtrace)
+ log("#X# -- end of dump --\n");
}
if (pop_errfile)
diff --git a/kernel/log.h b/kernel/log.h
index 0b4905c3..75993902 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -94,7 +94,9 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
const char *log_const(const RTLIL::Const &value, bool autoint = true);
const char *log_id(RTLIL::IdString id);
-template<typename T> static inline const char *log_id(T *obj) {
+template<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {
+ if (nullstr && obj == nullptr)
+ return nullstr;
return log_id(obj->name);
}
@@ -195,7 +197,7 @@ struct PerformanceTimer
t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;
return t;
# else
-# error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).
+# error "Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?)."
# endif
}
diff --git a/kernel/register.cc b/kernel/register.cc
index 402a5b3e..64956401 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -86,6 +86,8 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
void Pass::post_execute(Pass::pre_post_exec_state_t state)
{
+ IdString::checkpoint();
+
int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
runtime_ns += time_ns;
current_pass = state.parent_pass;
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index a4fa2cf0..b3214579 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -33,6 +33,8 @@ 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_;
std::vector<int> RTLIL::IdString::global_free_idx_list_;
+int RTLIL::IdString::last_created_idx_[8];
+int RTLIL::IdString::last_created_idx_ptr_;
RTLIL::Const::Const()
{
@@ -639,6 +641,11 @@ RTLIL::Module::~Module()
delete it->second;
}
+void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>)
+{
+ log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name));
+}
+
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, bool mayfail)
{
if (mayfail)
@@ -646,6 +653,14 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLI
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
}
+
+RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, dict<RTLIL::IdString, RTLIL::Module*>, dict<RTLIL::IdString, RTLIL::IdString>, bool mayfail)
+{
+ if (mayfail)
+ return RTLIL::IdString();
+ log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
+}
+
size_t RTLIL::Module::count_id(RTLIL::IdString id)
{
return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id);
@@ -745,7 +760,7 @@ namespace {
void check()
{
- if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" ||
+ 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:")
return;
@@ -2345,7 +2360,7 @@ 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" ||
+ 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:")
return;
@@ -2397,6 +2412,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
if (connections_.count("\\Y"))
parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]);
+ if (connections_.count("\\Q"))
+ parameters["\\WIDTH"] = GetSize(connections_["\\Q"]);
+
check();
}
@@ -3219,7 +3237,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed)
remove(width, width_ - width);
if (width_ < width) {
- RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0;
+ RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx;
if (!is_signed)
padding = RTLIL::State::S0;
while (width_ < width)
@@ -3780,6 +3798,11 @@ RTLIL::CaseRule::~CaseRule()
delete *it;
}
+bool RTLIL::CaseRule::empty() const
+{
+ return actions.empty() && switches.empty();
+}
+
RTLIL::CaseRule *RTLIL::CaseRule::clone() const
{
RTLIL::CaseRule *new_caserule = new RTLIL::CaseRule;
@@ -3796,6 +3819,11 @@ RTLIL::SwitchRule::~SwitchRule()
delete *it;
}
+bool RTLIL::SwitchRule::empty() const
+{
+ return cases.empty();
+}
+
RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const
{
RTLIL::SwitchRule *new_switchrule = new RTLIL::SwitchRule;
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 027faf41..52496e70 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -76,6 +76,9 @@ namespace RTLIL
struct IdString
{
+ #undef YOSYS_XTRACE_GET_PUT
+ #undef YOSYS_SORT_ID_FREE_LIST
+
// the global id string cache
static struct destruct_guard_t {
@@ -89,9 +92,43 @@ namespace RTLIL
static dict<char*, int, hash_cstr_ops> global_id_index_;
static std::vector<int> global_free_idx_list_;
+ static int last_created_idx_ptr_;
+ static int last_created_idx_[8];
+
+ static inline void xtrace_db_dump()
+ {
+ #ifdef YOSYS_XTRACE_GET_PUT
+ for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
+ {
+ if (global_id_storage_.at(idx) == nullptr)
+ log("#X# DB-DUMP index %d: FREE\n", idx);
+ else
+ log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
+ }
+ #endif
+ }
+
+ static inline void checkpoint()
+ {
+ 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;
+ }
+ #ifdef YOSYS_SORT_ID_FREE_LIST
+ std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
+ #endif
+ }
+
static inline int get_reference(int idx)
{
global_refcount_storage_.at(idx)++;
+ #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));
+ }
+ #endif
return idx;
}
@@ -107,6 +144,11 @@ namespace RTLIL
auto it = global_id_index_.find((char*)p);
if (it != global_id_index_.end()) {
global_refcount_storage_.at(it->second)++;
+ #ifdef YOSYS_XTRACE_GET_PUT
+ 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;
}
@@ -124,16 +166,22 @@ namespace RTLIL
global_refcount_storage_.at(idx)++;
// Avoid Create->Delete->Create pattern
- static IdString last_created_id;
- put_reference(last_created_id.index_);
- last_created_id.index_ = idx;
- get_reference(last_created_id.index_);
+ 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;
if (yosys_xtrace) {
log("#X# New IdString '%s' with index %d.\n", p, idx);
log_backtrace("-X- ", yosys_xtrace-1);
}
+ #ifdef YOSYS_XTRACE_GET_PUT
+ 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
return idx;
}
@@ -144,6 +192,12 @@ namespace RTLIL
if (!destruct_guard.ok)
return;
+ #ifdef YOSYS_XTRACE_GET_PUT
+ if (yosys_xtrace) {
+ log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
+ }
+ #endif
+
log_assert(global_refcount_storage_.at(idx) > 0);
if (--global_refcount_storage_.at(idx) != 0)
@@ -492,6 +546,14 @@ struct RTLIL::Const
return ret;
}
+ void extu(int width) {
+ bits.resize(width, RTLIL::State::S0);
+ }
+
+ void exts(int width) {
+ bits.resize(width, bits.empty() ? RTLIL::State::Sx : bits.back());
+ }
+
inline unsigned int hash() const {
unsigned int h = mkhash_init;
for (auto b : bits)
@@ -907,7 +969,9 @@ public:
Module();
virtual ~Module();
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail = false);
+ virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail = false);
virtual size_t count_id(RTLIL::IdString id);
+ virtual void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces);
virtual void sort();
virtual void check();
@@ -1225,6 +1289,8 @@ struct RTLIL::CaseRule
~CaseRule();
void optimize();
+ bool empty() const;
+
template<typename T> void rewrite_sigspecs(T &functor);
RTLIL::CaseRule *clone() const;
};
@@ -1236,6 +1302,8 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
~SwitchRule();
+ bool empty() const;
+
template<typename T> void rewrite_sigspecs(T &functor);
RTLIL::SwitchRule *clone() const;
};
@@ -1276,7 +1344,7 @@ inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
return wire ? (offset < other.offset) : (data < other.data);
if (wire != nullptr && other.wire != nullptr)
return wire->name < other.wire->name;
- return wire < other.wire;
+ return (wire != nullptr) < (other.wire != nullptr);
}
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index ad032899..450e4e4c 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -33,7 +33,7 @@
# include <dlfcn.h>
#endif
-#ifdef _WIN32
+#if defined(_WIN32)
# include <windows.h>
# include <io.h>
#elif defined(__APPLE__)
@@ -41,13 +41,15 @@
# include <unistd.h>
# include <dirent.h>
# include <sys/stat.h>
-# include <glob.h>
#else
# include <unistd.h>
# include <dirent.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
+#endif
+
+#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB)
# include <glob.h>
#endif
@@ -166,7 +168,7 @@ std::string vstringf(const char *fmt, va_list ap)
std::string string;
char *str = NULL;
-#if defined(_WIN32 )|| defined(__CYGWIN__)
+#if defined(_WIN32 )|| defined(__CYGWIN__)
int sz = 64, rc;
while (1) {
va_list apc;
@@ -216,12 +218,18 @@ std::string next_token(std::string &text, const char *sep, bool long_strings)
if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
string sep_string = sep;
- for (size_t i = pos_begin+1; i < text.size(); i++)
+ for (size_t i = pos_begin+1; i < text.size(); i++) {
if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
std::string token = text.substr(pos_begin, i-pos_begin+1);
text = text.substr(i+1);
return token;
}
+ if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) {
+ std::string token = text.substr(pos_begin, i-pos_begin+1);
+ text = text.substr(i+2);
+ return token + ";";
+ }
+ }
}
size_t pos_end = text.find_first_of(sep, pos_begin);
@@ -564,7 +572,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern)
{
std::vector<std::string> results;
-#ifdef _WIN32
+#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB)
results.push_back(filename_pattern);
#else
glob_t globbuf;
@@ -637,8 +645,9 @@ extern Tcl_Interp *yosys_get_tcl_interp()
struct TclPass : public Pass {
TclPass() : Pass("tcl", "execute a TCL script file") { }
void help() YS_OVERRIDE {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" tcl <filename>\n");
+ log(" tcl <filename> [args]\n");
log("\n");
log("This command executes the tcl commands in the specified file.\n");
log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
@@ -648,14 +657,24 @@ struct TclPass : public Pass {
log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n");
log("in order to avoid a name collision with the built in commands.\n");
log("\n");
+ log("If any arguments are specified, these arguments are provided to the script via\n");
+ log("the standard $argc and $argv variables.\n");
+ log("\n");
}
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
+ void execute(std::vector<std::string> args, RTLIL::Design *) YS_OVERRIDE {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
- if (args.size() > 2)
- extra_args(args, 1, design, false);
- if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK)
- log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp()));
+
+ std::vector<Tcl_Obj*> script_args;
+ for (auto it = args.begin() + 2; it != args.end(); ++it)
+ script_args.push_back(Tcl_NewStringObj((*it).c_str(), (*it).size()));
+
+ Tcl_Interp *interp = yosys_get_tcl_interp();
+ Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(script_args.size()), 0);
+ Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(script_args.size(), script_args.data()), 0);
+ Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(args[1].c_str(), args[1].size()), 0);
+ if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK)
+ log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(interp));
}
} TclPass;
#endif
@@ -733,7 +752,7 @@ std::string proc_self_dirname()
return "/";
}
#else
- #error Dont know how to determine process executable base path!
+ #error "Don't know how to determine process executable base path!"
#endif
#ifdef EMSCRIPTEN
@@ -799,7 +818,7 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
label += command[pos++];
- if (label.back() == ':' && GetSize(label) > 1)
+ if (GetSize(label) > 1 && label.back() == ':')
{
label = label.substr(0, GetSize(label)-1);
command = command.substr(pos);
@@ -821,7 +840,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen
command = "verilog";
else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
command = "verilog -sv";
- else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".vhd")
+ else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".vhd")
command = "vhdl";
else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif")
command = "blif";
@@ -833,7 +852,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen
command = "ilang";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
command = "script";
- else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".tcl")
+ else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".tcl")
command = "tcl";
else if (filename == "-")
command = "script";
diff --git a/libs/ezsat/ezminisat.h b/libs/ezsat/ezminisat.h
index 983e6fd0..3a34c13c 100644
--- a/libs/ezsat/ezminisat.h
+++ b/libs/ezsat/ezminisat.h
@@ -28,7 +28,7 @@
#include <time.h>
// minisat is using limit macros and format macros in their headers that
-// can be the source of some troubles when used from c++11. thefore we
+// can be the source of some troubles when used from c++11. therefore we
// don't force ezSAT users to use minisat headers..
namespace Minisat {
class Solver;
diff --git a/libs/subcircuit/README b/libs/subcircuit/README
index b1335681..ecaa987d 100644
--- a/libs/subcircuit/README
+++ b/libs/subcircuit/README
@@ -109,7 +109,7 @@ look at the demo.cc example program in this directory.
Setting up graphs
-----------------
-Instanciate the SubCircuit::Graph class and use the methods of this class to
+Instantiate the SubCircuit::Graph class and use the methods of this class to
set up the circuit.
SubCircuit::Graph myGraph;
@@ -152,7 +152,7 @@ rotate shift,
The method createConstant() can be used to add a constant driver to a signal.
The signal value is encoded as one char by bit, allowing for multi-valued
-logic matching. The follwoing command sets the lowest bit of cell6.A to a
+logic matching. The following command sets the lowest bit of cell6.A to a
logic 1:
myGraph.createConnection("cell6", "A", 0, '1');
@@ -314,7 +314,7 @@ bool userCompareEdge(needleGraphId, needleFromNodeId, needleFromUserData, needle
Perform additional checks on a pair of a pair of adjacent nodes (one
adjacent pair from the needle and one adjacent pair from the haystack)
- to determine wheter this edge from the needle is compatible with
+ to determine whether this edge from the needle is compatible with
that edge from the haystack. The default implementation always
returns true.
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index 277e8932..e6491918 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -119,6 +119,12 @@ than one bit from \B{S} is set the output is undefined. Cells of this type are u
``parallel cases'' (defined by using the {\tt parallel\_case} attribute or detected by
an optimization).
+The {\tt \$tribuf} cell is used to implement tristate logic. Cells of this type have a \B{WIDTH}
+parameter and inputs \B{A} and \B{EN} and an output \B{Y}. The \B{A} input and \B{Y} output are
+\B{WIDTH} bits wide, and the \B{EN} input is one bit wide. When \B{EN} is 0, the output \B{Y}
+is not driven. When \B{EN} is 1, the value from \B{A} input is sent to the \B{Y} output. Therefore,
+the {\tt \$tribuf} cell implements the function \lstinline[language=Verilog]; Y = EN ? A : 'bz;.
+
Behavioural code with cascaded {\tt if-then-else}- and {\tt case}-statements
usually results in trees of multiplexer cells. Many passes (from various
optimizations to FSM extraction) heavily depend on these multiplexer trees to
@@ -211,14 +217,15 @@ Add information about {\tt \$sr} cells (set-reset flip-flops) and d-type latches
\subsection{Memories}
\label{sec:memcells}
-Memories are either represented using RTLIL::Memory objects and {\tt \$memrd} and {\tt \$memwr} cells
-or simply by using {\tt \$mem} cells.
+Memories are either represented using RTLIL::Memory objects, {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit}
+cells, or by {\tt \$mem} cells alone.
In the first alternative the RTLIL::Memory objects hold the general metadata for the memory (bit width,
size in number of words, etc.) and for each port a {\tt \$memrd} (read port) or {\tt \$memwr} (write port)
cell is created. Having individual cells for read and write ports has the advantage that they can be
consolidated using resource sharing passes. In some cases this drastically reduces the number of required
-ports on the memory cell.
+ports on the memory cell. In this alternative, memory initialization data is represented by {\tt \$meminit} cells,
+which allow delaying constant folding for initialization addresses and data until after the frontend finishes.
The {\tt \$memrd} cells have a clock input \B{CLK}, an enable input \B{EN}, an
address input \B{ADDR}, and a data output \B{DATA}. They also have the
@@ -253,7 +260,7 @@ enable bit for each data bit), an address input \B{ADDR} and a data input
\begin{itemize}
\item \B{MEMID} \\
-The name of the RTLIL::Memory object that is associated with this read port.
+The name of the RTLIL::Memory object that is associated with this write port.
\item \B{ABITS} \\
The number of address bits (width of the \B{ADDR} input port).
@@ -262,7 +269,7 @@ The number of address bits (width of the \B{ADDR} input port).
The number of data bits (width of the \B{DATA} output port).
\item \B{CLK\_ENABLE} \\
-When this parameter is non-zero, the clock is used. Otherwise this read port is asynchronous and
+When this parameter is non-zero, the clock is used. Otherwise this write port is asynchronous and
the \B{CLK} input is not used.
\item \B{CLK\_POLARITY} \\
@@ -273,6 +280,27 @@ edge if this parameter is {\tt 1'b0}.
The cell with the higher integer value in this parameter wins a write conflict.
\end{itemize}
+The {\tt \$meminit} cells have an address input \B{ADDR} and a data input \B{DATA}, with the width
+of the \B{DATA} port equal to \B{WIDTH} parameter times \B{WORDS} parameter. Both of the inputs
+must resolve to a constant for synthesis to succeed.
+
+\begin{itemize}
+\item \B{MEMID} \\
+The name of the RTLIL::Memory object that is associated with this initialization cell.
+
+\item \B{ABITS} \\
+The number of address bits (width of the \B{ADDR} input port).
+
+\item \B{WIDTH} \\
+The number of data bits per memory location.
+
+\item \B{WORDS} \\
+The number of consecutive memory locations initialized by this cell.
+
+\item \B{PRIORITY} \\
+The cell with the higher integer value in this parameter wins an initialization conflict.
+\end{itemize}
+
The HDL frontend models a memory using RTLIL::Memory objects and asynchronous
{\tt \$memrd} and {\tt \$memwr} cells. The {\tt memory} pass (i.e.~its various sub-passes) migrates
{\tt \$dff} cells into the {\tt \$memrd} and {\tt \$memwr} cells making them synchronous, then
@@ -295,6 +323,9 @@ The number of address bits.
\item \B{WIDTH} \\
The number of data bits per word.
+\item \B{INIT} \\
+The initial memory contents.
+
\item \B{RD\_PORTS} \\
The number of read ports on this memory cell.
@@ -345,9 +376,11 @@ This input is \B{WR\_PORTS}*\B{ABITS} bits wide, containing all address signals
This input is \B{WR\_PORTS}*\B{WIDTH} bits wide, containing all data signals for the write ports.
\end{itemize}
-The {\tt techmap} pass can be used to manually map {\tt \$mem} cells to
-specialized memory cells on the target architecture, such as block ram resources
-on an FPGA.
+The {\tt memory\_collect} pass can be used to convert discrete {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit} cells
+belonging to the same memory to a single {\tt \$mem} cell, whereas the {\tt memory\_unpack} pass performs the inverse operation.
+The {\tt memory\_dff} pass can combine asynchronous memory ports that are fed by or feeding registers into synchronous memory ports.
+The {\tt memory\_bram} pass can be used to recognize {\tt \$mem} cells that can be implemented with a block RAM resource on an FPGA.
+The {\tt memory\_map} pass can be used to implement {\tt \$mem} cells as basic logic: word-wide DFFs and address decoders.
\subsection{Finite State Machines}
@@ -371,9 +404,15 @@ Verilog & Cell Type \\
\hline
\lstinline[language=Verilog]; Y = ~A; & {\tt \$\_NOT\_} \\
\lstinline[language=Verilog]; Y = A & B; & {\tt \$\_AND\_} \\
+\lstinline[language=Verilog]; Y = ~(A & B); & {\tt \$\_NAND\_} \\
+\lstinline[language=Verilog]; Y = A & ~B; & {\tt \$\_ANDNOT\_} \\
\lstinline[language=Verilog]; Y = A | B; & {\tt \$\_OR\_} \\
+\lstinline[language=Verilog]; Y = ~(A | B); & {\tt \$\_NOR\_} \\
+\lstinline[language=Verilog]; Y = A | ~B; & {\tt \$\_ORNOT\_} \\
\lstinline[language=Verilog]; Y = A ^ B; & {\tt \$\_XOR\_} \\
+\lstinline[language=Verilog]; Y = ~(A ^ B); & {\tt \$\_XNOR\_} \\
\lstinline[language=Verilog]; Y = S ? B : A; & {\tt \$\_MUX\_} \\
+\lstinline[language=Verilog]; Y = EN ? A : 'bz; & {\tt \$\_TBUF\_} \\
\hline
\lstinline[language=Verilog]; always @(negedge C) Q <= D; & {\tt \$\_DFF\_N\_} \\
\lstinline[language=Verilog]; always @(posedge C) Q <= D; & {\tt \$\_DFF\_P\_} \\
@@ -396,9 +435,10 @@ $ClkEdge$ & $RstLvl$ & $RstVal$ & Cell Type \\
\end{table}
Table~\ref{tab:CellLib_gates} lists all cell types used for gate level logic. The cell types
-{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_OR\_}, {\tt \$\_XOR\_} and {\tt \$\_MUX\_}
-are used to model combinatorial logic. The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_}
-represent d-type flip-flops.
+{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_},
+{\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_} and {\tt \$\_MUX\_} are used to model combinatorial logic.
+The cell type {\tt \$\_TBUF\_} is used to model tristate logic.
+The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops.
The cell types {\tt \$\_DFF\_NN0\_}, {\tt \$\_DFF\_NN1\_}, {\tt \$\_DFF\_NP0\_}, {\tt \$\_DFF\_NP1\_},
{\tt \$\_DFF\_PN0\_}, {\tt \$\_DFF\_PN1\_}, {\tt \$\_DFF\_PP0\_} and {\tt \$\_DFF\_PP1\_} implement
@@ -410,7 +450,7 @@ otherwise.
\begin{lstlisting}[mathescape,language=Verilog]
always @($ClkEdge$ C, $RstEdge$ R)
if (R == $RstLvl$)
- Q <= $RstVa$l;
+ Q <= $RstVal$;
else
Q <= D;
\end{lstlisting}
@@ -450,7 +490,6 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA
\end{fixme}
\begin{fixme}
-Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_ORNOT\_},
-{\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
+Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
\end{fixme}
diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex
index 964875d5..2feb0f1c 100644
--- a/manual/CHAPTER_Overview.tex
+++ b/manual/CHAPTER_Overview.tex
@@ -428,8 +428,8 @@ memory object has the following properties:
All read accesses to the memory are transformed to {\tt \$memrd} cells and all write accesses to
{\tt \$memwr} cells by the language frontend. These cells consist of independent read- and write-ports
-to the memory. The \B{MEMID} parameter on these cells is used to link them together and to the
-RTLIL::Memory object they belong to.
+to the memory. Memory initialization is transformed to {\tt \$meminit} cells by the language frontend.
+The \B{MEMID} parameter on these cells is used to link them together and to the RTLIL::Memory object they belong to.
The rationale behind using separate cells for the individual ports versus
creating a large multiport memory cell right in the language frontend is that
diff --git a/misc/launcher.c b/misc/launcher.c
new file mode 100644
index 00000000..157d68cf
--- /dev/null
+++ b/misc/launcher.c
@@ -0,0 +1,358 @@
+/* This file comes from the PyPA Setuptools repository, commit 16e452a:
+https://github.com/pypa/setuptools
+Modifications include this comment and inline inclusion of the LICENSE text. */
+
+/* Copyright (C) 2016 Jason R Coombs <jaraco@jaraco.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. */
+
+/* Setuptools Script Launcher for Windows
+
+ This is a stub executable for Windows that functions somewhat like
+ Effbot's "exemaker", in that it runs a script with the same name but
+ a .py extension, using information from a #! line. It differs in that
+ it spawns the actual Python executable, rather than attempting to
+ hook into the Python DLL. This means that the script will run with
+ sys.executable set to the Python executable, where exemaker ends up with
+ sys.executable pointing to itself. (Which means it won't work if you try
+ to run another Python process using sys.executable.)
+
+ To build/rebuild with mingw32, do this in the setuptools project directory:
+
+ gcc -DGUI=0 -mno-cygwin -O -s -o setuptools/cli.exe launcher.c
+ gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c
+
+ To build for Windows RT, install both Visual Studio Express for Windows 8
+ and for Windows Desktop (both freeware), create "win32" application using
+ "Windows Desktop" version, create new "ARM" target via
+ "Configuration Manager" menu and modify ".vcxproj" file by adding
+ "<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>" tag
+ as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM"
+ properties.
+
+ It links to msvcrt.dll, but this shouldn't be a problem since it doesn't
+ actually run Python in the same process. Note that using 'exec' instead
+ of 'spawn' doesn't work, because on Windows this leads to the Python
+ executable running in the *background*, attached to the same console
+ window, meaning you get a command prompt back *before* Python even finishes
+ starting. So, we have to use spawnv() and wait for Python to exit before
+ continuing. :(
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+#include <tchar.h>
+#include <fcntl.h>
+
+int child_pid=0;
+
+int fail(char *format, char *data) {
+ /* Print error message to stderr and return 2 */
+ fprintf(stderr, format, data);
+ return 2;
+}
+
+char *quoted(char *data) {
+ int i, ln = strlen(data), nb;
+
+ /* We allocate twice as much space as needed to deal with worse-case
+ of having to escape everything. */
+ char *result = calloc(ln*2+3, sizeof(char));
+ char *presult = result;
+
+ *presult++ = '"';
+ for (nb=0, i=0; i < ln; i++)
+ {
+ if (data[i] == '\\')
+ nb += 1;
+ else if (data[i] == '"')
+ {
+ for (; nb > 0; nb--)
+ *presult++ = '\\';
+ *presult++ = '\\';
+ }
+ else
+ nb = 0;
+ *presult++ = data[i];
+ }
+
+ for (; nb > 0; nb--) /* Deal w trailing slashes */
+ *presult++ = '\\';
+
+ *presult++ = '"';
+ *presult++ = 0;
+ return result;
+}
+
+
+
+
+
+
+
+
+
+
+char *loadable_exe(char *exename) {
+ /* HINSTANCE hPython; DLL handle for python executable */
+ char *result;
+
+ /* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hPython) return NULL; */
+
+ /* Return the absolute filename for spawnv */
+ result = calloc(MAX_PATH, sizeof(char));
+ strncpy(result, exename, MAX_PATH);
+ /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
+
+ FreeLibrary(hPython); */
+ return result;
+}
+
+
+char *find_exe(char *exename, char *script) {
+ char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
+ char path[_MAX_PATH], c, *result;
+
+ /* convert slashes to backslashes for uniform search below */
+ result = exename;
+ while (c = *result++) if (c=='/') result[-1] = '\\';
+
+ _splitpath(exename, drive, dir, fname, ext);
+ if (drive[0] || dir[0]=='\\') {
+ return loadable_exe(exename); /* absolute path, use directly */
+ }
+ /* Use the script's parent directory, which should be the Python home
+ (This should only be used for bdist_wininst-installed scripts, because
+ easy_install-ed scripts use the absolute path to python[w].exe
+ */
+ _splitpath(script, drive, dir, fname, ext);
+ result = dir + strlen(dir) -1;
+ if (*result == '\\') result--;
+ while (*result != '\\' && result>=dir) *result-- = 0;
+ _makepath(path, drive, dir, exename, NULL);
+ return loadable_exe(path);
+}
+
+
+char **parse_argv(char *cmdline, int *argc)
+{
+ /* Parse a command line in-place using MS C rules */
+
+ char **result = calloc(strlen(cmdline), sizeof(char *));
+ char *output = cmdline;
+ char c;
+ int nb = 0;
+ int iq = 0;
+ *argc = 0;
+
+ result[0] = output;
+ while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
+
+ do {
+ c = *cmdline++;
+ if (!c || (isspace(c) && !iq)) {
+ while (nb) {*output++ = '\\'; nb--; }
+ *output++ = 0;
+ result[++*argc] = output;
+ if (!c) return result;
+ while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
+ if (!*cmdline) return result; /* avoid empty arg if trailing ws */
+ continue;
+ }
+ if (c == '\\')
+ ++nb; /* count \'s */
+ else {
+ if (c == '"') {
+ if (!(nb & 1)) { iq = !iq; c = 0; } /* skip " unless odd # of \ */
+ nb = nb >> 1; /* cut \'s in half */
+ }
+ while (nb) {*output++ = '\\'; nb--; }
+ if (c) *output++ = c;
+ }
+ } while (1);
+}
+
+void pass_control_to_child(DWORD control_type) {
+ /*
+ * distribute-issue207
+ * passes the control event to child process (Python)
+ */
+ if (!child_pid) {
+ return;
+ }
+ GenerateConsoleCtrlEvent(child_pid,0);
+}
+
+BOOL control_handler(DWORD control_type) {
+ /*
+ * distribute-issue207
+ * control event handler callback function
+ */
+ switch (control_type) {
+ case CTRL_C_EVENT:
+ pass_control_to_child(0);
+ break;
+ }
+ return TRUE;
+}
+
+int create_and_wait_for_subprocess(char* command) {
+ /*
+ * distribute-issue207
+ * launches child process (Python)
+ */
+ DWORD return_value = 0;
+ LPSTR commandline = command;
+ STARTUPINFOA s_info;
+ PROCESS_INFORMATION p_info;
+ ZeroMemory(&p_info, sizeof(p_info));
+ ZeroMemory(&s_info, sizeof(s_info));
+ s_info.cb = sizeof(STARTUPINFO);
+ // set-up control handler callback funciotn
+ SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
+ if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
+ fprintf(stderr, "failed to create process.\n");
+ return 0;
+ }
+ child_pid = p_info.dwProcessId;
+ // wait for Python to exit
+ WaitForSingleObject(p_info.hProcess, INFINITE);
+ if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
+ fprintf(stderr, "failed to get exit code from process.\n");
+ return 0;
+ }
+ return return_value;
+}
+
+char* join_executable_and_args(char *executable, char **args, int argc)
+{
+ /*
+ * distribute-issue207
+ * CreateProcess needs a long string of the executable and command-line arguments,
+ * so we need to convert it from the args that was built
+ */
+ int len,counter;
+ char* cmdline;
+
+ len=strlen(executable)+2;
+ for (counter=1; counter<argc; counter++) {
+ len+=strlen(args[counter])+1;
+ }
+
+ cmdline = (char*)calloc(len, sizeof(char));
+ sprintf(cmdline, "%s", executable);
+ len=strlen(executable);
+ for (counter=1; counter<argc; counter++) {
+ sprintf(cmdline+len, " %s", args[counter]);
+ len+=strlen(args[counter])+1;
+ }
+ return cmdline;
+}
+
+int run(int argc, char **argv, int is_gui) {
+
+ char python[256]; /* python executable's filename*/
+ char *pyopt; /* Python option */
+ char script[256]; /* the script's filename */
+
+ int scriptf; /* file descriptor for script file */
+
+ char **newargs, **newargsp, **parsedargs; /* argument array for exec */
+ char *ptr, *end; /* working pointers for string manipulation */
+ char *cmdline;
+ int i, parsedargc; /* loop counter */
+
+ /* compute script name from our .exe name*/
+ GetModuleFileNameA(NULL, script, sizeof(script));
+ end = script + strlen(script);
+ while( end>script && *end != '.')
+ *end-- = '\0';
+ *end-- = '\0';
+ strcat(script, (GUI ? "-script.pyw" : "-script.py"));
+
+ /* figure out the target python executable */
+
+ scriptf = open(script, O_RDONLY);
+ if (scriptf == -1) {
+ return fail("Cannot open %s\n", script);
+ }
+ end = python + read(scriptf, python, sizeof(python));
+ close(scriptf);
+
+ ptr = python-1;
+ while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;}
+
+ *ptr-- = '\0';
+
+ if (strncmp(python, "#!", 2)) {
+ /* default to python.exe if no #! header */
+ strcpy(python, "#!python.exe");
+ }
+
+ parsedargs = parse_argv(python+2, &parsedargc);
+
+ /* Using spawnv() can fail strangely if you e.g. find the Cygwin
+ Python, so we'll make sure Windows can find and load it */
+
+ ptr = find_exe(parsedargs[0], script);
+ if (!ptr) {
+ return fail("Cannot find Python executable %s\n", parsedargs[0]);
+ }
+
+ /* printf("Python executable: %s\n", ptr); */
+
+ /* Argument array needs to be
+ parsedargc + argc, plus 1 for null sentinel */
+
+ newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *));
+ newargsp = newargs;
+
+ *newargsp++ = quoted(ptr);
+ for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]);
+
+ *newargsp++ = quoted(script);
+ for (i = 1; i < argc; i++) *newargsp++ = quoted(argv[i]);
+
+ *newargsp++ = NULL;
+
+ /* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
+
+ if (is_gui) {
+ /* Use exec, we don't need to wait for the GUI to finish */
+ execv(ptr, (const char * const *)(newargs));
+ return fail("Could not exec %s", ptr); /* shouldn't get here! */
+ }
+
+ /*
+ * distribute-issue207: using CreateProcessA instead of spawnv
+ */
+ cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
+ return create_and_wait_for_subprocess(cmdline);
+}
+
+int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
+ return run(__argc, __argv, GUI);
+}
+
+int main(int argc, char** argv) {
+ return run(argc, argv, GUI);
+}
diff --git a/misc/yosys.proto b/misc/yosys.proto
index 2870176c..a583e626 100644
--- a/misc/yosys.proto
+++ b/misc/yosys.proto
@@ -1,12 +1,12 @@
//
// yosys -- Yosys Open SYnthesis Suite
-//
+//
// Copyright (C) 2018 Serge Bazanski <q3k@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
@@ -73,7 +73,7 @@ message Module {
BitVector bits = 2;
}
map<string, Port> port = 2;
-
+
// Named cells in this module.
message Cell {
// Set to true when the name of this cell is automatically created and
@@ -129,7 +129,7 @@ message Model {
TYPE_FALSE = 6;
};
Type type = 1;
-
+
message Port {
// Name of port.
string portname = 1;
@@ -148,7 +148,7 @@ message Model {
// Set for AND, NAND.
Gate gate = 3;
}
-
+
// Set when the node drives given output port(s).
message OutPort {
// Name of port.
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index 44a83b2b..c8067a8b 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -29,4 +29,4 @@ OBJS += passes/cmds/chformal.o
OBJS += passes/cmds/chtype.o
OBJS += passes/cmds/blackbox.o
OBJS += passes/cmds/ltp.o
-
+OBJS += passes/cmds/bugpoint.o
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
new file mode 100644
index 00000000..606276e6
--- /dev/null
+++ b/passes/cmds/bugpoint.cc
@@ -0,0 +1,369 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2018 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/yosys.h"
+#include "backends/ilang/ilang_backend.h"
+
+USING_YOSYS_NAMESPACE
+using namespace ILANG_BACKEND;
+PRIVATE_NAMESPACE_BEGIN
+
+struct BugpointPass : public Pass {
+ BugpointPass() : Pass("bugpoint", "minimize testcases") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" bugpoint [options]\n");
+ log("\n");
+ log("This command minimizes testcases that crash Yosys. It removes an arbitrary part\n");
+ log("of the design and recursively invokes Yosys with a given script, repeating these\n");
+ log("steps while it can find a smaller design that still causes a crash. Once this\n");
+ log("command finishes, it replaces the current design with the smallest testcase it\n");
+ log("was able to produce.\n");
+ log("\n");
+ log("It is possible to specify the kinds of design part that will be removed. If none\n");
+ log("are specified, all parts of design will be removed.\n");
+ log("\n");
+ log(" -yosys <filename>\n");
+ log(" use this Yosys binary. if not specified, `yosys` is used.\n");
+ log("\n");
+ log(" -script <filename>\n");
+ log(" use this script to crash Yosys. required.\n");
+ log("\n");
+ log(" -grep <string>\n");
+ 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("\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("\n");
+ log(" -modules\n");
+ log(" try to remove modules.\n");
+ log("\n");
+ log(" -ports\n");
+ log(" try to remove module ports.\n");
+ log("\n");
+ log(" -cells\n");
+ log(" try to remove cells.\n");
+ log("\n");
+ log(" -connections\n");
+ log(" try to reconnect ports to 'x.\n");
+ log("\n");
+ }
+
+ bool run_yosys(RTLIL::Design *design, string yosys_cmd, string script)
+ {
+ design->sort();
+
+ std::ofstream f("bugpoint-case.il");
+ ILANG_BACKEND::dump_design(f, design, /*only_selected=*/false, /*flag_m=*/true, /*flag_n=*/false);
+ f.close();
+
+ string yosys_cmdline = stringf("%s -qq -L bugpoint-case.log -s %s bugpoint-case.il", yosys_cmd.c_str(), script.c_str());
+ return run_command(yosys_cmdline) == 0;
+ }
+
+ bool check_logfile(string grep)
+ {
+ if (grep.empty())
+ return true;
+
+ std::ifstream f("bugpoint-case.log");
+ while (!f.eof())
+ {
+ string line;
+ getline(f, line);
+ if (line.find(grep) != std::string::npos)
+ return true;
+ }
+ return false;
+ }
+
+ RTLIL::Design *clean_design(RTLIL::Design *design, bool do_clean = true, bool do_delete = false)
+ {
+ if (!do_clean)
+ return design;
+
+ RTLIL::Design *design_copy = new RTLIL::Design;
+ for (auto &it : design->modules_)
+ design_copy->add(it.second->clone());
+ Pass::call(design_copy, "clean -purge");
+
+ if (do_delete)
+ delete design;
+ return design_copy;
+ }
+
+ RTLIL::Design *simplify_something(RTLIL::Design *design, int &seed, bool stage2, bool modules, bool ports, bool cells, bool connections)
+ {
+ RTLIL::Design *design_copy = new RTLIL::Design;
+ for (auto &it : design->modules_)
+ design_copy->add(it.second->clone());
+
+ int index = 0;
+ if (modules)
+ {
+ for (auto &it : design_copy->modules_)
+ {
+ if (it.second->get_bool_attribute("\\blackbox"))
+ continue;
+
+ if (index++ == seed)
+ {
+ log("Trying to remove module %s.\n", it.first.c_str());
+ design_copy->remove(it.second);
+ return design_copy;
+ }
+ }
+ }
+ if (ports)
+ {
+ for (auto mod : design_copy->modules())
+ {
+ if (mod->get_bool_attribute("\\blackbox"))
+ continue;
+
+ for (auto wire : mod->wires())
+ {
+ if (!stage2 && wire->get_bool_attribute("$bugpoint"))
+ continue;
+
+ if (wire->port_input || wire->port_output)
+ {
+ if (index++ == seed)
+ {
+ log("Trying to remove module port %s.\n", log_signal(wire));
+ wire->port_input = wire->port_output = false;
+ mod->fixup_ports();
+ return design_copy;
+ }
+ }
+ }
+ }
+ }
+ if (cells)
+ {
+ for (auto mod : design_copy->modules())
+ {
+ if (mod->get_bool_attribute("\\blackbox"))
+ continue;
+
+ for (auto &it : mod->cells_)
+ {
+ if (index++ == seed)
+ {
+ log("Trying to remove cell %s.%s.\n", mod->name.c_str(), it.first.c_str());
+ mod->remove(it.second);
+ return design_copy;
+ }
+ }
+ }
+ }
+ if (connections)
+ {
+ for (auto mod : design_copy->modules())
+ {
+ if (mod->get_bool_attribute("\\blackbox"))
+ continue;
+
+ for (auto cell : mod->cells())
+ {
+ for (auto it : cell->connections_)
+ {
+ RTLIL::SigSpec port = cell->getPort(it.first);
+ bool is_undef = port.is_fully_undef();
+ bool is_port = port.is_wire() && (port.as_wire()->port_input || port.as_wire()->port_output);
+
+ if(is_undef || (!stage2 && is_port))
+ continue;
+
+ if (index++ == seed)
+ {
+ log("Trying to remove cell port %s.%s.%s.\n", mod->name.c_str(), cell->name.c_str(), it.first.c_str());
+ RTLIL::SigSpec port_x(State::Sx, port.size());
+ cell->unsetPort(it.first);
+ cell->setPort(it.first, port_x);
+ return design_copy;
+ }
+
+ if (!stage2 && (cell->input(it.first) || cell->output(it.first)) && index++ == seed)
+ {
+ log("Trying to expose cell port %s.%s.%s as module port.\n", mod->name.c_str(), cell->name.c_str(), it.first.c_str());
+ RTLIL::Wire *wire = mod->addWire(NEW_ID, port.size());
+ wire->set_bool_attribute("$bugpoint");
+ wire->port_input = cell->input(it.first);
+ wire->port_output = cell->output(it.first);
+ cell->unsetPort(it.first);
+ cell->setPort(it.first, wire);
+ mod->fixup_ports();
+ return design_copy;
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string yosys_cmd = "yosys", script, grep;
+ bool fast = false, clean = false;
+ bool modules = false, ports = false, cells = false, connections = false, has_part = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-yosys" && argidx + 1 < args.size()) {
+ yosys_cmd = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-script" && argidx + 1 < args.size()) {
+ script = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-grep" && argidx + 1 < args.size()) {
+ grep = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-fast") {
+ fast = true;
+ continue;
+ }
+ if (args[argidx] == "-clean") {
+ clean = true;
+ continue;
+ }
+ if (args[argidx] == "-modules") {
+ modules = true;
+ has_part = true;
+ continue;
+ }
+ if (args[argidx] == "-ports") {
+ ports = true;
+ has_part = true;
+ continue;
+ }
+ if (args[argidx] == "-cells") {
+ cells = true;
+ has_part = true;
+ continue;
+ }
+ if (args[argidx] == "-connections") {
+ connections = true;
+ has_part = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!has_part)
+ {
+ modules = true;
+ ports = true;
+ cells = true;
+ connections = true;
+ }
+
+ if (!design->full_selection())
+ log_cmd_error("This command only operates on fully selected designs!\n");
+
+ RTLIL::Design *crashing_design = clean_design(design, clean);
+ if (run_yosys(crashing_design, yosys_cmd, script))
+ log_cmd_error("The provided script file and Yosys binary do not crash on this design!\n");
+ if (!check_logfile(grep))
+ log_cmd_error("The provided grep string is not found in the log file!\n");
+
+ int seed = 0, crashing_seed = seed;
+ bool found_something = false, stage2 = false;
+ while (true)
+ {
+ if (RTLIL::Design *simplified = simplify_something(crashing_design, seed, stage2, modules, ports, cells, connections))
+ {
+ simplified = clean_design(simplified, fast, /*do_delete=*/true);
+
+ bool crashes;
+ if (clean)
+ {
+ RTLIL::Design *testcase = clean_design(simplified);
+ crashes = !run_yosys(testcase, yosys_cmd, script);
+ delete testcase;
+ }
+ else
+ {
+ crashes = !run_yosys(simplified, yosys_cmd, script);
+ }
+
+ if (crashes && check_logfile(grep))
+ {
+ log("Testcase crashes.\n");
+ if (crashing_design != design)
+ delete crashing_design;
+ crashing_design = simplified;
+ crashing_seed = seed;
+ found_something = true;
+ }
+ else
+ {
+ log("Testcase does not crash.\n");
+ delete simplified;
+ seed++;
+ }
+ }
+ else
+ {
+ seed = 0;
+ if (found_something)
+ found_something = false;
+ else
+ {
+ if (!stage2)
+ {
+ log("Demoting introduced module ports.\n");
+ stage2 = true;
+ }
+ else
+ {
+ log("Simplifications exhausted.\n");
+ break;
+ }
+ }
+ }
+ }
+
+ if (crashing_design != design)
+ {
+ Pass::call(design, "design -reset");
+ crashing_design = clean_design(crashing_design, clean, /*do_delete=*/true);
+ for (auto &it : crashing_design->modules_)
+ design->add(it.second->clone());
+ delete crashing_design;
+ }
+ }
+} BugpointPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/chformal.cc b/passes/cmds/chformal.cc
index 522758ea..7e32da65 100644
--- a/passes/cmds/chformal.cc
+++ b/passes/cmds/chformal.cc
@@ -32,7 +32,7 @@ struct ChformalPass : public Pass {
log(" chformal [types] [mode] [options] [selection]\n");
log("\n");
log("Make changes to the formal constraints of the design. The [types] options\n");
- log("the type of constraint to operate on. If none of the folling options is given,\n");
+ log("the type of constraint to operate on. If none of the following options are given,\n");
log("the command will operate on all constraint types:\n");
log("\n");
log(" -assert $assert cells, representing assert(...) constraints\n");
@@ -59,7 +59,7 @@ struct ChformalPass : public Pass {
log(" -assume2assert\n");
log(" -live2fair\n");
log(" -fair2live\n");
- log(" change the roles of cells as indicated. this options can be combined\n");
+ log(" change the roles of cells as indicated. these options can be combined\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc
index d480b79a..f93bada2 100644
--- a/passes/cmds/connect.cc
+++ b/passes/cmds/connect.cc
@@ -137,7 +137,7 @@ struct ConnectPass : public Pass {
if (!set_lhs.empty())
{
if (!unset_expr.empty() || !port_cell.empty())
- log_cmd_error("Cant use -set together with -unset and/or -port.\n");
+ log_cmd_error("Can't use -set together with -unset and/or -port.\n");
RTLIL::SigSpec sig_lhs, sig_rhs;
if (!RTLIL::SigSpec::parse_sel(sig_lhs, design, module, set_lhs))
@@ -157,7 +157,7 @@ struct ConnectPass : public Pass {
if (!unset_expr.empty())
{
if (!port_cell.empty() || flag_nounset)
- log_cmd_error("Cant use -unset together with -port and/or -nounset.\n");
+ log_cmd_error("Can't use -unset together with -port and/or -nounset.\n");
RTLIL::SigSpec sig;
if (!RTLIL::SigSpec::parse_sel(sig, design, module, unset_expr))
@@ -170,7 +170,7 @@ struct ConnectPass : public Pass {
if (!port_cell.empty())
{
if (flag_nounset)
- log_cmd_error("Cant use -port together with -nounset.\n");
+ log_cmd_error("Can't use -port together with -nounset.\n");
if (module->cells_.count(RTLIL::escape_id(port_cell)) == 0)
log_cmd_error("Can't find cell %s.\n", port_cell.c_str());
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index dce576fd..9b1830b7 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -24,7 +24,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name)
+static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name, bool flag_output)
{
from_name = RTLIL::escape_id(from_name);
to_name = RTLIL::escape_id(to_name);
@@ -37,13 +37,18 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
Wire *w = it.second;
log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
module->rename(w, to_name);
- if (w->port_id)
+ if (w->port_id || flag_output) {
+ if (flag_output)
+ w->port_output = true;
module->fixup_ports();
+ }
return;
}
for (auto &it : module->cells_)
if (it.first == from_name) {
+ if (flag_output)
+ log_cmd_error("Called with -output but the specified object is a cell.\n");
log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
module->rename(it.second, to_name);
return;
@@ -52,6 +57,51 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
log_cmd_error("Object `%s' not found!\n", from_name.c_str());
}
+static std::string derive_name_from_src(const std::string &src, int counter)
+{
+ std::string src_base = src.substr(0, src.find('|'));
+ if (src_base.empty())
+ return stringf("$%d", counter);
+ else
+ return stringf("\\%s$%d", src_base.c_str(), counter);
+}
+
+static IdString derive_name_from_wire(const RTLIL::Cell &cell)
+{
+ // Find output
+ const SigSpec *output = nullptr;
+ int num_outputs = 0;
+ for (auto &connection : cell.connections()) {
+ if (cell.output(connection.first)) {
+ output = &connection.second;
+ num_outputs++;
+ }
+ }
+
+ if (num_outputs != 1) // Skip cells thad drive multiple outputs
+ return cell.name;
+
+ std::string name = "";
+ for (auto &chunk : output->chunks()) {
+ // Skip cells that drive privately named wires
+ if (!chunk.wire || chunk.wire->name.str()[0] == '$')
+ return cell.name;
+
+ if (name != "")
+ name += "$";
+
+ name += chunk.wire->name.str();
+ if (chunk.wire->width != chunk.width) {
+ name += "[";
+ if (chunk.width != 1)
+ name += std::to_string(chunk.offset + chunk.width) + ":";
+ name += std::to_string(chunk.offset) + "]";
+ }
+ }
+
+ return name + cell.type.str();
+}
+
struct RenamePass : public Pass {
RenamePass() : Pass("rename", "rename object in the design") { }
void help() YS_OVERRIDE
@@ -64,6 +114,25 @@ struct RenamePass : public Pass {
log("by this command.\n");
log("\n");
log("\n");
+ log("\n");
+ log(" rename -output old_name new_name\n");
+ log("\n");
+ log("Like above, but also make the wire an output. This will fail if the object is\n");
+ log("not a wire.\n");
+ log("\n");
+ log("\n");
+ log(" rename -src [selection]\n");
+ log("\n");
+ log("Assign names auto-generated from the src attribute to all selected wires and\n");
+ log("cells with private names.\n");
+ log("\n");
+ log("\n");
+ log(" rename -wire [selection]\n");
+ log("\n");
+ log("Assign auto-generated names based on the wires they drive to all selected\n");
+ log("cells with private names. Ignores cells driving privatly named wires.\n");
+ log("\n");
+ log("\n");
log(" rename -enumerate [-pattern <pattern>] [selection]\n");
log("\n");
log("Assign short auto-generated names to all selected wires and cells with private\n");
@@ -71,11 +140,13 @@ struct RenamePass : public Pass {
log("The character %% in the pattern is replaced with a integer number. The default\n");
log("pattern is '_%%_'.\n");
log("\n");
+ log("\n");
log(" rename -hide [selection]\n");
log("\n");
log("Assign private names (the ones with $-prefix) to all selected wires and cells\n");
log("with public names. This ignores all selected ports.\n");
log("\n");
+ log("\n");
log(" rename -top new_name\n");
log("\n");
log("Rename top module.\n");
@@ -84,15 +155,33 @@ struct RenamePass : public Pass {
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string pattern_prefix = "_", pattern_suffix = "_";
+ bool flag_src = false;
+ bool flag_wire = false;
bool flag_enumerate = false;
bool flag_hide = false;
bool flag_top = false;
+ bool flag_output = false;
bool got_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
+ if (arg == "-src" && !got_mode) {
+ flag_src = true;
+ got_mode = true;
+ continue;
+ }
+ if (arg == "-output" && !got_mode) {
+ flag_output = true;
+ got_mode = true;
+ continue;
+ }
+ if (arg == "-wire" && !got_mode) {
+ flag_wire = true;
+ got_mode = true;
+ continue;
+ }
if (arg == "-enumerate" && !got_mode) {
flag_enumerate = true;
got_mode = true;
@@ -117,6 +206,57 @@ struct RenamePass : public Pass {
break;
}
+ if (flag_src)
+ {
+ extra_args(args, argidx, design);
+
+ for (auto &mod : design->modules_)
+ {
+ int counter = 0;
+
+ RTLIL::Module *module = mod.second;
+ if (!design->selected(module))
+ continue;
+
+ dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
+ for (auto &it : module->wires_) {
+ if (it.first[0] == '$' && design->selected(module, it.second))
+ it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++);
+ new_wires[it.second->name] = it.second;
+ }
+ module->wires_.swap(new_wires);
+ module->fixup_ports();
+
+ dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
+ for (auto &it : module->cells_) {
+ if (it.first[0] == '$' && design->selected(module, it.second))
+ it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++);
+ new_cells[it.second->name] = it.second;
+ }
+ module->cells_.swap(new_cells);
+ }
+ }
+ else
+ if (flag_wire)
+ {
+ extra_args(args, argidx, design);
+
+ for (auto &mod : design->modules_)
+ {
+ RTLIL::Module *module = mod.second;
+ if (!design->selected(module))
+ continue;
+
+ dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
+ for (auto &it : module->cells_) {
+ if (it.first[0] == '$' && design->selected(module, it.second))
+ it.second->name = derive_name_from_wire(*it.second);
+ new_cells[it.second->name] = it.second;
+ }
+ module->cells_.swap(new_cells);
+ }
+ }
+ else
if (flag_enumerate)
{
extra_args(args, argidx, design);
@@ -206,10 +346,12 @@ struct RenamePass : public Pass {
if (!design->selected_active_module.empty())
{
if (design->modules_.count(design->selected_active_module) > 0)
- rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name);
+ rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output);
}
else
{
+ if (flag_output)
+ log_cmd_error("Mode -output requires that there is an active module selected.\n");
for (auto &mod : design->modules_) {
if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
to_name = RTLIL::escape_id(to_name);
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index d97aa2b3..b5e8ef1a 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -896,6 +896,29 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
select_filter_active_mod(design, work_stack.back());
}
+static std::string describe_selection_for_assert(RTLIL::Design *design, RTLIL::Selection *sel)
+{
+ std::string desc = "Selection contains:\n";
+ for (auto mod_it : design->modules_)
+ {
+ if (sel->selected_module(mod_it.first)) {
+ for (auto &it : mod_it.second->wires_)
+ if (sel->selected_member(mod_it.first, it.first))
+ desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ for (auto &it : mod_it.second->memories)
+ if (sel->selected_member(mod_it.first, it.first))
+ desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ for (auto &it : mod_it.second->cells_)
+ if (sel->selected_member(mod_it.first, it.first))
+ desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ for (auto &it : mod_it.second->processes)
+ if (sel->selected_member(mod_it.first, it.first))
+ desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ }
+ }
+ return desc;
+}
+
PRIVATE_NAMESPACE_END
YOSYS_NAMESPACE_BEGIN
@@ -964,7 +987,7 @@ struct SelectPass : public Pass {
log("list of selected objects.\n");
log("\n");
log("Note that many commands support an optional [selection] argument that can be\n");
- log("used to YS_OVERRIDE the global selection for the command. The syntax of this\n");
+ log("used to override the global selection for the command. The syntax of this\n");
log("optional argument is identical to the syntax of the <selection> argument\n");
log("described here.\n");
log("\n");
@@ -1394,7 +1417,12 @@ struct SelectPass : public Pass {
log_cmd_error("No selection to check.\n");
work_stack.back().optimize(design);
if (!work_stack.back().empty())
- log_error("Assertion failed: selection is not empty:%s\n", sel_str.c_str());
+ {
+ RTLIL::Selection *sel = &work_stack.back();
+ sel->optimize(design);
+ std::string desc = describe_selection_for_assert(design, sel);
+ log_error("Assertion failed: selection is not empty:%s\n%s", sel_str.c_str(), desc.c_str());
+ }
return;
}
@@ -1404,7 +1432,12 @@ struct SelectPass : public Pass {
log_cmd_error("No selection to check.\n");
work_stack.back().optimize(design);
if (work_stack.back().empty())
- log_error("Assertion failed: selection is empty:%s\n", sel_str.c_str());
+ {
+ RTLIL::Selection *sel = &work_stack.back();
+ sel->optimize(design);
+ std::string desc = describe_selection_for_assert(design, sel);
+ log_error("Assertion failed: selection is empty:%s\n%s", sel_str.c_str(), desc.c_str());
+ }
return;
}
@@ -1431,14 +1464,23 @@ struct SelectPass : public Pass {
total_count++;
}
if (assert_count >= 0 && assert_count != total_count)
- log_error("Assertion failed: selection contains %d elements instead of the asserted %d:%s\n",
- total_count, assert_count, sel_str.c_str());
+ {
+ std::string desc = describe_selection_for_assert(design, sel);
+ log_error("Assertion failed: selection contains %d elements instead of the asserted %d:%s\n%s",
+ total_count, assert_count, sel_str.c_str(), desc.c_str());
+ }
if (assert_max >= 0 && assert_max < total_count)
- log_error("Assertion failed: selection contains %d elements, more than the maximum number %d:%s\n",
- total_count, assert_max, sel_str.c_str());
+ {
+ std::string desc = describe_selection_for_assert(design, sel);
+ log_error("Assertion failed: selection contains %d elements, more than the maximum number %d:%s\n%s",
+ total_count, assert_max, sel_str.c_str(), desc.c_str());
+ }
if (assert_min >= 0 && assert_min > total_count)
- log_error("Assertion failed: selection contains %d elements, less than the minimum number %d:%s\n",
- total_count, assert_min, sel_str.c_str());
+ {
+ std::string desc = describe_selection_for_assert(design, sel);
+ log_error("Assertion failed: selection contains %d elements, less than the minimum number %d:%s\n%s",
+ total_count, assert_min, sel_str.c_str(), desc.c_str());
+ }
return;
}
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index a1dfa9b5..f6949c82 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -137,12 +137,15 @@ struct SetundefPass : public Pass {
log(" replace with $anyconst drivers (for formal)\n");
log("\n");
log(" -random <seed>\n");
- log(" replace with random bits using the specified integer als seed\n");
+ log(" replace with random bits using the specified integer as seed\n");
log(" value for the random number generator.\n");
log("\n");
log(" -init\n");
log(" also create/update init values for flip-flops\n");
log("\n");
+ log(" -params\n");
+ log(" replace undef in cell parameters\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -150,6 +153,7 @@ struct SetundefPass : public Pass {
bool undriven_mode = false;
bool expose_mode = false;
bool init_mode = false;
+ bool params_mode = false;
SetundefWorker worker;
log_header(design, "Executing SETUNDEF pass (replace undef values with defined constants).\n");
@@ -199,6 +203,10 @@ struct SetundefPass : public Pass {
init_mode = true;
continue;
}
+ if (args[argidx] == "-params") {
+ params_mode = true;
+ continue;
+ }
if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
got_value = true;
worker.next_bit_mode = MODE_RANDOM;
@@ -228,6 +236,18 @@ struct SetundefPass : public Pass {
for (auto module : design->selected_modules())
{
+ if (params_mode)
+ {
+ for (auto *cell : module->selected_cells()) {
+ for (auto &parameter : cell->parameters) {
+ for (auto &bit : parameter.second.bits) {
+ if (bit > RTLIL::State::S1)
+ bit = worker.next_bit();
+ }
+ }
+ }
+ }
+
if (undriven_mode)
{
if (!module->processes.empty())
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index a4887324..58acd302 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -623,7 +623,7 @@ struct ShowPass : public Pass {
log(" assigned to each unique value of this attribute.\n");
log("\n");
log(" -width\n");
- log(" annotate busses with a label indicating the width of the bus.\n");
+ log(" annotate buses with a label indicating the width of the bus.\n");
log("\n");
log(" -signed\n");
log(" mark ports (A, B) that are declared as signed (using the [AB]_SIGNED\n");
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index ff80f385..ee96ace8 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -37,7 +37,7 @@ struct TeePass : public Pass {
log("specified logfile(s).\n");
log("\n");
log(" -q\n");
- log(" Do not print output to the normal destination (console and/or log file)\n");
+ log(" Do not print output to the normal destination (console and/or log file).\n");
log("\n");
log(" -o logfile\n");
log(" Write output to this file, truncate if exists.\n");
@@ -46,7 +46,7 @@ struct TeePass : public Pass {
log(" Write output to this file, append if exists.\n");
log("\n");
log(" +INT, -INT\n");
- log(" Add/subract INT from the -v setting for this command.\n");
+ log(" Add/subtract INT from the -v setting for this command.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
diff --git a/passes/equiv/Makefile.inc b/passes/equiv/Makefile.inc
index dd7b3be0..27ea54b2 100644
--- a/passes/equiv/Makefile.inc
+++ b/passes/equiv/Makefile.inc
@@ -9,4 +9,4 @@ OBJS += passes/equiv/equiv_induct.o
OBJS += passes/equiv/equiv_struct.o
OBJS += passes/equiv/equiv_purge.o
OBJS += passes/equiv/equiv_mark.o
-
+OBJS += passes/equiv/equiv_opt.o
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
index b1f88d55..dbd8682e 100644
--- a/passes/equiv/equiv_make.cc
+++ b/passes/equiv/equiv_make.cc
@@ -40,6 +40,16 @@ struct EquivMakeWorker
pool<SigBit> undriven_bits;
SigMap assign_map;
+ dict<SigBit, pool<Cell*>> bit2driven; // map: bit <--> and its driven cells
+
+ CellTypes comb_ct;
+
+ EquivMakeWorker()
+ {
+ comb_ct.setup_internals();
+ comb_ct.setup_stdcells();
+ }
+
void read_blacklists()
{
for (auto fn : blacklists)
@@ -278,16 +288,31 @@ struct EquivMakeWorker
}
}
+ init_bit2driven();
+
+ pool<Cell*> visited_cells;
for (auto c : cells_list)
for (auto &conn : c->connections())
if (!ct.cell_output(c->type, conn.first)) {
SigSpec old_sig = assign_map(conn.second);
SigSpec new_sig = rd_signal_map(old_sig);
- if (old_sig != new_sig) {
- log("Changing input %s of cell %s (%s): %s -> %s\n",
- log_id(conn.first), log_id(c), log_id(c->type),
- log_signal(old_sig), log_signal(new_sig));
- c->setPort(conn.first, new_sig);
+
+ if(old_sig != new_sig) {
+ SigSpec tmp_sig = old_sig;
+ for (int i = 0; i < GetSize(old_sig); i++) {
+ SigBit old_bit = old_sig[i], new_bit = new_sig[i];
+
+ visited_cells.clear();
+ if (check_signal_in_fanout(visited_cells, old_bit, new_bit))
+ continue;
+
+ log("Changing input %s of cell %s (%s): %s -> %s\n",
+ log_id(conn.first), log_id(c), log_id(c->type),
+ log_signal(old_bit), log_signal(new_bit));
+
+ tmp_sig[i] = new_bit;
+ }
+ c->setPort(conn.first, tmp_sig);
}
}
@@ -378,6 +403,57 @@ struct EquivMakeWorker
}
}
+ void init_bit2driven()
+ {
+ for (auto cell : equiv_mod->cells()) {
+ if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_"))
+ continue;
+ for (auto &conn : cell->connections())
+ {
+ if (yosys_celltypes.cell_input(cell->type, conn.first))
+ for (auto bit : assign_map(conn.second))
+ {
+ bit2driven[bit].insert(cell);
+ }
+ }
+ }
+ }
+
+ bool check_signal_in_fanout(pool<Cell*> & visited_cells, SigBit source_bit, SigBit target_bit)
+ {
+ if (source_bit == target_bit)
+ return true;
+
+ if (bit2driven.count(source_bit) == 0)
+ return false;
+
+ auto driven_cells = bit2driven.at(source_bit);
+ for (auto driven_cell: driven_cells)
+ {
+ bool is_comb = comb_ct.cell_known(driven_cell->type);
+ if (!is_comb)
+ continue;
+
+ if (visited_cells.count(driven_cell) > 0)
+ continue;
+ visited_cells.insert(driven_cell);
+
+ for (auto &conn: driven_cell->connections())
+ {
+ if (yosys_celltypes.cell_input(driven_cell->type, conn.first))
+ continue;
+
+ for (auto bit: conn.second) {
+ bool is_in_fanout = check_signal_in_fanout(visited_cells, bit, target_bit);
+ if (is_in_fanout == true)
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
void run()
{
copy_to_equiv();
diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc
new file mode 100644
index 00000000..86550a69
--- /dev/null
+++ b/passes/equiv/equiv_opt.cc
@@ -0,0 +1,157 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2018 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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivOptPass:public ScriptPass
+{
+ EquivOptPass() : ScriptPass("equiv_opt", "prove equivalence for optimized circuit") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_opt [options] [command]\n");
+ log("\n");
+ log("This command checks circuit equivalence before and after an optimization pass.\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 the start of the command list, and empty to\n");
+ log(" label is synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -map <filename>\n");
+ log(" expand the modules in this file before proving equivalence. this is\n");
+ log(" useful for handling architecture-specific primitives.\n");
+ log("\n");
+ log(" -assert\n");
+ log(" produce an error if the circuits are not equivalent\n");
+ log("\n");
+ log("The following commands are executed by this verification command:\n");
+ help_script();
+ log("\n");
+ }
+
+ std::string command, techmap_opts;
+ bool assert;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ command = "";
+ techmap_opts = "";
+ assert = 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] == "-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] == "-map" && argidx + 1 < args.size()) {
+ techmap_opts += " -map " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-assert") {
+ assert = true;
+ continue;
+ }
+ break;
+ }
+
+ for (; argidx < args.size(); argidx++) {
+ if (command.empty()) {
+ if (args[argidx].substr(0, 1) == "-")
+ cmd_error(args, argidx, "Unknown option.");
+ } else {
+ command += " ";
+ }
+ command += args[argidx];
+ }
+
+ if (command.empty())
+ log_cmd_error("No optimization pass specified!\n");
+
+ if (!design->full_selection())
+ log_cmd_error("This command only operates on fully selected designs!\n");
+
+ log_header(design, "Executing EQUIV_OPT pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ void script() YS_OVERRIDE
+ {
+ if (check_label("run_pass")) {
+ run("hierarchy -auto-top");
+ run("design -save preopt");
+ if (help_mode)
+ run("[command]");
+ else
+ run(command);
+ run("design -stash postopt");
+ }
+
+ if (check_label("prepare")) {
+ run("design -copy-from preopt -as gold A:top");
+ run("design -copy-from postopt -as gate A:top");
+ }
+
+ if ((!techmap_opts.empty() || help_mode) && check_label("techmap", "(only with -map)")) {
+ string opts;
+ if (help_mode)
+ opts = " -map <filename> ...";
+ else
+ opts = techmap_opts;
+ run("techmap -D EQUIV -autoproc" + opts);
+ }
+
+ if (check_label("prove")) {
+ run("equiv_make gold gate equiv");
+ run("equiv_induct equiv");
+ if (help_mode)
+ run("equiv_status [-assert] equiv");
+ else if (assert)
+ run("equiv_status -assert equiv");
+ else
+ run("equiv_status equiv");
+ }
+
+ if (check_label("restore")) {
+ run("design -load preopt");
+ }
+ }
+} EquivOptPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index fc504e98..5ae991b2 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -196,13 +196,13 @@ static void detect_fsm(RTLIL::Wire *wire)
vector<string> warnings;
if (is_module_port)
- warnings.push_back("Forcing fsm recoding on module port might result in larger circuit.\n");
+ warnings.push_back("Forcing FSM recoding on module port might result in larger circuit.\n");
if (!looks_like_good_state_reg)
- warnings.push_back("Users of state reg look like fsm recoding might result in larger circuit.\n");
+ warnings.push_back("Users of state reg look like FSM recoding might result in larger circuit.\n");
if (has_init_attr)
- warnings.push_back("Init value on fsm state registers are ignored. Possible simulation-synthesis mismatch!");
+ warnings.push_back("Initialization value on FSM state register is ignored. Possible simulation-synthesis mismatch!\n");
if (!looks_like_state_reg)
warnings.push_back("Doesn't look like a proper FSM. Possible simulation-synthesis mismatch!\n");
@@ -236,7 +236,7 @@ static void detect_fsm(RTLIL::Wire *wire)
log(" Users of register don't seem to benefit from recoding.\n");
if (has_init_attr)
- log(" Register has an initialization value.");
+ log(" Register has an initialization value.\n");
if (is_self_resetting)
log(" Circuit seems to be self-resetting.\n");
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index 67551f67..6095eaf3 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -178,7 +178,7 @@ undef_bit_in_next_state:
log_state_in = fsm_data.state_table.at(state_in);
if (states.count(ce.values_map(ce.assign_map(dff_in)).as_const()) == 0) {
- log(" transition: %10s %s -> INVALID_STATE(%s) %s <ignored invalid transistion!>%s\n",
+ log(" transition: %10s %s -> INVALID_STATE(%s) %s <ignored invalid transition!>%s\n",
log_signal(log_state_in), log_signal(tr.ctrl_in),
log_signal(ce.values_map(ce.assign_map(dff_in))), log_signal(tr.ctrl_out),
undef_bit_in_next_state_mode ? " SHORTENED" : "");
@@ -194,7 +194,7 @@ undef_bit_in_next_state:
log_signal(log_state_in), log_signal(tr.ctrl_in),
log_signal(fsm_data.state_table[tr.state_out]), log_signal(tr.ctrl_out));
} else {
- log(" transition: %10s %s -> %10s %s <ignored undef transistion!>\n",
+ log(" transition: %10s %s -> %10s %s <ignored undef transition!>\n",
log_signal(log_state_in), log_signal(tr.ctrl_in),
log_signal(fsm_data.state_table[tr.state_out]), log_signal(tr.ctrl_out));
}
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index 3a6ac274..048daee5 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -72,7 +72,8 @@ struct FsmOpt
new_transition_table.swap(fsm_data.transition_table);
new_state_table.swap(fsm_data.state_table);
- fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state);
+ if (fsm_data.reset_state != -1)
+ fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state);
}
}
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 5df69848..88c339e8 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -2,6 +2,7 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 Ruben Undheim <ruben.undheim@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
@@ -139,25 +140,73 @@ 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:") {
+ 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);
+ basicType = celltype.substr(pos_type + 1);
+ if (pos != nullptr) {
+ pos[0] = pos_idx;
+ pos[1] = pos_num;
+ pos[2] = pos_type;
+ }
+ }
+ return basicType;
+}
+
bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
{
bool did_something = false;
std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
std::string filename;
+ bool has_interface_ports = false;
+
+ // If any of the ports are actually interface ports, we will always need to
+ // reprocess the module:
+ if(!module->get_bool_attribute("\\interfaces_replaced_in_module")) {
+ for (auto &wire : module->wires_) {
+ if ((wire.second->port_input || wire.second->port_output) && wire.second->get_bool_attribute("\\is_interface"))
+ has_interface_ports = true;
+ }
+ }
+
+ // Always keep track of all derived interfaces available in the current module in 'interfaces_in_module':
+ dict<RTLIL::IdString, RTLIL::Module*> interfaces_in_module;
+ for (auto &cell_it : module->cells_)
+ {
+ RTLIL::Cell *cell = cell_it.second;
+ if(cell->get_bool_attribute("\\is_interface")) {
+ RTLIL::Module *intf_module = design->modules_[cell->type];
+ interfaces_in_module[cell->name] = intf_module;
+ }
+ }
+
for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
+ bool has_interfaces_not_found = false;
+
+ std::vector<RTLIL::IdString> connections_to_remove;
+ std::vector<RTLIL::IdString> connections_to_add_name;
+ std::vector<RTLIL::SigSpec> connections_to_add_signal;
if (cell->type.substr(0, 7) == "$array:") {
- int pos_idx = cell->type.str().find_first_of(':');
- int pos_num = cell->type.str().find_first_of(':', pos_idx + 1);
- int pos_type = cell->type.str().find_first_of(':', pos_num + 1);
+ 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());
array_cells[cell] = std::pair<int, int>(idx, num);
cell->type = cell->type.str().substr(pos_type + 1);
}
+ dict<RTLIL::IdString, RTLIL::Module*> interfaces_to_add_to_submodule;
+ dict<RTLIL::IdString, RTLIL::IdString> modports_used_in_submodule;
if (design->modules_.count(cell->type) == 0)
{
@@ -200,11 +249,85 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
if (design->modules_.count(cell->type) == 0)
log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str());
did_something = true;
- } else
+ } else {
+
+ RTLIL::Module *mod = design->module(cell->type);
+
+ // Go over all connections and see if any of them are SV interfaces. If they are, then add the replacements to
+ // some lists, so that the ports for sub-modules can be replaced further down:
+ for (auto &conn : cell->connections()) {
+ if(mod->wires_.count(conn.first) != 0 && mod->wire(conn.first)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list
+ //const pool<string> &interface_type_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_type");
+ //for (auto &d : interface_type_pool) { // TODO: Compare interface type to type in parent module (not crucially important, but good for robustness)
+ //}
+
+ // Find if the sub-module has set a modport for the current interface connection:
+ const pool<string> &interface_modport_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_modport");
+ std::string interface_modport = "";
+ for (auto &d : interface_modport_pool) {
+ interface_modport = "\\" + d;
+ }
+ if(conn.second.bits().size() == 1 && conn.second.bits()[0].wire->get_bool_attribute("\\is_interface")) { // Check if the connected wire is a potential interface in the parent module
+ std::string interface_name_str = conn.second.bits()[0].wire->name.str();
+ interface_name_str.replace(0,23,""); // Strip the prefix '$dummywireforinterface' from the dummy wire to get the name
+ interface_name_str = "\\" + interface_name_str;
+ RTLIL::IdString interface_name = interface_name_str;
+ bool not_found_interface = false;
+ if(module->get_bool_attribute("\\interfaces_replaced_in_module")) { // If 'interfaces' in the cell have not be been handled yet, there is no need to derive the sub-module either
+ // Check if the interface instance is present in module:
+ // Interface instances may either have the plain name or the name appended with '_inst_from_top_dummy'.
+ // Check for both of them here
+ int nexactmatch = interfaces_in_module.count(interface_name) > 0;
+ std::string interface_name_str2 = interface_name_str + "_inst_from_top_dummy";
+ RTLIL::IdString interface_name2 = interface_name_str2;
+ int nmatch2 = interfaces_in_module.count(interface_name2) > 0;
+ if (nexactmatch > 0 || nmatch2 > 0) {
+ if (nexactmatch != 0) // Choose the one with the plain name if it exists
+ interface_name2 = interface_name;
+ RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name2);
+ for (auto &mod_wire : mod_replace_ports->wires_) { // Go over all wires in interface, and add replacements to lists.
+ std::string signal_name1 = conn.first.str() + "." + log_id(mod_wire.first);
+ std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire.first);
+ connections_to_add_name.push_back(RTLIL::IdString(signal_name1));
+ if(module->wires_.count(signal_name2) == 0) {
+ log_error("Could not find signal '%s' in '%s'\n", signal_name2.c_str(), log_id(module->name));
+ }
+ else {
+ RTLIL::Wire *wire_in_parent = module->wire(signal_name2);
+ connections_to_add_signal.push_back(wire_in_parent);
+ }
+ }
+ connections_to_remove.push_back(conn.first);
+ interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name2);
+
+ // Add modports to a dict which will be passed to AstModule::derive
+ if (interface_modport != "") {
+ modports_used_in_submodule[conn.first] = interface_modport;
+ }
+ }
+ else not_found_interface = true;
+ }
+ else not_found_interface = true;
+ // If the interface instance has not already been derived in the module, we cannot complete at this stage. Set "has_interfaces_not_found"
+ // which will delay the expansion of this cell:
+ if (not_found_interface) {
+ // If we have already gone over all cells in this module, and the interface has still not been found - flag it as an error:
+ if(!(module->get_bool_attribute("\\cells_not_processed"))) {
+ log_warning("Could not find interface instance for `%s' in `%s'\n", log_id(interface_name), log_id(module));
+ }
+ else {
+ // Only set has_interfaces_not_found if it would be possible to find them, since otherwiser we will end up in an infinite loop:
+ has_interfaces_not_found = true;
+ }
+ }
+ }
+ }
+ }
+ //
+
if (flag_check || flag_simcheck)
{
- RTLIL::Module *mod = design->module(cell->type);
- for (auto &conn : cell->connections())
+ for (auto &conn : cell->connections()) {
if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
int id = atoi(conn.first.c_str()+1);
if (id <= 0 || id > GetSize(mod->ports))
@@ -213,11 +336,15 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
} else if (mod->wire(conn.first) == nullptr || mod->wire(conn.first)->port_id == 0)
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
+ }
for (auto &param : cell->parameters)
if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL)
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n",
log_id(cell->type), log_id(module), log_id(cell), log_id(param.first));
+
+ }
}
+ RTLIL::Module *mod = design->modules_[cell->type];
if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
if (flag_simcheck)
@@ -226,15 +353,62 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
continue;
}
- if (cell->parameters.size() == 0)
+ // If interface instances not yet found, skip cell for now, and say we did something, so that we will return back here:
+ if(has_interfaces_not_found) {
+ did_something = true; // waiting for interfaces to be handled
continue;
+ }
- RTLIL::Module *mod = design->modules_[cell->type];
- cell->type = mod->derive(design, cell->parameters);
+ // Do the actual replacements of the SV interface port connection with the individual signal connections:
+ for(unsigned int i=0;i<connections_to_add_name.size();i++) {
+ cell->connections_[connections_to_add_name[i]] = connections_to_add_signal[i];
+ }
+ // Remove the connection for the interface itself:
+ for(unsigned int i=0;i<connections_to_remove.size();i++) {
+ cell->connections_.erase(connections_to_remove[i]);
+ }
+
+ // If there are no overridden parameters AND not interfaces, then we can use the existing module instance as the type
+ // for the cell:
+ if (cell->parameters.size() == 0 && (interfaces_to_add_to_submodule.size() == 0 || !(cell->get_bool_attribute("\\module_not_derived")))) {
+ // If the cell being processed is an the interface instance itself, go down to "handle_interface_instance:",
+ // so that the signals of the interface are added to the parent module.
+ if (mod->get_bool_attribute("\\is_interface")) {
+ goto handle_interface_instance;
+ }
+ continue;
+ }
+
+ cell->type = mod->derive(design, cell->parameters, interfaces_to_add_to_submodule, modports_used_in_submodule);
cell->parameters.clear();
did_something = true;
+
+ handle_interface_instance:
+
+ // We add all the signals of the interface explicitly to the parent module. This is always needed when we encounter
+ // an interface instance:
+ if (mod->get_bool_attribute("\\is_interface") && cell->get_bool_attribute("\\module_not_derived")) {
+ cell->set_bool_attribute("\\is_interface");
+ RTLIL::Module *derived_module = design->modules_[cell->type];
+ interfaces_in_module[cell->name] = derived_module;
+ did_something = true;
+ }
+ // We clear 'module_not_derived' such that we will not rederive the cell again (needed when there are interfaces connected to the cell)
+ cell->attributes.erase("\\module_not_derived");
+ }
+ // Clear the attribute 'cells_not_processed' such that it can be known that we
+ // have been through all cells at least once, and that we can know whether
+ // to flag an error because of interface instances not found:
+ module->attributes.erase("\\cells_not_processed");
+
+
+ // If any interface instances or interface ports were found in the module, we need to rederive it completely:
+ if ((interfaces_in_module.size() > 0 || has_interface_ports) && !module->get_bool_attribute("\\interfaces_replaced_in_module")) {
+ module->reprocess_module(design, interfaces_in_module);
+ return did_something;
}
+
for (auto &it : array_cells)
{
RTLIL::Cell *cell = it.first;
@@ -284,10 +458,7 @@ 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:") {
- 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);
- celltype = celltype.substr(pos_type + 1);
+ celltype = basic_cell_type(celltype);
}
if (design->module(celltype))
hierarchy_worker(design, used, design->module(celltype), indent+4);
@@ -303,6 +474,20 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
for (auto &it : design->modules_)
if (used.count(it.second) == 0)
del_modules.push_back(it.second);
+ else {
+ // Now all interface ports must have been exploded, and it is hence
+ // safe to delete all of the remaining dummy interface ports:
+ pool<RTLIL::Wire*> del_wires;
+ for(auto &wire : it.second->wires_) {
+ if ((wire.second->port_input || wire.second->port_output) && wire.second->get_bool_attribute("\\is_interface")) {
+ del_wires.insert(wire.second);
+ }
+ }
+ if (del_wires.size() > 0) {
+ it.second->remove(del_wires);
+ it.second->fixup_ports();
+ }
+ }
int del_counter = 0;
for (auto mod : del_modules) {
@@ -333,14 +518,38 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
if (db.count(module) == 0) {
int score = 0;
db[module] = 0;
- for (auto cell : module->cells())
- if (design->module(cell->type))
- score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1);
+ for (auto cell : module->cells()) {
+ std::string celltype = cell->type.str();
+ // Is this an array instance
+ if (celltype.substr(0, 7) == "$array:") {
+ 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.
+ if (instModule != nullptr) {
+ score = max(score, find_top_mod_score(design, instModule, db) + 1);
+ }
+ }
db[module] = score;
}
return db.at(module);
}
+RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod)
+{
+ if(top_mod != NULL && top_mod->get_bool_attribute("\\initial_top"))
+ return top_mod;
+ else {
+ for (auto mod : design->modules()) {
+ if (mod->get_bool_attribute("\\top")) {
+ return mod;
+ }
+ }
+ }
+ return NULL;
+}
+
struct HierarchyPass : public Pass {
HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
void help() YS_OVERRIDE
@@ -360,7 +569,7 @@ struct HierarchyPass : public Pass {
log(" an unknown module is used as cell type.\n");
log("\n");
log(" -simcheck\n");
- log(" like -check, but also thow an error if blackbox modules are\n");
+ log(" like -check, but also throw an error if blackbox modules are\n");
log(" instantiated, and throw an error if the design has no top module\n");
log("\n");
log(" -purge_lib\n");
@@ -568,6 +777,14 @@ struct HierarchyPass : public Pass {
if (flag_simcheck && top_mod == nullptr)
log_error("Design has no top module.\n");
+ if (top_mod != NULL) {
+ for (auto &mod_it : design->modules_)
+ if (mod_it.second == top_mod)
+ mod_it.second->attributes["\\initial_top"] = RTLIL::Const(1);
+ else
+ mod_it.second->attributes.erase("\\initial_top");
+ }
+
bool did_something = true;
while (did_something)
{
@@ -586,19 +803,43 @@ struct HierarchyPass : public Pass {
if (expand_module(design, module, flag_check, flag_simcheck, libdirs))
did_something = true;
}
+
+
+ // The top module might have changed if interface instances have been detected in it:
+ RTLIL::Module *tmp_top_mod = check_if_top_has_changed(design, top_mod);
+ if (tmp_top_mod != NULL) {
+ if (tmp_top_mod != top_mod){
+ top_mod = tmp_top_mod;
+ did_something = true;
+ }
+ }
+
+ // Delete modules marked as 'to_delete':
+ std::vector<RTLIL::Module *> modules_to_delete;
+ for(auto &mod_it : design->modules_) {
+ if (mod_it.second->get_bool_attribute("\\to_delete")) {
+ modules_to_delete.push_back(mod_it.second);
+ }
+ }
+ for(size_t i=0; i<modules_to_delete.size(); i++) {
+ design->remove(modules_to_delete[i]);
+ }
}
+
if (top_mod != NULL) {
log_header(design, "Analyzing design hierarchy..\n");
hierarchy_clean(design, top_mod, purge_lib);
}
if (top_mod != NULL) {
- for (auto &mod_it : design->modules_)
+ for (auto &mod_it : design->modules_) {
if (mod_it.second == top_mod)
mod_it.second->attributes["\\top"] = RTLIL::Const(1);
else
mod_it.second->attributes.erase("\\top");
+ mod_it.second->attributes.erase("\\initial_top");
+ }
}
if (!nokeep_asserts) {
@@ -669,7 +910,7 @@ struct HierarchyPass : public Pass {
if (m == nullptr)
continue;
- if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) {
+ if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
IdString new_m_name = m->derive(design, cell->parameters, true);
if (new_m_name.empty())
continue;
diff --git a/passes/hierarchy/uniquify.cc b/passes/hierarchy/uniquify.cc
index c88ecd82..e6154e94 100644
--- a/passes/hierarchy/uniquify.cc
+++ b/passes/hierarchy/uniquify.cc
@@ -87,6 +87,8 @@ struct UniquifyPass : public Pass {
smod->name = newname;
cell->type = newname;
smod->set_bool_attribute("\\unique");
+ if (smod->attributes.count("\\hdlname") == 0)
+ smod->attributes["\\hdlname"] = string(log_id(tmod->name));
design->add(smod);
did_something = true;
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index e8552bbc..85ed1c05 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -472,8 +472,12 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
std::vector<SigSpec> new_wr_en(GetSize(old_wr_en));
std::vector<SigSpec> new_wr_data(GetSize(old_wr_data));
std::vector<SigSpec> new_rd_data(GetSize(old_rd_data));
+ std::vector<std::vector<State>> new_initdata;
std::vector<int> shuffle_map;
+ if (cell_init)
+ new_initdata.resize(mem_size);
+
for (auto &it : en_order)
{
auto &bits = bits_wr_en.at(it);
@@ -489,6 +493,10 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
}
for (int j = 0; j < rd_ports; j++)
new_rd_data[j].append(old_rd_data[j][bits[i]]);
+ if (cell_init) {
+ for (int j = 0; j < mem_size; j++)
+ new_initdata[j].push_back(initdata[j][bits[i]]);
+ }
shuffle_map.push_back(bits[i]);
}
@@ -499,6 +507,10 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
}
for (int j = 0; j < rd_ports; j++)
new_rd_data[j].append(State::Sx);
+ if (cell_init) {
+ for (int j = 0; j < mem_size; j++)
+ new_initdata[j].push_back(State::Sx);
+ }
shuffle_map.push_back(-1);
}
}
@@ -522,10 +534,15 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
for (int i = 0; i < rd_ports; i++)
rd_data.replace(i*mem_width, new_rd_data[i]);
+
+ if (cell_init) {
+ for (int i = 0; i < mem_size; i++)
+ initdata[i] = Const(new_initdata[i]);
+ }
}
// assign write ports
-
+ pair<SigBit, bool> wr_clkdom;
for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++)
{
bool clken = wr_clken[cell_port_i] == State::S1;
@@ -535,7 +552,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
pair<SigBit, bool> clkdom(clksig, clkpol);
if (!clken)
clkdom = pair<SigBit, bool>(State::S1, false);
-
+ wr_clkdom = clkdom;
log(" Write port #%d is in clock domain %s%s.\n",
cell_port_i, clkdom.second ? "" : "!",
clken ? log_signal(clkdom.first) : "~async~");
@@ -623,6 +640,8 @@ grow_read_ports:;
pi.sig_addr = SigSpec();
pi.sig_data = SigSpec();
pi.sig_en = SigSpec();
+ pi.make_outreg = false;
+ pi.make_transp = false;
}
new_portinfos.push_back(pi);
if (pi.dupidx == dup_count-1) {
@@ -700,7 +719,13 @@ grow_read_ports:;
if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
if (match.make_transp && wr_ports <= 1) {
pi.make_transp = true;
- enable_make_transp = true;
+ if (pi.clocks != 0) {
+ if (wr_ports == 1 && wr_clkdom != clkdom) {
+ log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ enable_make_transp = true;
+ }
} else {
log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
@@ -895,17 +920,18 @@ grow_read_ports:;
} else {
SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits);
c->setPort(stringf("\\%sDATA", pf), bram_dout);
-
- if (pi.make_outreg) {
+ if (pi.make_outreg && pi.make_transp) {
+ log(" Moving output register to address for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ SigSpec sig_addr_q = module->addWire(NEW_ID, bram.abits);
+ module->addDff(NEW_ID, pi.sig_clock, sig_addr, sig_addr_q, pi.effective_clkpol);
+ c->setPort(stringf("\\%sADDR", pf), sig_addr_q);
+ } else if (pi.make_outreg) {
SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits);
if (!pi.sig_en.empty())
bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en);
module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol);
bram_dout = bram_dout_q;
- }
-
- if (pi.make_transp)
- {
+ } else if (pi.make_transp) {
log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits),
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 70d98713..369fcc84 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -184,9 +184,6 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
mem->parameters["\\OFFSET"] = Const(memory->start_offset);
mem->parameters["\\SIZE"] = Const(memory->size);
mem->parameters["\\ABITS"] = Const(addr_bits);
-
- while (GetSize(init_data) > 1 && init_data.bits.back() == State::Sx && init_data.bits[GetSize(init_data)-2] == State::Sx)
- init_data.bits.pop_back();
mem->parameters["\\INIT"] = init_data;
log_assert(sig_wr_clk.size() == wr_ports);
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 32df1917..220d2929 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -41,7 +41,7 @@ struct MemoryDffWorker
if (wire->attributes.count("\\init") == 0)
continue;
SigSpec sig = sigmap(wire);
- Const initval = wire->attributes.count("\\init");
+ Const initval = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
if (initval[i] == State::S0 || initval[i] == State::S1)
init_bits.insert(sig[i]);
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 0d01e9d3..c3e0a2a4 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -12,5 +12,6 @@ OBJS += passes/opt/share.o
OBJS += passes/opt/wreduce.o
OBJS += passes/opt/opt_demorgan.o
OBJS += passes/opt/rmports.o
+OBJS += passes/opt/opt_lut.o
endif
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 0ba233c6..a05db2a4 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -155,6 +155,13 @@ 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) {
+ log(" 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);
+ continue;
+ }
+
RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
c->setPort("\\A", new_a);
@@ -259,6 +266,22 @@ bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative)
return last_bit_one;
}
+int get_highest_hot_index(RTLIL::SigSpec signal)
+{
+ for (int i = GetSize(signal) - 1; i >= 0; i--)
+ {
+ if (signal[i] == RTLIL::State::S0)
+ continue;
+
+ if (signal[i] == RTLIL::State::S1)
+ return i;
+
+ break;
+ }
+
+ return -1;
+}
+
// if the signal has only one bit set, return the index of that bit.
// otherwise return -1
int get_onehot_bit_index(RTLIL::SigSpec signal)
@@ -1344,118 +1367,139 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
- // replace a<0 or a>=0 with the top bit of a
+ // simplify comparisons
if (do_fine && (cell->type == "$lt" || cell->type == "$ge" || cell->type == "$gt" || cell->type == "$le"))
{
- //used to decide whether the signal needs to be negated
- bool is_lt = false;
-
- //references the variable signal in the comparison
- RTLIL::SigSpec sigVar;
-
- //references the constant signal in the comparison
- RTLIL::SigSpec sigConst;
-
- // note that this signal must be constant for the optimization
- // to take place, but it is not checked beforehand.
- // If new passes are added, this signal must be checked for const-ness
-
- //width of the variable port
- int width;
- int const_width;
-
- bool var_signed;
-
- if (cell->type == "$lt" || cell->type == "$ge") {
- is_lt = cell->type == "$lt" ? 1 : 0;
- sigVar = cell->getPort("\\A");
- sigConst = cell->getPort("\\B");
- width = cell->parameters["\\A_WIDTH"].as_int();
- const_width = cell->parameters["\\B_WIDTH"].as_int();
- var_signed = cell->parameters["\\A_SIGNED"].as_bool();
- } else
- if (cell->type == "$gt" || cell->type == "$le") {
- is_lt = cell->type == "$gt" ? 1 : 0;
- sigVar = cell->getPort("\\B");
- sigConst = cell->getPort("\\A");
- width = cell->parameters["\\B_WIDTH"].as_int();
- const_width = cell->parameters["\\A_WIDTH"].as_int();
- var_signed = cell->parameters["\\B_SIGNED"].as_bool();
- } else
- log_abort();
+ 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();
- // replace a(signed) < 0 with the high bit of a
- if (sigConst.is_fully_const() && sigConst.is_fully_zero() && var_signed == true)
+ if (!const_sig.is_fully_const())
{
- RTLIL::SigSpec a_prime(RTLIL::State::S0, cell->parameters["\\Y_WIDTH"].as_int());
- a_prime[0] = sigVar[width - 1];
- if (is_lt) {
- log("Replacing %s cell `%s' (implementing X<0) with X[%d]: %s\n",
- log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
- module->connect(cell->getPort("\\Y"), a_prime);
- module->remove(cell);
- } else {
- log("Replacing %s cell `%s' (implementing X>=0) with ~X[%d]: %s\n",
- log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
- module->addNot(NEW_ID, a_prime, cell->getPort("\\Y"));
- module->remove(cell);
- }
- did_something = true;
- goto next_cell;
- } else
- if (sigConst.is_fully_const() && sigConst.is_fully_def() && var_signed == false)
+ 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 (const_sig.is_fully_def() && const_sig.is_fully_const())
{
- if (sigConst.is_fully_zero()) {
- RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
- if (is_lt) {
- log("Replacing %s cell `%s' (implementing unsigned X<0) with constant false.\n",
- log_id(cell->type), log_id(cell));
- a_prime[0] = RTLIL::State::S0;
- } else {
- log("Replacing %s cell `%s' (implementing unsigned X>=0) with constant true.\n",
- log_id(cell->type), log_id(cell));
- a_prime[0] = RTLIL::State::S1;
+ std::string condition, replacement;
+ SigSpec replace_sig(State::S0, GetSize(cell->getPort("\\Y")));
+ bool replace = false;
+ bool remove = false;
+
+ if (!is_signed)
+ { /* unsigned */
+ if (const_sig.is_fully_zero() && cmp_type == "$lt") {
+ condition = "unsigned X<0";
+ replacement = "constant 0";
+ replace_sig[0] = State::S0;
+ replace = true;
+ }
+ if (const_sig.is_fully_zero() && cmp_type == "$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") {
+ 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") {
+ condition = "unsigned X<=~0";
+ replacement = "constant 1";
+ replace_sig[0] = State::S1;
+ replace = true;
}
- module->connect(cell->getPort("\\Y"), a_prime);
- module->remove(cell);
- did_something = true;
- goto next_cell;
- }
- int const_bit_set = get_onehot_bit_index(sigConst);
- if (const_bit_set >= 0 && const_bit_set < width) {
- int bit_set = const_bit_set;
- RTLIL::SigSpec a_prime(RTLIL::State::S0, width - bit_set);
- for (int i = bit_set; i < width; i++) {
- a_prime[i - bit_set] = sigVar[i];
+ int const_bit_hot = get_onehot_bit_index(const_sig);
+ if (const_bit_hot >= 0 && const_bit_hot < var_width)
+ {
+ RTLIL::SigSpec var_high_sig(RTLIL::State::S0, var_width - const_bit_hot);
+ for (int i = const_bit_hot; i < var_width; i++) {
+ var_high_sig[i - const_bit_hot] = var_sig[i];
+ }
+
+ if (cmp_type == "$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"));
+ remove = true;
+ }
+ if (cmp_type == "$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"));
+ remove = true;
+ }
}
- if (is_lt) {
- log("Replacing %s cell `%s' (implementing unsigned X<%s) with !X[%d:%d]: %s.\n",
- log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
- module->addLogicNot(NEW_ID, a_prime, cell->getPort("\\Y"));
- } else {
- log("Replacing %s cell `%s' (implementing unsigned X>=%s) with |X[%d:%d]: %s.\n",
- log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
- module->addReduceOr(NEW_ID, a_prime, cell->getPort("\\Y"));
+
+ int const_bit_set = get_highest_hot_index(const_sig);
+ if(const_bit_set >= var_width)
+ {
+ string cmp_name;
+ if (cmp_type == "$lt" || cmp_type == "$le")
+ {
+ if (cmp_type == "$lt") cmp_name = "<";
+ if (cmp_type == "$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 == "$gt") cmp_name = ">";
+ if (cmp_type == "$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;
+ replace = true;
+ }
}
- module->remove(cell);
- did_something = true;
- goto next_cell;
}
- else if(const_bit_set >= width && const_bit_set >= 0){
- RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
- if(is_lt){
- a_prime[0] = RTLIL::State::S1;
- log("Replacing %s cell `%s' (implementing unsigned X[%d:0] < %s[%d:0]) with constant 0.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
+ else
+ { /* signed */
+ if (const_sig.is_fully_zero() && cmp_type == "$lt")
+ {
+ condition = "signed X<0";
+ replacement = stringf("X[%d]", var_width - 1);
+ replace_sig[0] = var_sig[var_width - 1];
+ replace = true;
}
- else{
- log("Replacing %s cell `%s' (implementing unsigned X[%d:0]>= %s[%d:0]) with constant 1.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
+ if (const_sig.is_fully_zero() && cmp_type == "$ge")
+ {
+ condition = "signed X>=0";
+ replacement = stringf("X[%d]", var_width - 1);
+ module->addNot(NEW_ID, var_sig[var_width - 1], cell->getPort("\\Y"));
+ remove = true;
}
- module->connect(cell->getPort("\\Y"), a_prime);
+ }
+
+ if (replace || remove)
+ {
+ log("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->remove(cell);
did_something = true;
goto next_cell;
-
}
}
}
@@ -1477,7 +1521,7 @@ struct OptExprPass : public Pass {
log(" opt_expr [options] [selection]\n");
log("\n");
log("This pass performs const folding on internal cell types with constant inputs.\n");
- log("It also performs some simple expression rewritring.\n");
+ log("It also performs some simple expression rewriting.\n");
log("\n");
log(" -mux_undef\n");
log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc
new file mode 100644
index 00000000..26855fd7
--- /dev/null
+++ b/passes/opt/opt_lut.cc
@@ -0,0 +1,607 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2018 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/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/modtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct OptLutWorker
+{
+ dict<IdString, dict<int, IdString>> &dlogic;
+ RTLIL::Module *module;
+ ModIndex index;
+ SigMap sigmap;
+
+ pool<RTLIL::Cell*> luts;
+ dict<RTLIL::Cell*, int> luts_arity;
+ dict<RTLIL::Cell*, pool<RTLIL::Cell*>> luts_dlogics;
+ dict<RTLIL::Cell*, pool<int>> luts_dlogic_inputs;
+
+ int eliminated_count = 0, combined_count = 0;
+
+ 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");
+ int lut_index = 0;
+
+ for (int i = 0; i < lut_width; i++)
+ {
+ SigBit input = sigmap(lut_input[i]);
+ if (inputs.count(input))
+ {
+ lut_index |= inputs[input] << i;
+ }
+ else
+ {
+ lut_index |= SigSpec(lut_input[i]).as_bool() << i;
+ }
+ }
+
+ return lut_table.extract(lut_index).as_bool();
+ }
+
+ void show_stats_by_arity()
+ {
+ dict<int, int> arity_counts;
+ dict<IdString, int> dlogic_counts;
+ int max_arity = 0;
+
+ for (auto lut_arity : luts_arity)
+ {
+ max_arity = max(max_arity, lut_arity.second);
+ arity_counts[lut_arity.second]++;
+ }
+
+ for (auto &lut_dlogics : luts_dlogics)
+ {
+ for (auto &lut_dlogic : lut_dlogics.second)
+ {
+ dlogic_counts[lut_dlogic->type]++;
+ }
+ }
+
+ log("Number of LUTs: %8zu\n", luts.size());
+ for (int arity = 1; arity <= max_arity; arity++)
+ {
+ if (arity_counts[arity])
+ log(" %d-LUT %16d\n", arity, arity_counts[arity]);
+ }
+ for (auto &dlogic_count : dlogic_counts)
+ {
+ log(" with %-12s %4d\n", dlogic_count.first.c_str(), dlogic_count.second);
+ }
+ }
+
+ OptLutWorker(dict<IdString, dict<int, IdString>> &dlogic, RTLIL::Module *module, int limit) :
+ dlogic(dlogic), module(module), index(module), sigmap(module)
+ {
+ log("Discovering LUTs.\n");
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "$lut")
+ {
+ int lut_width = cell->getParam("\\WIDTH").as_int();
+ SigSpec lut_input = cell->getPort("\\A");
+ int lut_arity = 0;
+
+ log("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
+ // of such connections.
+ pool<RTLIL::Cell*> lut_all_dlogics;
+ for (int i = 0; i < lut_width; i++)
+ {
+ SigBit bit = lut_input[i];
+ for (auto &port : index.query_ports(bit))
+ {
+ if (dlogic.count(port.cell->type))
+ {
+ auto &dlogic_map = dlogic[port.cell->type];
+ if (dlogic_map.count(i))
+ {
+ if (port.port == dlogic_map[i])
+ {
+ lut_all_dlogics.insert(port.cell);
+ }
+ }
+ }
+ }
+ }
+
+ // Second, make sure that the connection to dedicated logic is legal. If it is not legal,
+ // it means one of the two things:
+ // * The connection is spurious. I.e. this is dedicated logic that will be packed
+ // with some other LUT, and it just happens to be connected to this LUT as well.
+ // * The connection is illegal.
+ // In either of these cases, we don't need to concern ourselves with preserving the connection
+ // between this LUT and this dedicated logic cell.
+ pool<RTLIL::Cell*> lut_legal_dlogics;
+ pool<int> lut_dlogic_inputs;
+ for (auto lut_dlogic : lut_all_dlogics)
+ {
+ auto &dlogic_map = dlogic[lut_dlogic->type];
+ bool legal = true;
+ for (auto &dlogic_conn : dlogic_map)
+ {
+ 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);
+ 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)));
+ legal = false;
+ break;
+ }
+ }
+
+ 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));
+ lut_legal_dlogics.insert(lut_dlogic);
+ for (auto &dlogic_conn : dlogic_map)
+ lut_dlogic_inputs.insert(dlogic_conn.first);
+ }
+ }
+
+ // Third, determine LUT arity. An n-wide LUT that has k constant inputs and m inputs shared with dedicated
+ // logic implements an (n-k-m)-ary function.
+ for (int i = 0; i < lut_width; i++)
+ {
+ SigBit bit = lut_input[i];
+ if (bit.wire || lut_dlogic_inputs.count(i))
+ lut_arity++;
+ }
+
+ log(" 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;
+ }
+ }
+ show_stats_by_arity();
+
+ log("\n");
+ log("Eliminating LUTs.\n");
+ pool<RTLIL::Cell*> worklist = luts;
+ while (worklist.size())
+ {
+ if (limit == 0)
+ {
+ log("Limit reached.\n");
+ break;
+ }
+
+ auto lut = worklist.pop();
+ SigSpec lut_input = sigmap(lut->getPort("\\A"));
+ pool<int> &lut_dlogic_inputs = luts_dlogic_inputs[lut];
+
+ vector<SigBit> lut_inputs;
+ for (auto &bit : lut_input)
+ {
+ if (bit.wire)
+ lut_inputs.push_back(sigmap(bit));
+ }
+
+ bool const0_match = true;
+ bool const1_match = true;
+ vector<bool> input_matches;
+ for (size_t i = 0; i < lut_inputs.size(); i++)
+ input_matches.push_back(true);
+
+ for (int eval = 0; eval < 1 << lut_inputs.size(); eval++)
+ {
+ dict<SigBit, bool> eval_inputs;
+ for (size_t i = 0; i < lut_inputs.size(); i++)
+ eval_inputs[lut_inputs[i]] = (eval >> i) & 1;
+ bool value = evaluate_lut(lut, eval_inputs);
+ if (value != 0)
+ const0_match = false;
+ if (value != 1)
+ const1_match = false;
+ for (size_t i = 0; i < lut_inputs.size(); i++)
+ {
+ if (value != eval_inputs[lut_inputs[i]])
+ input_matches[i] = false;
+ }
+ }
+
+ int input_match = -1;
+ for (size_t i = 0; i < lut_inputs.size(); i++)
+ if (input_matches[i])
+ input_match = i;
+
+ if (const0_match || const1_match || input_match != -1)
+ {
+ log("Found redundant cell %s.%s.\n", log_id(module), log_id(lut));
+
+ SigBit value;
+ if (const0_match)
+ {
+ log(" Cell evaluates constant 0.\n");
+ value = State::S0;
+ }
+ if (const1_match)
+ {
+ log(" Cell evaluates constant 1.\n");
+ value = State::S1;
+ }
+ if (input_match != -1) {
+ log(" 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");
+ }
+ else
+ {
+ SigSpec lut_output = lut->getPort("\\Y");
+ for (auto &port : index.query_ports(lut_output))
+ {
+ if (port.cell != lut && luts.count(port.cell))
+ worklist.insert(port.cell);
+ }
+
+ module->connect(lut_output, value);
+ sigmap.add(lut_output, value);
+
+ module->remove(lut);
+ luts.erase(lut);
+ luts_arity.erase(lut);
+ luts_dlogics.erase(lut);
+ luts_dlogic_inputs.erase(lut);
+
+ eliminated_count++;
+ if (limit > 0)
+ limit--;
+ }
+ }
+ }
+ show_stats_by_arity();
+
+ log("\n");
+ log("Combining LUTs.\n");
+ worklist = luts;
+ while (worklist.size())
+ {
+ if (limit == 0)
+ {
+ log("Limit reached.\n");
+ break;
+ }
+
+ 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();
+ 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"));
+ if (lutA_output_ports.size() != 2)
+ continue;
+
+ for (auto &port : lutA_output_ports)
+ {
+ if (port.cell == lutA)
+ continue;
+
+ 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();
+ 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));
+
+ if (index.query_is_output(lutA->getPort("\\Y")))
+ {
+ log(" Not combining LUTs (cascade connection feeds module output).\n");
+ continue;
+ }
+
+ pool<SigBit> lutA_inputs;
+ pool<SigBit> lutB_inputs;
+ for (auto &bit : lutA_input)
+ {
+ if (bit.wire)
+ lutA_inputs.insert(sigmap(bit));
+ }
+ for (auto &bit : lutB_input)
+ {
+ if (bit.wire)
+ lutB_inputs.insert(sigmap(bit));
+ }
+
+ pool<SigBit> common_inputs;
+ for (auto &bit : lutA_inputs)
+ {
+ if (lutB_inputs.count(bit))
+ common_inputs.insert(bit);
+ }
+
+ 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());
+ else
+ log(" 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());
+ 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);
+
+ 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");
+ }
+ 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");
+ }
+ else
+ {
+ combine_mask |= COMBINE_A;
+ }
+ if (lutM_arity > lutB_width)
+ {
+ log(" 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");
+ }
+ else
+ {
+ combine_mask |= COMBINE_B;
+ }
+
+ int combine = combine_mask;
+ if (combine == COMBINE_EITHER)
+ {
+ log(" Can combine into either cell.\n");
+ if (lutA_arity == 1)
+ {
+ log(" 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");
+ combine = COMBINE_A;
+ }
+ else
+ {
+ log(" Arbitrarily combining into cell A.\n");
+ combine = COMBINE_A;
+ }
+ }
+
+ RTLIL::Cell *lutM, *lutR;
+ pool<SigBit> lutM_inputs, lutR_inputs;
+ pool<int> lutM_dlogic_inputs;
+ if (combine == COMBINE_A)
+ {
+ log(" Combining LUTs into cell A.\n");
+ lutM = lutA;
+ lutM_inputs = lutA_inputs;
+ lutM_dlogic_inputs = lutA_dlogic_inputs;
+ lutR = lutB;
+ lutR_inputs = lutB_inputs;
+ }
+ else if (combine == COMBINE_B)
+ {
+ log(" Combining LUTs into cell B.\n");
+ lutM = lutB;
+ lutM_inputs = lutB_inputs;
+ lutM_dlogic_inputs = lutB_dlogic_inputs;
+ lutR = lutA;
+ lutR_inputs = lutA_inputs;
+ }
+ else
+ {
+ log(" Cannot combine LUTs.\n");
+ continue;
+ }
+
+ pool<SigBit> lutR_unique;
+ for (auto &bit : lutR_inputs)
+ {
+ if (!common_inputs.count(bit) && bit != lutA_output)
+ lutR_unique.insert(bit);
+ }
+
+ int lutM_width = lutM->getParam("\\WIDTH").as_int();
+ SigSpec lutM_input = sigmap(lutM->getPort("\\A"));
+ std::vector<SigBit> lutM_new_inputs;
+ for (int i = 0; i < lutM_width; i++)
+ {
+ bool input_unused = false;
+ if (sigmap(lutM_input[i]) == lutA_output)
+ input_unused = true;
+ if (!lutM_input[i].wire && !lutM_dlogic_inputs.count(i))
+ input_unused = true;
+
+ if (input_unused && lutR_unique.size())
+ {
+ SigBit new_input = lutR_unique.pop();
+ log(" 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);
+ lutM_new_inputs.push_back(SigBit());
+ }
+ else
+ {
+ log(" Leaving input %d as %s.\n", i, log_signal(lutM_input[i]));
+ lutM_new_inputs.push_back(lutM_input[i]);
+ }
+ }
+ log_assert(lutR_unique.size() == 0);
+
+ RTLIL::Const lutM_new_table(State::Sx, 1 << lutM_width);
+ for (int eval = 0; eval < 1 << lutM_width; eval++)
+ {
+ dict<SigBit, bool> eval_inputs;
+ for (size_t i = 0; i < lutM_new_inputs.size(); i++)
+ {
+ eval_inputs[lutM_new_inputs[i]] = (eval >> i) & 1;
+ }
+ eval_inputs[lutA_output] = evaluate_lut(lutA, eval_inputs);
+ 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());
+
+ lutM->setParam("\\LUT", lutM_new_table);
+ lutM->setPort("\\A", lutM_new_inputs);
+ lutM->setPort("\\Y", lutB_output);
+
+ luts_arity[lutM] = lutM_arity;
+ luts.erase(lutR);
+ luts_arity.erase(lutR);
+ lutR->module->remove(lutR);
+
+ worklist.insert(lutM);
+ worklist.erase(lutR);
+
+ combined_count++;
+ if (limit > 0)
+ limit--;
+ }
+ }
+ }
+ show_stats_by_arity();
+ }
+};
+
+static void split(std::vector<std::string> &tokens, const std::string &text, char sep)
+{
+ size_t start = 0, end = 0;
+ while ((end = text.find(sep, start)) != std::string::npos) {
+ tokens.push_back(text.substr(start, end - start));
+ start = end + 1;
+ }
+ tokens.push_back(text.substr(start));
+}
+
+struct OptLutPass : public Pass {
+ OptLutPass() : Pass("opt_lut", "optimize LUT cells") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" opt_lut [options] [selection]\n");
+ log("\n");
+ log("This pass combines cascaded $lut cells with unused inputs.\n");
+ log("\n");
+ log(" -dlogic <type>:<cell-port>=<LUT-input>[:<cell-port>=<LUT-input>...]\n");
+ log(" preserve connections to dedicated logic cell <type> that has ports\n");
+ log(" <cell-port> connected to LUT inputs <LUT-input>. this includes\n");
+ log(" the case where both LUT and dedicated logic input are connected to\n");
+ log(" the same constant.\n");
+ log("\n");
+ log(" -limit N\n");
+ log(" only perform the first N combines, then stop. useful for debugging.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing OPT_LUT pass (optimize LUTs).\n");
+
+ dict<IdString, dict<int, IdString>> dlogic;
+ int limit = -1;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-dlogic" && argidx+1 < args.size())
+ {
+ std::vector<std::string> tokens;
+ split(tokens, args[++argidx], ':');
+ if (tokens.size() < 2)
+ log_cmd_error("The -dlogic option requires at least one connection.\n");
+ IdString type = "\\" + tokens[0];
+ for (auto it = tokens.begin() + 1; it != tokens.end(); ++it) {
+ std::vector<std::string> conn_tokens;
+ split(conn_tokens, *it, '=');
+ if (conn_tokens.size() != 2)
+ log_cmd_error("Invalid format of -dlogic signal mapping.\n");
+ IdString logic_port = "\\" + conn_tokens[0];
+ int lut_input = atoi(conn_tokens[1].c_str());
+ dlogic[type][lut_input] = logic_port;
+ }
+ continue;
+ }
+ if (args[argidx] == "-limit" && argidx + 1 < args.size())
+ {
+ limit = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ int eliminated_count = 0, combined_count = 0;
+ for (auto module : design->selected_modules())
+ {
+ OptLutWorker worker(dlogic, module, limit - eliminated_count - combined_count);
+ eliminated_count += worker.eliminated_count;
+ combined_count += worker.combined_count;
+ }
+ if (eliminated_count)
+ design->scratchpad_set_bool("opt.did_something", true);
+ if (combined_count)
+ design->scratchpad_set_bool("opt.did_something", true);
+ log("\n");
+ log("Eliminated %d LUTs.\n", eliminated_count);
+ log("Combined %d LUTs.\n", combined_count);
+ }
+} OptLutPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 87c7ce9b..375697dc 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -36,6 +36,7 @@ struct OptMuxtreeWorker
RTLIL::Module *module;
SigMap assign_map;
int removed_count;
+ int glob_abort_cnt = 100000;
struct bitinfo_t {
bool seen_non_mux;
@@ -293,6 +294,9 @@ struct OptMuxtreeWorker
void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
+ if (glob_abort_cnt == 0)
+ return;
+
muxinfo_t &muxinfo = mux2info[mux_idx];
if (do_enable_ports)
@@ -315,7 +319,7 @@ struct OptMuxtreeWorker
knowledge.visited_muxes[m] = true;
parent_muxes.push_back(m);
}
- for (int m : parent_muxes)
+ for (int m : parent_muxes) {
if (root_enable_muxes.at(m))
continue;
else if (root_muxes.at(m)) {
@@ -327,6 +331,9 @@ struct OptMuxtreeWorker
eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1);
} else
eval_mux(knowledge, m, do_replace_known, do_enable_ports, abort_count);
+ if (glob_abort_cnt == 0)
+ return;
+ }
for (int m : parent_muxes)
knowledge.visited_muxes[m] = false;
@@ -390,6 +397,12 @@ struct OptMuxtreeWorker
void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
+ if (glob_abort_cnt == 0) {
+ log(" Giving up (too many iterations)\n");
+ return;
+ }
+ glob_abort_cnt--;
+
muxinfo_t &muxinfo = mux2info[mux_idx];
// set input ports to constants if we find known active or inactive signals
@@ -433,6 +446,9 @@ struct OptMuxtreeWorker
if (knowledge.known_inactive.at(portinfo.ctrl_sig))
continue;
eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
+
+ if (glob_abort_cnt == 0)
+ return;
}
}
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index 5880254c..e8570f0e 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -174,8 +174,6 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
cell->unsetParam("\\CLR_POLARITY");
cell->unsetPort("\\SET");
cell->unsetPort("\\CLR");
-
- return true;
}
else
{
@@ -186,11 +184,12 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
cell->unsetParam("\\CLR_POLARITY");
cell->unsetPort("\\SET");
cell->unsetPort("\\CLR");
-
- return true;
}
+
+ return true;
}
- else
+
+ if (!hasreset)
{
IdString new_type;
@@ -207,8 +206,10 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
cell->unsetPort("\\S");
cell->unsetPort("\\R");
- return did_something;
+ return true;
}
+
+ return did_something;
}
bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index b8028082..c85c2742 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -710,8 +710,12 @@ struct ShareWorker
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1);
RTLIL::SigSpec addr1 = c1->getPort("\\ADDR");
RTLIL::SigSpec addr2 = c2->getPort("\\ADDR");
- if (addr1 != addr2)
- supercell->setPort("\\ADDR", module->Mux(NEW_ID, addr2, addr1, act));
+ 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_aux.insert(supercell);
return supercell;
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 0164f58d..52245ce3 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -38,7 +38,8 @@ struct WreduceConfig
"$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
"$add", "$sub", "$mul", // "$div", "$mod", "$pow",
- "$mux", "$pmux"
+ "$mux", "$pmux",
+ "$dff", "$adff"
});
}
};
@@ -52,6 +53,8 @@ struct WreduceWorker
std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
std::set<SigBit> work_queue_bits;
pool<SigBit> keep_bits;
+ dict<SigBit, State> init_bits;
+ pool<SigBit> remove_init_bits;
WreduceWorker(WreduceConfig *config, Module *module) :
config(config), module(module), mi(module) { }
@@ -134,6 +137,91 @@ struct WreduceWorker
module->connect(sig_y.extract(n_kept, n_removed), sig_removed);
}
+ void run_cell_dff(Cell *cell)
+ {
+ // 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"));
+ Const initval;
+
+ int width_before = GetSize(sig_q);
+
+ if (width_before == 0)
+ return;
+
+ bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0;
+ bool sign_ext = !zero_ext;
+
+ for (int i = 0; i < GetSize(sig_q); i++) {
+ SigBit bit = sig_q[i];
+ if (init_bits.count(bit))
+ initval.bits.push_back(init_bits.at(bit));
+ else
+ initval.bits.push_back(State::Sx);
+ }
+
+ for (int i = GetSize(sig_q)-1; i >= 0; i--)
+ {
+ if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) {
+ module->connect(sig_q[i], State::S0);
+ remove_init_bits.insert(sig_q[i]);
+ sig_d.remove(i);
+ sig_q.remove(i);
+ continue;
+ }
+
+ if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) {
+ module->connect(sig_q[i], sig_q[i-1]);
+ remove_init_bits.insert(sig_q[i]);
+ sig_d.remove(i);
+ sig_q.remove(i);
+ continue;
+ }
+
+ auto info = mi.query(sig_q[i]);
+ if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
+ remove_init_bits.insert(sig_q[i]);
+ sig_d.remove(i);
+ sig_q.remove(i);
+ zero_ext = false;
+ sign_ext = false;
+ continue;
+ }
+
+ break;
+ }
+
+ if (width_before == GetSize(sig_q))
+ return;
+
+ if (GetSize(sig_q) == 0) {
+ log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
+ module->remove(cell);
+ return;
+ }
+
+ log("Removed top %d bits (of %d) from FF cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before,
+ log_id(module), log_id(cell), log_id(cell->type));
+
+ for (auto bit : sig_d)
+ work_queue_bits.insert(bit);
+
+ for (auto bit : sig_q)
+ 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");
+ arst_value.bits.resize(GetSize(sig_q));
+ cell->setParam("\\ARST_VALUE", arst_value);
+ }
+
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ cell->fixup_parameters();
+ }
+
void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something)
{
port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool();
@@ -176,6 +264,9 @@ struct WreduceWorker
if (cell->type.in("$mux", "$pmux"))
return run_cell_mux(cell);
+ if (cell->type.in("$dff", "$adff"))
+ return run_cell_dff(cell);
+
SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
if (sig.has_const())
@@ -235,8 +326,11 @@ struct WreduceWorker
} else {
while (GetSize(sig) > 0)
{
- auto info = mi.query(sig[GetSize(sig)-1]);
+ auto bit = sig[GetSize(sig)-1];
+ if (keep_bits.count(bit))
+ break;
+ auto info = mi.query(bit);
if (info->is_output || GetSize(info->ports) > 1)
break;
@@ -297,10 +391,21 @@ struct WreduceWorker
void run()
{
- for (auto w : module->wires())
+ // create a copy as mi.sigmap will be updated as we process the module
+ SigMap init_attr_sigmap = mi.sigmap;
+
+ for (auto w : module->wires()) {
if (w->get_bool_attribute("\\keep"))
for (auto bit : mi.sigmap(w))
keep_bits.insert(bit);
+ if (w->attributes.count("\\init")) {
+ Const initval = w->attributes.at("\\init");
+ SigSpec initsig = init_attr_sigmap(w);
+ int width = std::min(GetSize(initval), GetSize(initsig));
+ for (int i = 0; i < width; i++)
+ init_bits[initsig[i]] = initval[i];
+ }
+ }
for (auto c : module->selected_cells())
work_queue_cells.insert(c);
@@ -348,6 +453,24 @@ struct WreduceWorker
module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
module->swap_names(w, nw);
}
+
+ if (!remove_init_bits.empty()) {
+ for (auto w : module->wires()) {
+ if (w->attributes.count("\\init")) {
+ Const initval = w->attributes.at("\\init");
+ Const new_initval(State::Sx, GetSize(w));
+ SigSpec initsig = init_attr_sigmap(w);
+ int width = std::min(GetSize(initval), GetSize(initsig));
+ for (int i = 0; i < width; i++) {
+ log_dump(initsig[i], remove_init_bits.count(initsig[i]));
+ if (!remove_init_bits.count(initsig[i]))
+ new_initval[i] = initval[i];
+ }
+ w->attributes.at("\\init") = new_initval;
+ log_dump(w->name, initval, new_initval);
+ }
+ }
+ }
}
};
diff --git a/passes/pmgen/.gitignore b/passes/pmgen/.gitignore
new file mode 100644
index 00000000..c9263057
--- /dev/null
+++ b/passes/pmgen/.gitignore
@@ -0,0 +1 @@
+/ice40_dsp_pm.h
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
new file mode 100644
index 00000000..e0609d9b
--- /dev/null
+++ b/passes/pmgen/Makefile.inc
@@ -0,0 +1,8 @@
+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
+
+passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
+ $(P) mkdir -p passes/pmgen && python3 $^ $@
diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md
new file mode 100644
index 00000000..223b4305
--- /dev/null
+++ b/passes/pmgen/README.md
@@ -0,0 +1,224 @@
+Pattern Matcher Generator
+=========================
+
+The program `pmgen.py` reads a `.pmg` (Pattern Matcher Generator) file and
+writes a header-only C++ library that implements that pattern matcher.
+
+The "patterns" in this context are subgraphs in a Yosys RTLIL netlist.
+
+The algorithm used in the generated pattern matcher is a simple recursive
+search with backtracking. It is left to the author of the `.pmg` file to
+determine an efficient cell order for the search that allows for maximum
+use of indices and early backtracking.
+
+
+API of Generated Matcher
+========================
+
+When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing
+a class `foobar_pm`. That class is instantiated with an RTLIL module and a
+list of cells from that module:
+
+ foobar_pm pm(module, module->selected_cells());
+
+The caller must make sure that none of the cells in the 2nd argument are
+deleted for as long as the patter matcher instance is used.
+
+At any time it is possible to disable cells, preventing them from showing
+up in any future matches:
+
+ pm.blacklist(some_cell);
+
+The `.run(callback_function)` method searches for all matches and calls the
+callback function for each found match:
+
+ pm.run([&](){
+ log("found matching 'foo' cell: %s\n", log_id(pm.st.foo));
+ log(" with 'bar' cell: %s\n", log_id(pm.st.bar));
+ });
+
+The `.pmg` file declares matcher state variables that are accessible via the
+`.st.<state_name>` members. (The `.st` member is of type `foobar_pm::state_t`.)
+
+Similarly the `.pmg` file declares user data variables that become members of
+`.ud`, a struct of type `foobar_pm::udata_t`.
+
+
+The .pmg File Format
+====================
+
+The `.pmg` file format is a simple line-based file format. For the most part
+lines consist of whitespace-separated tokens.
+
+Lines in `.pmg` files starting with `//` are comments.
+
+Declaring state variables
+-------------------------
+
+One or more state variables can be declared using the `state` statement,
+followed by a C++ type in angle brackets, followed by a whitespace separated
+list of variable names. For example:
+
+ state <bool> flag1 flag2 happy big
+ state <SigSpec> sigA sigB sigY
+
+State variables are automatically managed by the generated backtracking algorithm
+and saved and restored as needed.
+
+They are automatically initialized to the default constructed value of their type
+when `.run(callback_function)` is called.
+
+Declaring udata variables
+-------------------------
+
+Udata (user-data) variables can be used for example to configure the matcher or
+the callback function used to perform actions on found matches.
+
+There is no automatic management of udata variables. For this reason it is
+recommended that the user-supplied matcher code treats them as read-only
+variables.
+
+They are declared like state variables, just using the `udata` statement:
+
+ udata <int> min_data_width max_data_width
+ udata <IdString> data_port_name
+
+They are atomatically initialzed to the default constructed value of their type
+when ther pattern matcher object is constructed.
+
+Embedded C++ code
+-----------------
+
+Many statements in a `.pmg` file contain C++ code. However, there are some
+slight additions to regular C++/Yosys/RTLIL code that make it a bit easier to
+write matchers:
+
+- Identifiers starting with a dollar sign or backslash are automatically
+ converted to special IdString variables that are initialized when the
+ matcher object is constructed.
+
+- The `port(<cell>, <portname>)` function is a handy alias for
+ `sigmap(<cell>->getPort(<portname>))`.
+
+- Similarly `param(<cell>, <paramname>)` looks up a parameter on a cell.
+
+- The function `nusers(<sigspec>)` returns the number of different cells
+ 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 `index` statements there is a special `===` operator for the index
+ lookup.
+
+Matching cells
+--------------
+
+Cells are matched using `match..endmatch` blocks. For example:
+
+ match mul
+ if ff
+ select mul->type == $mul
+ select nusers(port(mul, \Y) == 2
+ index <SigSpec> port(mul, \Y) === port(ff, \D)
+ filter some_weird_function(mul) < other_weird_function(ff)
+ optional
+ endmatch
+
+A `match` block starts with `match <statevar>` and implicitly generates
+a state variable `<statevar>` of type `RTLIL::Cell*`.
+
+All statements in the match block are optional. (An empty match block
+would simply match each and every cell in the module.)
+
+The `if <expression>` statement makes the match block conditional. If
+`<expression>` evaluates to `false` then the match block will be ignored
+and the corresponding state variable is set to `nullptr`. In our example
+we only try to match the `mul` cell if the `ff` state variable points
+to a cell. (Presumably `ff` is provided by a prior `match` block.)
+
+The `select` lines are evaluated once for each cell when the matcher is
+initialized. A `match` block will only consider cells for which all `select`
+expressions evaluated to `true`. Note that the state variable corresponding to
+the match (in the example `mul`) is the only state variable that may be used
+in `select` lines.
+
+Index lines are using the `index <type> expr1 === expr2` syntax. `expr1` is
+evaluated during matcher initialization and the same restrictions apply as for
+`select` expressions. `expr2` is evaluated when the match is calulated. It is a
+function of any state variables assigned to by previous blocks. Both expression
+are converted to the given type and compared for equality. Only cells for which
+all `index` statements in the block pass are considered by the match.
+
+Note that `select` and `index` are fast operations. Thus `select` and `index`
+should be used whenever possible to create efficient matchers.
+
+Finally, `filter <expression>` narrows down the remaining list of cells. For
+performance reasons `filter` statements should only be used for things that
+can't be done using `select` and `index`.
+
+The `optional` statement marks optional matches. I.e. the matcher will also
+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`.
+
+Additional code
+---------------
+
+Interleaved with `match..endmatch` blocks there may be `code..endcode` blocks.
+Such a block starts with the keyword `code` followed by a list of state variables
+that the block may modify. For example:
+
+ code addAB sigS
+ if (addA) {
+ addAB = addA;
+ sigS = port(addA, \B);
+ }
+ if (addB) {
+ addAB = addB;
+ sigS = port(addB, \A);
+ }
+ endcode
+
+The special keyword `reject` can be used to reject the current state and
+backtrack. For example:
+
+ code
+ if (ffA && ffB) {
+ if (port(ffA, \CLK) != port(ffB, \CLK))
+ reject;
+ if (param(ffA, \CLK_POLARITY) != param(ffB, \CLK_POLARITY))
+ reject;
+ }
+ endcode
+
+Similarly, the special keyword `accept` can be used to accept the current
+state. (`accept` will not backtrack. This means it continues with the current
+branch and may accept a larger match later.)
+
+The special keyword `branch` can be used to explore different cases. Note that
+each code block has an implicit `branch` at the end. So most use-cases of the
+`branch` keyword need to end the block with `reject` to avoid the implicit
+branch at the end. For example:
+
+ state <int> mode
+
+ code mode
+ for (mode = 0; mode < 8; mode++)
+ branch;
+ reject;
+ endcode
+
+But in some cases it is more natural to utilize the implicit branch statement:
+
+ state <IdString> portAB
+
+ code portAB
+ portAB = \A;
+ branch;
+ portAB = \B;
+ endcode
+
+There is an implicit `code..endcode` block at the end of each `.pgm` file
+that just accepts everything that gets all the way there.
diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc
new file mode 100644
index 00000000..3a054a46
--- /dev/null
+++ b/passes/pmgen/ice40_dsp.cc
@@ -0,0 +1,237 @@
+/*
+ * 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 "passes/pmgen/ice40_dsp_pm.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void create_ice40_dsp(ice40_dsp_pm &pm)
+{
+#if 0
+ log("\n");
+ log("ffA: %s\n", log_id(pm.st.ffA, "--"));
+ log("ffB: %s\n", log_id(pm.st.ffB, "--"));
+ log("mul: %s\n", log_id(pm.st.mul, "--"));
+ log("ffY: %s\n", log_id(pm.st.ffY, "--"));
+ log("addAB: %s\n", log_id(pm.st.addAB, "--"));
+ log("muxAB: %s\n", log_id(pm.st.muxAB, "--"));
+ log("ffS: %s\n", log_id(pm.st.ffS, "--"));
+#endif
+
+ log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(pm.st.mul));
+
+ if (GetSize(pm.st.sigA) > 16) {
+ log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA));
+ return;
+ }
+
+ if (GetSize(pm.st.sigB) > 16) {
+ log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB));
+ return;
+ }
+
+ if (GetSize(pm.st.sigS) > 32) {
+ log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS));
+ return;
+ }
+
+ if (GetSize(pm.st.sigY) > 32) {
+ log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY));
+ return;
+ }
+
+ bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool();
+
+ if (mul_signed) {
+ log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n");
+ return;
+ }
+
+ log(" replacing $mul with SB_MAC16 cell.\n");
+
+ Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");
+ pm.module->swap_names(cell, pm.st.mul);
+
+ // SB_MAC16 Input Interface
+
+ SigSpec A = pm.st.sigA;
+ A.extend_u0(16, mul_signed);
+
+ SigSpec B = pm.st.sigB;
+ B.extend_u0(16, mul_signed);
+
+ SigSpec CD;
+ if (pm.st.muxA)
+ CD = pm.st.muxA->getPort("\\B");
+ if (pm.st.muxB)
+ CD = pm.st.muxB->getPort("\\A");
+ CD.extend_u0(32, mul_signed);
+
+ cell->setPort("\\A", A);
+ cell->setPort("\\B", B);
+ cell->setPort("\\C", CD.extract(0, 16));
+ cell->setPort("\\D", CD.extract(16, 16));
+
+ cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0);
+ cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0);
+
+ cell->setPort("\\AHOLD", State::S0);
+ cell->setPort("\\BHOLD", State::S0);
+ cell->setPort("\\CHOLD", State::S0);
+ cell->setPort("\\DHOLD", State::S0);
+
+ cell->setPort("\\IRSTTOP", State::S0);
+ cell->setPort("\\IRSTBOT", State::S0);
+
+ if (pm.st.clock_vld)
+ {
+ cell->setPort("\\CLK", pm.st.clock);
+ cell->setPort("\\CE", State::S1);
+ cell->setParam("\\NEG_TRIGGER", pm.st.clock_pol ? State::S0 : State::S1);
+
+ log(" clock: %s (%s)", log_signal(pm.st.clock), pm.st.clock_pol ? "posedge" : "negedge");
+
+ if (pm.st.ffA)
+ log(" ffA:%s", log_id(pm.st.ffA));
+
+ if (pm.st.ffB)
+ log(" ffB:%s", log_id(pm.st.ffB));
+
+ if (pm.st.ffY)
+ log(" ffY:%s", log_id(pm.st.ffY));
+
+ if (pm.st.ffS)
+ log(" ffS:%s", log_id(pm.st.ffS));
+
+ log("\n");
+ }
+ else
+ {
+ cell->setPort("\\CLK", State::S0);
+ cell->setPort("\\CE", State::S0);
+ cell->setParam("\\NEG_TRIGGER", State::S0);
+ }
+
+ // SB_MAC16 Cascade Interface
+
+ cell->setPort("\\SIGNEXTIN", State::Sx);
+ cell->setPort("\\SIGNEXTOUT", pm.module->addWire(NEW_ID));
+
+ cell->setPort("\\CI", State::Sx);
+ cell->setPort("\\CO", pm.module->addWire(NEW_ID));
+
+ cell->setPort("\\ACCUMCI", State::Sx);
+ cell->setPort("\\ACCUMCO", pm.module->addWire(NEW_ID));
+
+ // SB_MAC16 Output Interface
+
+ SigSpec O = pm.st.ffS ? pm.st.sigS : pm.st.sigY;
+ if (GetSize(O) < 32)
+ O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
+
+ cell->setPort("\\O", O);
+
+ if (pm.st.addAB) {
+ log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type));
+ cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
+ cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
+ } else {
+ cell->setPort("\\ADDSUBTOP", State::S0);
+ cell->setPort("\\ADDSUBBOT", State::S0);
+ }
+
+ cell->setPort("\\ORSTTOP", State::S0);
+ cell->setPort("\\ORSTBOT", State::S0);
+
+ cell->setPort("\\OHOLDTOP", State::S0);
+ cell->setPort("\\OHOLDBOT", State::S0);
+
+ SigSpec acc_reset = State::S0;
+ if (pm.st.muxA)
+ acc_reset = pm.st.muxA->getPort("\\S");
+ if (pm.st.muxB)
+ acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S"));
+
+ cell->setPort("\\OLOADTOP", acc_reset);
+ cell->setPort("\\OLOADBOT", acc_reset);
+
+ // SB_MAC16 Remaining Parameters
+
+ cell->setParam("\\C_REG", State::S0);
+ cell->setParam("\\D_REG", State::S0);
+
+ cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
+ cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
+ cell->setParam("\\PIPELINE_16x16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0);
+ cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0);
+
+ cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2));
+ cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2));
+ cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0);
+ cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2));
+
+ cell->setParam("\\BOTOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2));
+ cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2));
+ cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0);
+ cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2));
+
+ cell->setParam("\\MODE_8x8", State::S0);
+ cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0);
+ cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
+
+ pm.autoremove(pm.st.mul);
+ pm.autoremove(pm.st.ffY);
+ pm.autoremove(pm.st.ffS);
+}
+
+struct Ice40DspPass : public Pass {
+ Ice40DspPass() : Pass("ice40_dsp", "iCE40: map multipliers") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ice40_dsp [options] [selection]\n");
+ log("\n");
+ log("Map multipliers and multiply-accumulate blocks to iCE40 DSP resources.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing ICE40_DSP pass (map multipliers).\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_dsp_pm(module, module->selected_cells()).run(create_ice40_dsp);
+ }
+} Ice40DspPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg
new file mode 100644
index 00000000..96c62e31
--- /dev/null
+++ b/passes/pmgen/ice40_dsp.pmg
@@ -0,0 +1,160 @@
+state <SigBit> clock
+state <bool> clock_pol clock_vld
+state <SigSpec> sigA sigB sigY sigS
+state <Cell*> addAB muxAB
+
+match mul
+ select mul->type.in($mul)
+ select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
+ select GetSize(mul->getPort(\Y)) > 10
+endmatch
+
+match ffA
+ select ffA->type.in($dff)
+ // select nusers(port(ffA, \Q)) == 2
+ index <SigSpec> port(ffA, \Q) === port(mul, \A)
+ optional
+endmatch
+
+code sigA clock clock_pol clock_vld
+ sigA = port(mul, \A);
+
+ if (ffA) {
+ sigA = port(ffA, \D);
+
+ clock = port(ffA, \CLK).as_bit();
+ clock_pol = param(ffA, \CLK_POLARITY).as_bool();
+ clock_vld = true;
+ }
+endcode
+
+match ffB
+ select ffB->type.in($dff)
+ // select nusers(port(ffB, \Q)) == 2
+ index <SigSpec> port(ffB, \Q) === port(mul, \B)
+ optional
+endmatch
+
+code sigB clock clock_pol clock_vld
+ sigB = port(mul, \B);
+
+ if (ffB) {
+ sigB = port(ffB, \D);
+ SigBit c = port(ffB, \CLK).as_bit();
+ bool cp = param(ffB, \CLK_POLARITY).as_bool();
+
+ if (clock_vld && (c != clock || cp != clock_pol))
+ reject;
+
+ clock = c;
+ clock_pol = cp;
+ clock_vld = true;
+ }
+endcode
+
+match ffY
+ select ffY->type.in($dff)
+ select nusers(port(ffY, \D)) == 2
+ index <SigSpec> port(ffY, \D) === port(mul, \Y)
+ optional
+endmatch
+
+code sigY clock clock_pol clock_vld
+ sigY = port(mul, \Y);
+
+ if (ffY) {
+ sigY = port(ffY, \Q);
+ SigBit c = port(ffY, \CLK).as_bit();
+ bool cp = param(ffY, \CLK_POLARITY).as_bool();
+
+ if (clock_vld && (c != clock || cp != clock_pol))
+ reject;
+
+ clock = c;
+ clock_pol = cp;
+ clock_vld = true;
+ }
+endcode
+
+match addA
+ select addA->type.in($add)
+ select nusers(port(addA, \A)) == 2
+ index <SigSpec> port(addA, \A) === sigY
+ optional
+endmatch
+
+match addB
+ if !addA
+ select addB->type.in($add, $sub)
+ select nusers(port(addB, \B)) == 2
+ index <SigSpec> port(addB, \B) === sigY
+ optional
+endmatch
+
+code addAB sigS
+ if (addA) {
+ addAB = addA;
+ sigS = port(addA, \B);
+ }
+ if (addB) {
+ addAB = addB;
+ sigS = port(addB, \A);
+ }
+ if (addAB) {
+ int natural_mul_width = GetSize(sigA) + GetSize(sigB);
+ int actual_mul_width = GetSize(sigY);
+ int actual_acc_width = GetSize(sigS);
+
+ if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
+ reject;
+ if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool()))
+ reject;
+ }
+endcode
+
+match muxA
+ if addAB
+ select muxA->type.in($mux)
+ select nusers(port(muxA, \A)) == 2
+ index <SigSpec> port(muxA, \A) === port(addAB, \Y)
+ optional
+endmatch
+
+match muxB
+ if addAB
+ if !muxA
+ select muxB->type.in($mux)
+ select nusers(port(muxB, \B)) == 2
+ index <SigSpec> port(muxB, \B) === port(addAB, \Y)
+ optional
+endmatch
+
+code muxAB
+ muxAB = addAB;
+ if (muxA)
+ muxAB = muxA;
+ if (muxB)
+ muxAB = muxB;
+endcode
+
+match ffS
+ if muxAB
+ select ffS->type.in($dff)
+ select nusers(port(ffS, \D)) == 2
+ index <SigSpec> port(ffS, \D) === port(muxAB, \Y)
+ index <SigSpec> port(ffS, \Q) === sigS
+endmatch
+
+code clock clock_pol clock_vld
+ if (ffS) {
+ SigBit c = port(ffS, \CLK).as_bit();
+ bool cp = param(ffS, \CLK_POLARITY).as_bool();
+
+ if (clock_vld && (c != clock || cp != clock_pol))
+ reject;
+
+ clock = c;
+ clock_pol = cp;
+ clock_vld = true;
+ }
+endcode
diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py
new file mode 100644
index 00000000..d9747b06
--- /dev/null
+++ b/passes/pmgen/pmgen.py
@@ -0,0 +1,486 @@
+#!/usr/bin/env python3
+
+import re
+import sys
+import pprint
+
+pp = pprint.PrettyPrinter(indent=4)
+
+pmgfile = sys.argv[1]
+assert pmgfile.endswith(".pmg")
+prefix = pmgfile[0:-4]
+prefix = prefix.split('/')[-1]
+outfile = sys.argv[2]
+
+state_types = dict()
+udata_types = dict()
+blocks = list()
+ids = dict()
+
+def rewrite_cpp(s):
+ t = list()
+ i = 0
+ while i < len(s):
+ if s[i] in ("'", '"') and i + 1 < len(s):
+ j = i + 1
+ while j + 1 < len(s) and s[j] != s[i]:
+ if s[j] == '\\' and j + 1 < len(s):
+ j += 1
+ j += 1
+ t.append(s[i:j+1])
+ i = j + 1
+ continue
+
+ if s[i] in ('$', '\\') and i + 1 < len(s):
+ j = i + 1
+ while True:
+ if j == len(s):
+ j -= 1
+ break
+ if ord('a') <= ord(s[j]) <= ord('z'):
+ j += 1
+ continue
+ if ord('A') <= ord(s[j]) <= ord('Z'):
+ j += 1
+ continue
+ if ord('0') <= ord(s[j]) <= ord('9'):
+ j += 1
+ continue
+ if s[j] == '_':
+ j += 1
+ continue
+ j -= 1
+ break
+
+ n = s[i:j+1]
+ i = j + 1
+
+ if n[0] == '$':
+ v = "id_d_" + n[1:]
+ else:
+ v = "id_b_" + n[1:]
+
+ if v not in ids:
+ ids[v] = n
+ else:
+ assert ids[v] == n
+
+ t.append(v)
+ continue
+
+ if s[i] == "\t":
+ t.append(" ")
+ else:
+ t.append(s[i])
+
+ i += 1
+
+ return "".join(t)
+
+with open(pmgfile, "r") as f:
+ while True:
+ line = f.readline()
+ if line == "": break
+ line = line.strip()
+
+ cmd = line.split()
+ if len(cmd) == 0 or cmd[0].startswith("//"): continue
+ cmd = cmd[0]
+
+ if cmd == "state":
+ m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
+ assert m
+ type_str = m.group(1)
+ states_str = m.group(2)
+ for s in re.split(r"\s+", states_str):
+ assert s not in state_types
+ state_types[s] = type_str
+ continue
+
+ if cmd == "udata":
+ m = re.match(r"^udata\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
+ assert m
+ type_str = m.group(1)
+ udatas_str = m.group(2)
+ for s in re.split(r"\s+", udatas_str):
+ assert s not in udata_types
+ udata_types[s] = type_str
+ continue
+
+ if cmd == "match":
+ block = dict()
+ block["type"] = "match"
+
+ line = line.split()
+ assert len(line) == 2
+ assert line[1] not in state_types
+ block["cell"] = line[1]
+ state_types[line[1]] = "Cell*";
+
+ block["if"] = list()
+ block["select"] = list()
+ block["index"] = list()
+ block["filter"] = list()
+ block["optional"] = False
+
+ while True:
+ l = f.readline()
+ assert l != ""
+ a = l.split()
+ if len(a) == 0 or a[0].startswith("//"): continue
+ if a[0] == "endmatch": break
+
+ if a[0] == "if":
+ b = l.lstrip()[2:]
+ block["if"].append(rewrite_cpp(b.strip()))
+ continue
+
+ if a[0] == "select":
+ b = l.lstrip()[6:]
+ block["select"].append(rewrite_cpp(b.strip()))
+ continue
+
+ if a[0] == "index":
+ m = re.match(r"^\s*index\s+<(.*?)>\s+(.*?)\s*===\s*(.*?)\s*$", l)
+ assert m
+ block["index"].append((m.group(1), rewrite_cpp(m.group(2)), rewrite_cpp(m.group(3))))
+ continue
+
+ if a[0] == "filter":
+ b = l.lstrip()[6:]
+ block["filter"].append(rewrite_cpp(b.strip()))
+ continue
+
+ if a[0] == "optional":
+ block["optional"] = True
+ continue
+
+ assert False
+
+ blocks.append(block)
+
+ if cmd == "code":
+ block = dict()
+ block["type"] = "code"
+ block["code"] = list()
+ block["states"] = set()
+
+ for s in line.split()[1:]:
+ assert s in state_types
+ block["states"].add(s)
+
+ while True:
+ 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()))
+
+ blocks.append(block)
+
+with open(outfile, "w") as f:
+ print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f)
+ print("", file=f)
+
+ print("#include \"kernel/yosys.h\"", file=f)
+ print("#include \"kernel/sigtools.h\"", file=f)
+ print("", file=f)
+
+ print("YOSYS_NAMESPACE_BEGIN", file=f)
+ print("", file=f)
+
+ print("struct {}_pm {{".format(prefix), file=f)
+ print(" Module *module;", file=f)
+ print(" SigMap sigmap;", file=f)
+ print(" std::function<void()> on_accept;".format(prefix), file=f)
+ print("", file=f)
+
+ for index in range(len(blocks)):
+ block = blocks[index]
+ if block["type"] == "match":
+ index_types = list()
+ for entry in block["index"]:
+ index_types.append(entry[0])
+ 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(" 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(" int rollback;", file=f)
+ print("", file=f)
+
+ print(" struct state_t {", file=f)
+ for s, t in sorted(state_types.items()):
+ print(" {} {};".format(t, s), file=f)
+ print(" } st;", file=f)
+ print("", file=f)
+
+ print(" struct udata_t {", file=f)
+ for s, t in sorted(udata_types.items()):
+ print(" {} {};".format(t, s), file=f)
+ print(" } ud;", file=f)
+ print("", file=f)
+
+ for v, n in sorted(ids.items()):
+ if n[0] == "\\":
+ print(" IdString {}{{\"\\{}\"}};".format(v, n), file=f)
+ else:
+ print(" IdString {}{{\"{}\"}};".format(v, n), file=f)
+ print("", file=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(" }", 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(" }", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" void check_blacklist() {", file=f)
+ print(" if (!blacklist_dirty)", file=f)
+ print(" return;", file=f)
+ print(" blacklist_dirty = false;", file=f)
+ for index in range(len(blocks)):
+ block = blocks[index]
+ if block["type"] == "match":
+ print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f)
+ print(" rollback = {};".format(index+1), file=f)
+ print(" return;", file=f)
+ print(" }", file=f)
+ print(" rollback = 0;", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" SigSpec port(Cell *cell, IdString portname) {", file=f)
+ print(" return sigmap(cell->getPort(portname));", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" Const param(Cell *cell, IdString paramname) {", file=f)
+ print(" return cell->getParam(paramname);", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" int nusers(const SigSpec &sig) {", file=f)
+ print(" pool<Cell*> users;", file=f)
+ print(" for (auto bit : sigmap(sig))", file=f)
+ print(" for (auto user : sigusers[bit])", file=f)
+ print(" users.insert(user);", file=f)
+ print(" return GetSize(users);", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
+ print(" module(module), sigmap(module) {", file=f)
+ for s, t in sorted(udata_types.items()):
+ if t.endswith("*"):
+ print(" ud.{} = nullptr;".format(s), file=f)
+ else:
+ print(" ud.{} = {}();".format(s, t), file=f)
+ 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)):
+ block = blocks[index]
+ 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_{}_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(" } while (0);", file=f)
+
+ print(" }", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" ~{}_pm() {{".format(prefix), file=f)
+ print(" for (auto cell : autoremove_cells)", file=f)
+ print(" module->remove(cell);", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" void run(std::function<void()> on_accept_f) {", file=f)
+ print(" on_accept = on_accept_f;", file=f)
+ print(" rollback = 0;", file=f)
+ print(" blacklist_dirty = false;", file=f)
+ for s, t in sorted(state_types.items()):
+ if t.endswith("*"):
+ print(" st.{} = nullptr;".format(s), file=f)
+ else:
+ print(" st.{} = {}();".format(s, t), file=f)
+ print(" block_0();", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f)
+ print(" run([&](){on_accept_f(*this);});", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ for index in range(len(blocks)):
+ block = blocks[index]
+
+ print(" void block_{}() {{".format(index), file=f)
+
+ const_st = set()
+ nonconst_st = set()
+ restore_st = set()
+
+ for i in range(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"])
+ else:
+ assert False
+
+ if block["type"] == "code":
+ for s in block["states"]:
+ if s in const_st:
+ const_st.remove(s)
+ restore_st.add(s)
+ nonconst_st.add(s)
+ elif block["type"] == "match":
+ s = block["cell"]
+ assert s not in const_st
+ nonconst_st.add(s)
+ else:
+ assert False
+
+ for s in sorted(const_st):
+ t = state_types[s]
+ if t.endswith("*"):
+ print(" {} const &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
+ else:
+ print(" const {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
+
+ for s in sorted(nonconst_st):
+ t = state_types[s]
+ print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
+
+ if len(restore_st):
+ print("", file=f)
+ for s in sorted(restore_st):
+ t = state_types[s]
+ print(" {} backup_{} = {};".format(t, s, s), file=f)
+
+ if block["type"] == "code":
+ print("", file=f)
+ print(" do {", file=f)
+ print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f)
+ print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f)
+ print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
+
+ for line in block["code"]:
+ print(" " + line, file=f)
+
+ print("", file=f)
+ print(" block_{}();".format(index+1), file=f)
+ print("#undef reject", file=f)
+ print("#undef accept", file=f)
+ print("#undef branch", file=f)
+ print(" } while (0);", file=f)
+ print("", file=f)
+ print("rollback_label:", file=f)
+ print(" YS_ATTRIBUTE(unused);", file=f)
+
+ if len(restore_st) or len(nonconst_st):
+ print("", file=f)
+ for s in sorted(restore_st):
+ t = state_types[s]
+ print(" {} = backup_{};".format(s, s), file=f)
+ for s in sorted(nonconst_st):
+ if s not in restore_st:
+ t = state_types[s]
+ if t.endswith("*"):
+ print(" {} = nullptr;".format(s), file=f)
+ else:
+ print(" {} = {}();".format(s, t), file=f)
+
+ elif block["type"] == "match":
+ assert len(restore_st) == 0
+
+ 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(" return;", file=f)
+ print(" }", file=f)
+
+ print("", file=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("", 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)
+ 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(" }", file=f)
+ print(" rollback = 0;", file=f)
+ print(" }", file=f)
+ print(" }", file=f)
+
+ print("", file=f)
+ print(" {} = nullptr;".format(block["cell"]), file=f)
+
+ if block["optional"]:
+ print(" block_{}();".format(index+1), file=f)
+
+ else:
+ assert False
+
+
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" void block_{}() {{".format(len(blocks)), file=f)
+ print(" on_accept();", file=f)
+ print(" check_blacklist();", file=f)
+ print(" }", file=f)
+ print("};", file=f)
+
+ print("", file=f)
+ print("YOSYS_NAMESPACE_END", file=f)
+
+# pp.pprint(blocks)
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index b9e43d1d..52141a8e 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -77,18 +77,42 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did
}
else
{
- bool all_cases_are_empty = true;
- for (auto cs : sw->cases) {
- if (cs->actions.size() != 0 || cs->switches.size() != 0)
- all_cases_are_empty = false;
+ bool all_fully_def = true;
+ for (auto cs : sw->cases)
+ {
if (max_depth != 0)
proc_clean_case(cs, did_something, count, max_depth-1);
+ int size = 0;
+ for (auto cmp : cs->compare)
+ {
+ size += cmp.size();
+ if (!cmp.is_fully_def())
+ all_fully_def = false;
+ }
+ if (sw->signal.size() != size)
+ all_fully_def = false;
}
- if (all_cases_are_empty) {
- did_something = true;
- for (auto cs : sw->cases)
- delete cs;
- sw->cases.clear();
+ if (all_fully_def)
+ {
+ for (auto cs = sw->cases.begin(); cs != sw->cases.end();)
+ {
+ if ((*cs)->empty())
+ {
+ did_something = true;
+ delete *cs;
+ cs = sw->cases.erase(cs);
+ }
+ else ++cs;
+ }
+ }
+ else
+ {
+ while (!sw->cases.empty() && sw->cases.back()->empty())
+ {
+ did_something = true;
+ delete sw->cases.back();
+ sw->cases.pop_back();
+ }
}
}
}
@@ -106,7 +130,7 @@ void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int m
}
for (size_t i = 0; i < cs->switches.size(); i++) {
RTLIL::SwitchRule *sw = cs->switches[i];
- if (sw->cases.size() == 0) {
+ if (sw->empty()) {
cs->switches.erase(cs->switches.begin() + (i--));
did_something = true;
delete sw;
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index 8ab0280c..fc3ac879 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -8,4 +8,8 @@ OBJS += passes/sat/expose.o
OBJS += passes/sat/assertpmux.o
OBJS += passes/sat/clk2fflogic.o
OBJS += passes/sat/async2sync.o
+OBJS += passes/sat/supercover.o
+OBJS += passes/sat/fmcombine.o
+OBJS += passes/sat/mutate.o
+OBJS += passes/sat/cutpoint.o
diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc
index c92db711..d045d0dc 100644
--- a/passes/sat/async2sync.cc
+++ b/passes/sat/async2sync.cc
@@ -39,7 +39,7 @@ struct Async2syncPass : public Pass {
log("reset value in the next cycle regardless of the data-in value at the time of\n");
log("the clock edge.\n");
log("\n");
- log("Currently only $adff cells are supported by this pass.\n");
+ log("Currently only $adff and $dffsr cells are supported by this pass.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -84,7 +84,7 @@ struct Async2syncPass : public Pass {
bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool();
Const arst_val = cell->parameters["\\ARST_VALUE"];
- SigSpec sig_clk = cell->getPort("\\CLK");
+ // SigSpec sig_clk = cell->getPort("\\CLK");
SigSpec sig_arst = cell->getPort("\\ARST");
SigSpec sig_d = cell->getPort("\\D");
SigSpec sig_q = cell->getPort("\\Q");
@@ -120,6 +120,55 @@ struct Async2syncPass : public Pass {
cell->type = "$dff";
continue;
}
+
+ if (cell->type.in("$dffsr"))
+ {
+ // bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool();
+ bool set_pol = cell->parameters["\\SET_POLARITY"].as_bool();
+ bool clr_pol = cell->parameters["\\CLR_POLARITY"].as_bool();
+
+ // SigSpec sig_clk = cell->getPort("\\CLK");
+ SigSpec sig_set = cell->getPort("\\SET");
+ SigSpec sig_clr = cell->getPort("\\CLR");
+ SigSpec sig_d = cell->getPort("\\D");
+ SigSpec sig_q = cell->getPort("\\Q");
+
+ log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(sig_set), log_signal(sig_clr), log_signal(sig_d), log_signal(sig_q));
+
+ Const init_val;
+ for (int i = 0; i < GetSize(sig_q); i++) {
+ SigBit bit = sigmap(sig_q[i]);
+ init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
+ del_initbits.insert(bit);
+ }
+
+ Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
+ Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
+ new_q->attributes["\\init"] = init_val;
+
+ if (!set_pol)
+ sig_set = module->Not(NEW_ID, sig_set);
+
+ if (clr_pol)
+ sig_clr = module->Not(NEW_ID, sig_clr);
+
+ SigSpec tmp = module->Or(NEW_ID, sig_d, sig_set);
+ module->addAnd(NEW_ID, tmp, sig_clr, new_d);
+
+ tmp = module->Or(NEW_ID, new_q, sig_set);
+ module->addAnd(NEW_ID, tmp, sig_clr, sig_q);
+
+ cell->setPort("\\D", new_d);
+ cell->setPort("\\Q", new_q);
+ cell->unsetPort("\\SET");
+ cell->unsetPort("\\CLR");
+ cell->unsetParam("\\SET_POLARITY");
+ cell->unsetParam("\\CLR_POLARITY");
+ cell->type = "$dff";
+ continue;
+ }
}
for (auto wire : module->wires())
diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc
new file mode 100644
index 00000000..048aec7f
--- /dev/null
+++ b/passes/sat/cutpoint.cc
@@ -0,0 +1,168 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct CutpointPass : public Pass {
+ CutpointPass() : Pass("cutpoint", "add hi/lo cover cells for each wire bit") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" cutpoint [options] [selection]\n");
+ log("\n");
+ log("This command adds formal cut points to the design.\n");
+ log("\n");
+ log(" -undef\n");
+ log(" set cupoint nets to undef (x). the default behavior is to create a\n");
+ log(" $anyseq cell and drive the cutpoint net from that\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool flag_undef = false;
+
+ log_header(design, "Executing CUTPOINT pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-undef") {
+ flag_undef = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ if (design->selected_whole_module(module->name)) {
+ log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module));
+ module->new_connections(std::vector<RTLIL::SigSig>());
+ for (auto cell : vector<Cell*>(module->cells()))
+ module->remove(cell);
+ vector<Wire*> output_wires;
+ for (auto wire : module->wires())
+ if (wire->port_output)
+ output_wires.push_back(wire);
+ for (auto wire : output_wires)
+ module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire)));
+ continue;
+ }
+
+ SigMap sigmap(module);
+ pool<SigBit> cutpoint_bits;
+
+ for (auto cell : module->selected_cells()) {
+ if (cell->type == "$anyseq")
+ continue;
+ log("Removing cell %s.%s, making all cell outputs cutpoints.\n", log_id(module), log_id(cell));
+ for (auto &conn : cell->connections()) {
+ if (cell->output(conn.first))
+ module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second)));
+ }
+ module->remove(cell);
+ }
+
+ for (auto wire : module->selected_wires()) {
+ if (wire->port_output) {
+ log("Making output wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
+ Wire *new_wire = module->addWire(NEW_ID, wire);
+ module->swap_names(wire, new_wire);
+ module->connect(new_wire, flag_undef ? Const(State::Sx, GetSize(new_wire)) : module->Anyseq(NEW_ID, GetSize(new_wire)));
+ wire->port_id = 0;
+ wire->port_input = false;
+ wire->port_output = false;
+ continue;
+ }
+ log("Making wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
+ for (auto bit : sigmap(wire))
+ cutpoint_bits.insert(bit);
+ }
+
+ if (!cutpoint_bits.empty())
+ {
+ for (auto cell : module->cells()) {
+ for (auto &conn : cell->connections()) {
+ if (!cell->output(conn.first))
+ continue;
+ SigSpec sig = sigmap(conn.second);
+ int bit_count = 0;
+ for (auto &bit : sig) {
+ if (cutpoint_bits.count(bit))
+ bit_count++;
+ }
+ if (bit_count == 0)
+ continue;
+ SigSpec dummy = module->addWire(NEW_ID, bit_count);
+ bit_count = 0;
+ for (auto &bit : sig) {
+ if (cutpoint_bits.count(bit))
+ bit = dummy[bit_count++];
+ }
+ cell->setPort(conn.first, sig);
+ }
+ }
+
+ vector<Wire*> rewrite_wires;
+ for (auto wire : module->wires()) {
+ if (!wire->port_input)
+ continue;
+ int bit_count = 0;
+ for (auto &bit : sigmap(wire))
+ if (cutpoint_bits.count(bit))
+ bit_count++;
+ if (bit_count)
+ rewrite_wires.push_back(wire);
+ }
+
+ for (auto wire : rewrite_wires) {
+ Wire *new_wire = module->addWire(NEW_ID, wire);
+ SigSpec lhs, rhs, sig = sigmap(wire);
+ for (int i = 0; i < GetSize(sig); i++)
+ if (!cutpoint_bits.count(sig[i])) {
+ lhs.append(SigBit(wire, i));
+ rhs.append(SigBit(new_wire, i));
+ }
+ if (GetSize(lhs))
+ module->connect(lhs, rhs);
+ module->swap_names(wire, new_wire);
+ wire->port_id = 0;
+ wire->port_input = false;
+ wire->port_output = false;
+ }
+
+ SigSpec sig(cutpoint_bits);
+ sig.sort_and_unify();
+
+ for (auto chunk : sig.chunks()) {
+ SigSpec s(chunk);
+ module->connect(s, flag_undef ? Const(State::Sx, GetSize(s)) : module->Anyseq(NEW_ID, GetSize(s)));
+ }
+ }
+ }
+ }
+} CutpointPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc
new file mode 100644
index 00000000..cd75ca86
--- /dev/null
+++ b/passes/sat/fmcombine.cc
@@ -0,0 +1,341 @@
+/*
+ * 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 "kernel/celltypes.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct opts_t
+{
+ bool fwd = false;
+ bool bwd = false;
+ bool nop = false;
+};
+
+struct FmcombineWorker
+{
+ const opts_t &opts;
+ Design *design;
+ Module *original = nullptr;
+ Module *module = nullptr;
+ IdString orig_type, combined_type;
+
+ FmcombineWorker(Design *design, IdString orig_type, const opts_t &opts) :
+ opts(opts), design(design), original(design->module(orig_type)),
+ orig_type(orig_type), combined_type("$fmcombine" + orig_type.str())
+ {
+ }
+
+ SigSpec import_sig(SigSpec sig, const string &suffix)
+ {
+ SigSpec newsig;
+ for (auto chunk : sig.chunks()) {
+ if (chunk.wire != nullptr)
+ chunk.wire = module->wire(chunk.wire->name.str() + suffix);
+ newsig.append(chunk);
+ }
+ return newsig;
+ }
+
+ void import_prim_cell(Cell *cell, const string &suffix)
+ {
+ Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
+ c->parameters = cell->parameters;
+ c->attributes = cell->attributes;
+
+ for (auto &conn : cell->connections())
+ c->setPort(conn.first, import_sig(conn.second, suffix));
+ }
+
+ void import_hier_cell(Cell *cell)
+ {
+ if (!cell->parameters.empty())
+ log_cmd_error("Cell %s.%s has unresolved instance parameters.\n", log_id(original), log_id(cell));
+
+ FmcombineWorker sub_worker(design, cell->type, opts);
+ sub_worker.generate();
+
+ Cell *c = module->addCell(cell->name.str() + "_combined", sub_worker.combined_type);
+ // c->parameters = cell->parameters;
+ c->attributes = cell->attributes;
+
+ for (auto &conn : cell->connections()) {
+ c->setPort(conn.first.str() + "_gold", import_sig(conn.second, "_gold"));
+ c->setPort(conn.first.str() + "_gate", import_sig(conn.second, "_gate"));
+ }
+ }
+
+ void generate()
+ {
+ if (design->module(combined_type)) {
+ // log("Combined module %s already exists.\n", log_id(combined_type));
+ return;
+ }
+
+ log("Generating combined module %s from module %s.\n", log_id(combined_type), log_id(orig_type));
+ module = design->addModule(combined_type);
+
+ for (auto wire : original->wires()) {
+ module->addWire(wire->name.str() + "_gold", wire);
+ module->addWire(wire->name.str() + "_gate", wire);
+ }
+ module->fixup_ports();
+
+ for (auto cell : original->cells()) {
+ if (design->module(cell->type) == nullptr) {
+ import_prim_cell(cell, "_gold");
+ import_prim_cell(cell, "_gate");
+ } else {
+ import_hier_cell(cell);
+ }
+ }
+
+ for (auto &conn : original->connections()) {
+ module->connect(import_sig(conn.first, "_gold"), import_sig(conn.second, "_gold"));
+ module->connect(import_sig(conn.first, "_gate"), import_sig(conn.second, "_gate"));
+ }
+
+ if (opts.nop)
+ return;
+
+ CellTypes ct;
+ ct.setup_internals_eval();
+ ct.setup_stdcells_eval();
+
+ SigMap sigmap(module);
+
+ dict<SigBit, SigBit> data_bit_to_eq_net;
+ dict<Cell*, SigSpec> cell_to_eq_nets;
+ dict<SigSpec, SigSpec> reduce_db;
+ dict<SigSpec, SigSpec> invert_db;
+
+ for (auto cell : original->cells())
+ {
+ if (!ct.cell_known(cell->type))
+ continue;
+
+ for (auto &conn : cell->connections())
+ {
+ if (!cell->output(conn.first))
+ continue;
+
+ SigSpec A = import_sig(conn.second, "_gold");
+ SigSpec B = import_sig(conn.second, "_gate");
+ SigBit EQ = module->Eq(NEW_ID, A, B);
+
+ for (auto bit : sigmap({A, B}))
+ data_bit_to_eq_net[bit] = EQ;
+
+ cell_to_eq_nets[cell].append(EQ);
+ }
+ }
+
+ for (auto cell : original->cells())
+ {
+ if (!ct.cell_known(cell->type))
+ continue;
+
+ bool skip_cell = !cell_to_eq_nets.count(cell);
+ pool<SigBit> src_eq_bits;
+
+ for (auto &conn : cell->connections())
+ {
+ if (skip_cell)
+ break;
+
+ if (cell->output(conn.first))
+ continue;
+
+ SigSpec A = import_sig(conn.second, "_gold");
+ SigSpec B = import_sig(conn.second, "_gate");
+
+ for (auto bit : sigmap({A, B})) {
+ if (data_bit_to_eq_net.count(bit))
+ src_eq_bits.insert(data_bit_to_eq_net.at(bit));
+ else
+ skip_cell = true;
+ }
+ }
+
+ if (!skip_cell) {
+ SigSpec antecedent = SigSpec(src_eq_bits);
+ antecedent.sort_and_unify();
+
+ if (GetSize(antecedent) > 1) {
+ if (reduce_db.count(antecedent) == 0)
+ reduce_db[antecedent] = module->ReduceAnd(NEW_ID, antecedent);
+ antecedent = reduce_db.at(antecedent);
+ }
+
+ SigSpec consequent = cell_to_eq_nets.at(cell);
+ consequent.sort_and_unify();
+
+ if (GetSize(consequent) > 1) {
+ if (reduce_db.count(consequent) == 0)
+ reduce_db[consequent] = module->ReduceAnd(NEW_ID, consequent);
+ consequent = reduce_db.at(consequent);
+ }
+
+ if (opts.fwd)
+ module->addAssume(NEW_ID, consequent, antecedent);
+
+ if (opts.bwd)
+ {
+ if (invert_db.count(antecedent) == 0)
+ invert_db[antecedent] = module->Not(NEW_ID, antecedent);
+
+ if (invert_db.count(consequent) == 0)
+ invert_db[consequent] = module->Not(NEW_ID, consequent);
+
+ module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent));
+ }
+ }
+ }
+ }
+};
+
+struct FmcombinePass : public Pass {
+ FmcombinePass() : Pass("fmcombine", "combine two instances of a cell into one") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" fmcombine [options] module_name gold_cell gate_cell\n");
+ // log(" fmcombine [options] @gold_cell @gate_cell\n");
+ log("\n");
+ log("This pass takes two cells, which are instances of the same module, and replaces\n");
+ log("them with one instance of a special 'combined' module, that effectively\n");
+ log("contains two copies of the original module, plus some formal properties.\n");
+ log("\n");
+ log("This is useful for formal test benches that check what differences in behavior\n");
+ log("a slight difference in input causes in a module.\n");
+ log("\n");
+ log(" -fwd\n");
+ log(" Insert forward hint assumptions into the combined module.\n");
+ log("\n");
+ log(" -bwd\n");
+ log(" Insert backward hint assumptions into the combined module.\n");
+ log(" (Backward hints are logically equivalend to fordward hits, but\n");
+ log(" some solvers are faster with bwd hints, or even both -bwd and -fwd.)\n");
+ log("\n");
+ log(" -nop\n");
+ log(" Don't insert hint assumptions into the combined module.\n");
+ log(" (This should not provide any speedup over the original design, but\n");
+ log(" strangely sometimes it does.)\n");
+ log("\n");
+ log("If none of -fwd, -bwd, and -nop is given, then -fwd is used as default.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ opts_t opts;
+ Module *module = nullptr;
+ Cell *gold_cell = nullptr;
+ Cell *gate_cell = nullptr;
+
+ log_header(design, "Executing FMCOMBINE pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-o" && argidx+1 < args.size()) {
+ // filename = args[++argidx];
+ // continue;
+ // }
+ if (args[argidx] == "-fwd") {
+ opts.fwd = true;
+ continue;
+ }
+ if (args[argidx] == "-bwd") {
+ opts.bwd = true;
+ continue;
+ }
+ if (args[argidx] == "-nop") {
+ opts.nop = true;
+ continue;
+ }
+ break;
+ }
+ if (argidx+2 == args.size())
+ {
+ string gold_name = args[argidx++];
+ string gate_name = args[argidx++];
+ log_cmd_error("fmcombine @gold_cell @gate_cell call style is not implemented yet.");
+ }
+ else if (argidx+3 == args.size())
+ {
+ IdString module_name = RTLIL::escape_id(args[argidx++]);
+ IdString gold_name = RTLIL::escape_id(args[argidx++]);
+ IdString gate_name = RTLIL::escape_id(args[argidx++]);
+
+ module = design->module(module_name);
+ if (module == nullptr)
+ log_cmd_error("Module %s not found.\n", log_id(module_name));
+
+ gold_cell = module->cell(gold_name);
+ if (gold_cell == nullptr)
+ log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gold_name), log_id(module));
+
+ gate_cell = module->cell(gate_name);
+ if (gate_cell == nullptr)
+ log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gate_name), log_id(module));
+ }
+ else
+ {
+ log_cmd_error("Invalid number of arguments.\n");
+ }
+ // extra_args(args, argidx, design);
+
+ if (opts.nop && (opts.fwd || opts.bwd))
+ log_cmd_error("Option -nop can not be combined with -fwd and/or -bwd.\n");
+
+ if (!opts.nop && !opts.fwd && !opts.bwd)
+ opts.fwd = true;
+
+ if (gold_cell->type != gate_cell->type)
+ log_cmd_error("Types of gold and gate cells do not match.\n");
+ if (!gold_cell->parameters.empty())
+ log_cmd_error("Gold cell has unresolved instance parameters.\n");
+ if (!gate_cell->parameters.empty())
+ log_cmd_error("Gold cell has unresolved instance parameters.\n");
+
+ FmcombineWorker worker(design, gold_cell->type, opts);
+ worker.generate();
+ IdString combined_cell_name = module->uniquify(stringf("\\%s_%s", log_id(gold_cell), log_id(gate_cell)));
+
+ Cell *cell = module->addCell(combined_cell_name, worker.combined_type);
+ cell->attributes = gold_cell->attributes;
+ cell->add_strpool_attribute("\\src", gate_cell->get_strpool_attribute("\\src"));
+
+ log("Combining cells %s and %s in module %s into new cell %s.\n", log_id(gold_cell), log_id(gate_cell), log_id(module), log_id(cell));
+
+ for (auto &conn : gold_cell->connections())
+ cell->setPort(conn.first.str() + "_gold", conn.second);
+ module->remove(gold_cell);
+
+ for (auto &conn : gate_cell->connections())
+ cell->setPort(conn.first.str() + "_gate", conn.second);
+ module->remove(gate_cell);
+ }
+} FmcombinePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc
new file mode 100644
index 00000000..c50678c5
--- /dev/null
+++ b/passes/sat/mutate.cc
@@ -0,0 +1,956 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct mutate_t {
+ string mode;
+ pool<string> src;
+ IdString module, cell;
+ IdString port, wire;
+ int portbit = -1;
+ int ctrlbit = -1;
+ int wirebit = -1;
+ bool used = false;
+};
+
+struct mutate_opts_t {
+ int seed = 0;
+ std::string mode;
+ pool<string> src;
+ IdString module, cell, port, wire;
+ int portbit = -1;
+ int ctrlbit = -1;
+ int wirebit = -1;
+
+ IdString ctrl_name;
+ int ctrl_width = -1, ctrl_value = -1;
+
+ bool none = false;
+
+ int pick_cover_prcnt = 80;
+
+ int weight_cover = 500;
+
+ int weight_pq_w = 100;
+ int weight_pq_b = 100;
+ int weight_pq_c = 100;
+ int weight_pq_s = 100;
+
+ int weight_pq_mw = 100;
+ int weight_pq_mb = 100;
+ int weight_pq_mc = 100;
+ int weight_pq_ms = 100;
+};
+
+void database_add(std::vector<mutate_t> &database, const mutate_opts_t &opts, const mutate_t &entry)
+{
+ if (!opts.mode.empty() && opts.mode != entry.mode)
+ return;
+
+ if (!opts.src.empty()) {
+ bool found_match = false;
+ for (auto &s : opts.src) {
+ if (entry.src.count(s))
+ found_match = true;
+ }
+ if (!found_match)
+ return;
+ }
+
+ if (!opts.module.empty() && opts.module != entry.module)
+ return;
+
+ if (!opts.cell.empty() && opts.cell != entry.cell)
+ return;
+
+ if (!opts.port.empty() && opts.port != entry.port)
+ return;
+
+ if (opts.portbit >= 0 && opts.portbit != entry.portbit)
+ return;
+
+ if (opts.ctrlbit >= 0 && opts.ctrlbit != entry.ctrlbit)
+ return;
+
+ if (!opts.wire.empty() && opts.wire != entry.wire)
+ return;
+
+ if (opts.wirebit >= 0 && opts.wirebit != entry.wirebit)
+ return;
+
+ database.push_back(entry);
+}
+
+struct xs128_t
+{
+ uint32_t x = 123456789;
+ uint32_t y = 0, z = 0, w = 0;
+
+ xs128_t(int seed = 0) : w(seed) {
+ next();
+ next();
+ next();
+ }
+
+ void next() {
+ uint32_t t = x ^ (x << 11);
+ x = y, y = z, z = w;
+ w ^= (w >> 19) ^ t ^ (t >> 8);
+ }
+
+ int operator()() {
+ next();
+ return w & 0x3fffffff;
+ }
+
+ int operator()(int n) {
+ if (n < 2)
+ return 0;
+ while (1) {
+ int k = (*this)(), p = k % n;
+ if ((k - p + n) <= 0x40000000)
+ return p;
+ }
+ }
+};
+
+struct coverdb_t
+{
+ dict<string, int> src_db;
+ dict<tuple<IdString, IdString>, int> wire_db;
+ dict<tuple<IdString, IdString, int>, int> wirebit_db;
+
+ void insert(const mutate_t &m) {
+ if (!m.wire.empty()) {
+ wire_db[tuple<IdString, IdString>(m.module, m.wire)] = 0;
+ wirebit_db[tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)] = 0;
+ }
+ for (auto &s : m.src) {
+ src_db[s] = 0;
+ }
+ }
+
+ void update(const mutate_t &m) {
+ if (!m.wire.empty()) {
+ wire_db.at(tuple<IdString, IdString>(m.module, m.wire))++;
+ wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit))++;
+ }
+ for (auto &s : m.src) {
+ src_db.at(s)++;
+ }
+ }
+
+ int score(const mutate_t &m) {
+ int this_score = m.src.empty() ? 0 : 1;
+ if (!m.wire.empty()) {
+ this_score += wire_db.at(tuple<IdString, IdString>(m.module, m.wire)) ? 0 : 5;
+ this_score += wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)) ? 0 : 1;
+ }
+ for (auto &s : m.src) {
+ this_score += src_db.at(s) ? 0 : 5;
+ }
+ return this_score;
+ }
+};
+
+struct mutate_queue_t
+{
+ pool<mutate_t*, hash_ptr_ops> db;
+
+ mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
+ mutate_t *m = nullptr;
+ if (rng(100) < opts.pick_cover_prcnt) {
+ vector<mutate_t*> candidates, rmqueue;
+ int best_score = -1;
+ for (auto p : db) {
+ if (p->used) {
+ rmqueue.push_back(p);
+ continue;
+ }
+ int this_score = coverdb.score(*p);
+ if (this_score > best_score) {
+ best_score = this_score;
+ candidates.clear();
+ }
+ if (best_score == this_score)
+ candidates.push_back(p);
+ }
+ for (auto p : rmqueue)
+ db.erase(p);
+ if (!candidates.empty())
+ m = candidates[rng(GetSize(candidates))];
+ }
+ if (m == nullptr) {
+ while (!db.empty()) {
+ int i = rng(GetSize(db));
+ auto it = db.element(i);
+ mutate_t *p = *it;
+ db.erase(it);
+ if (p->used == false) {
+ m = p;
+ break;
+ }
+ }
+ }
+ return m;
+ }
+
+ void add(mutate_t *m) {
+ db.insert(m);
+ }
+};
+
+template <typename K, typename T>
+struct mutate_chain_queue_t
+{
+ dict<K, T> db;
+
+ mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
+ while (!db.empty()) {
+ int i = rng(GetSize(db));
+ auto it = db.element(i);
+ mutate_t *m = it->second.pick(rng, coverdb, opts);
+ if (m != nullptr)
+ return m;
+ db.erase(it);
+ }
+ return nullptr;
+ }
+
+ template<typename... Args>
+ void add(mutate_t *m, K key, Args... args) {
+ db[key].add(m, args...);
+ }
+};
+
+template <typename K, typename T>
+struct mutate_once_queue_t
+{
+ dict<K, T> db;
+
+ mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
+ while (!db.empty()) {
+ int i = rng(GetSize(db));
+ auto it = db.element(i);
+ mutate_t *m = it->second.pick(rng, coverdb, opts);
+ db.erase(it);
+ if (m != nullptr)
+ return m;
+ }
+ return nullptr;
+ }
+
+ template<typename... Args>
+ void add(mutate_t *m, K key, Args... args) {
+ db[key].add(m, args...);
+ }
+};
+
+void database_reduce(std::vector<mutate_t> &database, const mutate_opts_t &opts, int N, xs128_t &rng)
+{
+ std::vector<mutate_t> new_database;
+ coverdb_t coverdb;
+
+ int total_weight = opts.weight_cover + opts.weight_pq_w + opts.weight_pq_b + opts.weight_pq_c + opts.weight_pq_s;
+ total_weight += opts.weight_pq_mw + opts.weight_pq_mb + opts.weight_pq_mc + opts.weight_pq_ms;
+
+ if (N >= GetSize(database))
+ return;
+
+ mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_wire;
+ mutate_once_queue_t<tuple<IdString, IdString, int>, mutate_queue_t> primary_queue_bit;
+ mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_cell;
+ mutate_once_queue_t<string, mutate_queue_t> primary_queue_src;
+
+ mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_wire;
+ mutate_chain_queue_t<IdString, mutate_once_queue_t<pair<IdString, int>, mutate_queue_t>> primary_queue_module_bit;
+ mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_cell;
+ mutate_chain_queue_t<IdString, mutate_once_queue_t<string, mutate_queue_t>> primary_queue_module_src;
+
+ for (auto &m : database)
+ {
+ coverdb.insert(m);
+
+ if (!m.wire.empty()) {
+ primary_queue_wire.add(&m, tuple<IdString, IdString>(m.module, m.wire));
+ primary_queue_bit.add(&m, tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit));
+ primary_queue_module_wire.add(&m, m.module, m.wire);
+ primary_queue_module_bit.add(&m, m.module, pair<IdString, int>(m.wire, m.wirebit));
+ }
+
+ primary_queue_cell.add(&m, tuple<IdString, IdString>(m.module, m.cell));
+ primary_queue_module_cell.add(&m, m.module, m.cell);
+
+ for (auto &s : m.src) {
+ primary_queue_src.add(&m, s);
+ primary_queue_module_src.add(&m, m.module, s);
+ }
+ }
+
+ vector<mutate_t*> cover_candidates;
+ int best_cover_score = -1;
+ bool skip_cover = false;
+
+ while (GetSize(new_database) < N)
+ {
+ int k = rng(total_weight);
+
+ k -= opts.weight_cover;
+ if (k < 0) {
+ while (!skip_cover) {
+ if (cover_candidates.empty()) {
+ best_cover_score = -1;
+ for (auto &m : database) {
+ if (m.used || m.src.empty())
+ continue;
+ int this_score = -1;
+ for (auto &s : m.src) {
+ if (this_score == -1 || this_score > coverdb.src_db.at(s))
+ this_score = coverdb.src_db.at(s);
+ }
+ log_assert(this_score != -1);
+ if (best_cover_score == -1 || this_score < best_cover_score) {
+ cover_candidates.clear();
+ best_cover_score = this_score;
+ }
+ if (best_cover_score == this_score)
+ cover_candidates.push_back(&m);
+ }
+ if (best_cover_score == -1) {
+ skip_cover = true;
+ break;
+ }
+ }
+
+ mutate_t *m = nullptr;
+ while (!cover_candidates.empty())
+ {
+ int idx = rng(GetSize(cover_candidates));
+ mutate_t *p = cover_candidates[idx];
+ cover_candidates[idx] = cover_candidates.back();
+ cover_candidates.pop_back();
+
+ if (p->used)
+ continue;
+
+ int this_score = -1;
+ for (auto &s : p->src) {
+ if (this_score == -1 || this_score > coverdb.src_db.at(s))
+ this_score = coverdb.src_db.at(s);
+ }
+
+ if (this_score != best_cover_score)
+ continue;
+
+ m = p;
+ break;
+ }
+
+ if (m != nullptr) {
+ m->used = true;
+ coverdb.update(*m);
+ new_database.push_back(*m);
+ break;
+ }
+ }
+ continue;
+ }
+
+#define X(__wght, __queue) \
+ k -= __wght; \
+ if (k < 0) { \
+ mutate_t *m = __queue.pick(rng, coverdb, opts); \
+ if (m != nullptr) { \
+ m->used = true; \
+ coverdb.update(*m); \
+ new_database.push_back(*m); \
+ }; \
+ continue; \
+ }
+
+ X(opts.weight_pq_w, primary_queue_wire)
+ X(opts.weight_pq_b, primary_queue_bit)
+ X(opts.weight_pq_c, primary_queue_cell)
+ X(opts.weight_pq_s, primary_queue_src)
+
+ X(opts.weight_pq_mw, primary_queue_module_wire)
+ X(opts.weight_pq_mb, primary_queue_module_bit)
+ X(opts.weight_pq_mc, primary_queue_module_cell)
+ X(opts.weight_pq_ms, primary_queue_module_src)
+#undef X
+ }
+
+ std::swap(new_database, database);
+
+ int covered_src_cnt = 0;
+ int covered_wire_cnt = 0;
+ int covered_wirebit_cnt = 0;
+
+ for (auto &it : coverdb.src_db)
+ if (it.second)
+ covered_src_cnt++;
+
+ for (auto &it : coverdb.wire_db)
+ if (it.second)
+ covered_wire_cnt++;
+
+ for (auto &it : coverdb.wirebit_db)
+ if (it.second)
+ covered_wirebit_cnt++;
+
+ log("Covered %d/%d src attributes (%.2f%%).\n", covered_src_cnt, GetSize(coverdb.src_db), 100.0 * covered_src_cnt / GetSize(coverdb.src_db));
+ log("Covered %d/%d wires (%.2f%%).\n", covered_wire_cnt, GetSize(coverdb.wire_db), 100.0 * covered_wire_cnt / GetSize(coverdb.wire_db));
+ log("Covered %d/%d wire bits (%.2f%%).\n", covered_wirebit_cnt, GetSize(coverdb.wirebit_db), 100.0 * covered_wirebit_cnt / GetSize(coverdb.wirebit_db));
+}
+
+void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, const string &srcsfile, int N)
+{
+ pool<string> sources;
+ std::vector<mutate_t> database;
+ xs128_t rng(opts.seed);
+
+ for (auto module : design->selected_modules())
+ {
+ if (!opts.module.empty() && module->name != opts.module)
+ continue;
+
+ SigMap sigmap(module);
+ dict<SigBit, int> bit_user_cnt;
+
+ for (auto wire : module->wires()) {
+ if (wire->name[0] == '\\' && wire->attributes.count("\\src"))
+ sigmap.add(wire);
+ }
+
+ for (auto cell : module->cells()) {
+ for (auto &conn : cell->connections()) {
+ if (cell->output(conn.first))
+ continue;
+ for (auto bit : sigmap(conn.second))
+ bit_user_cnt[bit]++;
+ }
+ }
+
+ for (auto wire : module->selected_wires())
+ {
+ for (SigBit bit : SigSpec(wire))
+ {
+ SigBit sigbit = sigmap(bit);
+
+ if (bit.wire == nullptr || sigbit.wire == nullptr)
+ continue;
+
+ if (!bit.wire->port_id != !sigbit.wire->port_id) {
+ if (bit.wire->port_id)
+ sigmap.add(bit);
+ continue;
+ }
+
+ if (!bit.wire->name[0] != !sigbit.wire->name[0]) {
+ if (bit.wire->name[0] == '\\')
+ sigmap.add(bit);
+ continue;
+ }
+ }
+ }
+
+ for (auto cell : module->selected_cells())
+ {
+ if (!opts.cell.empty() && cell->name != opts.cell)
+ continue;
+
+ for (auto &conn : cell->connections())
+ {
+ for (int i = 0; i < GetSize(conn.second); i++) {
+ mutate_t entry;
+ entry.module = module->name;
+ entry.cell = cell->name;
+ entry.port = conn.first;
+ entry.portbit = i;
+
+ for (auto &s : cell->get_strpool_attribute("\\src"))
+ entry.src.insert(s);
+
+ SigBit bit = sigmap(conn.second[i]);
+ if (bit.wire && bit.wire->name[0] == '\\' && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) {
+ for (auto &s : bit.wire->get_strpool_attribute("\\src"))
+ entry.src.insert(s);
+ entry.wire = bit.wire->name;
+ entry.wirebit = bit.offset;
+ }
+
+ if (!srcsfile.empty())
+ sources.insert(entry.src.begin(), entry.src.end());
+
+ entry.mode = "inv";
+ database_add(database, opts, entry);
+
+ entry.mode = "const0";
+ database_add(database, opts, entry);
+
+ entry.mode = "const1";
+ database_add(database, opts, entry);
+
+ entry.mode = "cnot0";
+ entry.ctrlbit = rng(GetSize(conn.second));
+ if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
+ database_add(database, opts, entry);
+
+ entry.mode = "cnot1";
+ entry.ctrlbit = rng(GetSize(conn.second));
+ if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
+ database_add(database, opts, entry);
+ }
+ }
+ }
+ }
+
+ log("Raw database size: %d\n", GetSize(database));
+ if (N != 0) {
+ database_reduce(database, opts, opts.none ? N-1 : N, rng);
+ log("Reduced database size: %d\n", GetSize(database));
+ }
+
+ if (!srcsfile.empty()) {
+ std::ofstream sout;
+ sout.open(srcsfile, std::ios::out | std::ios::trunc);
+ if (!sout.is_open())
+ log_error("Could not open file \"%s\" with write access.\n", srcsfile.c_str());
+ sources.sort();
+ for (auto &s : sources)
+ sout << s << std::endl;
+ }
+
+ std::ofstream fout;
+
+ if (!filename.empty()) {
+ fout.open(filename, std::ios::out | std::ios::trunc);
+ if (!fout.is_open())
+ log_error("Could not open file \"%s\" with write access.\n", filename.c_str());
+ }
+
+ int ctrl_value = opts.ctrl_value;
+
+ if (opts.none) {
+ string str = "mutate";
+ if (!opts.ctrl_name.empty())
+ str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++);
+ str += " -mode none";
+ if (filename.empty())
+ log("%s\n", str.c_str());
+ else
+ fout << str << std::endl;
+ }
+
+ for (auto &entry : database) {
+ string str = "mutate";
+ if (!opts.ctrl_name.empty())
+ str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++);
+ str += stringf(" -mode %s", entry.mode.c_str());
+ if (!entry.module.empty())
+ str += stringf(" -module %s", log_id(entry.module));
+ if (!entry.cell.empty())
+ str += stringf(" -cell %s", log_id(entry.cell));
+ if (!entry.port.empty())
+ str += stringf(" -port %s", log_id(entry.port));
+ if (entry.portbit >= 0)
+ str += stringf(" -portbit %d", entry.portbit);
+ if (entry.ctrlbit >= 0)
+ str += stringf(" -ctrlbit %d", entry.ctrlbit);
+ if (!entry.wire.empty())
+ str += stringf(" -wire %s", log_id(entry.wire));
+ if (entry.wirebit >= 0)
+ str += stringf(" -wirebit %d", entry.wirebit);
+ for (auto &s : entry.src)
+ str += stringf(" -src %s", s.c_str());
+ if (filename.empty())
+ log("%s\n", str.c_str());
+ else
+ fout << str << std::endl;
+ }
+}
+
+SigSpec mutate_ctrl_sig(Module *module, IdString name, int width)
+{
+ Wire *ctrl_wire = module->wire(name);
+
+ if (ctrl_wire == nullptr)
+ {
+ log("Adding ctrl port %s to module %s.\n", log_id(name), log_id(module));
+
+ ctrl_wire = module->addWire(name, width);
+ ctrl_wire->port_input = true;
+ module->fixup_ports();
+
+ for (auto mod : module->design->modules())
+ for (auto cell : mod->cells())
+ {
+ if (cell->type != module->name)
+ continue;
+
+ SigSpec ctrl = mutate_ctrl_sig(mod, name, width);
+
+ log("Connecting ctrl port to cell %s in module %s.\n", log_id(cell), log_id(mod));
+ cell->setPort(name, ctrl);
+ }
+ }
+
+ log_assert(GetSize(ctrl_wire) == width);
+ return ctrl_wire;
+}
+
+SigBit mutate_ctrl(Module *module, const mutate_opts_t &opts)
+{
+ if (opts.ctrl_name.empty())
+ return State::S1;
+
+ SigSpec sig = mutate_ctrl_sig(module, opts.ctrl_name, opts.ctrl_width);
+ return module->Eq(NEW_ID, sig, Const(opts.ctrl_value, GetSize(sig)));
+}
+
+SigSpec mutate_ctrl_mux(Module *module, const mutate_opts_t &opts, SigSpec unchanged_sig, SigSpec changed_sig)
+{
+ SigBit ctrl_bit = mutate_ctrl(module, opts);
+ if (ctrl_bit == State::S0)
+ return unchanged_sig;
+ if (ctrl_bit == State::S1)
+ return changed_sig;
+ return module->Mux(NEW_ID, unchanged_sig, changed_sig, ctrl_bit);
+}
+
+void mutate_inv(Design *design, const mutate_opts_t &opts)
+{
+ Module *module = design->module(opts.module);
+ Cell *cell = module->cell(opts.cell);
+
+ SigBit bit = cell->getPort(opts.port)[opts.portbit];
+ SigBit inbit, outbit;
+
+ if (cell->input(opts.port))
+ {
+ log("Add input inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
+ SigBit outbit = module->Not(NEW_ID, bit);
+ bit = mutate_ctrl_mux(module, opts, bit, outbit);
+ }
+ else
+ {
+ log("Add output inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
+ SigBit inbit = module->addWire(NEW_ID);
+ SigBit outbit = module->Not(NEW_ID, inbit);
+ module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
+ bit = inbit;
+ }
+
+ SigSpec s = cell->getPort(opts.port);
+ s[opts.portbit] = bit;
+ cell->setPort(opts.port, s);
+}
+
+void mutate_const(Design *design, const mutate_opts_t &opts, bool one)
+{
+ Module *module = design->module(opts.module);
+ Cell *cell = module->cell(opts.cell);
+
+ SigBit bit = cell->getPort(opts.port)[opts.portbit];
+ SigBit inbit, outbit;
+
+ if (cell->input(opts.port))
+ {
+ log("Add input constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
+ SigBit outbit = one ? State::S1 : State::S0;
+ bit = mutate_ctrl_mux(module, opts, bit, outbit);
+ }
+ else
+ {
+ log("Add output constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
+ SigBit inbit = module->addWire(NEW_ID);
+ SigBit outbit = one ? State::S1 : State::S0;
+ module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
+ bit = inbit;
+ }
+
+ SigSpec s = cell->getPort(opts.port);
+ s[opts.portbit] = bit;
+ cell->setPort(opts.port, s);
+}
+
+void mutate_cnot(Design *design, const mutate_opts_t &opts, bool one)
+{
+ Module *module = design->module(opts.module);
+ Cell *cell = module->cell(opts.cell);
+
+ SigBit bit = cell->getPort(opts.port)[opts.portbit];
+ SigBit ctrl = cell->getPort(opts.port)[opts.ctrlbit];
+ SigBit inbit, outbit;
+
+ if (cell->input(opts.port))
+ {
+ log("Add input cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
+ SigBit outbit = one ? module->Xor(NEW_ID, bit, ctrl) : module->Xnor(NEW_ID, bit, ctrl);
+ bit = mutate_ctrl_mux(module, opts, bit, outbit);
+ }
+ else
+ {
+ log("Add output cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
+ SigBit inbit = module->addWire(NEW_ID);
+ SigBit outbit = one ? module->Xor(NEW_ID, inbit, ctrl) : module->Xnor(NEW_ID, inbit, ctrl);
+ module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
+ bit = inbit;
+ }
+
+ SigSpec s = cell->getPort(opts.port);
+ s[opts.portbit] = bit;
+ cell->setPort(opts.port, s);
+}
+
+struct MutatePass : public Pass {
+ MutatePass() : Pass("mutate", "generate or apply design mutations") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" mutate -list N [options] [selection]\n");
+ log("\n");
+ log("Create a list of N mutations using an even sampling.\n");
+ log("\n");
+ log(" -o filename\n");
+ log(" Write list to this file instead of console output\n");
+ log("\n");
+ log(" -s filename\n");
+ log(" Write a list of all src tags found in the design to the specified file\n");
+ log("\n");
+ log(" -seed N\n");
+ log(" RNG seed for selecting mutations\n");
+ log("\n");
+ log(" -none\n");
+ log(" Include a \"none\" mutation in the output\n");
+ log("\n");
+ log(" -ctrl name width value\n");
+ log(" Add -ctrl options to the output. Use 'value' for first mutation, then\n");
+ log(" simply count up from there.\n");
+ log("\n");
+ log(" -mode name\n");
+ log(" -module name\n");
+ log(" -cell name\n");
+ log(" -port name\n");
+ log(" -portbit int\n");
+ log(" -ctrlbit int\n");
+ log(" -wire name\n");
+ log(" -wirebit int\n");
+ log(" -src string\n");
+ log(" Filter list of mutation candidates to those matching\n");
+ log(" the given parameters.\n");
+ log("\n");
+ log(" -cfg option int\n");
+ log(" Set a configuration option. Options available:\n");
+ log(" weight_pq_w weight_pq_b weight_pq_c weight_pq_s\n");
+ log(" weight_pq_mw weight_pq_mb weight_pq_mc weight_pq_ms\n");
+ log(" weight_cover pick_cover_prcnt\n");
+ log("\n");
+ log("\n");
+ log(" mutate -mode MODE [options]\n");
+ log("\n");
+ log("Apply the given mutation.\n");
+ log("\n");
+ log(" -ctrl name width value\n");
+ log(" Add a control signal with the given name and width. The mutation is\n");
+ log(" activated if the control signal equals the given value.\n");
+ log("\n");
+ log(" -module name\n");
+ log(" -cell name\n");
+ log(" -port name\n");
+ log(" -portbit int\n");
+ log(" -ctrlbit int\n");
+ log(" Mutation parameters, as generated by 'mutate -list N'.\n");
+ log("\n");
+ log(" -wire name\n");
+ log(" -wirebit int\n");
+ log(" -src string\n");
+ log(" Ignored. (They are generated by -list for documentation purposes.)\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ mutate_opts_t opts;
+ string filename;
+ string srcsfile;
+ int N = -1;
+
+ log_header(design, "Executing MUTATE pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-list" && argidx+1 < args.size()) {
+ N = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-o" && argidx+1 < args.size()) {
+ filename = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-s" && argidx+1 < args.size()) {
+ srcsfile = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-seed" && argidx+1 < args.size()) {
+ opts.seed = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-none") {
+ opts.none = true;
+ continue;
+ }
+ if (args[argidx] == "-mode" && argidx+1 < args.size()) {
+ opts.mode = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-ctrl" && argidx+3 < args.size()) {
+ opts.ctrl_name = RTLIL::escape_id(args[++argidx]);
+ opts.ctrl_width = atoi(args[++argidx].c_str());
+ opts.ctrl_value = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-module" && argidx+1 < args.size()) {
+ opts.module = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-cell" && argidx+1 < args.size()) {
+ opts.cell = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-port" && argidx+1 < args.size()) {
+ opts.port = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-portbit" && argidx+1 < args.size()) {
+ opts.portbit = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-ctrlbit" && argidx+1 < args.size()) {
+ opts.ctrlbit = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-wire" && argidx+1 < args.size()) {
+ opts.wire = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-wirebit" && argidx+1 < args.size()) {
+ opts.wirebit = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-src" && argidx+1 < args.size()) {
+ opts.src.insert(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-cfg" && argidx+2 < args.size()) {
+ if (args[argidx+1] == "pick_cover_prcnt") {
+ opts.pick_cover_prcnt = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ if (args[argidx+1] == "weight_cover") {
+ opts.weight_cover = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ if (args[argidx+1] == "weight_pq_w") {
+ opts.weight_pq_w = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ if (args[argidx+1] == "weight_pq_b") {
+ opts.weight_pq_b = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ if (args[argidx+1] == "weight_pq_c") {
+ opts.weight_pq_c = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ if (args[argidx+1] == "weight_pq_s") {
+ opts.weight_pq_s = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ if (args[argidx+1] == "weight_pq_mw") {
+ opts.weight_pq_mw = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ if (args[argidx+1] == "weight_pq_mb") {
+ opts.weight_pq_mb = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ if (args[argidx+1] == "weight_pq_mc") {
+ opts.weight_pq_mc = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ if (args[argidx+1] == "weight_pq_ms") {
+ opts.weight_pq_ms = atoi(args[argidx+2].c_str());
+ argidx += 2;
+ continue;
+ }
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (N >= 0) {
+ mutate_list(design, opts, filename, srcsfile, N);
+ return;
+ }
+
+ if (opts.mode == "none") {
+ if (!opts.ctrl_name.empty()) {
+ Module *topmod = opts.module.empty() ? design->top_module() : design->module(opts.module);
+ if (topmod)
+ mutate_ctrl_sig(topmod, opts.ctrl_name, opts.ctrl_width);
+ }
+ return;
+ }
+
+ if (opts.mode == "inv") {
+ mutate_inv(design, opts);
+ return;
+ }
+
+ if (opts.mode == "const0" || opts.mode == "const1") {
+ mutate_const(design, opts, opts.mode == "const1");
+ return;
+ }
+
+ if (opts.mode == "cnot0" || opts.mode == "cnot1") {
+ mutate_cnot(design, opts, opts.mode == "cnot1");
+ return;
+ }
+
+ log_cmd_error("Invalid mode: %s\n", opts.mode.c_str());
+ }
+} MutatePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/supercover.cc b/passes/sat/supercover.cc
new file mode 100644
index 00000000..ba44f02d
--- /dev/null
+++ b/passes/sat/supercover.cc
@@ -0,0 +1,92 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SupercoverPass : public Pass {
+ SupercoverPass() : Pass("supercover", "add hi/lo cover cells for each wire bit") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" supercover [options] [selection]\n");
+ log("\n");
+ log("This command adds two cover cells for each bit of each selected wire, one\n");
+ log("checking for a hi signal level and one checking for lo level.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ // bool flag_noinit = false;
+
+ log_header(design, "Executing SUPERCOVER pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-noinit") {
+ // flag_noinit = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ pool<SigBit> handled_bits;
+
+ int cnt_wire = 0, cnt_bits = 0;
+ log("Adding cover cells to module %s.\n", log_id(module));
+ for (auto wire : module->selected_wires())
+ {
+ bool counted_wire = false;
+ std::string src = wire->get_src_attribute();
+
+ for (auto bit : sigmap(SigSpec(wire)))
+ {
+ if (bit.wire == nullptr)
+ continue;
+
+ if (handled_bits.count(bit))
+ continue;
+
+ SigSpec inv = module->Not(NEW_ID, bit);
+ module->addCover(NEW_ID, bit, State::S1, src);
+ module->addCover(NEW_ID, inv, State::S1, src);
+
+ handled_bits.insert(bit);
+ if (!counted_wire) {
+ counted_wire = false;
+ cnt_wire++;
+ }
+ cnt_bits++;
+ }
+ }
+ log(" added cover cells to %d wires, %d bits.\n", cnt_wire, cnt_bits);
+ }
+ }
+} SupercoverPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 4faa0ab0..cf9e198a 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -36,6 +36,7 @@ OBJS += passes/techmap/attrmvcp.o
OBJS += passes/techmap/attrmap.o
OBJS += passes/techmap/zinit.o
OBJS += passes/techmap/dff2dffs.o
+OBJS += passes/techmap/flowmap.o
endif
GENFILES += passes/techmap/techmap.inc
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index d2d15a4a..21b70f49 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -327,8 +327,26 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
}
}
-std::string remap_name(RTLIL::IdString abc_name)
+std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr)
{
+ std::string abc_sname = abc_name.substr(1);
+ if (abc_sname.substr(0, 5) == "ys__n") {
+ int sid = std::stoi(abc_sname.substr(5));
+ bool inv = abc_sname.back() == 'v';
+ for (auto sig : signal_list) {
+ if (sig.id == sid && sig.bit.wire != nullptr) {
+ std::stringstream sstr;
+ sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
+ if (sig.bit.wire->width != 1)
+ sstr << "[" << sig.bit.offset << "]";
+ if (inv)
+ sstr << "_inv";
+ if (orig_wire != nullptr)
+ *orig_wire = sig.bit.wire;
+ return sstr.str();
+ }
+ }
+ }
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
return sstr.str();
@@ -353,12 +371,12 @@ void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std:
}
for (auto n : nodes)
- fprintf(f, " n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit),
+ fprintf(f, " ys__n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit),
n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
for (auto &e : edges)
for (auto n : e.second)
- fprintf(f, " n%d -> n%d;\n", e.first, n);
+ fprintf(f, " ys__n%d -> ys__n%d;\n", e.first, n);
fprintf(f, "}\n");
}
@@ -624,7 +642,7 @@ struct abc_output_filter
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
- const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode)
+ const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, bool abc_dress)
{
module = current_module;
map_autoidx = autoidx++;
@@ -728,7 +746,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
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);
-
+ if (abc_dress)
+ abc_script += "; dress";
abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
abc_script = add_echos_to_abc_cmd(abc_script);
@@ -784,7 +803,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (auto &si : signal_list) {
if (!si.is_port || si.type != G(NONE))
continue;
- fprintf(f, " n%d", si.id);
+ fprintf(f, " ys__n%d", si.id);
pi_map[count_input++] = log_signal(si.bit);
}
if (count_input == 0)
@@ -796,17 +815,17 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (auto &si : signal_list) {
if (!si.is_port || si.type == G(NONE))
continue;
- fprintf(f, " n%d", si.id);
+ fprintf(f, " ys__n%d", si.id);
po_map[count_output++] = log_signal(si.bit);
}
fprintf(f, "\n");
for (auto &si : signal_list)
- fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.bit));
+ fprintf(f, "# ys__n%-5d %s\n", si.id, log_signal(si.bit));
for (auto &si : signal_list) {
if (si.bit.wire == NULL) {
- fprintf(f, ".names n%d\n", si.id);
+ fprintf(f, ".names ys__n%d\n", si.id);
if (si.bit == RTLIL::State::S1)
fprintf(f, "1\n");
}
@@ -815,68 +834,68 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
int count_gates = 0;
for (auto &si : signal_list) {
if (si.type == G(BUF)) {
- fprintf(f, ".names n%d n%d\n", si.in1, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id);
fprintf(f, "1 1\n");
} else if (si.type == G(NOT)) {
- fprintf(f, ".names n%d n%d\n", si.in1, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id);
fprintf(f, "0 1\n");
} else if (si.type == G(AND)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "11 1\n");
} else if (si.type == G(NAND)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "0- 1\n");
fprintf(f, "-0 1\n");
} else if (si.type == G(OR)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "-1 1\n");
fprintf(f, "1- 1\n");
} else if (si.type == G(NOR)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "00 1\n");
} else if (si.type == G(XOR)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "01 1\n");
fprintf(f, "10 1\n");
} else if (si.type == G(XNOR)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "00 1\n");
fprintf(f, "11 1\n");
} else if (si.type == G(ANDNOT)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "10 1\n");
} else if (si.type == G(ORNOT)) {
- fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id);
fprintf(f, "1- 1\n");
fprintf(f, "-0 1\n");
} else if (si.type == G(MUX)) {
- fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ 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(AOI3)) {
- fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ 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");
fprintf(f, "0-0 1\n");
} else if (si.type == G(OAI3)) {
- fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ 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");
fprintf(f, "--0 1\n");
} else if (si.type == G(AOI4)) {
- fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
fprintf(f, "-0-0 1\n");
fprintf(f, "-00- 1\n");
fprintf(f, "0--0 1\n");
fprintf(f, "0-0- 1\n");
} else if (si.type == G(OAI4)) {
- fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
+ fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
fprintf(f, "00-- 1\n");
fprintf(f, "--00 1\n");
} else if (si.type == G(FF)) {
if (si.init == State::S0 || si.init == State::S1) {
- fprintf(f, ".latch n%d n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
+ fprintf(f, ".latch ys__n%d ys__n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
recover_init = true;
} else
- fprintf(f, ".latch n%d n%d 2\n", si.in1, si.id);
+ fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id);
} else if (si.type != G(NONE))
log_abort();
if (si.type != G(NONE))
@@ -889,7 +908,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
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);
log_push();
-
if (count_output > 0)
{
log_header(design, "Executing ABC.\n");
@@ -988,7 +1006,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
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 *wire = module->addWire(remap_name(w->name));
+ 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;
design->select(module, wire);
}
@@ -1213,7 +1234,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (auto &si : signal_list)
if (si.is_port) {
char buffer[100];
- snprintf(buffer, 100, "\\n%d", si.id);
+ snprintf(buffer, 100, "\\ys__n%d", si.id);
RTLIL::SigSig conn;
if (si.type != G(NONE)) {
conn.first = si.bit;
@@ -1407,6 +1428,11 @@ struct AbcPass : public Pass {
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(" -dress\n");
+ log(" run the 'dress' command after all other ABC commands. This aims to\n");
+ log(" preserve naming by an equivalence check between the original and post-ABC\n");
+ log(" netlists (experimental).\n");
+ log("\n");
log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
log("loaded into ABC before the ABC script is executed.\n");
log("\n");
@@ -1441,6 +1467,7 @@ struct AbcPass : public Pass {
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
bool show_tempdir = false, sop_mode = false;
+ bool abc_dress = false;
vector<int> lut_costs;
markgroups = false;
@@ -1555,6 +1582,10 @@ struct AbcPass : public Pass {
map_mux16 = true;
continue;
}
+ if (arg == "-dress") {
+ abc_dress = true;
+ continue;
+ }
if (arg == "-g" && argidx+1 < args.size()) {
for (auto g : split_tokens(args[++argidx], ",")) {
vector<string> gate_list;
@@ -1704,7 +1735,7 @@ struct AbcPass : public Pass {
if (!dff_mode || !clk_str.empty()) {
abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
- delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
+ delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress);
continue;
}
@@ -1849,7 +1880,7 @@ struct AbcPass : public Pass {
en_polarity = std::get<2>(it.first);
en_sig = assign_map(std::get<3>(it.first));
abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
- keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode);
+ keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress);
assign_map.set(mod);
}
}
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
index 9f0c7bf6..47d0ff41 100644
--- a/passes/techmap/deminout.cc
+++ b/passes/techmap/deminout.cc
@@ -83,9 +83,9 @@ 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_"))
+ if (conn.first == "\\Y" && cell->type.in("$mux", "$pmux", "$_MUX_", "$_TBUF_", "$tribuf"))
{
- bool tribuf = (cell->type == "$_TBUF_");
+ bool tribuf = (cell->type == "$_TBUF_" || cell->type == "$tribuf");
if (!tribuf) {
for (auto &c : cell->connections()) {
@@ -113,7 +113,8 @@ struct DeminoutPass : public Pass {
{
if (bits_numports[bit] > 1 || bits_inout.count(bit))
new_input = true, new_output = true;
-
+ if (bit == State::S0 || bit == State::S1)
+ new_output = true;
if (bits_written.count(bit)) {
new_output = true;
if (bits_tribuf.count(bit))
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
index 3291f5a4..7e104096 100644
--- a/passes/techmap/dff2dffe.cc
+++ b/passes/techmap/dff2dffe.cc
@@ -267,6 +267,10 @@ struct Dff2dffePass : public Pass {
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("\n");
+ log(" -unmap-mince N\n");
+ log(" Same as -unmap but only unmap $dffe where the clock enable port\n");
+ log(" signal is used by less $dffe than the specified number\n");
+ log("\n");
log(" -direct <internal_gate_type> <external_gate_type>\n");
log(" map directly to external gate type. <internal_gate_type> can\n");
log(" be any internal gate-level FF cell (except $_DFFE_??_). the\n");
@@ -289,6 +293,7 @@ struct Dff2dffePass : public Pass {
log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
bool unmap_mode = false;
+ int min_ce_use = -1;
dict<IdString, IdString> direct_dict;
size_t argidx;
@@ -297,6 +302,11 @@ struct Dff2dffePass : public Pass {
unmap_mode = true;
continue;
}
+ if (args[argidx] == "-unmap-mince" && argidx + 1 < args.size()) {
+ unmap_mode = true;
+ min_ce_use = std::stoi(args[++argidx]);
+ continue;
+ }
if (args[argidx] == "-direct" && argidx + 2 < args.size()) {
string direct_from = RTLIL::escape_id(args[++argidx]);
string direct_to = RTLIL::escape_id(args[++argidx]);
@@ -343,8 +353,21 @@ struct Dff2dffePass : public Pass {
if (!mod->has_processes_warn())
{
if (unmap_mode) {
+ SigMap sigmap(mod);
for (auto cell : mod->selected_cells()) {
if (cell->type == "$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")))
+ 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())
@@ -355,6 +378,18 @@ struct Dff2dffePass : public Pass {
continue;
}
if (cell->type.substr(0, 7) == "$_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")))
+ 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";
RTLIL::SigSpec tmp = mod->addWire(NEW_ID);
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index a8eecc97..48390488 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -43,18 +43,37 @@ struct DffinitPass : public Pass {
log(" initial value of 1 or 0. (multi-bit values are not supported in this\n");
log(" mode.)\n");
log("\n");
+ log(" -strinit <string for high> <string for low> \n");
+ log(" use string values in the command line to represent a single-bit\n");
+ log(" initial value of 1 or 0. (multi-bit values are not supported in this\n");
+ log(" mode.)\n");
+ log("\n");
+ log(" -noreinit\n");
+ log(" fail if the FF cell has already a defined initial value set in other\n");
+ log(" passes and the initial value of the net it drives is not equal to\n");
+ log(" the already defined initial value.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n");
dict<IdString, dict<IdString, IdString>> ff_types;
- bool highlow_mode = false;
+ bool highlow_mode = false, noreinit = false;
+ std::string high_string, low_string;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-highlow") {
highlow_mode = true;
+ high_string = "high";
+ low_string = "low";
+ continue;
+ }
+ if (args[argidx] == "-strinit" && argidx+2 < args.size()) {
+ highlow_mode = true;
+ high_string = args[++argidx];
+ low_string = args[++argidx];
continue;
}
if (args[argidx] == "-ff" && argidx+3 < args.size()) {
@@ -64,6 +83,10 @@ struct DffinitPass : public Pass {
ff_types[cell_name][output_port] = init_param;
continue;
}
+ if (args[argidx] == "-noreinit") {
+ noreinit = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -112,6 +135,10 @@ struct DffinitPass : public Pass {
continue;
while (GetSize(value.bits) <= i)
value.bits.push_back(State::S0);
+ if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i]))
+ log_error("Trying to assign a different init value for %s.%s.%s which technically "
+ "have a conflicted init value.\n",
+ log_id(module), log_id(cell), log_id(it.second));
value.bits[i] = init_bits.at(sig[i]);
cleanup_bits.insert(sig[i]);
}
@@ -121,9 +148,9 @@ struct DffinitPass : public Pass {
log_error("Multi-bit init value for %s.%s.%s is incompatible with -highlow mode.\n",
log_id(module), log_id(cell), log_id(it.second));
if (value[0] == State::S1)
- value = Const("high");
+ value = Const(high_string);
else
- value = Const("low");
+ value = Const(low_string);
}
log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second),
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 416ed2bd..274177a6 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -100,6 +100,18 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name,
for (auto child : cell->children)
if (child->id == "pin" && child->args.size() == 1 && child->args[0] == pin_name)
return true;
+
+ /* If we end up here, the pin specified in the attribute does not exist, which is an error,
+ or, the attribute contains an expression which we do not yet support.
+ For now, we'll simply produce a warning to let the user know something is up.
+ */
+ if (pin_name.find_first_of("^*|&") == std::string::npos) {
+ log_warning("Malformed liberty file - cannot find pin '%s' in cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str());
+ }
+ else {
+ log_warning("Found unsupported expression '%s' in pin attribute of cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str());
+ }
+
return false;
}
@@ -648,8 +660,8 @@ struct DfflibmapPass : public Pass {
map_adff_to_dff("$_DFF_PP0_", "$_DFF_P_");
map_adff_to_dff("$_DFF_PP1_", "$_DFF_P_");
- log(" final dff cell mappings:\n");
- logmap_all();
+ log(" final dff cell mappings:\n");
+ logmap_all();
for (auto &it : design->modules_)
if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc
new file mode 100644
index 00000000..0b7931e4
--- /dev/null
+++ b/passes/techmap/flowmap.cc
@@ -0,0 +1,1613 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2018 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.
+ *
+ */
+
+// [[CITE]] FlowMap algorithm
+// Jason Cong; Yuzheng Ding, "An Optimal Technology Mapping Algorithm for Delay Optimization in Lookup-Table Based FPGA Designs,"
+// Computer-Aided Design of Integrated Circuits and Systems, IEEE Transactions on, Vol. 13, pp. 1-12, Jan. 1994.
+// doi: 10.1109/43.273754
+
+// [[CITE]] FlowMap-r algorithm
+// Jason Cong; Yuzheng Ding, "On Area/Depth Tradeoff in LUT-Based FPGA Technology Mapping,"
+// Very Large Scale Integration Systems, IEEE Transactions on, Vol. 2, June 1994.
+// doi: 10.1109/92.28574
+
+// Required reading material:
+//
+// Min-cut max-flow theorem:
+// https://www.coursera.org/lecture/algorithms-part2/maxflow-mincut-theorem-beb9G
+// FlowMap paper:
+// http://cadlab.cs.ucla.edu/~cong/papers/iccad92.pdf (short version)
+// https://limsk.ece.gatech.edu/book/papers/flowmap.pdf (long version)
+// FlowMap-r paper:
+// http://cadlab.cs.ucla.edu/~cong/papers/dac93.pdf (short version)
+// https://sci-hub.tw/10.1109/92.285741 (long version)
+
+// Notes on correspondence between paper and implementation:
+//
+// 1. In the FlowMap paper, the nodes are logic elements (analogous to Yosys cells) and edges are wires. However, in our implementation,
+// we use an inverted approach: the nodes are Yosys wire bits, and the edges are derived from (but aren't represented by) Yosys cells.
+// This may seem counterintuitive. Three observations may help understanding this. First, for a cell with a 1-bit Y output that is
+// the sole driver of its output net (which is the typical case), these representations are equivalent, because there is an exact
+// correspondence between cells and output wires. Second, in the paper, primary inputs (analogous to Yosys cell or module ports) are
+// nodes, and in Yosys, inputs are wires; our approach allows a direct mapping from both primary inputs and 1-output logic elements to
+// flow graph nodes. Third, Yosys cells may have multiple outputs or multi-bit outputs, and by using Yosys wire bits as flow graph nodes,
+// such cells are supported without any additional effort; any Yosys cell with n output wire bits ends up being split into n flow graph
+// nodes.
+//
+// 2. The FlowMap paper introduces three networks: Nt, Nt', and Nt''. The network Nt is directly represented by a subgraph of RTLIL graph,
+// which is parsed into an equivalent but easier to traverse representation in FlowmapWorker. The network Nt' is built explicitly
+// from a subgraph of Nt, and uses a similar representation in FlowGraph. The network Nt'' is implicit in FlowGraph, which is possible
+// because of the following observation: each Nt' node corresponds to an Nt'' edge of capacity 1, and each Nt' edge corresponds to
+// an Nt'' edge of capacity ∞. Therefore, we only need to explicitly record flow for Nt' edges and through Nt' nodes.
+//
+// 3. The FlowMap paper ambiguously states: "Moreover, we can find such a cut (X′′, X̅′′) by performing a depth first search starting at
+// the source s, and including in X′′ all the nodes which are reachable from s." This actually refers to a specific kind of search,
+// min-cut computation. Min-cut computation involves computing the set of nodes reachable from s by an undirected path with no full
+// (i.e. zero capacity) forward edges or empty (i.e. no flow) backward edges. In addition, the depth first search is required to compute
+// a max-volume max-flow min-cut specifically, because a max-flow min-cut is not, in general, unique.
+
+// Notes on implementation:
+//
+// 1. To compute depth optimal packing, an intermediate representation is used, where each cell with n output bits is split into n graph
+// nodes. Each such graph node is represented directly with the wire bit (RTLIL::SigBit instance) that corresponds to the output bit
+// it is created from. Fan-in and fan-out are represented explicitly by edge lists derived from the RTLIL graph. This IR never changes
+// after it has been computed.
+//
+// In terms of data, this IR is comprised of `inputs`, `outputs`, `nodes`, `edges_fw` and `edges_bw` fields.
+//
+// We call this IR "gate IR".
+//
+// 2. To compute area optimal packing, another intermediate representation is used, which consists of some K-feasible cone for every node
+// that exists in the gate IR. Immediately after depth optimal packing with FlowMap, each such cone occupies the lowest possible depth,
+// but this is not true in general, and transformations of this IR may change the cones, although each transformation has to keep each
+// cone K-feasible. In this IR, LUT fan-in and fan-out are represented explicitly by edge lists; if a K-feasible cone chosen for node A
+// includes nodes B and C, there are edges between all predecessors of A, B and C in the gate IR and node A in this IR. Moreover, in
+// this IR, cones may be *realized* or *derealized*. Only realized cones will end up mapped to actual LUTs in the output of this pass.
+//
+// Intuitively, this IR contains (some, ideally but not necessarily optimal) LUT representation for each input cell. By starting at outputs
+// and traversing the graph of this IR backwards, each K-feasible cone is converted to an actual LUT at the end of the pass. This is
+// the same as iterating through each realized LUT.
+//
+// The following are the invariants of this IR:
+// a) Each gate IR node corresponds to a K-feasible cut.
+// b) Each realized LUT is reachable through backward edges from some output.
+// c) The LUT fan-in is exactly the fan-in of its constituent gates minus the fan-out of its constituent gates.
+// The invariants are kept even for derealized LUTs, since the whole point of this IR is ease of packing, unpacking, and repacking LUTs.
+//
+// In terms of data, this IR is comprised of `lut_nodes` (the set of all realized LUTs), `lut_gates` (the map from a LUT to its
+// constituent gates), `lut_edges_fw` and `lut_edges_bw` fields. The `inputs` and `outputs` fields are shared with the gate IR.
+//
+// We call this IR "LUT IR".
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/modtools.h"
+#include "kernel/consteval.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct GraphStyle
+{
+ string label;
+ string color, fillcolor;
+
+ GraphStyle(string label = "", string color = "black", string fillcolor = "") :
+ label(label), color(color), fillcolor(fillcolor) {}
+};
+
+static string dot_escape(string value)
+{
+ std::string escaped;
+ for (char c : value) {
+ if (c == '\n')
+ {
+ escaped += "\\n";
+ continue;
+ }
+ if (c == '\\' || c == '"')
+ escaped += "\\";
+ escaped += c;
+ }
+ return escaped;
+}
+
+static void dump_dot_graph(string filename,
+ pool<RTLIL::SigBit> nodes, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> edges,
+ pool<RTLIL::SigBit> inputs, pool<RTLIL::SigBit> outputs,
+ std::function<GraphStyle(RTLIL::SigBit)> node_style =
+ [](RTLIL::SigBit) { return GraphStyle{}; },
+ std::function<GraphStyle(RTLIL::SigBit, RTLIL::SigBit)> edge_style =
+ [](RTLIL::SigBit, RTLIL::SigBit) { return GraphStyle{}; },
+ string name = "")
+{
+ FILE *f = fopen(filename.c_str(), "w");
+ fprintf(f, "digraph \"%s\" {\n", name.c_str());
+ fprintf(f, " rankdir=\"TB\";\n");
+
+ dict<RTLIL::SigBit, int> ids;
+ for (auto node : nodes)
+ {
+ ids[node] = ids.size();
+
+ string shape = "ellipse";
+ if (inputs[node])
+ shape = "box";
+ if (outputs[node])
+ shape = "octagon";
+ auto prop = node_style(node);
+ string style = "";
+ if (!prop.fillcolor.empty())
+ style = "filled";
+ fprintf(f, " n%d [ shape=%s, fontname=\"Monospace\", label=\"%s\", color=\"%s\", fillcolor=\"%s\", style=\"%s\" ];\n",
+ ids[node], shape.c_str(), dot_escape(prop.label.c_str()).c_str(), prop.color.c_str(), prop.fillcolor.c_str(), style.c_str());
+ }
+
+ fprintf(f, " { rank=\"source\"; ");
+ for (auto input : inputs)
+ if (nodes[input])
+ fprintf(f, "n%d; ", ids[input]);
+ fprintf(f, "}\n");
+
+ fprintf(f, " { rank=\"sink\"; ");
+ for (auto output : outputs)
+ if (nodes[output])
+ fprintf(f, "n%d; ", ids[output]);
+ fprintf(f, "}\n");
+
+ for (auto edge : edges)
+ {
+ auto source = edge.first;
+ for (auto sink : edge.second) {
+ if (nodes[source] && nodes[sink])
+ {
+ auto prop = edge_style(source, sink);
+ fprintf(f, " n%d -> n%d [ label=\"%s\", color=\"%s\", fillcolor=\"%s\" ];\n",
+ ids[source], ids[sink], dot_escape(prop.label.c_str()).c_str(), prop.color.c_str(), prop.fillcolor.c_str());
+ }
+ }
+ }
+
+ fprintf(f, "}\n");
+ fclose(f);
+}
+
+struct FlowGraph
+{
+ const RTLIL::SigBit source;
+ RTLIL::SigBit sink;
+ pool<RTLIL::SigBit> nodes = {source};
+ dict<RTLIL::SigBit, pool<RTLIL::SigBit>> edges_fw, edges_bw;
+
+ const int MAX_NODE_FLOW = 1;
+ dict<RTLIL::SigBit, int> node_flow;
+ dict<pair<RTLIL::SigBit, RTLIL::SigBit>, int> edge_flow;
+
+ dict<RTLIL::SigBit, pool<RTLIL::SigBit>> collapsed;
+
+ void dump_dot_graph(string filename)
+ {
+ auto node_style = [&](RTLIL::SigBit node) {
+ string label = (node == source) ? "(source)" : log_signal(node);
+ for (auto collapsed_node : collapsed[node])
+ label += stringf(" %s", log_signal(collapsed_node));
+ int flow = node_flow[node];
+ if (node != source && node != sink)
+ label += stringf("\n%d/%d", flow, MAX_NODE_FLOW);
+ else
+ label += stringf("\n%d/∞", flow);
+ return GraphStyle{label, flow < MAX_NODE_FLOW ? "green" : "black"};
+ };
+ auto edge_style = [&](RTLIL::SigBit source, RTLIL::SigBit sink) {
+ int flow = edge_flow[{source, sink}];
+ return GraphStyle{stringf("%d/∞", flow), flow > 0 ? "blue" : "black"};
+ };
+ ::dump_dot_graph(filename, nodes, edges_fw, {source}, {sink}, node_style, edge_style);
+ }
+
+ // Here, we are working on the Nt'' network, but our representation is the Nt' network.
+ // The difference between these is that where in Nt' we have a subgraph:
+ //
+ // v1 -> v2 -> v3
+ //
+ // in Nt'' we have a corresponding subgraph:
+ //
+ // v'1b -∞-> v'2t -f-> v'2b -∞-> v'3t
+ //
+ // To address this, we split each node v into two nodes, v't and v'b. This representation is virtual,
+ // in the sense that nodes v't and v'b are overlaid on top of the original node v, and only exist
+ // in paths and worklists.
+
+ struct NodePrime
+ {
+ RTLIL::SigBit node;
+ bool is_bottom;
+
+ NodePrime(RTLIL::SigBit node, bool is_bottom) :
+ node(node), is_bottom(is_bottom) {}
+
+ bool operator==(const NodePrime &other) const
+ {
+ return node == other.node && is_bottom == other.is_bottom;
+ }
+ bool operator!=(const NodePrime &other) const
+ {
+ return !(*this == other);
+ }
+ unsigned int hash() const
+ {
+ return hash_ops<pair<RTLIL::SigBit, int>>::hash({node, is_bottom});
+ }
+
+ static NodePrime top(RTLIL::SigBit node)
+ {
+ return NodePrime(node, /*is_bottom=*/false);
+ }
+
+ static NodePrime bottom(RTLIL::SigBit node)
+ {
+ return NodePrime(node, /*is_bottom=*/true);
+ }
+
+ NodePrime as_top() const
+ {
+ log_assert(is_bottom);
+ return top(node);
+ }
+
+ NodePrime as_bottom() const
+ {
+ log_assert(!is_bottom);
+ return bottom(node);
+ }
+ };
+
+ bool find_augmenting_path(bool commit)
+ {
+ NodePrime source_prime = {source, true};
+ NodePrime sink_prime = {sink, false};
+ vector<NodePrime> path = {source_prime};
+ pool<NodePrime> visited = {};
+ bool found;
+ do {
+ found = false;
+
+ auto node_prime = path.back();
+ visited.insert(node_prime);
+
+ if (!node_prime.is_bottom) // vt
+ {
+ if (!visited[node_prime.as_bottom()] && node_flow[node_prime.node] < MAX_NODE_FLOW)
+ {
+ path.push_back(node_prime.as_bottom());
+ found = true;
+ }
+ else
+ {
+ for (auto node_pred : edges_bw[node_prime.node])
+ {
+ if (!visited[NodePrime::bottom(node_pred)] && edge_flow[{node_pred, node_prime.node}] > 0)
+ {
+ path.push_back(NodePrime::bottom(node_pred));
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ else // vb
+ {
+ if (!visited[node_prime.as_top()] && node_flow[node_prime.node] > 0)
+ {
+ path.push_back(node_prime.as_top());
+ found = true;
+ }
+ else
+ {
+ for (auto node_succ : edges_fw[node_prime.node])
+ {
+ if (!visited[NodePrime::top(node_succ)] /* && edge_flow[...] < ∞ */)
+ {
+ path.push_back(NodePrime::top(node_succ));
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!found && path.size() > 1)
+ {
+ path.pop_back();
+ found = true;
+ }
+ } while(path.back() != sink_prime && found);
+
+ if (commit && path.back() == sink_prime)
+ {
+ auto prev_prime = path.front();
+ for (auto node_prime : path)
+ {
+ if (node_prime == source_prime)
+ continue;
+
+ log_assert(prev_prime.is_bottom ^ node_prime.is_bottom);
+ if (prev_prime.node == node_prime.node)
+ {
+ auto node = node_prime.node;
+ if (!prev_prime.is_bottom && node_prime.is_bottom)
+ {
+ log_assert(node_flow[node] == 0);
+ node_flow[node]++;
+ }
+ else
+ {
+ log_assert(node_flow[node] != 0);
+ node_flow[node]--;
+ }
+ }
+ else
+ {
+ if (prev_prime.is_bottom && !node_prime.is_bottom)
+ {
+ log_assert(true /* edge_flow[...] < ∞ */);
+ edge_flow[{prev_prime.node, node_prime.node}]++;
+ }
+ else
+ {
+ log_assert((edge_flow[{node_prime.node, prev_prime.node}] > 0));
+ edge_flow[{node_prime.node, prev_prime.node}]--;
+ }
+ }
+ prev_prime = node_prime;
+ }
+
+ node_flow[source]++;
+ node_flow[sink]++;
+ }
+ return path.back() == sink_prime;
+ }
+
+ int maximum_flow(int order)
+ {
+ int flow = 0;
+ while (flow < order && find_augmenting_path(/*commit=*/true))
+ flow++;
+ return flow + find_augmenting_path(/*commit=*/false);
+ }
+
+ pair<pool<RTLIL::SigBit>, pool<RTLIL::SigBit>> edge_cut()
+ {
+ pool<RTLIL::SigBit> x, xi;
+
+ NodePrime source_prime = {source, true};
+ NodePrime sink_prime = {sink, false};
+ pool<NodePrime> visited;
+ vector<NodePrime> worklist = {source_prime};
+ while (!worklist.empty())
+ {
+ auto node_prime = worklist.back();
+ worklist.pop_back();
+ if (visited[node_prime])
+ continue;
+ visited.insert(node_prime);
+
+ if (!node_prime.is_bottom)
+ x.insert(node_prime.node);
+
+ // Mincut is constructed by traversing a graph in an undirected way along forward edges that aren't full, or backward edges
+ // that aren't empty.
+ if (!node_prime.is_bottom) // top
+ {
+ if (node_flow[node_prime.node] < MAX_NODE_FLOW)
+ worklist.push_back(node_prime.as_bottom());
+ for (auto node_pred : edges_bw[node_prime.node])
+ if (edge_flow[{node_pred, node_prime.node}] > 0)
+ worklist.push_back(NodePrime::bottom(node_pred));
+ }
+ else // bottom
+ {
+ if (node_flow[node_prime.node] > 0)
+ worklist.push_back(node_prime.as_top());
+ for (auto node_succ : edges_fw[node_prime.node])
+ if (true /* edge_flow[...] < ∞ */)
+ worklist.push_back(NodePrime::top(node_succ));
+ }
+ }
+
+ for (auto node : nodes)
+ if (!x[node])
+ xi.insert(node);
+
+ for (auto collapsed_node : collapsed[sink])
+ xi.insert(collapsed_node);
+
+ log_assert(!x[sink] && xi[sink]);
+ return {x, xi};
+ }
+};
+
+struct FlowmapWorker
+{
+ int order;
+ int r_alpha, r_beta, r_gamma;
+ bool debug, debug_relax;
+
+ RTLIL::Module *module;
+ SigMap sigmap;
+ ModIndex index;
+
+ dict<RTLIL::SigBit, ModIndex::PortInfo> node_origins;
+
+ // Gate IR
+ pool<RTLIL::SigBit> nodes, inputs, outputs;
+ dict<RTLIL::SigBit, pool<RTLIL::SigBit>> edges_fw, edges_bw;
+ dict<RTLIL::SigBit, int> labels;
+
+ // LUT IR
+ pool<RTLIL::SigBit> lut_nodes;
+ dict<RTLIL::SigBit, pool<RTLIL::SigBit>> lut_gates;
+ dict<RTLIL::SigBit, pool<RTLIL::SigBit>> lut_edges_fw, lut_edges_bw;
+ dict<RTLIL::SigBit, int> lut_depths, lut_altitudes, lut_slacks;
+
+ int gate_count = 0, lut_count = 0, packed_count = 0;
+ int gate_area = 0, lut_area = 0;
+
+ enum class GraphMode {
+ Label,
+ Cut,
+ Slack,
+ };
+
+ void dump_dot_graph(string filename, GraphMode mode,
+ pool<RTLIL::SigBit> subgraph_nodes = {}, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> subgraph_edges = {},
+ dict<RTLIL::SigBit, pool<RTLIL::SigBit>> collapsed = {},
+ pair<pool<RTLIL::SigBit>, pool<RTLIL::SigBit>> cut = {})
+ {
+ if (subgraph_nodes.empty())
+ subgraph_nodes = nodes;
+ if (subgraph_edges.empty())
+ subgraph_edges = edges_fw;
+
+ auto node_style = [&](RTLIL::SigBit node) {
+ string label = log_signal(node);
+ for (auto collapsed_node : collapsed[node])
+ if (collapsed_node != node)
+ label += stringf(" %s", log_signal(collapsed_node));
+ switch (mode)
+ {
+ case GraphMode::Label:
+ if (labels[node] == -1)
+ {
+ label += "\nl=?";
+ return GraphStyle{label};
+ }
+ else
+ {
+ label += stringf("\nl=%d", labels[node]);
+ string fillcolor = stringf("/set311/%d", 1 + labels[node] % 11);
+ return GraphStyle{label, "", fillcolor};
+ }
+
+ case GraphMode::Cut:
+ if (cut.first[node])
+ return GraphStyle{label, "blue"};
+ if (cut.second[node])
+ return GraphStyle{label, "red"};
+ return GraphStyle{label};
+
+ case GraphMode::Slack:
+ label += stringf("\nd=%d a=%d\ns=%d", lut_depths[node], lut_altitudes[node], lut_slacks[node]);
+ return GraphStyle{label, lut_slacks[node] == 0 ? "red" : "black"};
+ }
+ return GraphStyle{label};
+ };
+ auto edge_style = [&](RTLIL::SigBit, RTLIL::SigBit) {
+ return GraphStyle{};
+ };
+ ::dump_dot_graph(filename, subgraph_nodes, subgraph_edges, inputs, outputs, node_style, edge_style, module->name.str());
+ }
+
+ void dump_dot_lut_graph(string filename, GraphMode mode)
+ {
+ pool<RTLIL::SigBit> lut_and_input_nodes;
+ lut_and_input_nodes.insert(lut_nodes.begin(), lut_nodes.end());
+ lut_and_input_nodes.insert(inputs.begin(), inputs.end());
+ dump_dot_graph(filename, mode, lut_and_input_nodes, lut_edges_fw, lut_gates);
+ }
+
+ pool<RTLIL::SigBit> find_subgraph(RTLIL::SigBit sink)
+ {
+ pool<RTLIL::SigBit> subgraph;
+ pool<RTLIL::SigBit> worklist = {sink};
+ while (!worklist.empty())
+ {
+ auto node = worklist.pop();
+ subgraph.insert(node);
+ for (auto source : edges_bw[node])
+ {
+ if (!subgraph[source])
+ worklist.insert(source);
+ }
+ }
+ return subgraph;
+ }
+
+ FlowGraph build_flow_graph(RTLIL::SigBit sink, int p)
+ {
+ FlowGraph flow_graph;
+ flow_graph.sink = sink;
+
+ pool<RTLIL::SigBit> worklist = {sink}, visited;
+ while (!worklist.empty())
+ {
+ auto node = worklist.pop();
+ visited.insert(node);
+
+ auto collapsed_node = labels[node] == p ? sink : node;
+ if (node != collapsed_node)
+ flow_graph.collapsed[collapsed_node].insert(node);
+ flow_graph.nodes.insert(collapsed_node);
+
+ for (auto node_pred : edges_bw[node])
+ {
+ auto collapsed_node_pred = labels[node_pred] == p ? sink : node_pred;
+ if (node_pred != collapsed_node_pred)
+ flow_graph.collapsed[collapsed_node_pred].insert(node_pred);
+ if (collapsed_node != collapsed_node_pred)
+ {
+ flow_graph.edges_bw[collapsed_node].insert(collapsed_node_pred);
+ flow_graph.edges_fw[collapsed_node_pred].insert(collapsed_node);
+ }
+ if (inputs[node_pred])
+ {
+ flow_graph.edges_bw[collapsed_node_pred].insert(flow_graph.source);
+ flow_graph.edges_fw[flow_graph.source].insert(collapsed_node_pred);
+ }
+
+ if (!visited[node_pred])
+ worklist.insert(node_pred);
+ }
+ }
+ return flow_graph;
+ }
+
+ void discover_nodes(pool<IdString> cell_types)
+ {
+ for (auto cell : module->selected_cells())
+ {
+ if (!cell_types[cell->type])
+ continue;
+
+ if (!cell->known())
+ log_error("Cell %s (%s.%s) is unknown.\n", cell->type.c_str(), log_id(module), log_id(cell));
+
+ pool<RTLIL::SigBit> fanout;
+ for (auto conn : cell->connections())
+ {
+ if (!cell->output(conn.first)) continue;
+ int offset = -1;
+ for (auto bit : conn.second)
+ {
+ offset++;
+ if (!bit.wire) continue;
+ auto mapped_bit = sigmap(bit);
+ if (nodes[mapped_bit])
+ log_error("Multiple drivers found for wire %s.\n", log_signal(mapped_bit));
+ nodes.insert(mapped_bit);
+ node_origins[mapped_bit] = ModIndex::PortInfo(cell, conn.first, offset);
+ fanout.insert(mapped_bit);
+ }
+ }
+
+ int fanin = 0;
+ for (auto conn : cell->connections())
+ {
+ if (!cell->input(conn.first)) continue;
+ for (auto bit : sigmap(conn.second))
+ {
+ if (!bit.wire) continue;
+ for (auto fanout_bit : fanout)
+ {
+ edges_fw[bit].insert(fanout_bit);
+ edges_bw[fanout_bit].insert(bit);
+ }
+ fanin++;
+ }
+ }
+
+ if (fanin > order)
+ log_error("Cell %s (%s.%s) with fan-in %d cannot be mapped to a %d-LUT.\n",
+ cell->type.c_str(), log_id(module), log_id(cell), fanin, order);
+
+ gate_count++;
+ gate_area += 1 << fanin;
+ }
+
+ for (auto edge : edges_fw)
+ {
+ if (!nodes[edge.first])
+ {
+ inputs.insert(edge.first);
+ nodes.insert(edge.first);
+ }
+ }
+
+ for (auto node : nodes)
+ {
+ auto node_info = index.query(node);
+ if (node_info->is_output && !inputs[node])
+ outputs.insert(node);
+ for (auto port : node_info->ports)
+ if (!cell_types[port.cell->type] && !inputs[node])
+ outputs.insert(node);
+ }
+
+ if (debug)
+ {
+ dump_dot_graph("flowmap-initial.dot", GraphMode::Label);
+ log("Dumped initial graph to `flowmap-initial.dot`.\n");
+ }
+ }
+
+ void label_nodes()
+ {
+ for (auto node : nodes)
+ labels[node] = -1;
+ for (auto input : inputs)
+ {
+ if (input.wire->attributes.count("\\$flowmap_level"))
+ labels[input] = input.wire->attributes["\\$flowmap_level"].as_int();
+ else
+ labels[input] = 0;
+ }
+
+ pool<RTLIL::SigBit> worklist = nodes;
+ int debug_num = 0;
+ while (!worklist.empty())
+ {
+ auto sink = worklist.pop();
+ if (labels[sink] != -1)
+ continue;
+
+ bool inputs_have_labels = true;
+ for (auto sink_input : edges_bw[sink])
+ {
+ if (labels[sink_input] == -1)
+ {
+ inputs_have_labels = false;
+ break;
+ }
+ }
+ if (!inputs_have_labels)
+ continue;
+
+ if (debug)
+ {
+ debug_num++;
+ log("Examining subgraph %d rooted in %s.\n", debug_num, log_signal(sink));
+ }
+
+ pool<RTLIL::SigBit> subgraph = find_subgraph(sink);
+
+ int p = 1;
+ for (auto subgraph_node : subgraph)
+ p = max(p, labels[subgraph_node]);
+
+ FlowGraph flow_graph = build_flow_graph(sink, p);
+ int flow = flow_graph.maximum_flow(order);
+ pool<RTLIL::SigBit> x, xi;
+ if (flow <= order)
+ {
+ labels[sink] = p;
+ auto cut = flow_graph.edge_cut();
+ x = cut.first;
+ xi = cut.second;
+ }
+ else
+ {
+ labels[sink] = p + 1;
+ x = subgraph;
+ x.erase(sink);
+ xi.insert(sink);
+ }
+ lut_gates[sink] = xi;
+
+ pool<RTLIL::SigBit> k;
+ for (auto xi_node : xi)
+ {
+ for (auto xi_node_pred : edges_bw[xi_node])
+ if (x[xi_node_pred])
+ k.insert(xi_node_pred);
+ }
+ log_assert((int)k.size() <= order);
+ lut_edges_bw[sink] = k;
+ for (auto k_node : k)
+ lut_edges_fw[k_node].insert(sink);
+
+ if (debug)
+ {
+ log(" Maximum flow: %d. Assigned label %d.\n", flow, labels[sink]);
+ dump_dot_graph(stringf("flowmap-%d-sub.dot", debug_num), GraphMode::Cut, subgraph, {}, {}, {x, xi});
+ log(" Dumped subgraph to `flowmap-%d-sub.dot`.\n", debug_num);
+ flow_graph.dump_dot_graph(stringf("flowmap-%d-flow.dot", debug_num));
+ log(" Dumped flow graph to `flowmap-%d-flow.dot`.\n", debug_num);
+ log(" LUT inputs:");
+ for (auto k_node : k)
+ log(" %s", log_signal(k_node));
+ log(".\n");
+ log(" LUT packed gates:");
+ for (auto xi_node : xi)
+ log(" %s", log_signal(xi_node));
+ log(".\n");
+ }
+
+ for (auto sink_succ : edges_fw[sink])
+ worklist.insert(sink_succ);
+ }
+
+ if (debug)
+ {
+ dump_dot_graph("flowmap-labeled.dot", GraphMode::Label);
+ log("Dumped labeled graph to `flowmap-labeled.dot`.\n");
+ }
+ }
+
+ int map_luts()
+ {
+ pool<RTLIL::SigBit> worklist = outputs;
+ while (!worklist.empty())
+ {
+ auto lut_node = worklist.pop();
+ lut_nodes.insert(lut_node);
+ for (auto input_node : lut_edges_bw[lut_node])
+ if (!lut_nodes[input_node] && !inputs[input_node])
+ worklist.insert(input_node);
+ }
+
+ 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);
+
+ if (debug)
+ {
+ dump_dot_lut_graph("flowmap-mapped.dot", GraphMode::Label);
+ log("Dumped mapped graph to `flowmap-mapped.dot`.\n");
+ }
+
+ return depth;
+ }
+
+ void realize_derealize_lut(RTLIL::SigBit lut, pool<RTLIL::SigBit> *changed = nullptr)
+ {
+ pool<RTLIL::SigBit> worklist = {lut};
+ while (!worklist.empty())
+ {
+ auto lut = worklist.pop();
+ if (inputs[lut])
+ continue;
+
+ bool realized_successors = false;
+ for (auto lut_succ : lut_edges_fw[lut])
+ if (lut_nodes[lut_succ])
+ realized_successors = true;
+
+ if (realized_successors && !lut_nodes[lut])
+ lut_nodes.insert(lut);
+ else if (!realized_successors && lut_nodes[lut])
+ lut_nodes.erase(lut);
+ else
+ continue;
+
+ for (auto lut_pred : lut_edges_bw[lut])
+ worklist.insert(lut_pred);
+
+ if (changed)
+ changed->insert(lut);
+ }
+ }
+
+ void add_lut_edge(RTLIL::SigBit pred, RTLIL::SigBit succ, pool<RTLIL::SigBit> *changed = nullptr)
+ {
+ log_assert(!lut_edges_fw[pred][succ] && !lut_edges_bw[succ][pred]);
+ log_assert((int)lut_edges_bw[succ].size() < order);
+
+ lut_edges_fw[pred].insert(succ);
+ lut_edges_bw[succ].insert(pred);
+ realize_derealize_lut(pred, changed);
+
+ if (changed)
+ {
+ changed->insert(pred);
+ changed->insert(succ);
+ }
+ }
+
+ void remove_lut_edge(RTLIL::SigBit pred, RTLIL::SigBit succ, pool<RTLIL::SigBit> *changed = nullptr)
+ {
+ log_assert(lut_edges_fw[pred][succ] && lut_edges_bw[succ][pred]);
+
+ lut_edges_fw[pred].erase(succ);
+ lut_edges_bw[succ].erase(pred);
+ realize_derealize_lut(pred, changed);
+
+ if (changed)
+ {
+ if (lut_nodes[pred])
+ changed->insert(pred);
+ changed->insert(succ);
+ }
+ }
+
+ pair<pool<RTLIL::SigBit>, pool<RTLIL::SigBit>> cut_lut_at_gate(RTLIL::SigBit lut, RTLIL::SigBit lut_gate)
+ {
+ pool<RTLIL::SigBit> gate_inputs = lut_edges_bw[lut];
+ pool<RTLIL::SigBit> other_inputs;
+ pool<RTLIL::SigBit> worklist = {lut};
+ while (!worklist.empty())
+ {
+ auto node = worklist.pop();
+ for (auto node_pred : edges_bw[node])
+ {
+ if (node_pred == lut_gate)
+ continue;
+ if (lut_gates[lut][node_pred])
+ worklist.insert(node_pred);
+ else
+ {
+ gate_inputs.erase(node_pred);
+ other_inputs.insert(node_pred);
+ }
+ }
+ }
+ return {gate_inputs, other_inputs};
+ }
+
+ void compute_lut_distances(dict<RTLIL::SigBit, int> &lut_distances, bool forward,
+ pool<RTLIL::SigBit> initial = {}, pool<RTLIL::SigBit> *changed = nullptr)
+ {
+ pool<RTLIL::SigBit> terminals = forward ? inputs : outputs;
+ auto &lut_edges_next = forward ? lut_edges_fw : lut_edges_bw;
+ auto &lut_edges_prev = forward ? lut_edges_bw : lut_edges_fw;
+
+ if (initial.empty())
+ initial = terminals;
+ for (auto node : initial)
+ lut_distances.erase(node);
+
+ pool<RTLIL::SigBit> worklist = initial;
+ while (!worklist.empty())
+ {
+ auto lut = worklist.pop();
+ int lut_distance = 0;
+ if (forward && inputs[lut])
+ lut_distance = labels[lut]; // to support (* $flowmap_level=n *)
+ for (auto lut_prev : lut_edges_prev[lut])
+ if ((lut_nodes[lut_prev] || inputs[lut_prev]) && lut_distances.count(lut_prev))
+ lut_distance = max(lut_distance, lut_distances[lut_prev] + 1);
+ if (!lut_distances.count(lut) || lut_distances[lut] != lut_distance)
+ {
+ lut_distances[lut] = lut_distance;
+ if (changed != nullptr && !inputs[lut])
+ changed->insert(lut);
+ for (auto lut_next : lut_edges_next[lut])
+ if (lut_nodes[lut_next] || inputs[lut_next])
+ worklist.insert(lut_next);
+ }
+ }
+ }
+
+ void check_lut_distances(const dict<RTLIL::SigBit, int> &lut_distances, bool forward)
+ {
+ dict<RTLIL::SigBit, int> gold_lut_distances;
+ compute_lut_distances(gold_lut_distances, forward);
+ for (auto lut_distance : lut_distances)
+ if (lut_nodes[lut_distance.first])
+ log_assert(lut_distance.second == gold_lut_distances[lut_distance.first]);
+ }
+
+ // LUT depth is the length of the longest path from any input in LUT fan-in to LUT.
+ // LUT altitude (for lack of a better term) is the length of the longest path from LUT to any output in LUT fan-out.
+ void update_lut_depths_altitudes(pool<RTLIL::SigBit> worklist = {}, pool<RTLIL::SigBit> *changed = nullptr)
+ {
+ compute_lut_distances(lut_depths, /*forward=*/true, worklist, changed);
+ compute_lut_distances(lut_altitudes, /*forward=*/false, worklist, changed);
+ if (debug_relax && !worklist.empty()) {
+ check_lut_distances(lut_depths, /*forward=*/true);
+ check_lut_distances(lut_altitudes, /*forward=*/false);
+ }
+ }
+
+ // LUT critical output set is the set of outputs whose depth will increase (equivalently, slack will decrease) if the depth of
+ // the LUT increases. (This is referred to as RPOv for LUTv in the paper.)
+ void compute_lut_critical_outputs(dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs,
+ pool<RTLIL::SigBit> worklist = {})
+ {
+ if (worklist.empty())
+ worklist = lut_nodes;
+
+ while (!worklist.empty())
+ {
+ bool updated_some = false;
+ for (auto lut : worklist)
+ {
+ if (outputs[lut])
+ lut_critical_outputs[lut] = {lut};
+ else
+ {
+ bool all_succ_computed = true;
+ lut_critical_outputs[lut] = {};
+ for (auto lut_succ : lut_edges_fw[lut])
+ {
+ if (lut_nodes[lut_succ] && lut_depths[lut_succ] == lut_depths[lut] + 1)
+ {
+ if (lut_critical_outputs.count(lut_succ))
+ lut_critical_outputs[lut].insert(lut_critical_outputs[lut_succ].begin(), lut_critical_outputs[lut_succ].end());
+ else
+ {
+ all_succ_computed = false;
+ break;
+ }
+ }
+ }
+ if (!all_succ_computed)
+ {
+ lut_critical_outputs.erase(lut);
+ continue;
+ }
+ }
+ worklist.erase(lut);
+ updated_some = true;
+ }
+ log_assert(updated_some);
+ }
+ }
+
+ // Invalidating LUT critical output sets is tricky, because increasing the depth of a LUT may take other, adjacent LUTs off the critical
+ // path to the output. Conservatively, if we increase depth of some LUT, every LUT in its input cone needs to have its critical output
+ // set invalidated, too.
+ pool<RTLIL::SigBit> invalidate_lut_critical_outputs(dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs,
+ pool<RTLIL::SigBit> worklist)
+ {
+ pool<RTLIL::SigBit> changed;
+ while (!worklist.empty())
+ {
+ auto lut = worklist.pop();
+ changed.insert(lut);
+ lut_critical_outputs.erase(lut);
+ for (auto lut_pred : lut_edges_bw[lut])
+ {
+ if (lut_nodes[lut_pred] && !changed[lut_pred])
+ {
+ changed.insert(lut_pred);
+ worklist.insert(lut_pred);
+ }
+ }
+ }
+ return changed;
+ }
+
+ void check_lut_critical_outputs(const dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs)
+ {
+ dict<RTLIL::SigBit, pool<RTLIL::SigBit>> gold_lut_critical_outputs;
+ compute_lut_critical_outputs(gold_lut_critical_outputs);
+ for (auto lut_critical_output : lut_critical_outputs)
+ if (lut_nodes[lut_critical_output.first])
+ log_assert(lut_critical_output.second == gold_lut_critical_outputs[lut_critical_output.first]);
+ }
+
+ void update_lut_critical_outputs(dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs,
+ pool<RTLIL::SigBit> worklist = {})
+ {
+ if (!worklist.empty())
+ {
+ pool<RTLIL::SigBit> invalidated = invalidate_lut_critical_outputs(lut_critical_outputs, worklist);
+ compute_lut_critical_outputs(lut_critical_outputs, invalidated);
+ check_lut_critical_outputs(lut_critical_outputs);
+ }
+ else
+ compute_lut_critical_outputs(lut_critical_outputs);
+ }
+
+ void update_breaking_node_potentials(dict<RTLIL::SigBit, dict<RTLIL::SigBit, int>> &potentials,
+ const dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs)
+ {
+ for (auto lut : lut_nodes)
+ {
+ if (potentials.count(lut))
+ continue;
+ if (lut_gates[lut].size() == 1 || lut_slacks[lut] == 0)
+ continue;
+
+ if (debug_relax)
+ log(" Computing potentials for LUT %s.\n", log_signal(lut));
+
+ for (auto lut_gate : lut_gates[lut])
+ {
+ if (lut == lut_gate)
+ continue;
+
+ if (debug_relax)
+ log(" Considering breaking node %s.\n", log_signal(lut_gate));
+
+ int r_ex, r_im, r_slk;
+
+ auto cut_inputs = cut_lut_at_gate(lut, lut_gate);
+ pool<RTLIL::SigBit> gate_inputs = cut_inputs.first, other_inputs = cut_inputs.second;
+ if (gate_inputs.empty() && (int)other_inputs.size() == order)
+ {
+ if (debug_relax)
+ log(" Breaking would result in a (k+1)-LUT.\n");
+ continue;
+ }
+
+ pool<RTLIL::SigBit> elim_fanin_luts;
+ for (auto gate_input : gate_inputs)
+ {
+ if (lut_edges_fw[gate_input].size() == 1)
+ {
+ log_assert(lut_edges_fw[gate_input][lut]);
+ elim_fanin_luts.insert(gate_input);
+ }
+ }
+ if (debug_relax)
+ {
+ if (!lut_nodes[lut_gate])
+ log(" Breaking requires a new LUT.\n");
+ if (!gate_inputs.empty())
+ {
+ log(" Breaking eliminates LUT inputs");
+ for (auto gate_input : gate_inputs)
+ log(" %s", log_signal(gate_input));
+ log(".\n");
+ }
+ if (!elim_fanin_luts.empty())
+ {
+ log(" Breaking eliminates fan-in LUTs");
+ for (auto elim_fanin_lut : elim_fanin_luts)
+ log(" %s", log_signal(elim_fanin_lut));
+ log(".\n");
+ }
+ }
+ r_ex = (lut_nodes[lut_gate] ? 0 : -1) + elim_fanin_luts.size();
+
+ pool<pair<RTLIL::SigBit, RTLIL::SigBit>> maybe_mergeable_luts;
+
+ // Try to merge LUTv with one of its successors.
+ RTLIL::SigBit last_lut_succ;
+ int fanout = 0;
+ for (auto lut_succ : lut_edges_fw[lut])
+ {
+ if (lut_nodes[lut_succ])
+ {
+ fanout++;
+ last_lut_succ = lut_succ;
+ }
+ }
+ if (fanout == 1)
+ maybe_mergeable_luts.insert({lut, last_lut_succ});
+
+ // Try to merge LUTv with one of its predecessors.
+ for (auto lut_pred : other_inputs)
+ {
+ int fanout = 0;
+ for (auto lut_pred_succ : lut_edges_fw[lut_pred])
+ if (lut_nodes[lut_pred_succ] || lut_pred_succ == lut_gate)
+ fanout++;
+ if (fanout == 1)
+ maybe_mergeable_luts.insert({lut_pred, lut});
+ }
+
+ // Try to merge LUTw with one of its predecessors.
+ for (auto lut_gate_pred : lut_edges_bw[lut_gate])
+ {
+ int fanout = 0;
+ for (auto lut_gate_pred_succ : lut_edges_fw[lut_gate_pred])
+ if (lut_nodes[lut_gate_pred_succ] || lut_gate_pred_succ == lut_gate)
+ fanout++;
+ if (fanout == 1)
+ maybe_mergeable_luts.insert({lut_gate_pred, lut_gate});
+ }
+
+ r_im = 0;
+ for (auto maybe_mergeable_pair : maybe_mergeable_luts)
+ {
+ log_assert(lut_edges_fw[maybe_mergeable_pair.first][maybe_mergeable_pair.second]);
+ pool<RTLIL::SigBit> unique_inputs;
+ for (auto fst_lut_pred : lut_edges_bw[maybe_mergeable_pair.first])
+ if (lut_nodes[fst_lut_pred])
+ unique_inputs.insert(fst_lut_pred);
+ for (auto snd_lut_pred : lut_edges_bw[maybe_mergeable_pair.second])
+ if (lut_nodes[snd_lut_pred])
+ unique_inputs.insert(snd_lut_pred);
+ unique_inputs.erase(maybe_mergeable_pair.first);
+ if ((int)unique_inputs.size() <= order)
+ {
+ if (debug_relax)
+ log(" Breaking may allow merging %s and %s.\n",
+ log_signal(maybe_mergeable_pair.first), log_signal(maybe_mergeable_pair.second));
+ r_im++;
+ }
+ }
+
+ int lut_gate_depth;
+ if (lut_nodes[lut_gate])
+ lut_gate_depth = lut_depths[lut_gate];
+ else
+ {
+ lut_gate_depth = 0;
+ for (auto lut_gate_pred : lut_edges_bw[lut_gate])
+ lut_gate_depth = max(lut_gate_depth, lut_depths[lut_gate_pred] + 1);
+ }
+ if (lut_depths[lut] >= lut_gate_depth + 1)
+ r_slk = 0;
+ else
+ {
+ int depth_delta = lut_gate_depth + 1 - lut_depths[lut];
+ if (depth_delta > lut_slacks[lut])
+ {
+ if (debug_relax)
+ log(" Breaking would increase depth by %d, which is more than available slack.\n", depth_delta);
+ continue;
+ }
+
+ if (debug_relax)
+ {
+ log(" Breaking increases depth of LUT by %d.\n", depth_delta);
+ if (lut_critical_outputs.at(lut).size())
+ {
+ log(" Breaking decreases slack of outputs");
+ for (auto lut_critical_output : lut_critical_outputs.at(lut))
+ {
+ log(" %s", log_signal(lut_critical_output));
+ log_assert(lut_slacks[lut_critical_output] > 0);
+ }
+ log(".\n");
+ }
+ }
+ r_slk = lut_critical_outputs.at(lut).size() * depth_delta;
+ }
+
+ int p = 100 * (r_alpha * r_ex + r_beta * r_im + r_gamma) / (r_slk + 1);
+ if (debug_relax)
+ log(" Potential for breaking node %s: %d (Rex=%d, Rim=%d, Rslk=%d).\n",
+ log_signal(lut_gate), p, r_ex, r_im, r_slk);
+ potentials[lut][lut_gate] = p;
+ }
+ }
+ }
+
+ 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();
+
+ for (auto node : lut_nodes)
+ {
+ lut_slacks[node] = depth_bound - (lut_depths[node] + lut_altitudes[node]);
+ log_assert(lut_slacks[node] >= 0);
+ }
+ if (debug)
+ {
+ dump_dot_lut_graph(stringf("flowmap-relax-%d-initial.dot", depth_bound), GraphMode::Slack);
+ log(" Dumped initial slack graph to `flowmap-relax-%d-initial.dot`.\n", depth_bound);
+ }
+
+ dict<RTLIL::SigBit, dict<RTLIL::SigBit, int>> potentials;
+ for (int break_num = 1; ; break_num++)
+ {
+ update_breaking_node_potentials(potentials, lut_critical_outputs);
+
+ if (potentials.empty())
+ {
+ log(" Relaxed to %zu (+%zu) LUTs.\n", lut_nodes.size(), lut_nodes.size() - initial_count);
+ if (!first && break_num == 1)
+ {
+ log(" Design fully relaxed.\n");
+ return true;
+ }
+ else
+ {
+ log(" Slack exhausted.\n");
+ break;
+ }
+ }
+
+ RTLIL::SigBit breaking_lut, breaking_gate;
+ int best_potential = INT_MIN;
+ for (auto lut_gate_potentials : potentials)
+ {
+ for (auto gate_potential : lut_gate_potentials.second)
+ {
+ if (gate_potential.second > best_potential)
+ {
+ breaking_lut = lut_gate_potentials.first;
+ breaking_gate = gate_potential.first;
+ best_potential = gate_potential.second;
+ }
+ }
+ }
+ log(" Breaking LUT %s to %s LUT %s (potential %d).\n",
+ log_signal(breaking_lut), lut_nodes[breaking_gate] ? "reuse" : "extract", log_signal(breaking_gate), best_potential);
+
+ if (debug_relax)
+ log(" Removing breaking gate %s from LUT.\n", log_signal(breaking_gate));
+ lut_gates[breaking_lut].erase(breaking_gate);
+
+ auto cut_inputs = cut_lut_at_gate(breaking_lut, breaking_gate);
+ pool<RTLIL::SigBit> gate_inputs = cut_inputs.first, other_inputs = cut_inputs.second;
+
+ pool<RTLIL::SigBit> worklist = lut_gates[breaking_lut];
+ pool<RTLIL::SigBit> elim_gates = gate_inputs;
+ while (!worklist.empty())
+ {
+ auto lut_gate = worklist.pop();
+ bool all_gate_preds_elim = true;
+ for (auto lut_gate_pred : edges_bw[lut_gate])
+ if (!elim_gates[lut_gate_pred])
+ all_gate_preds_elim = false;
+ if (all_gate_preds_elim)
+ {
+ if (debug_relax)
+ log(" Removing gate %s from LUT.\n", log_signal(lut_gate));
+ lut_gates[breaking_lut].erase(lut_gate);
+ for (auto lut_gate_succ : edges_fw[lut_gate])
+ worklist.insert(lut_gate_succ);
+ }
+ }
+ log_assert(!lut_gates[breaking_lut].empty());
+
+ pool<RTLIL::SigBit> directly_affected_nodes = {breaking_lut};
+ for (auto gate_input : gate_inputs)
+ {
+ if (debug_relax)
+ log(" Removing LUT edge %s -> %s.\n", log_signal(gate_input), log_signal(breaking_lut));
+ remove_lut_edge(gate_input, breaking_lut, &directly_affected_nodes);
+ }
+ if (debug_relax)
+ log(" Adding LUT edge %s -> %s.\n", log_signal(breaking_gate), log_signal(breaking_lut));
+ add_lut_edge(breaking_gate, breaking_lut, &directly_affected_nodes);
+
+ if (debug_relax)
+ log(" Updating slack and potentials.\n");
+
+ pool<RTLIL::SigBit> indirectly_affected_nodes = {};
+ update_lut_depths_altitudes(directly_affected_nodes, &indirectly_affected_nodes);
+ update_lut_critical_outputs(lut_critical_outputs, indirectly_affected_nodes);
+ for (auto node : indirectly_affected_nodes)
+ {
+ lut_slacks[node] = depth_bound - (lut_depths[node] + lut_altitudes[node]);
+ log_assert(lut_slacks[node] >= 0);
+ if (debug_relax)
+ log(" LUT %s now has depth %d and slack %d.\n", log_signal(node), lut_depths[node], lut_slacks[node]);
+ }
+
+ worklist = indirectly_affected_nodes;
+ pool<RTLIL::SigBit> visited;
+ while (!worklist.empty())
+ {
+ auto node = worklist.pop();
+ visited.insert(node);
+ potentials.erase(node);
+ // We are invalidating the entire output cone of the gate IR node, not just of the LUT IR node. This is done to also invalidate
+ // all LUTs that could contain one of the indirectly affected nodes as a *part* of them, as they may not be in the output cone
+ // of any of the LUT IR nodes, e.g. if we have a LUT IR node A and node B as predecessors of node C, where node B includes all
+ // gates from node A.
+ for (auto node_succ : edges_fw[node])
+ if (!visited[node_succ])
+ worklist.insert(node_succ);
+ }
+
+ if (debug)
+ {
+ dump_dot_lut_graph(stringf("flowmap-relax-%d-break-%d.dot", depth_bound, break_num), GraphMode::Slack);
+ log(" Dumped slack graph after break %d to `flowmap-relax-%d-break-%d.dot`.\n", break_num, depth_bound, break_num);
+ }
+ }
+
+ return false;
+ }
+
+ void optimize_area(int depth, int optarea)
+ {
+ dict<RTLIL::SigBit, pool<RTLIL::SigBit>> lut_critical_outputs;
+ update_lut_depths_altitudes();
+ update_lut_critical_outputs(lut_critical_outputs);
+
+ for (int depth_bound = depth; depth_bound <= depth + optarea; depth_bound++)
+ {
+ log("Relaxing with depth bound %d.\n", depth_bound);
+ bool fully_relaxed = relax_depth_for_bound(depth_bound == depth, depth_bound, lut_critical_outputs);
+
+ if (fully_relaxed)
+ break;
+ }
+ }
+
+ void pack_cells(int minlut)
+ {
+ ConstEval ce(module);
+ for (auto input_node : inputs)
+ ce.stop(input_node);
+
+ pool<RTLIL::SigBit> mapped_nodes;
+ for (auto node : lut_nodes)
+ {
+ if (node_origins.count(node))
+ {
+ auto origin = node_origins[node];
+ if (origin.cell->getPort(origin.port).size() == 1)
+ log("Packing %s.%s.%s (%s).\n",
+ log_id(module), log_id(origin.cell), origin.port.c_str(), log_signal(node));
+ else
+ log("Packing %s.%s.%s [%d] (%s).\n",
+ log_id(module), log_id(origin.cell), origin.port.c_str(), origin.offset, log_signal(node));
+ }
+ else
+ {
+ log("Packing %s.%s.\n", log_id(module), log_signal(node));
+ }
+
+ for (auto gate_node : lut_gates[node])
+ {
+ log_assert(node_origins.count(gate_node));
+
+ if (gate_node == node)
+ continue;
+
+ auto gate_origin = node_origins[gate_node];
+ if (gate_origin.cell->getPort(gate_origin.port).size() == 1)
+ log(" Packing %s.%s.%s (%s).\n",
+ log_id(module), log_id(gate_origin.cell), gate_origin.port.c_str(), log_signal(gate_node));
+ else
+ log(" Packing %s.%s.%s [%d] (%s).\n",
+ log_id(module), log_id(gate_origin.cell), gate_origin.port.c_str(), gate_origin.offset, log_signal(gate_node));
+ }
+
+ vector<RTLIL::SigBit> input_nodes(lut_edges_bw[node].begin(), lut_edges_bw[node].end());
+ RTLIL::Const lut_table(State::Sx, max(1 << input_nodes.size(), 1 << minlut));
+ for (unsigned i = 0; i < (1 << input_nodes.size()); i++)
+ {
+ ce.push();
+ for (size_t n = 0; n < input_nodes.size(); n++)
+ ce.set(input_nodes[n], ((i >> n) & 1) ? State::S1 : State::S0);
+
+ RTLIL::SigSpec value = node, undef;
+ if (!ce.eval(value, undef))
+ {
+ string env;
+ for (auto input_node : input_nodes)
+ env += stringf(" %s = %s\n", log_signal(input_node), log_signal(ce.values_map(input_node)));
+ log_error("Cannot evaluate %s because %s is not defined.\nEvaluation environment:\n%s",
+ log_signal(node), log_signal(undef), env.c_str());
+ }
+
+ lut_table[i] = value.as_bool() ? State::S1 : State::S0;
+ ce.pop();
+ }
+
+ RTLIL::SigSpec lut_a, lut_y = node;
+ for (auto input_node : input_nodes)
+ lut_a.append_bit(input_node);
+ lut_a.append(RTLIL::Const(State::Sx, minlut - input_nodes.size()));
+
+ RTLIL::Cell *lut = module->addLut(NEW_ID, lut_a, lut_y, lut_table);
+ mapped_nodes.insert(node);
+ 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"));
+ 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));
+ else
+ log(" Packed into a %zu-LUT %s.%s (implemented as %d-LUT).\n", input_nodes.size(), log_id(module), log_id(lut), minlut);
+ }
+
+ for (auto node : mapped_nodes)
+ {
+ auto origin = node_origins[node];
+ RTLIL::SigSpec driver = origin.cell->getPort(origin.port);
+ driver[origin.offset] = module->addWire(NEW_ID);
+ origin.cell->setPort(origin.port, driver);
+ }
+ }
+
+ FlowmapWorker(int order, int minlut, pool<IdString> cell_types, int r_alpha, int r_beta, int r_gamma,
+ bool relax, int optarea, bool debug, bool debug_relax,
+ RTLIL::Module *module) :
+ order(order), r_alpha(r_alpha), r_beta(r_beta), r_gamma(r_gamma), debug(debug), debug_relax(debug_relax),
+ module(module), sigmap(module), index(module)
+ {
+ log("Labeling cells.\n");
+ discover_nodes(cell_types);
+ label_nodes();
+ int depth = map_luts();
+
+ if (relax)
+ {
+ log("\n");
+ log("Optimizing area.\n");
+ optimize_area(depth, optarea);
+ }
+
+ log("\n");
+ log("Packing cells.\n");
+ pack_cells(minlut);
+ }
+};
+
+static void split(std::vector<std::string> &tokens, const std::string &text, char sep)
+{
+ size_t start = 0, end = 0;
+ while ((end = text.find(sep, start)) != std::string::npos) {
+ tokens.push_back(text.substr(start, end - start));
+ start = end + 1;
+ }
+ tokens.push_back(text.substr(start));
+}
+
+struct FlowmapPass : public Pass {
+ FlowmapPass() : Pass("flowmap", "pack LUTs with FlowMap") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" flowmap [options] [selection]\n");
+ log("\n");
+ log("This pass uses the FlowMap technology mapping algorithm to pack logic gates\n");
+ log("into k-LUTs with optimal depth. It allows mapping any circuit elements that can\n");
+ log("be evaluated with the `eval` pass, including cells with multiple output ports\n");
+ log("and multi-bit input and output ports.\n");
+ log("\n");
+ log(" -maxlut k\n");
+ log(" perform technology mapping for a k-LUT architecture. if not specified,\n");
+ log(" defaults to 3.\n");
+ log("\n");
+ log(" -minlut n\n");
+ log(" only produce n-input or larger LUTs. if not specified, defaults to 1.\n");
+ log("\n");
+ log(" -cells <cell>[,<cell>,...]\n");
+ log(" map specified cells. if not specified, maps $_NOT_, $_AND_, $_OR_,\n");
+ log(" $_XOR_ and $_MUX_, which are the outputs of the `simplemap` pass.\n");
+ log("\n");
+ log(" -relax\n");
+ log(" perform depth relaxation and area minimization.\n");
+ log("\n");
+ log(" -r-alpha n, -r-beta n, -r-gamma n\n");
+ log(" parameters of depth relaxation heuristic potential function.\n");
+ log(" if not specified, alpha=8, beta=2, gamma=1.\n");
+ log("\n");
+ log(" -optarea n\n");
+ log(" optimize for area by trading off at most n logic levels for fewer LUTs.\n");
+ log(" n may be zero, to optimize for area without increasing depth.\n");
+ log(" implies -relax.\n");
+ log("\n");
+ log(" -debug\n");
+ log(" dump intermediate graphs.\n");
+ log("\n");
+ log(" -debug-relax\n");
+ log(" explain decisions performed during depth relaxation.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ int order = 3;
+ int minlut = 1;
+ vector<string> cells;
+ bool relax = false;
+ int r_alpha = 8, r_beta = 2, r_gamma = 1;
+ int optarea = 0;
+ bool debug = false, debug_relax = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-maxlut" && argidx + 1 < args.size())
+ {
+ order = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-minlut" && argidx + 1 < args.size())
+ {
+ minlut = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-cells" && argidx + 1 < args.size())
+ {
+ split(cells, args[++argidx], ',');
+ continue;
+ }
+ if (args[argidx] == "-relax")
+ {
+ relax = true;
+ continue;
+ }
+ if (args[argidx] == "-r-alpha" && argidx + 1 < args.size())
+ {
+ r_alpha = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-r-beta" && argidx + 1 < args.size())
+ {
+ r_beta = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-r-gamma" && argidx + 1 < args.size())
+ {
+ r_gamma = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-optarea" && argidx + 1 < args.size())
+ {
+ relax = true;
+ optarea = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-debug")
+ {
+ debug = true;
+ continue;
+ }
+ if (args[argidx] == "-debug-relax")
+ {
+ debug = debug_relax = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ pool<IdString> cell_types;
+ if (!cells.empty())
+ {
+ for (auto &cell : cells)
+ cell_types.insert(cell);
+ }
+ else
+ {
+ cell_types = {"$_NOT_", "$_AND_", "$_OR_", "$_XOR_", "$_MUX_"};
+ }
+
+ const char *algo_r = relax ? "-r" : "";
+ log_header(design, "Executing FLOWMAP pass (pack LUTs with FlowMap%s).\n", algo_r);
+
+ int gate_count = 0, lut_count = 0, packed_count = 0;
+ int gate_area = 0, lut_area = 0;
+ for (auto module : design->selected_modules())
+ {
+ FlowmapWorker worker(order, minlut, cell_types, r_alpha, r_beta, r_gamma, relax, optarea, debug, debug_relax, module);
+ gate_count += worker.gate_count;
+ lut_count += worker.lut_count;
+ packed_count += worker.packed_count;
+ gate_area += worker.gate_area;
+ lut_area += worker.lut_area;
+ }
+
+ log("\n");
+ log("Packed %d cells (%d of them duplicated) into %d LUTs.\n", packed_count, packed_count - gate_count, lut_count);
+ log("Solution takes %.1f%% of original gate area.\n", lut_area * 100.0 / gate_area);
+ }
+} FlowmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index d3b1ff02..991cc449 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -24,6 +24,7 @@
#include <istream>
#include <fstream>
#include <iostream>
+#include <sstream>
#ifndef FILTERLIB
#include "kernel/log.h"
@@ -86,10 +87,12 @@ int LibertyParser::lexer(std::string &str)
{
int c;
+ // eat whitespace
do {
c = f.get();
} while (c == ' ' || c == '\t' || c == '\r');
+ // search for identifiers, numbers, plus or minus.
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = c;
while (1) {
@@ -111,6 +114,8 @@ int LibertyParser::lexer(std::string &str)
}
}
+ // if it wasn't an identifer, number of array range,
+ // maybe it's a string?
if (c == '"') {
str = "";
while (1) {
@@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str)
return 'v';
}
+ // if it wasn't a string, perhaps it's a comment or a forward slash?
if (c == '/') {
c = f.get();
- if (c == '*') {
+ if (c == '*') { // start of '/*' block comment
int last_c = 0;
while (c > 0 && (last_c != '*' || c != '/')) {
last_c = c;
@@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str)
line++;
}
return lexer(str);
- } else if (c == '/') {
+ } else if (c == '/') { // start of '//' line comment
while (c > 0 && c != '\n')
c = f.get();
line++;
@@ -144,24 +150,31 @@ int LibertyParser::lexer(std::string &str)
}
f.unget();
// fprintf(stderr, "LEX: char >>/<<\n");
- return '/';
+ return '/'; // a single '/' charater.
}
+ // check for a backslash
if (c == '\\') {
- c = f.get();
+ c = f.get();
if (c == '\r')
c = f.get();
- if (c == '\n')
+ if (c == '\n') {
+ line++;
return lexer(str);
+ }
f.unget();
return '\\';
}
+ // check for a new line
if (c == '\n') {
line++;
- return ';';
+ return 'n';
}
+ // anything else, such as ';' will get passed
+ // through as literal items.
+
// if (c >= 32 && c < 255)
// fprintf(stderr, "LEX: char >>%c<<\n", c);
// else
@@ -175,14 +188,39 @@ LibertyAst *LibertyParser::parse()
int tok = lexer(str);
- while (tok == ';')
+ // there are liberty files in the wild that
+ // have superfluous ';' at the end of
+ // a { ... }. We simply ignore a ';' here.
+ // and get to the next statement.
+
+ while ((tok == 'n') || (tok == ';'))
tok = lexer(str);
if (tok == '}' || tok < 0)
return NULL;
- if (tok != 'v')
- error();
+ if (tok != 'v') {
+ std::string eReport;
+ switch(tok)
+ {
+ case 'n':
+ error("Unexpected newline.");
+ break;
+ case '[':
+ case ']':
+ case '}':
+ case '{':
+ case '\"':
+ case ':':
+ eReport = "Unexpected '";
+ eReport += static_cast<char>(tok);
+ eReport += "'.";
+ error(eReport);
+ break;
+ default:
+ error();
+ }
+ }
LibertyAst *ast = new LibertyAst;
ast->id = str;
@@ -191,7 +229,9 @@ LibertyAst *LibertyParser::parse()
{
tok = lexer(str);
- if (tok == ';')
+ // allow both ';' and new lines to
+ // terminate a statement.
+ if ((tok == ';') || (tok == 'n'))
break;
if (tok == ':' && ast->value.empty()) {
@@ -207,7 +247,12 @@ LibertyAst *LibertyParser::parse()
ast->value += str;
tok = lexer(str);
}
- if (tok == ';')
+
+ // In a liberty file, all key : value pairs should end in ';'
+ // However, there are some liberty files in the wild that
+ // just have a newline. We'll be kind and accept a newline
+ // instead of the ';' too..
+ if ((tok == ';') || (tok == 'n'))
break;
else
error();
@@ -222,8 +267,70 @@ LibertyAst *LibertyParser::parse()
continue;
if (tok == ')')
break;
- if (tok != 'v')
- error();
+
+ // FIXME: the AST needs to be extended to store
+ // these vector ranges.
+ if (tok == '[')
+ {
+ // parse vector range [A] or [A:B]
+ std::string arg;
+ tok = lexer(arg);
+ if (tok != 'v')
+ {
+ // expected a vector array index
+ error("Expected a number.");
+ }
+ else
+ {
+ // fixme: check for number A
+ }
+ tok = lexer(arg);
+ // optionally check for : in case of [A:B]
+ // if it isn't we just expect ']'
+ // as we have [A]
+ if (tok == ':')
+ {
+ tok = lexer(arg);
+ if (tok != 'v')
+ {
+ // expected a vector array index
+ error("Expected a number.");
+ }
+ else
+ {
+ // fixme: check for number B
+ tok = lexer(arg);
+ }
+ }
+ // expect a closing bracket of array range
+ if (tok != ']')
+ {
+ error("Expected ']' on array range.");
+ }
+ continue;
+ }
+ if (tok != 'v') {
+ std::string eReport;
+ switch(tok)
+ {
+ case 'n':
+ error("Unexpected newline.");
+ break;
+ case '[':
+ case ']':
+ case '}':
+ case '{':
+ case '\"':
+ case ':':
+ eReport = "Unexpected '";
+ eReport += static_cast<char>(tok);
+ eReport += "'.";
+ error(eReport);
+ break;
+ default:
+ error();
+ }
+ }
ast->args.push_back(arg);
}
continue;
@@ -249,14 +356,31 @@ LibertyAst *LibertyParser::parse()
void LibertyParser::error()
{
- log_error("Syntax error in line %d.\n", line);
+ log_error("Syntax error in liberty file on line %d.\n", line);
+}
+
+void LibertyParser::error(const std::string &str)
+{
+ std::stringstream ss;
+ ss << "Syntax error in liberty file on line " << line << ".\n";
+ ss << " " << str << "\n";
+ log_error("%s", ss.str().c_str());
}
#else
void LibertyParser::error()
{
- fprintf(stderr, "Syntax error in line %d.\n", line);
+ fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
+ exit(1);
+}
+
+void LibertyParser::error(const std::string &str)
+{
+ std::stringstream ss;
+ ss << "Syntax error in liberty file on line " << line << ".\n";
+ ss << " " << str << "\n";
+ printf("%s", ss.str().c_str());
exit(1);
}
@@ -264,21 +388,21 @@ void LibertyParser::error()
#define CHECK_NV(result, check) \
do { \
- auto _R = (result); \
- if (!(_R check)) { \
- fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
- #result, (long int)_R, #check, __FILE__, __LINE__); \
- abort(); \
- } \
+ auto _R = (result); \
+ if (!(_R check)) { \
+ fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
+ #result, (long int)_R, #check, __FILE__, __LINE__); \
+ abort(); \
+ } \
} while(0)
#define CHECK_COND(result) \
do { \
- if (!(result)) { \
- fprintf(stderr, "Error from '%s' in %s:%d.\n", \
- #result, __FILE__, __LINE__); \
- abort(); \
- } \
+ if (!(result)) { \
+ fprintf(stderr, "Error from '%s' in %s:%d.\n", \
+ #result, __FILE__, __LINE__); \
+ abort(); \
+ } \
} while(0)
/**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h
index cf632557..c9ebd06c 100644
--- a/passes/techmap/libparse.h
+++ b/passes/techmap/libparse.h
@@ -46,9 +46,17 @@ namespace Yosys
LibertyAst *ast;
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
~LibertyParser() { if (ast) delete ast; }
+
+ /* lexer return values:
+ 'v': identifier, string, array range [...] -> str holds the token string
+ 'n': newline
+ anything else is a single character.
+ */
int lexer(std::string &str);
- LibertyAst *parse();
+
+ LibertyAst *parse();
void error();
+ void error(const std::string &str);
};
}
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index d32bbff1..a4ed7955 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -32,7 +32,7 @@ int lut2mux(Cell *cell)
if (GetSize(sig_a) == 1)
{
- cell->module->addMuxGate(NEW_ID, lut[0], lut[1], sig_a, sig_y);
+ cell->module->addMuxGate(NEW_ID, lut.extract(0)[0], lut.extract(1)[0], sig_a, sig_y);
}
else
{
diff --git a/passes/tests/flowmap/flow.v b/passes/tests/flowmap/flow.v
new file mode 100644
index 00000000..297ef910
--- /dev/null
+++ b/passes/tests/flowmap/flow.v
@@ -0,0 +1,22 @@
+// Exact reproduction of Figure 2(a) from 10.1109/43.273754.
+module top(...);
+ input a,b,c,d,e,f;
+ wire nA = b&c;
+ wire A = !nA;
+ wire nB = c|d;
+ wire B = !nB;
+ wire nC = e&f;
+ wire C = !nC;
+ wire D = A|B;
+ wire E = a&D;
+ wire nF = D&C;
+ wire F = !nF;
+ wire nG = F|B;
+ wire G = !nG;
+ wire H = a&F;
+ wire I = E|G;
+ wire J = G&C;
+ wire np = H&I;
+ output p = !np;
+ output q = A|J;
+endmodule
diff --git a/passes/tests/flowmap/flowp.v b/passes/tests/flowmap/flowp.v
new file mode 100644
index 00000000..2fb40ffa
--- /dev/null
+++ b/passes/tests/flowmap/flowp.v
@@ -0,0 +1,16 @@
+// Like flow.v, but results in a network identical to Figure 2(b).
+module top(...);
+ input a,b,c,d,e,f;
+ wire A = b&c;
+ wire B = c|d;
+ wire C = e&f;
+ wire D = A|B;
+ wire E = a&D;
+ wire F = D&C;
+ wire G = F|B;
+ wire H = a&F;
+ wire I = E|G;
+ wire J = G&C;
+ output p = H&I;
+ output q = A|J;
+endmodule
diff --git a/passes/tests/flowmap/pack1.v b/passes/tests/flowmap/pack1.v
new file mode 100644
index 00000000..9454edf3
--- /dev/null
+++ b/passes/tests/flowmap/pack1.v
@@ -0,0 +1,11 @@
+// Exact reproduction of Figure 3(a) from 10.1109/92.285741.
+module top(...);
+ input a,b,c,d,e,f,g,h;
+ wire x = !(c|d);
+ wire y = !(e&f);
+ wire u = !(a&b);
+ wire v = !(x|y);
+ wire w = !(g&h);
+ output s = !(u|v);
+ output t = !(v|w);
+endmodule
diff --git a/passes/tests/flowmap/pack1p.v b/passes/tests/flowmap/pack1p.v
new file mode 100644
index 00000000..fdb27883
--- /dev/null
+++ b/passes/tests/flowmap/pack1p.v
@@ -0,0 +1,11 @@
+// Like pack1.v, but results in a simpler network.
+module top(...);
+ input a,b,c,d,e,f,g,h;
+ wire x = c|d;
+ wire y = e&f;
+ wire u = a&b;
+ wire v = x|y;
+ wire w = g&h;
+ output s = u|v;
+ output t = v|w;
+endmodule
diff --git a/passes/tests/flowmap/pack2.v b/passes/tests/flowmap/pack2.v
new file mode 100644
index 00000000..445e4afb
--- /dev/null
+++ b/passes/tests/flowmap/pack2.v
@@ -0,0 +1,15 @@
+// Exact reproduction of Figure 4(a) from 10.1109/92.285741.
+module top(...);
+ (* $flowmap_level=1 *) input a;
+ (* $flowmap_level=1 *) input b;
+ (* $flowmap_level=2 *) input c;
+ (* $flowmap_level=1 *) input d;
+ (* $flowmap_level=3 *) input e;
+ (* $flowmap_level=1 *) input f;
+ wire u = !(a&b);
+ wire w = !(c|d);
+ wire v = !(u|w);
+ wire n0 = !(w&e);
+ wire n1 = !(n0|f);
+ output n2 = !(v&n1);
+endmodule
diff --git a/passes/tests/flowmap/pack2p.v b/passes/tests/flowmap/pack2p.v
new file mode 100644
index 00000000..d4b41733
--- /dev/null
+++ b/passes/tests/flowmap/pack2p.v
@@ -0,0 +1,15 @@
+// Like pack2.v, but results in a simpler network.
+module top(...);
+ (* $flowmap_level=1 *) input a;
+ (* $flowmap_level=1 *) input b;
+ (* $flowmap_level=2 *) input c;
+ (* $flowmap_level=1 *) input d;
+ (* $flowmap_level=3 *) input e;
+ (* $flowmap_level=1 *) input f;
+ wire u = a&b;
+ wire w = c|d;
+ wire v = u|w;
+ wire n0 = w&e;
+ wire n1 = n0|f;
+ output n2 = v&n1;
+endmodule
diff --git a/passes/tests/flowmap/pack3.v b/passes/tests/flowmap/pack3.v
new file mode 100644
index 00000000..06147a1a
--- /dev/null
+++ b/passes/tests/flowmap/pack3.v
@@ -0,0 +1,15 @@
+// Exact reproduction of Figure 5(a) (bottom) from 10.1109/92.285741.
+module top(...);
+ input a,b,c,d,e,f,g,h,i,j;
+ wire x = !(a&b);
+ wire y = !(c|d);
+ wire z = !(e|f);
+ wire n0 = !(g&h);
+ wire n1 = !(i|j);
+ wire w = !(x&y);
+ wire n2 = !(z&n0);
+ wire n3 = !(n0|n1);
+ wire n4 = !(n2|n3);
+ wire v = !(w|n5);
+ output u = !(w&v);
+endmodule
diff --git a/passes/tests/flowmap/pack3p.v b/passes/tests/flowmap/pack3p.v
new file mode 100644
index 00000000..bc6ac175
--- /dev/null
+++ b/passes/tests/flowmap/pack3p.v
@@ -0,0 +1,15 @@
+// Like pack2.v, but results in a simpler network.
+module top(...);
+ input a,b,c,d,e,f,g,h,i,j;
+ wire x = a&b;
+ wire y = c|d;
+ wire z = e|f;
+ wire n0 = g&h;
+ wire n1 = i|j;
+ wire w = x&y;
+ wire n2 = z&n0;
+ wire n3 = n0|n1;
+ wire n4 = n2|n3;
+ wire v = w|n5;
+ output u = w&v;
+endmodule
diff --git a/techlibs/achronix/speedster22i/cells_map.v b/techlibs/achronix/speedster22i/cells_map.v
index 95f5d59c..9f647cbe 100755
--- a/techlibs/achronix/speedster22i/cells_map.v
+++ b/techlibs/achronix/speedster22i/cells_map.v
@@ -32,7 +32,7 @@ endmodule
// > end buffers <
// > Look-Up table <
-// > VT: I still think Achronix folks would have choosen a better \
+// > VT: I still think Achronix folks would have chosen a better \
// > logic architecture.
// LUT Map
module \$lut (A, Y);
@@ -43,30 +43,30 @@ module \$lut (A, Y);
generate
if (WIDTH == 1) begin
// VT: This is not consistent and ACE will complain: assign Y = ~A[0];
- LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_
+ LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_
(.dout(Y), .din0(A[0]), .din1(1'b0), .din2(1'b0), .din3(1'b0));
end else
if (WIDTH == 2) begin
- LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_
+ LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_
(.dout(Y), .din0(A[0]), .din1(A[1]), .din2(1'b0), .din3(1'b0));
end else
if(WIDTH == 3) begin
- LUT4 #(.lut_function({2{LUT}})) _TECHMAP_REPLACE_
+ LUT4 #(.lut_function({2{LUT}})) _TECHMAP_REPLACE_
(.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(1'b0));
end else
if(WIDTH == 4) begin
- LUT4 #(.lut_function(LUT)) _TECHMAP_REPLACE_
+ LUT4 #(.lut_function(LUT)) _TECHMAP_REPLACE_
(.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(A[3]));
end else
wire _TECHMAP_FAIL_ = 1;
endgenerate
-endmodule
+endmodule
// > end LUT <
// > Flops <
// DFF flop
module \$_DFF_P_ (input D, C, output Q);
- DFF _TECHMAP_REPLACE_
+ DFF _TECHMAP_REPLACE_
(.q(Q), .d(D), .ck(C));
-endmodule
+endmodule
diff --git a/techlibs/achronix/speedster22i/cells_sim.v b/techlibs/achronix/speedster22i/cells_sim.v
index da23fed7..a0c60b4b 100755
--- a/techlibs/achronix/speedster22i/cells_sim.v
+++ b/techlibs/achronix/speedster22i/cells_sim.v
@@ -30,7 +30,7 @@ endmodule
module PADOUT (output padout, input padin, input oe);
assign padout = padin;
assign oe = oe;
-endmodule
+endmodule
module LUT4 (output dout,
input din0, din1, din2, din3);
@@ -61,19 +61,19 @@ reg [1:0] s1;
end
endfunction
-always @(dataa_w or datab_w or datac_w or datad_w or cin_w) begin
+always @(dataa_w or datab_w or datac_w or datad_w) begin
combout_rt = lut_data(lut_function, dataa_w, datab_w,
datac_w, datad_w);
end
assign dout = combout_rt & 1'b1;
-endmodule
+endmodule
module DFF (output q,
input d, ck);
reg q;
always @(posedge ck)
q <= d;
-
+
endmodule
diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc
index 92b10781..626860d9 100755
--- a/techlibs/achronix/synth_achronix.cc
+++ b/techlibs/achronix/synth_achronix.cc
@@ -95,8 +95,8 @@ struct SynthAchronixPass : public ScriptPass {
run_to = args[argidx].substr(pos+1);
continue;
}
- if (args[argidx] == "-flatten") {
- flatten = true;
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
continue;
}
if (args[argidx] == "-retime") {
@@ -108,7 +108,7 @@ struct SynthAchronixPass : public ScriptPass {
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH_ACHRONIX pass.\n");
log_push();
diff --git a/techlibs/anlogic/Makefile.inc b/techlibs/anlogic/Makefile.inc
new file mode 100644
index 00000000..67cf9cf1
--- /dev/null
+++ b/techlibs/anlogic/Makefile.inc
@@ -0,0 +1,12 @@
+
+OBJS += techlibs/anlogic/synth_anlogic.o
+OBJS += techlibs/anlogic/anlogic_eqn.o
+OBJS += techlibs/anlogic/anlogic_determine_init.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))
+$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_sim.v))
+$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/eagle_bb.v))
+$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams.txt))
+$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams_map.v))
+$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/dram_init_16x4.vh))
diff --git a/techlibs/anlogic/anlogic_determine_init.cc b/techlibs/anlogic/anlogic_determine_init.cc
new file mode 100644
index 00000000..34b1d4f8
--- /dev/null
+++ b/techlibs/anlogic/anlogic_determine_init.cc
@@ -0,0 +1,72 @@
+/*
+ * 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
new file mode 100644
index 00000000..741bf04c
--- /dev/null
+++ b/techlibs/anlogic/anlogic_eqn.cc
@@ -0,0 +1,113 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2018 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
+
+struct AnlogicEqnPass : public Pass {
+ AnlogicEqnPass() : Pass("anlogic_eqn", "Anlogic: Calculate equations for luts") { }
+ void help() YS_OVERRIDE
+ {
+ log("\n");
+ log(" anlogic_eqn [selection]\n");
+ log("\n");
+ log("Calculate equations for luts since bitstream generator depends on it.\n");
+ log("\n");
+ }
+
+ Const init2eqn(Const init, int inputs)
+ {
+ std::string init_bits = init.as_string();
+ const char* names[] = { "A" , "B", "C", "D", "E", "F" };
+
+ std::string eqn;
+ int width = (int)pow(2,inputs);
+ for(int i=0;i<width;i++)
+ {
+ if (init_bits[width-1-i]=='1')
+ {
+ eqn += "(";
+ for(int j=0;j<inputs;j++)
+ {
+ if (i & (1<<j))
+ eqn += names[j];
+ else
+ eqn += std::string("~") + names[j];
+
+ if (j!=(inputs-1)) eqn += "*";
+ }
+ eqn += ")+";
+ }
+ }
+ if (eqn.empty()) return Const("0");
+ eqn = eqn.substr(0, eqn.length()-1);
+ return Const(eqn);
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing ANLOGIC_EQN pass (calculate equations for luts).\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 == "\\AL_MAP_LUT1")
+ {
+ cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),1));
+ cnt++;
+ }
+ if (cell->type == "\\AL_MAP_LUT2")
+ {
+ cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),2));
+ cnt++;
+ }
+ if (cell->type == "\\AL_MAP_LUT3")
+ {
+ cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),3));
+ cnt++;
+ }
+ if (cell->type == "\\AL_MAP_LUT4")
+ {
+ cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),4));
+ cnt++;
+ }
+ if (cell->type == "\\AL_MAP_LUT5")
+ {
+ cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),5));
+ cnt++;
+ }
+ if (cell->type == "\\AL_MAP_LUT6")
+ {
+ cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),6));
+ cnt++;
+ }
+ }
+ }
+ log_header(design, "Updated %lu of AL_MAP_LUT* elements with equation.\n", cnt);
+ }
+} AnlogicEqnPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/anlogic/arith_map.v b/techlibs/anlogic/arith_map.v
new file mode 100644
index 00000000..11cd140e
--- /dev/null
+++ b/techlibs/anlogic/arith_map.v
@@ -0,0 +1,84 @@
+/*
+ * 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_anlogic_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 CO;
+
+ 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] COx;
+ wire [Y_WIDTH+1:0] C = {COx, CI};
+
+ wire dummy;
+ (* keep *)
+ AL_MAP_ADDER #(
+ .ALUTYPE("ADD_CARRY"))
+ adder_cin (
+ .a(C[0]),
+ .o({COx[0], 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]})
+ );
+ end
+ end: slice
+ endgenerate
+ /* End implementation */
+ assign X = AA ^ BB;
+endmodule \ No newline at end of file
diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v
new file mode 100644
index 00000000..cfc743a4
--- /dev/null
+++ b/techlibs/anlogic/cells_map.v
@@ -0,0 +1,61 @@
+module \$_DFF_N_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(1'b0)); endmodule
+module \$_DFF_P_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(1'b0)); endmodule
+
+module \$_DFFE_NN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule
+module \$_DFFE_NP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule
+module \$_DFFE_PN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule
+module \$_DFFE_PP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule
+
+module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
+module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
+module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
+module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule
+module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule
+module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
+module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
+module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule
+
+module \$_DLATCH_N_ (E, D, Q);
+ wire [1023:0] _TECHMAP_DO_ = "simplemap; opt";
+ input E, D;
+ output Q = !E ? D : Q;
+endmodule
+
+module \$_DLATCH_P_ (E, D, Q);
+ wire [1023:0] _TECHMAP_DO_ = "simplemap; opt";
+ input E, D;
+ output Q = E ? D : 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
+ AL_MAP_LUT1 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]));
+ end else
+ if (WIDTH == 2) begin
+ AL_MAP_LUT2 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1]));
+ end else
+ if (WIDTH == 3) begin
+ AL_MAP_LUT3 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1]), .c(A[2]));
+ end else
+ if (WIDTH == 4) begin
+ AL_MAP_LUT4 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1]), .c(A[2]), .d(A[3]));
+ end else
+ if (WIDTH == 5) begin
+ AL_MAP_LUT5 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1]), .c(A[2]), .d(A[3]), .e(A[4]));
+ end else
+ if (WIDTH == 6) begin
+ AL_MAP_LUT6 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1]), .c(A[2]), .d(A[3]), .e(A[4]), .f(A[5]));
+ end else begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ endgenerate
+endmodule
+`endif
diff --git a/techlibs/anlogic/cells_sim.v b/techlibs/anlogic/cells_sim.v
new file mode 100644
index 00000000..058e7660
--- /dev/null
+++ b/techlibs/anlogic/cells_sim.v
@@ -0,0 +1,103 @@
+module AL_MAP_SEQ (
+ output q,
+ input ce,
+ input clk,
+ input sr,
+ input d
+);
+ parameter DFFMODE = "FF"; //FF,LATCH
+ parameter REGSET = "RESET"; //RESET/SET
+ parameter SRMUX = "SR"; //SR/INV
+ parameter SRMODE = "SYNC"; //SYNC/ASYNC
+endmodule
+
+module AL_MAP_LUT1 (
+ output o,
+ input a
+);
+ parameter [1:0] INIT = 2'h0;
+ parameter EQN = "(A)";
+ assign o = INIT >> a;
+endmodule
+
+module AL_MAP_LUT2 (
+ output o,
+ input a,
+ input b
+);
+ parameter [3:0] INIT = 4'h0;
+ parameter EQN = "(A)";
+ assign o = INIT >> {b, a};
+endmodule
+
+module AL_MAP_LUT3 (
+ output o,
+ input a,
+ input b,
+ input c
+);
+ parameter [7:0] INIT = 8'h0;
+ parameter EQN = "(A)";
+ assign o = INIT >> {c, b, a};
+endmodule
+
+module AL_MAP_LUT4 (
+ output o,
+ input a,
+ input b,
+ input c,
+ input d
+);
+ parameter [15:0] INIT = 16'h0;
+ parameter EQN = "(A)";
+ assign o = INIT >> {d, c, b, a};
+endmodule
+
+module AL_MAP_LUT5 (
+ output o,
+ input a,
+ input b,
+ input c,
+ input d,
+ input e
+);
+ parameter [31:0] INIT = 32'h0;
+ parameter EQN = "(A)";
+ assign o = INIT >> {e, d, c, b, a};
+endmodule
+
+
+module AL_MAP_LUT6 (
+ output o,
+ input a,
+ input b,
+ input c,
+ input d,
+ input e,
+ input f
+);
+ parameter [63:0] INIT = 64'h0;
+ parameter EQN = "(A)";
+ assign o = INIT >> {f, e, d, c, b, a};
+endmodule
+
+module AL_MAP_ALU2B (
+ input cin,
+ input a0, b0, c0, d0,
+ input a1, b1, c1, d1,
+ output s0, s1, cout
+);
+ parameter [15:0] INIT0 = 16'h0000;
+ parameter [15:0] INIT1 = 16'h0000;
+ parameter FUNC0 = "NO";
+ parameter FUNC1 = "NO";
+endmodule
+
+module AL_MAP_ADDER (
+ input a,
+ input b,
+ input c,
+ output [1:0] o
+);
+ parameter ALUTYPE = "ADD";
+endmodule
diff --git a/techlibs/anlogic/dram_init_16x4.vh b/techlibs/anlogic/dram_init_16x4.vh
new file mode 100644
index 00000000..32fb1578
--- /dev/null
+++ b/techlibs/anlogic/dram_init_16x4.vh
@@ -0,0 +1,16 @@
+.INIT_D0({INIT[15*4+0], INIT[14*4+0], INIT[13*4+0], INIT[12*4+0],
+ INIT[11*4+0], INIT[10*4+0], INIT[9*4+0], INIT[8*4+0],
+ INIT[7*4+0], INIT[6*4+0], INIT[5*4+0], INIT[4*4+0],
+ INIT[3*4+0], INIT[2*4+0], INIT[1*4+0], INIT[0*4+0]}),
+.INIT_D1({INIT[15*4+1], INIT[14*4+1], INIT[13*4+1], INIT[12*4+1],
+ INIT[11*4+1], INIT[10*4+1], INIT[9*4+1], INIT[8*4+1],
+ INIT[7*4+1], INIT[6*4+1], INIT[5*4+1], INIT[4*4+1],
+ INIT[3*4+1], INIT[2*4+1], INIT[1*4+1], INIT[0*4+1]}),
+.INIT_D2({INIT[15*4+2], INIT[14*4+2], INIT[13*4+2], INIT[12*4+2],
+ INIT[11*4+2], INIT[10*4+2], INIT[9*4+2], INIT[8*4+2],
+ INIT[7*4+2], INIT[6*4+2], INIT[5*4+2], INIT[4*4+2],
+ INIT[3*4+2], INIT[2*4+2], INIT[1*4+2], INIT[0*4+2]}),
+.INIT_D3({INIT[15*4+3], INIT[14*4+3], INIT[13*4+3], INIT[12*4+3],
+ INIT[11*4+3], INIT[10*4+3], INIT[9*4+3], INIT[8*4+3],
+ INIT[7*4+3], INIT[6*4+3], INIT[5*4+3], INIT[4*4+3],
+ INIT[3*4+3], INIT[2*4+3], INIT[1*4+3], INIT[0*4+3]})
diff --git a/techlibs/anlogic/drams.txt b/techlibs/anlogic/drams.txt
new file mode 100644
index 00000000..4e903c0a
--- /dev/null
+++ b/techlibs/anlogic/drams.txt
@@ -0,0 +1,16 @@
+bram $__ANLOGIC_DRAM16X4
+ init 1
+ abits 4
+ dbits 4
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 1
+endbram
+
+match $__ANLOGIC_DRAM16X4
+ make_outreg
+endmatch
diff --git a/techlibs/anlogic/drams_map.v b/techlibs/anlogic/drams_map.v
new file mode 100644
index 00000000..084e2a25
--- /dev/null
+++ b/techlibs/anlogic/drams_map.v
@@ -0,0 +1,22 @@
+module \$__ANLOGIC_DRAM16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter [63:0]INIT = 64'bx;
+ input CLK1;
+
+ input [3:0] A1ADDR;
+ output [3:0] A1DATA;
+
+ input [3:0] B1ADDR;
+ input [3:0] B1DATA;
+ input B1EN;
+
+ EG_LOGIC_DRAM16X4 #(
+ `include "dram_init_16x4.vh"
+ ) _TECHMAP_REPLACE_ (
+ .di(B1DATA),
+ .waddr(B1ADDR),
+ .wclk(CLK1),
+ .we(B1EN),
+ .raddr(A1ADDR),
+ .do(A1DATA)
+ );
+endmodule
diff --git a/techlibs/anlogic/eagle_bb.v b/techlibs/anlogic/eagle_bb.v
new file mode 100644
index 00000000..7cbec331
--- /dev/null
+++ b/techlibs/anlogic/eagle_bb.v
@@ -0,0 +1,1028 @@
+// Anlogic Eagle - Blackbox cells
+// FIXME: Create sim models
+
+(* blackbox *)
+module EG_LOGIC_BUF(
+ output o,
+ input i
+);
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_BUFG(
+ output o,
+ input i
+);
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_BUFIO(
+ input clki,
+ input rst,
+ input coe,
+ output clko,
+ output clkdiv1,
+ output clkdivx
+);
+ parameter GSR = "DISABLE";
+ parameter DIV = 2;
+ parameter STOPCLK = "DISABLE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_BUFGMUX(
+ output o,
+ input i0,
+ input i1,
+ input s
+);
+ parameter INIT_OUT = "0";
+ parameter PRESELECT_I0 = "TRUE";
+ parameter PRESELECT_I1 = "FALSE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_MBOOT(
+ input rebootn,
+ input [7:0] dynamic_addr
+);
+ parameter ADDR_SOURCE_SEL = "STATIC";
+ parameter STATIC_ADDR = 8'b00000000;
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_DNA(
+ output dout,
+ input clk,
+ input din,
+ input shift_en
+);
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_GCTRL(
+ output done,
+ output highz
+);
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_GSRN(
+ input gsrn,
+ input sync_clk
+);
+ parameter GSRN_SYNC_SEL = "DISABLE";
+ parameter USR_GSRN_EN = "DISABLE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_CCLK(
+ output cclk,
+ input en
+);
+ parameter FREQ = "4.5";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_IDELAY(
+ output o,
+ input i
+);
+ parameter INDEL = 0;
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_IDDR(
+ output q1,
+ output q0,
+ input clk,
+ input d,
+ input rst
+);
+ parameter ASYNCRST = "ENABLE";
+ parameter PIPEMODE = "PIPED";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_ODDR(
+ output q,
+ input clk,
+ input d1,
+ input d0,
+ input rst
+);
+ parameter ASYNCRST = "ENABLE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_IDDRx2(
+ output q3,
+ output q2,
+ output q1,
+ output q0,
+ input pclk,
+ input sclk,
+ input d,
+ input rst
+);
+ parameter ASYNCRST = "ENABLE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_ODELAY(
+ output o,
+ input i
+);
+ parameter OUTDEL = 0;
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_ODDRx2(
+ output q,
+ input pclk,
+ input sclk,
+ input d3,
+ input d2,
+ input d1,
+ input d0,
+ input rst
+);
+ parameter ASYNCRST = "ENABLE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_ODDRx2l(
+ output q,
+ input sclk,
+ input d3,
+ input d2,
+ input d1,
+ input d0,
+ input rst
+);
+ parameter ASYNCRST = "ENABLE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_FIFO(
+ input rst,
+ input [DATA_WIDTH_W-1:0] di,
+ output [DATA_WIDTH_R-1:0] do,
+ input clkw,
+ input we,
+ input clkr,
+ input re,
+ input ore,
+ input [2:0] csw,
+ input [2:0] csr,
+ output empty_flag,
+ output aempty_flag,
+ output full_flag,
+ output afull_flag
+);
+ parameter DATA_WIDTH_W = 9;
+ parameter DATA_WIDTH_R = DATA_WIDTH_W;
+ parameter DATA_DEPTH_W = 1024;
+ parameter DATA_DEPTH_R = DATA_WIDTH_W * DATA_DEPTH_W / DATA_WIDTH_R;
+ parameter MODE = "FIFO8K";
+ parameter REGMODE_W = "NOREG";
+ parameter REGMODE_R = "NOREG";
+ parameter E = 0;
+ parameter AE = 6;
+ parameter AF = DATA_DEPTH_W - 6;
+ parameter F = DATA_DEPTH_W;
+ parameter GSR = "DISABLE";
+ parameter RESETMODE = "ASYNC";
+ parameter ASYNC_RESET_RELEASE = "SYNC";
+ parameter ENDIAN = "LITTLE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_DRAM(
+ input [DATA_WIDTH_W-1:0] di,
+ input [ADDR_WIDTH_W-1:0] waddr,
+ input wclk,
+ input we,
+ output [DATA_WIDTH_R-1:0] do,
+ input [ADDR_WIDTH_R-1:0] raddr
+);
+ parameter DATA_WIDTH_W = 9;
+ parameter ADDR_WIDTH_W = 10;
+ parameter DATA_DEPTH_W = 2 ** ADDR_WIDTH_W;
+ parameter DATA_WIDTH_R = 9;
+ parameter ADDR_WIDTH_R = 10;
+ parameter DATA_DEPTH_R = 2 ** ADDR_WIDTH_R;
+ parameter INIT_FILE = "NONE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_DRAM16X4(
+ input [3:0] di,
+ input [3:0] waddr,
+ input wclk,
+ input we,
+ input [3:0]raddr,
+ output [3:0]do
+);
+ parameter INIT_D0=16'h0000;
+ parameter INIT_D1=16'h0000;
+ parameter INIT_D2=16'h0000;
+ parameter INIT_D3=16'h0000;
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_MULT(
+ output [OUTPUT_WIDTH-1:0] p,
+ input [INPUT_WIDTH_A-1:0] a,
+ input [INPUT_WIDTH_B-1:0] b,
+ input cea,
+ input ceb,
+ input cepd,
+ input clk,
+ input rstan,
+ input rstbn,
+ input rstpdn
+);
+ parameter INPUT_WIDTH_A = 18;
+ parameter INPUT_WIDTH_B = 18;
+ parameter OUTPUT_WIDTH = 36;
+ parameter INPUTFORMAT = "SIGNED";
+ parameter INPUTREGA = "ENABLE";
+ parameter INPUTREGB = "ENABLE";
+ parameter OUTPUTREG = "ENABLE";
+ parameter SRMODE = "ASYNC";
+ parameter IMPLEMENT = "AUTO";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_SEQ_DIV(
+ input clk,
+ input rst,
+ input start,
+ input [NUMER_WIDTH-1:0] numer,
+ input [DENOM_WIDTH-1:0] denom,
+ output [NUMER_WIDTH-1:0] quotient,
+ output [DENOM_WIDTH-1:0] remain,
+ output done
+);
+ parameter NUMER_WIDTH = 16;
+ parameter DENOM_WIDTH = 16;
+endmodule
+
+(* blackbox *)
+module EG_PHY_BRAM(
+ output [8:0] doa,
+ output [8:0] dob,
+ input [8:0] dia,
+ input [8:0] dib,
+ input [2:0] csa,
+ input [2:0] csb,
+ input cea,
+ input ocea,
+ input clka,
+ input wea,
+ input rsta,
+ input ceb,
+ input oceb,
+ input clkb,
+ input web,
+ input rstb,
+ input [12:0] addra,
+ input [12:0] addrb
+);
+ parameter MODE = "DP8K";
+ parameter DATA_WIDTH_A = "9";
+ parameter DATA_WIDTH_B = "9";
+ parameter READBACK = "OFF";
+ parameter REGMODE_A = "NOREG";
+ parameter REGMODE_B = "NOREG";
+ parameter WRITEMODE_A = "NORMAL";
+ parameter WRITEMODE_B = "NORMAL";
+ parameter GSR = "ENABLE";
+ parameter RESETMODE = "SYNC";
+ parameter ASYNC_RESET_RELEASE = "SYNC";
+ parameter CEAMUX = "SIG";
+ parameter CEBMUX = "SIG";
+ parameter OCEAMUX = "SIG";
+ parameter OCEBMUX = "SIG";
+ parameter RSTAMUX = "SIG";
+ parameter RSTBMUX = "SIG";
+ parameter CLKAMUX = "SIG";
+ parameter CLKBMUX = "SIG";
+ parameter WEAMUX = "SIG";
+ parameter WEBMUX = "SIG";
+ parameter CSA0 = "SIG" ;
+ parameter CSA1 = "SIG" ;
+ parameter CSA2 = "SIG" ;
+ parameter CSB0 = "SIG" ;
+ parameter CSB1 = "SIG" ;
+ parameter CSB2 = "SIG" ;
+ parameter INIT_FILE = "NONE";
+ 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;
+endmodule
+
+(* blackbox *)
+module EG_PHY_BRAM32K(
+ output [15:0] doa,
+ output [15:0] dob,
+ input [15:0] dia,
+ input [15:0] dib,
+ input [10:0] addra,
+ input [10:0] addrb,
+ input bytea,
+ input bytewea,
+ input byteb,
+ input byteweb,
+ input csa,
+ input wea,
+ input csb,
+ input web,
+ input clka,
+ input rsta,
+ input clkb,
+ input rstb,
+ input ocea,
+ input oceb
+);
+ parameter MODE = "DP16K";
+ parameter DATA_WIDTH_A = "16";
+ parameter DATA_WIDTH_B = "16";
+ parameter REGMODE_A = "NOREG";
+ parameter REGMODE_B = "NOREG";
+ parameter WRITEMODE_A = "NORMAL";
+ parameter WRITEMODE_B = "NORMAL";
+ parameter SRMODE = "SYNC";
+ parameter CSAMUX = "SIG";
+ parameter CSBMUX = "SIG";
+ parameter OCEAMUX = "SIG";
+ parameter OCEBMUX = "SIG";
+ parameter RSTAMUX = "SIG";
+ parameter RSTBMUX = "SIG";
+ parameter CLKAMUX = "SIG";
+ parameter CLKBMUX = "SIG";
+ parameter WEAMUX = "SIG";
+ parameter WEBMUX = "SIG";
+ parameter READBACK = "OFF";
+ parameter INIT_FILE = "";
+ 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 INIT_40 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_41 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_42 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_43 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_44 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_45 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_46 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_47 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_48 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_49 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_50 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_51 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_52 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_53 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_54 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_55 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_56 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_57 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_58 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_59 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_60 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_61 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_62 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_63 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_64 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_65 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_66 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_67 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_68 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_69 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_70 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_71 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_72 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_73 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_74 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_75 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_76 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_77 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_78 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_79 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+endmodule
+
+(* blackbox *)
+module EG_PHY_FIFO(
+ input [8:0] dia,
+ input [8:0] dib,
+ input [2:0] csr,
+ input [2:0] csw,
+ input we,
+ input re,
+ input clkw,
+ input clkr,
+ input rst,
+ input rprst,
+ input orea,
+ input oreb,
+ output [8:0] dob,
+ output [8:0] doa,
+ output empty_flag,
+ output aempty_flag,
+ output afull_flag,
+ output full_flag
+);
+ parameter MODE = "FIFO8K";
+ parameter DATA_WIDTH_A = "18";
+ parameter DATA_WIDTH_B = "18";
+ parameter READBACK = "OFF";
+ parameter REGMODE_A = "NOREG";
+ parameter REGMODE_B = "NOREG";
+ parameter [13:0] AE = 14'b00000001100000;
+ parameter [13:0] AF = 14'b01111110010000;
+ parameter [13:0] F = 14'b01111111110000;
+ parameter [13:0] AEP1 = 14'b00000001110000;
+ parameter [13:0] AFM1 = 14'b01111110000000;
+ parameter [13:0] FM1 = 14'b01111111100000;
+ parameter [4:0] E = 5'b00000;
+ parameter [5:0] EP1 = 6'b010000;
+ parameter GSR = "ENABLE";
+ parameter RESETMODE = "ASYNC";
+ parameter ASYNC_RESET_RELEASE = "SYNC";
+ parameter CEA = "SIG";
+ parameter CEB = "SIG";
+ parameter OCEA = "SIG";
+ parameter OCEB = "SIG";
+ parameter RSTA = "SIG";
+ parameter RSTB = "SIG";
+ parameter CLKA = "SIG";
+ parameter CLKB = "SIG";
+ parameter WEA = "SIG";
+ parameter WEB = "SIG";
+ parameter CSA0 = "SIG";
+ parameter CSA1 = "SIG";
+ parameter CSA2 = "SIG";
+ parameter CSB0 = "SIG";
+ parameter CSB1 = "SIG";
+ parameter CSB2 = "SIG";
+endmodule
+
+(* blackbox *)
+module EG_PHY_MULT18(
+ output [17:0] acout,
+ output [17:0] bcout,
+ output [35:0] p,
+ input signeda,
+ input signedb,
+ input [17:0] a,
+ input [17:0] b,
+ input [17:0] acin,
+ input [17:0] bcin,
+ input cea,
+ input ceb,
+ input cepd,
+ input clk,
+ input rstan,
+ input rstbn,
+ input rstpdn,
+ input sourcea,
+ input sourceb
+);
+ parameter INPUTREGA = "ENABLE";
+ parameter INPUTREGB = "ENABLE";
+ parameter OUTPUTREG = "ENABLE";
+ parameter SRMODE = "ASYNC";
+ parameter MODE = "MULT18X18C";
+ parameter CEAMUX = "SIG";
+ parameter CEBMUX = "SIG";
+ parameter CEPDMUX = "SIG";
+ parameter RSTANMUX = "SIG";
+ parameter RSTBNMUX = "SIG";
+ parameter RSTPDNMUX = "SIG";
+ parameter CLKMUX = "SIG";
+ parameter SIGNEDAMUX = "SIG";
+ parameter SIGNEDBMUX = "SIG";
+ parameter SOURCEAMUX = "SIG";
+ parameter SOURCEBMUX = "SIG";
+endmodule
+
+(* blackbox *)
+module EG_PHY_GCLK(
+ input clki,
+ output clko
+);
+endmodule
+
+(* blackbox *)
+module EG_PHY_IOCLK(
+ input clki,
+ input stop,
+ output clko
+);
+ parameter STOPCLK = "DISABLE";
+endmodule
+
+(* blackbox *)
+module EG_PHY_CLKDIV(
+ output clkdiv1,
+ output clkdivx,
+ input clki,
+ input rst,
+ input rls
+);
+ parameter GSR = "DISABLE";
+ parameter DIV = 2;
+endmodule
+
+(* blackbox *)
+module EG_PHY_CONFIG(
+ output jrstn,
+ output [1:0] jrti,
+ output jshift,
+ output jtck,
+ output jtdi,
+ output jupdate,
+ output [1:0] jscanen,
+ output jtms,
+ input [1:0] jtdo,
+ input [7:0] jtag8_ipa,
+ input [7:0] jtag8_ipb,
+ output done,
+ output highz,
+ output cclk,
+ input cclk_en,
+ input gsrn_sync_clk,
+ input usr_gsrn,
+ output dna_dout,
+ input dna_clk,
+ input dna_din,
+ input dna_shift_en,
+ input mboot_rebootn,
+ input [7:0] mboot_dynamic_addr
+);
+ parameter MBOOT_AUTO_SEL = "DISABLE";
+ parameter ADDR_SOURCE_SEL = "STATIC";
+ parameter STATIC_ADDR = 8'b0;
+ parameter DONE_PERSISTN = "ENABLE";
+ parameter INIT_PERSISTN = "ENABLE";
+ parameter PROGRAMN_PERSISTN = "DISABLE";
+ parameter JTAG_PERSISTN = "DISABLE";
+ parameter GSRN_SYNC_SEL = "DISABLE";
+ parameter FREQ = "2.5";
+ parameter USR_GSRN_EN = "DISABLE";
+endmodule
+
+(* blackbox *)
+module EG_PHY_OSC(
+ input osc_dis,
+ output osc_clk
+);
+ parameter STDBY = "DISABLE";
+endmodule
+
+(* blackbox *)
+module EG_PHY_PWRMNT(
+ output pwr_dwn_n,
+ input sel_pwr,
+ input pwr_mnt_pd
+);
+ parameter MNT_LVL = 0;
+endmodule
+
+(* blackbox *)
+module EG_PHY_DDR_8M_16(
+ input clk,
+ input clk_n,
+ input ras_n,
+ input cas_n,
+ input we_n,
+ input cs_n,
+ input [11:0] addr,
+ input [1:0] ba,
+ inout [15:0] dq,
+ input ldqs,
+ input udqs,
+ input ldm,
+ input udm,
+ input cke
+);
+endmodule
+
+(* blackbox *)
+module EG_PHY_SDRAM_2M_32(
+ input clk,
+ input ras_n,
+ input cas_n,
+ input we_n,
+ input [10:0] addr,
+ input [1:0] ba,
+ inout [31:0] dq,
+ input cs_n,
+ input dm0,
+ input dm1,
+ input dm2,
+ input dm3,
+ input cke
+);
+endmodule
+
+(* blackbox *)
+module EG_PHY_PAD(
+ input ipad,
+ output opad,
+ inout bpad,
+ input rst,
+ input ce,
+ input isclk,
+ input ipclk,
+ input osclk,
+ input opclk,
+ input ts,
+ input [3:0] do,
+ output di,
+ output [3:0] diq
+);
+ parameter DEDCLK = "DISABLE";
+ parameter GSR = "ENABLE";
+ parameter SRMODE = "SYNC";
+ parameter TSMUX = "1";
+ parameter INSCLKMUX = "0";
+ parameter INPCLKMUX = "CLK";
+ parameter INCEMUX = "CE";
+ parameter INRSTMUX = "0";
+ parameter IN_REGSET = "RESET";
+ parameter IN_DFFMODE = "NONE";
+ parameter IDDRMODE = "OFF";
+ parameter IDDRPIPEMODE = "NONE";
+ parameter INDELMUX = "NODEL";
+ parameter INDEL = 0;
+ parameter OUTSCLKMUX = "0";
+ parameter OUTPCLKMUX = "CLK";
+ parameter OUTCEMUX = "CE";
+ parameter OUTRSTMUX = "0";
+ parameter DO_REGSET = "RESET";
+ parameter DO_DFFMODE = "NONE";
+ parameter ODDRMODE = "OFF";
+ parameter OUTDELMUX = "NODEL";
+ parameter OUTDEL = 0;
+ parameter TO_REGSET = "RESET";
+ parameter TO_DFFMODE = "NONE";
+ parameter MODE = "IN";
+ parameter DRIVE = "NONE";
+ parameter IOTYPE = "LVCMOS25";
+endmodule
+
+(* blackbox *)
+module EG_PHY_MSLICE(
+ input [1:0] a,
+ input [1:0] b,
+ input [1:0] c,
+ input [1:0] d,
+ input [1:0] mi,
+ input clk,
+ input ce,
+ input sr,
+ input fci,
+ output [1:0] f,
+ output [1:0] fx,
+ output [1:0] q,
+ output fco,
+ input dpram_mode,
+ input [1:0] dpram_di,
+ input dpram_we,
+ input dpram_wclk,
+ input [3:0] dpram_waddr
+);
+ parameter INIT_LUT0 = 16'h0000;
+ parameter INIT_LUT1 = 16'h0000;
+ parameter MODE = "LOGIC";
+ parameter ALUTYPE = "ADD";
+ parameter MSFXMUX = "OFF";
+ parameter GSR = "ENABLE";
+ parameter TESTMODE = "OFF";
+ parameter CEMUX = "CE";
+ parameter SRMUX = "SR";
+ parameter CLKMUX = "CLK";
+ parameter SRMODE = "ASYNC";
+ parameter DFFMODE = "FF";
+ parameter REG0_SD = "MI";
+ parameter REG1_SD = "MI";
+ parameter REG0_REGSET = "SET";
+ parameter REG1_REGSET = "SET";
+endmodule
+
+(* blackbox *)
+module EG_PHY_LSLICE(
+ input [1:0] a,
+ input [1:0] b,
+ input [1:0] c,
+ input [1:0] d,
+ input [1:0] e,
+ input [1:0] mi,
+ input clk,
+ input ce,
+ input sr,
+ input fci,
+ output [1:0] f,
+ output [1:0] fx,
+ output [1:0] q,
+ output fco,
+ output [3:0] dpram_di,
+ output [3:0] dpram_waddr,
+ output dpram_wclk,
+ output dpram_we,
+ output dpram_mode
+);
+ parameter INIT_LUTF0 = 16'h0000;
+ parameter INIT_LUTG0 = 16'h0000;
+ parameter INIT_LUTF1 = 16'h0000;
+ parameter INIT_LUTG1 = 16'h0000;
+ parameter MODE = "LOGIC";
+ parameter GSR = "ENABLE";
+ parameter TESTMODE = "OFF";
+ parameter CEMUX = "1";
+ parameter SRMUX = "SR";
+ parameter CLKMUX = "CLK";
+ parameter SRMODE = "ASYNC";
+ parameter DFFMODE = "FF";
+ parameter REG0_SD = "MI";
+ parameter REG1_SD = "MI";
+ parameter REG0_REGSET = "SET";
+ parameter REG1_REGSET = "SET";
+ parameter DEMUX0 = "D";
+ parameter DEMUX1 = "D";
+ parameter CMIMUX0 = "C";
+ parameter CMIMUX1 = "C";
+ parameter LSFMUX0 = "LUTF";
+ parameter LSFXMUX0 = "LUTG";
+ parameter LSFMUX1 = "LUTF";
+ parameter LSFXMUX1 = "LUTG";
+endmodule
+
+(* blackbox *)
+module EG_PHY_PLL(
+ output [4:0] clkc,
+ output extlock,
+ input stdby,
+ input refclk,
+ input fbclk,
+ input reset,
+ output psdone,
+ input psclk,
+ input psdown,
+ input psstep,
+ input [2:0] psclksel,
+ output [7:0] do,
+ input dclk,
+ input dcs,
+ input dwe,
+ input [7:0] di,
+ input [5:0] daddr
+);
+ parameter DYNCFG = "DISABLE";
+ parameter IF_ESCLKSTSW = "DISABLE";
+ parameter REFCLK_SEL = "INTERNAL";
+ parameter FIN = "100.0000";
+ parameter REFCLK_DIV = 1;
+ parameter FBCLK_DIV = 1;
+ parameter CLKC0_DIV = 1;
+ parameter CLKC1_DIV = 1;
+ parameter CLKC2_DIV = 1;
+ parameter CLKC3_DIV = 1;
+ parameter CLKC4_DIV = 1;
+ parameter CLKC0_ENABLE = "DISABLE";
+ parameter CLKC1_ENABLE = "DISABLE";
+ parameter CLKC2_ENABLE = "DISABLE";
+ parameter CLKC3_ENABLE = "DISABLE";
+ parameter CLKC4_ENABLE = "DISABLE";
+ parameter CLKC0_DIV2_ENABLE = "DISABLE";
+ parameter CLKC1_DIV2_ENABLE = "DISABLE";
+ parameter CLKC2_DIV2_ENABLE = "DISABLE";
+ parameter CLKC3_DIV2_ENABLE = "DISABLE";
+ parameter CLKC4_DIV2_ENABLE = "DISABLE";
+ parameter FEEDBK_MODE = "NORMAL";
+ parameter FEEDBK_PATH = "VCO_PHASE_0";
+ parameter STDBY_ENABLE = "ENABLE";
+ parameter CLKC0_FPHASE = 0;
+ parameter CLKC1_FPHASE = 0;
+ parameter CLKC2_FPHASE = 0;
+ parameter CLKC3_FPHASE = 0;
+ parameter CLKC4_FPHASE = 0;
+ parameter CLKC0_CPHASE = 1;
+ parameter CLKC1_CPHASE = 1;
+ parameter CLKC2_CPHASE = 1;
+ parameter CLKC3_CPHASE = 1;
+ parameter CLKC4_CPHASE = 1;
+ parameter GMC_GAIN = 7;
+ parameter GMC_TEST = 14;
+ parameter ICP_CURRENT = 14;
+ parameter KVCO = 7;
+ parameter LPF_CAPACITOR = 3;
+ parameter LPF_RESISTOR = 1;
+ parameter PLLRST_ENA = "ENABLE";
+ parameter PLLMRST_ENA = "DISABLE";
+ parameter PLLC2RST_ENA = "DISABLE";
+ parameter PLLC34RST_ENA = "DISABLE";
+ parameter PREDIV_MUXC0 = "VCO";
+ parameter PREDIV_MUXC1 = "VCO";
+ parameter PREDIV_MUXC2 = "VCO";
+ parameter PREDIV_MUXC3 = "VCO";
+ parameter PREDIV_MUXC4 = "VCO";
+ parameter ODIV_MUXC0 = "DIV";
+ parameter ODIV_MUXC1 = "DIV";
+ parameter ODIV_MUXC2 = "DIV";
+ parameter ODIV_MUXC3 = "DIV";
+ parameter ODIV_MUXC4 = "DIV";
+ parameter FREQ_LOCK_ACCURACY = 2;
+ parameter PLL_LOCK_MODE = 0;
+ parameter INTFB_WAKE = "DISABLE";
+ parameter DPHASE_SOURCE = "DISABLE";
+ parameter VCO_NORESET = "DISABLE";
+ parameter STDBY_VCO_ENA = "DISABLE";
+ parameter NORESET = "DISABLE";
+ parameter SYNC_ENABLE = "ENABLE";
+ parameter DERIVE_PLL_CLOCKS = "DISABLE";
+ parameter GEN_BASIC_CLOCK = "DISABLE";
+endmodule
+
+(* blackbox *)
+module EG_LOGIC_BRAM(
+ output [DATA_WIDTH_A-1:0] doa,
+ output [DATA_WIDTH_B-1:0] dob,
+ input [DATA_WIDTH_A-1:0] dia,
+ input [DATA_WIDTH_B-1:0] dib,
+ input cea,
+ input ocea,
+ input clka,
+ input wea,
+ input rsta,
+ input ceb,
+ input oceb,
+ input clkb,
+ input web,
+ input rstb,
+ input [BYTE_A - 1 : 0] bea,
+ input [BYTE_B - 1 : 0] beb,
+ input [ADDR_WIDTH_A-1:0] addra,
+ input [ADDR_WIDTH_B-1:0] addrb
+);
+ parameter DATA_WIDTH_A = 9;
+ parameter DATA_WIDTH_B = DATA_WIDTH_A;
+ parameter ADDR_WIDTH_A = 10;
+ parameter ADDR_WIDTH_B = ADDR_WIDTH_A;
+ parameter DATA_DEPTH_A = 2 ** ADDR_WIDTH_A;
+ parameter DATA_DEPTH_B = 2 ** ADDR_WIDTH_B;
+ parameter BYTE_ENABLE = 0;
+ parameter BYTE_A = BYTE_ENABLE == 0 ? 1 : DATA_WIDTH_A / BYTE_ENABLE;
+ parameter BYTE_B = BYTE_ENABLE == 0 ? 1 : DATA_WIDTH_B / BYTE_ENABLE;
+ parameter MODE = "DP";
+ parameter REGMODE_A = "NOREG";
+ parameter REGMODE_B = "NOREG";
+ parameter WRITEMODE_A = "NORMAL";
+ parameter WRITEMODE_B = "NORMAL";
+ parameter RESETMODE = "SYNC";
+ parameter DEBUGGABLE = "NO";
+ parameter PACKABLE = "NO";
+ parameter FORCE_KEEP = "OFF";
+ parameter INIT_FILE = "NONE";
+ parameter FILL_ALL = "NONE";
+ parameter IMPLEMENT = "9K";
+endmodule
+
+(* blackbox *)
+module EG_PHY_ADC(
+ input clk,
+ input pd,
+ input [2:0] s,
+ input soc,
+ output eoc,
+ output [11:0] dout
+);
+ parameter CH0 = "DISABLE";
+ parameter CH1 = "DISABLE";
+ parameter CH2 = "DISABLE";
+ parameter CH3 = "DISABLE";
+ parameter CH4 = "DISABLE";
+ parameter CH5 = "DISABLE";
+ parameter CH6 = "DISABLE";
+ parameter CH7 = "DISABLE";
+ parameter VREF = "DISABLE";
+endmodule
diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc
new file mode 100644
index 00000000..620bf396
--- /dev/null
+++ b/techlibs/anlogic/synth_anlogic.cc
@@ -0,0 +1,213 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2018 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 SynthAnlogicPass : public ScriptPass
+{
+ SynthAnlogicPass() : ScriptPass("synth_anlogic", "synthesis for Anlogic FPGAs") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_anlogic [options]\n");
+ log("\n");
+ log("This command runs synthesis for Anlogic 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_ANLOGIC 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 +/anlogic/cells_sim.v +/anlogic/eagle_bb.v");
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
+
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
+ {
+ run("proc");
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
+ }
+
+ if (check_label("coarse"))
+ {
+ run("synth -run coarse");
+ }
+
+ if (check_label("dram"))
+ {
+ run("memory_bram -rules +/anlogic/drams.txt");
+ run("techmap -map +/anlogic/drams_map.v");
+ run("anlogic_determine_init");
+ }
+
+ if (check_label("fine"))
+ {
+ run("opt -fast -mux_undef -undriven -fine");
+ run("memory_map");
+ run("opt -undriven -fine");
+ run("techmap -map +/techmap.v -map +/anlogic/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 +/anlogic/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:6");
+ run("clean");
+ }
+
+ if (check_label("map_cells"))
+ {
+ run("techmap -map +/anlogic/cells_map.v");
+ run("clean");
+ run("anlogic_eqn");
+ }
+
+ 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()));
+ }
+ }
+} SynthAnlogicPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc
index ab961ac0..0e05620b 100644
--- a/techlibs/common/Makefile.inc
+++ b/techlibs/common/Makefile.inc
@@ -25,5 +25,6 @@ $(eval $(call add_share_file,share,techlibs/common/techmap.v))
$(eval $(call add_share_file,share,techlibs/common/pmux2mux.v))
$(eval $(call add_share_file,share,techlibs/common/adff2dff.v))
$(eval $(call add_share_file,share,techlibs/common/dff2ff.v))
+$(eval $(call add_share_file,share,techlibs/common/gate2lut.v))
+$(eval $(call add_share_file,share,techlibs/common/cmp2lut.v))
$(eval $(call add_share_file,share,techlibs/common/cells.lib))
-
diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v
new file mode 100644
index 00000000..8aa1eb95
--- /dev/null
+++ b/techlibs/common/cmp2lut.v
@@ -0,0 +1,105 @@
+// Certain arithmetic operations between a signal of width n and a constant can be directly mapped
+// to a single k-LUT (where n <= k). This is preferable to normal alumacc techmapping process
+// because for many targets, arithmetic techmapping creates hard logic (such as carry cells) which often
+// cannot be optimized further.
+//
+// TODO: Currently, only comparisons with 1-bit output are mapped. Potentially, all arithmetic cells
+// with n <= k inputs should be techmapped in this way, because this shortens the critical path
+// from n to 1 by avoiding carry chains.
+
+(* techmap_celltype = "$eq $ne $lt $le $gt $ge" *)
+module _90_lut_cmp_ (A, B, Y);
+
+parameter A_SIGNED = 0;
+parameter B_SIGNED = 0;
+parameter A_WIDTH = 0;
+parameter B_WIDTH = 0;
+parameter Y_WIDTH = 0;
+
+input [A_WIDTH-1:0] A;
+input [B_WIDTH-1:0] B;
+output [Y_WIDTH-1:0] Y;
+
+parameter _TECHMAP_CELLTYPE_ = "";
+
+parameter _TECHMAP_CONSTMSK_A_ = 0;
+parameter _TECHMAP_CONSTVAL_A_ = 0;
+parameter _TECHMAP_CONSTMSK_B_ = 0;
+parameter _TECHMAP_CONSTVAL_B_ = 0;
+
+function automatic integer gen_lut;
+ input integer width;
+ input integer operation;
+ input integer swap;
+ input integer sign;
+ input integer operand;
+ integer n, i_var, i_cst, lhs, rhs, o_bit;
+ begin
+ gen_lut = width'b0;
+ for (n = 0; n < (1 << width); n++) begin
+ if (sign)
+ i_var = n[width-1:0];
+ else
+ i_var = n;
+ i_cst = operand;
+ if (swap) begin
+ lhs = i_cst;
+ rhs = i_var;
+ end else begin
+ lhs = i_var;
+ rhs = i_cst;
+ end
+ if (operation == 0)
+ o_bit = (lhs < rhs);
+ if (operation == 1)
+ o_bit = (lhs <= rhs);
+ if (operation == 2)
+ o_bit = (lhs > rhs);
+ if (operation == 3)
+ o_bit = (lhs >= rhs);
+ if (operation == 4)
+ o_bit = (lhs == rhs);
+ if (operation == 5)
+ o_bit = (lhs != rhs);
+ gen_lut = gen_lut | (o_bit << n);
+ end
+ end
+endfunction
+
+generate
+ if (_TECHMAP_CELLTYPE_ == "$lt")
+ localparam operation = 0;
+ if (_TECHMAP_CELLTYPE_ == "$le")
+ localparam operation = 1;
+ if (_TECHMAP_CELLTYPE_ == "$gt")
+ localparam operation = 2;
+ if (_TECHMAP_CELLTYPE_ == "$ge")
+ localparam operation = 3;
+ if (_TECHMAP_CELLTYPE_ == "$eq")
+ localparam operation = 4;
+ if (_TECHMAP_CELLTYPE_ == "$ne")
+ localparam operation = 5;
+
+ if (A_WIDTH > `LUT_WIDTH || B_WIDTH > `LUT_WIDTH || Y_WIDTH != 1)
+ wire _TECHMAP_FAIL_ = 1;
+ else if (&_TECHMAP_CONSTMSK_B_)
+ \$lut #(
+ .WIDTH(A_WIDTH),
+ .LUT({ gen_lut(A_WIDTH, operation, 0, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_B_) })
+ ) _TECHMAP_REPLACE_ (
+ .A(A),
+ .Y(Y)
+ );
+ else if (&_TECHMAP_CONSTMSK_A_)
+ \$lut #(
+ .WIDTH(B_WIDTH),
+ .LUT({ gen_lut(B_WIDTH, operation, 1, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_A_) })
+ ) _TECHMAP_REPLACE_ (
+ .A(B),
+ .Y(Y)
+ );
+ else
+ wire _TECHMAP_FAIL_ = 1;
+endgenerate
+
+endmodule
diff --git a/techlibs/common/gate2lut.v b/techlibs/common/gate2lut.v
new file mode 100644
index 00000000..99c123f4
--- /dev/null
+++ b/techlibs/common/gate2lut.v
@@ -0,0 +1,87 @@
+(* techmap_celltype = "$_NOT_" *)
+module _90_lut_not (A, Y);
+ input A;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ .LUT(4'b01)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
+
+(* techmap_celltype = "$_OR_" *)
+module _90_lut_or (A, B, Y);
+ input A, B;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {B, A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ .LUT(4'b1110)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
+
+(* techmap_celltype = "$_AND_" *)
+module _90_lut_and (A, B, Y);
+ input A, B;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {B, A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ .LUT(4'b1000)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
+
+(* techmap_celltype = "$_XOR_" *)
+module _90_lut_xor (A, B, Y);
+ input A, B;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {B, A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ .LUT(4'b0110)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
+
+(* techmap_celltype = "$_MUX_" *)
+module _90_lut_mux (A, B, S, Y);
+ input A, B, S;
+ output Y;
+
+ wire [`LUT_WIDTH-1:0] AA;
+ assign AA = {S, B, A};
+
+ \$lut #(
+ .WIDTH(`LUT_WIDTH),
+ // A 1010 1010
+ // B 1100 1100
+ // S 1111 0000
+ .LUT(8'b_1100_1010)
+ ) lut (
+ .A(AA),
+ .Y(Y)
+ );
+endmodule
diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc
index 897f37db..86fb4d6c 100644
--- a/techlibs/common/prep.cc
+++ b/techlibs/common/prep.cc
@@ -153,7 +153,7 @@ struct PrepPass : public ScriptPass
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing PREP pass.\n");
log_push();
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index 937512e7..289673e8 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -465,7 +465,7 @@ endmodule
//-
//- $_SR_NP_ (S, R, Q)
//-
-//- A set-reset latch with negative polarity SET and positive polarioty RESET.
+//- A set-reset latch with negative polarity SET and positive polarity RESET.
//-
//- Truth table: S R | Q
//- -----+---
@@ -489,7 +489,7 @@ endmodule
//-
//- $_SR_PN_ (S, R, Q)
//-
-//- A set-reset latch with positive polarity SET and negative polarioty RESET.
+//- A set-reset latch with positive polarity SET and negative polarity RESET.
//-
//- Truth table: S R | Q
//- -----+---
diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc
index efb21475..ccfa76e0 100644
--- a/techlibs/common/synth.cc
+++ b/techlibs/common/synth.cc
@@ -51,6 +51,9 @@ struct SynthPass : public ScriptPass
log(" -encfile <file>\n");
log(" passed to 'fsm_recode' via 'fsm'\n");
log("\n");
+ log(" -lut <k>\n");
+ log(" perform synthesis for a k-LUT architecture.\n");
+ log("\n");
log(" -nofsm\n");
log(" do not run FSM optimization\n");
log("\n");
@@ -80,6 +83,7 @@ struct SynthPass : public ScriptPass
string top_module, fsm_opts, memory_opts;
bool autotop, flatten, noalumacc, nofsm, noabc, noshare;
+ int lut;
void clear_flags() YS_OVERRIDE
{
@@ -89,6 +93,7 @@ struct SynthPass : public ScriptPass
autotop = false;
flatten = false;
+ lut = 0;
noalumacc = false;
nofsm = false;
noabc = false;
@@ -130,6 +135,10 @@ struct SynthPass : public ScriptPass
flatten = true;
continue;
}
+ if (args[argidx] == "-lut") {
+ lut = atoi(args[++argidx].c_str());
+ continue;
+ }
if (args[argidx] == "-nofsm") {
nofsm = true;
continue;
@@ -155,7 +164,7 @@ struct SynthPass : public ScriptPass
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH pass.\n");
log_push();
@@ -186,19 +195,23 @@ struct SynthPass : public ScriptPass
{
run("proc");
if (help_mode || flatten)
- run("flatten", "(if -flatten)");
+ run("flatten", " (if -flatten)");
run("opt_expr");
run("opt_clean");
run("check");
run("opt");
run("wreduce");
+ if (help_mode)
+ run("techmap -map +/cmp2lut.v", " (if -lut)");
+ else
+ run(stringf("techmap -map +/cmp2lut.v -D LUT_WIDTH=%d", lut));
if (!noalumacc)
- run("alumacc");
+ run("alumacc", " (unless -noalumacc)");
if (!noshare)
- run("share");
+ run("share", " (unless -noshare)");
run("opt");
if (!nofsm)
- run("fsm" + fsm_opts);
+ run("fsm" + fsm_opts, " (unless -nofsm)");
run("opt -fast");
run("memory -nomap" + memory_opts);
run("opt_clean");
@@ -210,12 +223,33 @@ struct SynthPass : public ScriptPass
run("memory_map");
run("opt -full");
run("techmap");
+ if (help_mode)
+ {
+ run("techmap -map +/gate2lut.v", "(if -noabc and -lut)");
+ run("clean; opt_lut", " (if -noabc and -lut)");
+ }
+ else if (noabc && lut)
+ {
+ run(stringf("techmap -map +/gate2lut.v -D LUT_WIDTH=%d", lut));
+ run("clean; opt_lut");
+ }
run("opt -fast");
if (!noabc) {
#ifdef YOSYS_ENABLE_ABC
- run("abc -fast");
- run("opt -fast");
+ if (help_mode)
+ {
+ 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));
+ else
+ run("abc -fast");
+ }
+ run("opt -fast", " (unless -noabc)");
#endif
}
}
diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc
index a5dac356..21bbcaef 100644
--- a/techlibs/coolrunner2/synth_coolrunner2.cc
+++ b/techlibs/coolrunner2/synth_coolrunner2.cc
@@ -111,7 +111,7 @@ struct SynthCoolrunner2Pass : public ScriptPass
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH_COOLRUNNER2 pass.\n");
log_push();
@@ -129,7 +129,7 @@ struct SynthCoolrunner2Pass : public ScriptPass
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}
- if (check_label("flatten", "(unless -noflatten)") && flatten)
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
{
run("proc");
run("flatten");
diff --git a/techlibs/easic/synth_easic.cc b/techlibs/easic/synth_easic.cc
index b5ed93be..dd9e3dab 100644
--- a/techlibs/easic/synth_easic.cc
+++ b/techlibs/easic/synth_easic.cc
@@ -117,7 +117,7 @@ struct SynthEasicPass : public ScriptPass
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH_EASIC pass.\n");
log_push();
diff --git a/techlibs/ecp5/.gitignore b/techlibs/ecp5/.gitignore
new file mode 100644
index 00000000..54c32973
--- /dev/null
+++ b/techlibs/ecp5/.gitignore
@@ -0,0 +1,9 @@
+bram_init_1_2_4.vh
+bram_init_9_18_36.vh
+brams_init.mk
+bram_conn_1.vh
+bram_conn_2.vh
+bram_conn_4.vh
+bram_conn_9.vh
+bram_conn_18.vh
+brams_connect.mk
diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc
index 9d324734..4db087e8 100644
--- a/techlibs/ecp5/Makefile.inc
+++ b/techlibs/ecp5/Makefile.inc
@@ -1,8 +1,44 @@
-OBJS += techlibs/ecp5/synth_ecp5.o
+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/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))
+
+EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
+.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
+
+techlibs/ecp5/brams_init.mk: techlibs/ecp5/brams_init.py
+ $(Q) mkdir -p techlibs/ecp5
+ $(P) python3 $<
+ $(Q) touch $@
+
+techlibs/ecp5/brams_connect.mk: techlibs/ecp5/brams_connect.py
+ $(Q) mkdir -p techlibs/ecp5
+ $(P) python3 $<
+ $(Q) touch $@
+
+
+techlibs/ecp5/bram_init_1_2_4.vh: techlibs/ecp5/brams_init.mk
+techlibs/ecp5/bram_init_9_18_36.vh: techlibs/ecp5/brams_init.mk
+
+techlibs/ecp5/bram_conn_1.vh: techlibs/ecp5/brams_connect.mk
+techlibs/ecp5/bram_conn_2.vh: techlibs/ecp5/brams_connect.mk
+techlibs/ecp5/bram_conn_4.vh: techlibs/ecp5/brams_connect.mk
+techlibs/ecp5/bram_conn_9.vh: techlibs/ecp5/brams_connect.mk
+techlibs/ecp5/bram_conn_18.vh: techlibs/ecp5/brams_connect.mk
+
+$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_init_1_2_4.vh))
+$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_init_9_18_36.vh))
+
+$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_1.vh))
+$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_2.vh))
+$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_4.vh))
+$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_9.vh))
+$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_18.vh))
diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v
index 1094c5f8..eb794760 100644
--- a/techlibs/ecp5/arith_map.v
+++ b/techlibs/ecp5/arith_map.v
@@ -33,7 +33,7 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
input CI, BI;
output [Y_WIDTH-1:0] CO;
- wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
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));
diff --git a/techlibs/ecp5/bram.txt b/techlibs/ecp5/bram.txt
new file mode 100644
index 00000000..f223a42b
--- /dev/null
+++ b/techlibs/ecp5/bram.txt
@@ -0,0 +1,29 @@
+bram $__ECP5_DP16KD
+ init 1
+
+ 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 1 0
+ enable 2 1 @a10d18
+ enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1
+ transp 0 2
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+match $__ECP5_DP16KD
+ min bits 2048
+ min efficiency 5
+ shuffle_enable B
+endmatch
diff --git a/techlibs/ecp5/brams_connect.py b/techlibs/ecp5/brams_connect.py
new file mode 100755
index 00000000..f86dcfcf
--- /dev/null
+++ b/techlibs/ecp5/brams_connect.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+
+def write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits):
+ ada_conn = [".ADA%d(%s)" % (i, ada_bits[i]) for i in range(len(ada_bits))]
+ adb_conn = [".ADB%d(%s)" % (i, adb_bits[i]) for i in range(len(adb_bits))]
+ dia_conn = [".DIA%d(%s)" % (i, dia_bits[i]) for i in range(len(dia_bits))]
+ dob_conn = [".DOB%d(%s)" % (i, dob_bits[i]) for i in range(len(dob_bits))]
+ print(" %s," % ", ".join(ada_conn), file=f)
+ print(" %s," % ", ".join(adb_conn), file=f)
+ print(" %s," % ", ".join(dia_conn), file=f)
+ print(" %s," % ", ".join(dob_conn), file=f)
+
+with open("techlibs/ecp5/bram_conn_1.vh", "w") as f:
+ ada_bits = ["A1ADDR[%d]" % i for i in range(14)]
+ adb_bits = ["B1ADDR[%d]" % i for i in range(14)]
+ dia_bits = ["A1DATA[0]"] + ["1'b0" for i in range(17)]
+ dob_bits = ["B1DATA[0]"]
+ write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
+
+with open("techlibs/ecp5/bram_conn_2.vh", "w") as f:
+ ada_bits = ["1'b0"] + ["A1ADDR[%d]" % i for i in range(13)]
+ adb_bits = ["1'b0"] + ["B1ADDR[%d]" % i for i in range(13)]
+ dia_bits = ["A1DATA[%d]" % i for i in range(2)] + ["1'b0" for i in range(16)]
+ dob_bits = ["B1DATA[%d]" % i for i in range(2)]
+ write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
+
+with open("techlibs/ecp5/bram_conn_4.vh", "w") as f:
+ ada_bits = ["1'b0", "1'b0"] + ["A1ADDR[%d]" % i for i in range(12)]
+ adb_bits = ["1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(12)]
+ dia_bits = ["A1DATA[%d]" % i for i in range(4)] + ["1'b0" for i in range(14)]
+ dob_bits = ["B1DATA[%d]" % i for i in range(4)]
+ write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
+
+with open("techlibs/ecp5/bram_conn_9.vh", "w") as f:
+ ada_bits = ["1'b0", "1'b0", "1'b0"] + ["A1ADDR[%d]" % i for i in range(11)]
+ adb_bits = ["1'b0", "1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(11)]
+ dia_bits = ["A1DATA[%d]" % i for i in range(9)] + ["1'b0" for i in range(9)]
+ dob_bits = ["B1DATA[%d]" % i for i in range(9)]
+ write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
+
+with open("techlibs/ecp5/bram_conn_18.vh", "w") as f:
+ ada_bits = ["A1EN[0]", "A1EN[1]", "1'b0", "1'b0"] + ["A1ADDR[%d]" % i for i in range(10)]
+ adb_bits = ["1'b0", "1'b0", "1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(10)]
+ dia_bits = ["A1DATA[%d]" % i for i in range(18)]
+ dob_bits = ["B1DATA[%d]" % i for i in range(18)]
+ write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
diff --git a/techlibs/ecp5/brams_init.py b/techlibs/ecp5/brams_init.py
new file mode 100755
index 00000000..96a47bdc
--- /dev/null
+++ b/techlibs/ecp5/brams_init.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+with open("techlibs/ecp5/bram_init_1_2_4.vh", "w") as f:
+ for i in range(0, 0x40):
+ init_snippets = []
+ for j in range(32):
+ init_snippets.append("INIT[%4d*8 +: 8]" % (32 * i + j))
+ init_snippets.append("3'b000" if (j % 2 == 1) else "1'b0")
+ init_snippets = list(reversed(init_snippets))
+ for k in range(8, 64, 8):
+ init_snippets[k] = "\n " + init_snippets[k]
+ print(".INITVAL_%02X({%s})," % (i, ", ".join(init_snippets)), file=f)
+
+with open("techlibs/ecp5/bram_init_9_18_36.vh", "w") as f:
+ for i in range(0, 0x40):
+ init_snippets = []
+ for j in range(16):
+ init_snippets.append("INIT[%3d*18 +: 18]" % (16 * i + j))
+ init_snippets.append("2'b00")
+ init_snippets = list(reversed(init_snippets))
+ for k in range(8, 32, 8):
+ init_snippets[k] = "\n " + init_snippets[k]
+ print(".INITVAL_%02X({%s})," % (i, ", ".join(init_snippets)), file=f)
diff --git a/techlibs/ecp5/brams_map.v b/techlibs/ecp5/brams_map.v
new file mode 100644
index 00000000..b2c13686
--- /dev/null
+++ b/techlibs/ecp5/brams_map.v
@@ -0,0 +1,115 @@
+module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 10;
+ parameter CFG_DBITS = 18;
+ parameter CFG_ENABLE_A = 2;
+
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+ parameter [18431:0] INIT = 18432'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 CLKAMUX = CLKPOL2 ? "CLKA" : "INV";
+ localparam CLKBMUX = CLKPOL3 ? "CLKB" : "INV";
+
+ localparam WRITEMODE_A = TRANSP2 ? "WRITETHROUGH" : "READBEFOREWRITE";
+
+ generate if (CFG_DBITS == 1) begin
+ DP16KD #(
+ `include "bram_init_1_2_4.vh"
+ .DATA_WIDTH_A(1),
+ .DATA_WIDTH_B(1),
+ .CLKAMUX(CLKAMUX),
+ .CLKBMUX(CLKBMUX),
+ .WRITEMODE_A(WRITEMODE_A),
+ .WRITEMODE_B("READBEFOREWRITE"),
+ .GSR("DISABLED")
+ ) _TECHMAP_REPLACE_ (
+ `include "bram_conn_1.vh"
+ .CLKA(CLK2), .CLKB(CLK3),
+ .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
+ .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
+ .RSTA(1'b0), .RSTB(1'b0)
+ );
+ end else if (CFG_DBITS == 2) begin
+ DP16KD #(
+ `include "bram_init_1_2_4.vh"
+ .DATA_WIDTH_A(2),
+ .DATA_WIDTH_B(2),
+ .CLKAMUX(CLKAMUX),
+ .CLKBMUX(CLKBMUX),
+ .WRITEMODE_A(WRITEMODE_A),
+ .WRITEMODE_B("READBEFOREWRITE"),
+ .GSR("DISABLED")
+ ) _TECHMAP_REPLACE_ (
+ `include "bram_conn_2.vh"
+ .CLKA(CLK2), .CLKB(CLK3),
+ .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
+ .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
+ .RSTA(1'b0), .RSTB(1'b0)
+ );
+ end else if (CFG_DBITS <= 4) begin
+ DP16KD #(
+ `include "bram_init_1_2_4.vh"
+ .DATA_WIDTH_A(4),
+ .DATA_WIDTH_B(4),
+ .CLKAMUX(CLKAMUX),
+ .CLKBMUX(CLKBMUX),
+ .WRITEMODE_A(WRITEMODE_A),
+ .WRITEMODE_B("READBEFOREWRITE"),
+ .GSR("DISABLED")
+ ) _TECHMAP_REPLACE_ (
+ `include "bram_conn_4.vh"
+ .CLKA(CLK2), .CLKB(CLK3),
+ .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
+ .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
+ .RSTA(1'b0), .RSTB(1'b0)
+ );
+ end else if (CFG_DBITS <= 9) begin
+ DP16KD #(
+ `include "bram_init_9_18_36.vh"
+ .DATA_WIDTH_A(9),
+ .DATA_WIDTH_B(9),
+ .CLKAMUX(CLKAMUX),
+ .CLKBMUX(CLKBMUX),
+ .WRITEMODE_A(WRITEMODE_A),
+ .WRITEMODE_B("READBEFOREWRITE"),
+ .GSR("DISABLED")
+ ) _TECHMAP_REPLACE_ (
+ `include "bram_conn_9.vh"
+ .CLKA(CLK2), .CLKB(CLK3),
+ .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
+ .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
+ .RSTA(1'b0), .RSTB(1'b0)
+ );
+ end else if (CFG_DBITS <= 18) begin
+ DP16KD #(
+ `include "bram_init_9_18_36.vh"
+ .DATA_WIDTH_A(18),
+ .DATA_WIDTH_B(18),
+ .CLKAMUX(CLKAMUX),
+ .CLKBMUX(CLKBMUX),
+ .WRITEMODE_A(WRITEMODE_A),
+ .WRITEMODE_B("READBEFOREWRITE"),
+ .GSR("DISABLED")
+ ) _TECHMAP_REPLACE_ (
+ `include "bram_conn_18.vh"
+ .CLKA(CLK2), .CLKB(CLK3),
+ .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
+ .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
+ .RSTA(1'b0), .RSTB(1'b0)
+ );
+ end else begin
+ wire TECHMAP_FAIL = 1'b1;
+ end endgenerate
+endmodule
diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v
new file mode 100644
index 00000000..223e19b9
--- /dev/null
+++ b/techlibs/ecp5/cells_bb.v
@@ -0,0 +1,666 @@
+// ECP5 Blackbox cells
+// FIXME: Create sim models
+
+(* blackbox *)
+module MULT18X18D(
+ input A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17,
+ input B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16, B17,
+ input C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17,
+ input SIGNEDA, SIGNEDB, SOURCEA, SOURCEB,
+ input CLK0, CLK1, CLK2, CLK3,
+ input CE0, CE1, CE2, CE3,
+ input RST0, RST1, RST2, RST3,
+ input SRIA0, SRIA1, SRIA2, SRIA3, SRIA4, SRIA5, SRIA6, SRIA7, SRIA8, SRIA9, SRIA10, SRIA11, SRIA12, SRIA13, SRIA14, SRIA15, SRIA16, SRIA17,
+ input SRIB0, SRIB1, SRIB2, SRIB3, SRIB4, SRIB5, SRIB6, SRIB7, SRIB8, SRIB9, SRIB10, SRIB11, SRIB12, SRIB13, SRIB14, SRIB15, SRIB16, SRIB17,
+ output SROA0, SROA1, SROA2, SROA3, SROA4, SROA5, SROA6, SROA7, SROA8, SROA9, SROA10, SROA11, SROA12, SROA13, SROA14, SROA15, SROA16, SROA17,
+ output SROB0, SROB1, SROB2, SROB3, SROB4, SROB5, SROB6, SROB7, SROB8, SROB9, SROB10, SROB11, SROB12, SROB13, SROB14, SROB15, SROB16, SROB17,
+ output ROA0, ROA1, ROA2, ROA3, ROA4, ROA5, ROA6, ROA7, ROA8, ROA9, ROA10, ROA11, ROA12, ROA13, ROA14, ROA15, ROA16, ROA17,
+ output ROB0, ROB1, ROB2, ROB3, ROB4, ROB5, ROB6, ROB7, ROB8, ROB9, ROB10, ROB11, ROB12, ROB13, ROB14, ROB15, ROB16, ROB17,
+ output ROC0, ROC1, ROC2, ROC3, ROC4, ROC5, ROC6, ROC7, ROC8, ROC9, ROC10, ROC11, ROC12, ROC13, ROC14, ROC15, ROC16, ROC17,
+ output P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35,
+ output SIGNEDP
+);
+ parameter REG_INPUTA_CLK = "NONE";
+ parameter REG_INPUTA_CE = "CE0";
+ parameter REG_INPUTA_RST = "RST0";
+ parameter REG_INPUTB_CLK = "NONE";
+ parameter REG_INPUTB_CE = "CE0";
+ parameter REG_INPUTB_RST = "RST0";
+ parameter REG_INPUTC_CLK = "NONE";
+ parameter REG_PIPELINE_CLK = "NONE";
+ parameter REG_PIPELINE_CE = "CE0";
+ parameter REG_PIPELINE_RST = "RST0";
+ parameter REG_OUTPUT_CLK = "NONE";
+ parameter [127:0] CLK0_DIV = "ENABLED";
+ parameter [127:0] CLK1_DIV = "ENABLED";
+ parameter [127:0] CLK2_DIV = "ENABLED";
+ parameter [127:0] CLK3_DIV = "ENABLED";
+ parameter [127:0] GSR = "ENABLED";
+ parameter [127:0] SOURCEB_MODE = "B_SHIFT";
+ parameter [127:0] RESETMODE = "SYNC";
+endmodule
+
+(* blackbox *)
+module ALU54B(
+ input CLK0, CLK1, CLK2, CLK3,
+ input CE0, CE1, CE2, CE3,
+ input RST0, RST1, RST2, RST3,
+ input SIGNEDIA, SIGNEDIB, SIGNEDCIN,
+ input A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35,
+ input B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B20, B21, B22, B23, B24, B25, B26, B27, B28, B29, B30, B31, B32, B33, B34, B35,
+ input C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26, C27, C28, C29, C30, C31, C32, C33, C34, C35, C36, C37, C38, C39, C40, C41, C42, C43, C44, C45, C46, C47, C48, C49, C50, C51, C52, C53,
+ input CFB0, CFB1, CFB2, CFB3, CFB4, CFB5, CFB6, CFB7, CFB8, CFB9, CFB10, CFB11, CFB12, CFB13, CFB14, CFB15, CFB16, CFB17, CFB18, CFB19, CFB20, CFB21, CFB22, CFB23, CFB24, CFB25, CFB26, CFB27, CFB28, CFB29, CFB30, CFB31, CFB32, CFB33, CFB34, CFB35, CFB36, CFB37, CFB38, CFB39, CFB40, CFB41, CFB42, CFB43, CFB44, CFB45, CFB46, CFB47, CFB48, CFB49, CFB50, CFB51, CFB52, CFB53,
+ input MA0, MA1, MA2, MA3, MA4, MA5, MA6, MA7, MA8, MA9, MA10, MA11, MA12, MA13, MA14, MA15, MA16, MA17, MA18, MA19, MA20, MA21, MA22, MA23, MA24, MA25, MA26, MA27, MA28, MA29, MA30, MA31, MA32, MA33, MA34, MA35,
+ input MB0, MB1, MB2, MB3, MB4, MB5, MB6, MB7, MB8, MB9, MB10, MB11, MB12, MB13, MB14, MB15, MB16, MB17, MB18, MB19, MB20, MB21, MB22, MB23, MB24, MB25, MB26, MB27, MB28, MB29, MB30, MB31, MB32, MB33, MB34, MB35,
+ input CIN0, CIN1, CIN2, CIN3, CIN4, CIN5, CIN6, CIN7, CIN8, CIN9, CIN10, CIN11, CIN12, CIN13, CIN14, CIN15, CIN16, CIN17, CIN18, CIN19, CIN20, CIN21, CIN22, CIN23, CIN24, CIN25, CIN26, CIN27, CIN28, CIN29, CIN30, CIN31, CIN32, CIN33, CIN34, CIN35, CIN36, CIN37, CIN38, CIN39, CIN40, CIN41, CIN42, CIN43, CIN44, CIN45, CIN46, CIN47, CIN48, CIN49, CIN50, CIN51, CIN52, CIN53,
+ input OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7, OP8, OP9, OP10,
+ output R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, R32, R33, R34, R35, R36, R37, R38, R39, R40, R41, R42, R43, R44, R45, R46, R47, R48, R49, R50, R51, R52, R53,
+ output CO0, CO1, CO2, CO3, CO4, CO5, CO6, CO7, CO8, CO9, CO10, CO11, CO12, CO13, CO14, CO15, CO16, CO17, CO18, CO19, CO20, CO21, CO22, CO23, CO24, CO25, CO26, CO27, CO28, CO29, CO30, CO31, CO32, CO33, CO34, CO35, CO36, CO37, CO38, CO39, CO40, CO41, CO42, CO43, CO44, CO45, CO46, CO47, CO48, CO49, CO50, CO51, CO52, CO53,
+ output EQZ, EQZM, EQOM, EQPAT, EQPATB,
+ output OVER, UNDER, OVERUNDER,
+ output SIGNEDR
+);
+ parameter REG_INPUTC0_CLK = "NONE";
+ parameter REG_INPUTC1_CLK = "NONE";
+ parameter REG_OPCODEOP0_0_CLK = "NONE";
+ parameter REG_OPCODEOP0_0_CE = "CE0";
+ parameter REG_OPCODEOP0_0_RST = "RST0";
+ parameter REG_OPCODEOP1_0_CLK = "NONE";
+ parameter REG_OPCODEOP0_1_CLK = "NONE";
+ parameter REG_OPCODEOP0_1_CE = "CE0";
+ parameter REG_OPCODEOP0_1_RST = "RST0";
+ parameter REG_OPCODEIN_0_CLK = "NONE";
+ parameter REG_OPCODEIN_0_CE = "CE0";
+ parameter REG_OPCODEIN_0_RST = "RST0";
+ parameter REG_OPCODEIN_1_CLK = "NONE";
+ parameter REG_OPCODEIN_1_CE = "CE0";
+ parameter REG_OPCODEIN_1_RST = "RST0";
+ parameter REG_OUTPUT0_CLK = "NONE";
+ parameter REG_OUTPUT1_CLK = "NONE";
+ parameter REG_FLAG_CLK = "NONE";
+ parameter [127:0] MCPAT_SOURCE = "STATIC";
+ parameter [127:0] MASKPAT_SOURCE = "STATIC";
+ parameter MASK01 = "0x00000000000000";
+ parameter [127:0] CLK0_DIV = "ENABLED";
+ parameter [127:0] CLK1_DIV = "ENABLED";
+ parameter [127:0] CLK2_DIV = "ENABLED";
+ parameter [127:0] CLK3_DIV = "ENABLED";
+ parameter MCPAT = "0x00000000000000";
+ parameter MASKPAT = "0x00000000000000";
+ parameter RNDPAT = "0x00000000000000";
+ parameter [127:0] GSR = "ENABLED";
+ parameter [127:0] RESETMODE = "SYNC";
+ parameter FORCE_ZERO_BARREL_SHIFT = "DISABLED";
+ parameter LEGACY = "DISABLED";
+endmodule
+
+(* blackbox *)
+module EHXPLLL (
+ input CLKI, CLKFB,
+ input PHASESEL1, PHASESEL0, PHASEDIR, PHASESTEP, PHASELOADREG,
+ input STDBY, PLLWAKESYNC,
+ input RST, ENCLKOP, ENCLKOS, ENCLKOS2, ENCLKOS3,
+ output CLKOP, CLKOS, CLKOS2, CLKOS3,
+ output LOCK, INTLOCK,
+ output REFCLK, CLKINTFB
+);
+ parameter CLKI_DIV = 1;
+ parameter CLKFB_DIV = 1;
+ parameter CLKOP_DIV = 8;
+ parameter CLKOS_DIV = 8;
+ parameter CLKOS2_DIV = 8;
+ parameter CLKOS3_DIV = 8;
+ parameter CLKOP_ENABLE = "ENABLED";
+ parameter CLKOS_ENABLE = "DISABLED";
+ parameter CLKOS2_ENABLE = "DISABLED";
+ parameter CLKOS3_ENABLE = "DISABLED";
+ parameter CLKOP_CPHASE = 0;
+ parameter CLKOS_CPHASE = 0;
+ parameter CLKOS2_CPHASE = 0;
+ parameter CLKOS3_CPHASE = 0;
+ parameter CLKOP_FPHASE = 0;
+ parameter CLKOS_FPHASE = 0;
+ parameter CLKOS2_FPHASE = 0;
+ parameter CLKOS3_FPHASE = 0;
+ parameter FEEDBK_PATH = "CLKOP";
+ parameter CLKOP_TRIM_POL = "RISING";
+ parameter CLKOP_TRIM_DELAY = 0;
+ parameter CLKOS_TRIM_POL = "RISING";
+ parameter CLKOS_TRIM_DELAY = 0;
+ parameter OUTDIVIDER_MUXA = "DIVA";
+ parameter OUTDIVIDER_MUXB = "DIVB";
+ parameter OUTDIVIDER_MUXC = "DIVC";
+ parameter OUTDIVIDER_MUXD = "DIVD";
+ parameter PLL_LOCK_MODE = 0;
+ parameter PLL_LOCK_DELAY = 200;
+ parameter STDBY_ENABLE = "DISABLED";
+ parameter REFIN_RESET = "DISABLED";
+ parameter SYNC_ENABLE = "DISABLED";
+ parameter INT_LOCK_STICKY = "ENABLED";
+ parameter DPHASE_SOURCE = "DISABLED";
+ parameter PLLRST_ENA = "DISABLED";
+ parameter INTFB_WAKE = "DISABLED";
+endmodule
+
+(* blackbox *)
+module DTR(
+ input STARTPULSE,
+ output DTROUT7, DTROUT6, DTROUT5, DTROUT4, DTROUT3, DTROUT2, DTROUT1, DTROUT0
+);
+endmodule
+
+(* blackbox *)
+module OSCG(
+ output OSC
+);
+parameter DIV = 128;
+endmodule
+
+(* blackbox *) (* keep *)
+module USRMCLK(
+ input USRMCLKI, USRMCLKTS,
+ output USRMCLKO
+);
+endmodule
+
+(* blackbox *) (* keep *)
+module JTAGG(
+ input TCK, TMS, TDI, JTDO2, JTDO1,
+ output TDO, JTDI, JTCK, JRTI2, JRTI1,
+ output JSHIFT, JUPDATE, JRSTN, JCE2, JCE1
+);
+parameter ER1 = "ENABLED";
+parameter ER2 = "ENABLED";
+endmodule
+
+(* blackbox *)
+module DELAYF(
+ input A, LOADN, MOVE, DIRECTION,
+ output Z, CFLAG
+);
+ parameter DEL_MODE = "USER_DEFINED";
+ parameter DEL_VALUE = 0;
+endmodule
+
+(* blackbox *)
+module DELAYG(
+ input A,
+ output Z
+);
+ parameter DEL_MODE = "USER_DEFINED";
+ parameter DEL_VALUE = 0;
+endmodule
+
+(* blackbox *)
+module IDDRX1F(
+ input D, SCLK, RST,
+ output Q0, Q1
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module IDDRX2F(
+ input D, SCLK, ECLK, RST,
+ output Q0, Q1, Q2, Q3
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module IDDR71B(
+ input D, SCLK, ECLK, RST, ALIGNWD,
+ output Q0, Q1, Q2, Q3, Q4, Q5, Q6
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module IDDRX2DQA(
+ input D, DQSR90, ECLK, SCLK, RST,
+ input RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0,
+ output Q0, Q1, Q2, Q3, QWL
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module ODDRX1F(
+ input SCLK, RST, D0, D1,
+ output Q
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module ODDRX2F(
+ input SCLK, ECLK, RST, D0, D1, D2, D3,
+ output Q
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module ODDR71B(
+ input SCLK, ECLK, RST, D0, D1, D2, D3, D4, D5, D6,
+ output Q
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module OSHX2A(
+ input D0, D1, RST, ECLK, SCLK,
+ output Q
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module ODDRX2DQA(
+ input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW270,
+ output Q
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module ODDRX2DQSB(
+ input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW,
+ output Q
+);
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module TSHX2DQA(
+ input T0, T1, SCLK, ECLK, DQSW270, RST,
+ output Q
+);
+ parameter GSR = "ENABLED";
+ parameter REGSET = "SET";
+endmodule
+
+(* blackbox *)
+module TSHX2DQSA(
+ input T0, T1, SCLK, ECLK, DQSW, RST,
+ output Q
+);
+ parameter GSR = "ENABLED";
+ parameter REGSET = "SET";
+endmodule
+
+(* blackbox *)
+module DQSBUFM(
+ input DQSI, READ1, READ0, READCLKSEL2, READCLKSEL1, READCLKSEL0, DDRDEL,
+ input ECLK, SCLK,
+ input DYNDELAY7, DYNDELAY6, DYNDELAY5, DYNDELAY4,
+ input DYNDELAY3, DYNDELAY2, DYNDELAY1, DYNDELAY0,
+ input RST, RDLOADN, RDMOVE, RDDIRECTION, WRLOADN, WRMOVE, WRDIRECTION, PAUSE,
+ output DQSR90, DQSW, DQSW270,
+ output RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0,
+ output DATAVALID, BURSTDET, RDCFLAG, WRCFLAG
+);
+ parameter DQS_LI_DEL_ADJ = "FACTORYONLY";
+ parameter DQS_LI_DEL_VAL = 0;
+ parameter DQS_LO_DEL_ADJ = "FACTORYONLY";
+ parameter DQS_LO_DEL_VAL = 0;
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module DDRDLLA(
+ input CLK, RST, UDDCNTLN, FREEZE,
+ output LOCK, DDRDEL, DCNTL7, DCNTL6, DCNTL5, DCNTL4, DCNTL3, DCNTL2, DCNTL1, DCNTL0
+);
+ parameter FORCE_MAX_DELAY = "NO";
+ parameter GSR = "ENABLED";
+endmodule
+
+(* blackbox *)
+module CLKDIVF(
+ input CLKI, RST, ALIGNWD,
+ output CDIVX
+);
+ parameter GSR = "DISABLED";
+ parameter DIV = "2.0";
+endmodule
+
+(* blackbox *)
+module ECLKSYNCB(
+ input ECLKI, STOP,
+ output ECLKO
+);
+endmodule
+
+(* blackbox *)
+module DCCA(
+ input CLKI, CE,
+ output CLKO
+);
+endmodule
+
+(* blackbox *) (* keep *)
+module DCUA(
+ input CH0_HDINP, CH1_HDINP, CH0_HDINN, CH1_HDINN,
+ input D_TXBIT_CLKP_FROM_ND, D_TXBIT_CLKN_FROM_ND, D_SYNC_ND, D_TXPLL_LOL_FROM_ND,
+ input CH0_RX_REFCLK, CH1_RX_REFCLK, CH0_FF_RXI_CLK, CH1_FF_RXI_CLK, CH0_FF_TXI_CLK, CH1_FF_TXI_CLK, CH0_FF_EBRD_CLK, CH1_FF_EBRD_CLK,
+ input CH0_FF_TX_D_0, CH1_FF_TX_D_0, CH0_FF_TX_D_1, CH1_FF_TX_D_1, CH0_FF_TX_D_2, CH1_FF_TX_D_2, CH0_FF_TX_D_3, CH1_FF_TX_D_3,
+ input CH0_FF_TX_D_4, CH1_FF_TX_D_4, CH0_FF_TX_D_5, CH1_FF_TX_D_5, CH0_FF_TX_D_6, CH1_FF_TX_D_6, CH0_FF_TX_D_7, CH1_FF_TX_D_7,
+ input CH0_FF_TX_D_8, CH1_FF_TX_D_8, CH0_FF_TX_D_9, CH1_FF_TX_D_9, CH0_FF_TX_D_10, CH1_FF_TX_D_10, CH0_FF_TX_D_11, CH1_FF_TX_D_11,
+ input CH0_FF_TX_D_12, CH1_FF_TX_D_12, CH0_FF_TX_D_13, CH1_FF_TX_D_13, CH0_FF_TX_D_14, CH1_FF_TX_D_14, CH0_FF_TX_D_15, CH1_FF_TX_D_15,
+ input CH0_FF_TX_D_16, CH1_FF_TX_D_16, CH0_FF_TX_D_17, CH1_FF_TX_D_17, CH0_FF_TX_D_18, CH1_FF_TX_D_18, CH0_FF_TX_D_19, CH1_FF_TX_D_19,
+ input CH0_FF_TX_D_20, CH1_FF_TX_D_20, CH0_FF_TX_D_21, CH1_FF_TX_D_21, CH0_FF_TX_D_22, CH1_FF_TX_D_22, CH0_FF_TX_D_23, CH1_FF_TX_D_23,
+ input CH0_FFC_EI_EN, CH1_FFC_EI_EN, CH0_FFC_PCIE_DET_EN, CH1_FFC_PCIE_DET_EN, CH0_FFC_PCIE_CT, CH1_FFC_PCIE_CT, CH0_FFC_SB_INV_RX, CH1_FFC_SB_INV_RX,
+ input CH0_FFC_ENABLE_CGALIGN, CH1_FFC_ENABLE_CGALIGN, CH0_FFC_SIGNAL_DETECT, CH1_FFC_SIGNAL_DETECT, CH0_FFC_FB_LOOPBACK, CH1_FFC_FB_LOOPBACK, CH0_FFC_SB_PFIFO_LP, CH1_FFC_SB_PFIFO_LP,
+ input CH0_FFC_PFIFO_CLR, CH1_FFC_PFIFO_CLR, CH0_FFC_RATE_MODE_RX, CH1_FFC_RATE_MODE_RX, CH0_FFC_RATE_MODE_TX, CH1_FFC_RATE_MODE_TX, CH0_FFC_DIV11_MODE_RX, CH1_FFC_DIV11_MODE_RX, CH0_FFC_RX_GEAR_MODE, CH1_FFC_RX_GEAR_MODE, CH0_FFC_TX_GEAR_MODE, CH1_FFC_TX_GEAR_MODE,
+ input CH0_FFC_DIV11_MODE_TX, CH1_FFC_DIV11_MODE_TX, CH0_FFC_LDR_CORE2TX_EN, CH1_FFC_LDR_CORE2TX_EN, CH0_FFC_LANE_TX_RST, CH1_FFC_LANE_TX_RST, CH0_FFC_LANE_RX_RST, CH1_FFC_LANE_RX_RST,
+ input CH0_FFC_RRST, CH1_FFC_RRST, CH0_FFC_TXPWDNB, CH1_FFC_TXPWDNB, CH0_FFC_RXPWDNB, CH1_FFC_RXPWDNB, CH0_LDR_CORE2TX, CH1_LDR_CORE2TX,
+ input D_SCIWDATA0, D_SCIWDATA1, D_SCIWDATA2, D_SCIWDATA3, D_SCIWDATA4, D_SCIWDATA5, D_SCIWDATA6, D_SCIWDATA7,
+ input D_SCIADDR0, D_SCIADDR1, D_SCIADDR2, D_SCIADDR3, D_SCIADDR4, D_SCIADDR5, D_SCIENAUX, D_SCISELAUX,
+ input CH0_SCIEN, CH1_SCIEN, CH0_SCISEL, CH1_SCISEL, D_SCIRD, D_SCIWSTN, D_CYAWSTN, D_FFC_SYNC_TOGGLE,
+ input D_FFC_DUAL_RST, D_FFC_MACRO_RST, D_FFC_MACROPDB, D_FFC_TRST, CH0_FFC_CDR_EN_BITSLIP, CH1_FFC_CDR_EN_BITSLIP, D_SCAN_ENABLE, D_SCAN_IN_0,
+ input D_SCAN_IN_1, D_SCAN_IN_2, D_SCAN_IN_3, D_SCAN_IN_4, D_SCAN_IN_5, D_SCAN_IN_6, D_SCAN_IN_7, D_SCAN_MODE,
+ input D_SCAN_RESET, D_CIN0, D_CIN1, D_CIN2, D_CIN3, D_CIN4, D_CIN5, D_CIN6,D_CIN7, D_CIN8, D_CIN9, D_CIN10, D_CIN11,
+ output CH0_HDOUTP, CH1_HDOUTP, CH0_HDOUTN, CH1_HDOUTN, D_TXBIT_CLKP_TO_ND, D_TXBIT_CLKN_TO_ND, D_SYNC_PULSE2ND, D_TXPLL_LOL_TO_ND,
+ output CH0_FF_RX_F_CLK, CH1_FF_RX_F_CLK, CH0_FF_RX_H_CLK, CH1_FF_RX_H_CLK, CH0_FF_TX_F_CLK, CH1_FF_TX_F_CLK, CH0_FF_TX_H_CLK, CH1_FF_TX_H_CLK,
+ output CH0_FF_RX_PCLK, CH1_FF_RX_PCLK, CH0_FF_TX_PCLK, CH1_FF_TX_PCLK, CH0_FF_RX_D_0, CH1_FF_RX_D_0, CH0_FF_RX_D_1, CH1_FF_RX_D_1,
+ output CH0_FF_RX_D_2, CH1_FF_RX_D_2, CH0_FF_RX_D_3, CH1_FF_RX_D_3, CH0_FF_RX_D_4, CH1_FF_RX_D_4, CH0_FF_RX_D_5, CH1_FF_RX_D_5,
+ output CH0_FF_RX_D_6, CH1_FF_RX_D_6, CH0_FF_RX_D_7, CH1_FF_RX_D_7, CH0_FF_RX_D_8, CH1_FF_RX_D_8, CH0_FF_RX_D_9, CH1_FF_RX_D_9,
+ output CH0_FF_RX_D_10, CH1_FF_RX_D_10, CH0_FF_RX_D_11, CH1_FF_RX_D_11, CH0_FF_RX_D_12, CH1_FF_RX_D_12, CH0_FF_RX_D_13, CH1_FF_RX_D_13,
+ output CH0_FF_RX_D_14, CH1_FF_RX_D_14, CH0_FF_RX_D_15, CH1_FF_RX_D_15, CH0_FF_RX_D_16, CH1_FF_RX_D_16, CH0_FF_RX_D_17, CH1_FF_RX_D_17,
+ output CH0_FF_RX_D_18, CH1_FF_RX_D_18, CH0_FF_RX_D_19, CH1_FF_RX_D_19, CH0_FF_RX_D_20, CH1_FF_RX_D_20, CH0_FF_RX_D_21, CH1_FF_RX_D_21,
+ output CH0_FF_RX_D_22, CH1_FF_RX_D_22, CH0_FF_RX_D_23, CH1_FF_RX_D_23, CH0_FFS_PCIE_DONE, CH1_FFS_PCIE_DONE, CH0_FFS_PCIE_CON, CH1_FFS_PCIE_CON,
+ output CH0_FFS_RLOS, CH1_FFS_RLOS, CH0_FFS_LS_SYNC_STATUS, CH1_FFS_LS_SYNC_STATUS, CH0_FFS_CC_UNDERRUN, CH1_FFS_CC_UNDERRUN, CH0_FFS_CC_OVERRUN, CH1_FFS_CC_OVERRUN,
+ output CH0_FFS_RXFBFIFO_ERROR, CH1_FFS_RXFBFIFO_ERROR, CH0_FFS_TXFBFIFO_ERROR, CH1_FFS_TXFBFIFO_ERROR, CH0_FFS_RLOL, CH1_FFS_RLOL, CH0_FFS_SKP_ADDED, CH1_FFS_SKP_ADDED,
+ output CH0_FFS_SKP_DELETED, CH1_FFS_SKP_DELETED, CH0_LDR_RX2CORE, CH1_LDR_RX2CORE, D_SCIRDATA0, D_SCIRDATA1, D_SCIRDATA2, D_SCIRDATA3,
+ output D_SCIRDATA4, D_SCIRDATA5, D_SCIRDATA6, D_SCIRDATA7, D_SCIINT, D_SCAN_OUT_0, D_SCAN_OUT_1, D_SCAN_OUT_2, D_SCAN_OUT_3, D_SCAN_OUT_4, D_SCAN_OUT_5, D_SCAN_OUT_6, D_SCAN_OUT_7,
+ output D_COUT0, D_COUT1, D_COUT2, D_COUT3, D_COUT4, D_COUT5, D_COUT6, D_COUT7, D_COUT8, D_COUT9, D_COUT10, D_COUT11, D_COUT12, D_COUT13, D_COUT14, D_COUT15, D_COUT16, D_COUT17, D_COUT18, D_COUT19,
+
+ input D_REFCLKI,
+ output D_FFS_PLOL
+);
+ parameter CH0_AUTO_CALIB_EN = "0b0";
+ parameter CH0_AUTO_FACQ_EN = "0b0";
+ parameter CH0_BAND_THRESHOLD = "0b000000";
+ parameter CH0_CALIB_CK_MODE = "0b0";
+ parameter CH0_CC_MATCH_1 = "0b0000000000";
+ parameter CH0_CC_MATCH_2 = "0b0000000000";
+ parameter CH0_CC_MATCH_3 = "0b0000000000";
+ parameter CH0_CC_MATCH_4 = "0b0000000000";
+ parameter CH0_CDR_CNT4SEL = "0b00";
+ parameter CH0_CDR_CNT8SEL = "0b00";
+ parameter CH0_CTC_BYPASS = "0b0";
+ parameter CH0_DCOATDCFG = "0b00";
+ parameter CH0_DCOATDDLY = "0b00";
+ parameter CH0_DCOBYPSATD = "0b0";
+ parameter CH0_DCOCALDIV = "0b000";
+ parameter CH0_DCOCTLGI = "0b000";
+ parameter CH0_DCODISBDAVOID = "0b0";
+ parameter CH0_DCOFLTDAC = "0b00";
+ parameter CH0_DCOFTNRG = "0b000";
+ parameter CH0_DCOIOSTUNE = "0b000";
+ parameter CH0_DCOITUNE = "0b00";
+ parameter CH0_DCOITUNE4LSB = "0b000";
+ parameter CH0_DCOIUPDNX2 = "0b0";
+ parameter CH0_DCONUOFLSB = "0b000";
+ parameter CH0_DCOSCALEI = "0b00";
+ parameter CH0_DCOSTARTVAL = "0b000";
+ parameter CH0_DCOSTEP = "0b00";
+ parameter CH0_DEC_BYPASS = "0b0";
+ parameter CH0_ENABLE_CG_ALIGN = "0b0";
+ parameter CH0_ENC_BYPASS = "0b0";
+ parameter CH0_FF_RX_F_CLK_DIS = "0b0";
+ parameter CH0_FF_RX_H_CLK_EN = "0b0";
+ parameter CH0_FF_TX_F_CLK_DIS = "0b0";
+ parameter CH0_FF_TX_H_CLK_EN = "0b0";
+ parameter CH0_GE_AN_ENABLE = "0b0";
+ parameter CH0_INVERT_RX = "0b0";
+ parameter CH0_INVERT_TX = "0b0";
+ parameter CH0_LDR_CORE2TX_SEL = "0b0";
+ parameter CH0_LDR_RX2CORE_SEL = "0b0";
+ parameter CH0_LEQ_OFFSET_SEL = "0b0";
+ parameter CH0_LEQ_OFFSET_TRIM = "0b000";
+ parameter CH0_LSM_DISABLE = "0b0";
+ parameter CH0_MATCH_2_ENABLE = "0b0";
+ parameter CH0_MATCH_4_ENABLE = "0b0";
+ parameter CH0_MIN_IPG_CNT = "0b00";
+ parameter CH0_PCIE_EI_EN = "0b0";
+ parameter CH0_PCIE_MODE = "0b0";
+ parameter CH0_PCS_DET_TIME_SEL = "0b00";
+ parameter CH0_PDEN_SEL = "0b0";
+ parameter CH0_PRBS_ENABLE = "0b0";
+ parameter CH0_PRBS_LOCK = "0b0";
+ parameter CH0_PRBS_SELECTION = "0b0";
+ parameter CH0_RATE_MODE_RX = "0b0";
+ parameter CH0_RATE_MODE_TX = "0b0";
+ parameter CH0_RCV_DCC_EN = "0b0";
+ parameter CH0_REG_BAND_OFFSET = "0b0000";
+ parameter CH0_REG_BAND_SEL = "0b000000";
+ parameter CH0_REG_IDAC_EN = "0b0";
+ parameter CH0_REG_IDAC_SEL = "0b0000000000";
+ parameter CH0_REQ_EN = "0b0";
+ parameter CH0_REQ_LVL_SET = "0b00";
+ parameter CH0_RIO_MODE = "0b0";
+ parameter CH0_RLOS_SEL = "0b0";
+ parameter CH0_RPWDNB = "0b0";
+ parameter CH0_RTERM_RX = "0b00000";
+ parameter CH0_RTERM_TX = "0b00000";
+ parameter CH0_RXIN_CM = "0b00";
+ parameter CH0_RXTERM_CM = "0b00";
+ parameter CH0_RX_DCO_CK_DIV = "0b000";
+ parameter CH0_RX_DIV11_SEL = "0b0";
+ parameter CH0_RX_GEAR_BYPASS = "0b0";
+ parameter CH0_RX_GEAR_MODE = "0b0";
+ parameter CH0_RX_LOS_CEQ = "0b00";
+ parameter CH0_RX_LOS_EN = "0b0";
+ parameter CH0_RX_LOS_HYST_EN = "0b0";
+ parameter CH0_RX_LOS_LVL = "0b000";
+ parameter CH0_RX_RATE_SEL = "0b0000";
+ parameter CH0_RX_SB_BYPASS = "0b0";
+ parameter CH0_SB_BYPASS = "0b0";
+ parameter CH0_SEL_SD_RX_CLK = "0b0";
+ parameter CH0_TDRV_DAT_SEL = "0b00";
+ parameter CH0_TDRV_POST_EN = "0b0";
+ parameter CH0_TDRV_PRE_EN = "0b0";
+ parameter CH0_TDRV_SLICE0_CUR = "0b000";
+ parameter CH0_TDRV_SLICE0_SEL = "0b00";
+ parameter CH0_TDRV_SLICE1_CUR = "0b000";
+ parameter CH0_TDRV_SLICE1_SEL = "0b00";
+ parameter CH0_TDRV_SLICE2_CUR = "0b00";
+ parameter CH0_TDRV_SLICE2_SEL = "0b00";
+ parameter CH0_TDRV_SLICE3_CUR = "0b00";
+ parameter CH0_TDRV_SLICE3_SEL = "0b00";
+ parameter CH0_TDRV_SLICE4_CUR = "0b00";
+ parameter CH0_TDRV_SLICE4_SEL = "0b00";
+ parameter CH0_TDRV_SLICE5_CUR = "0b00";
+ parameter CH0_TDRV_SLICE5_SEL = "0b00";
+ parameter CH0_TPWDNB = "0b0";
+ parameter CH0_TX_CM_SEL = "0b00";
+ parameter CH0_TX_DIV11_SEL = "0b0";
+ parameter CH0_TX_GEAR_BYPASS = "0b0";
+ parameter CH0_TX_GEAR_MODE = "0b0";
+ parameter CH0_TX_POST_SIGN = "0b0";
+ parameter CH0_TX_PRE_SIGN = "0b0";
+ parameter CH0_UC_MODE = "0b0";
+ parameter CH0_UDF_COMMA_A = "0b0000000000";
+ parameter CH0_UDF_COMMA_B = "0b0000000000";
+ parameter CH0_UDF_COMMA_MASK = "0b0000000000";
+ parameter CH0_WA_BYPASS = "0b0";
+ parameter CH0_WA_MODE = "0b0";
+ parameter CH1_AUTO_CALIB_EN = "0b0";
+ parameter CH1_AUTO_FACQ_EN = "0b0";
+ parameter CH1_BAND_THRESHOLD = "0b000000";
+ parameter CH1_CALIB_CK_MODE = "0b0";
+ parameter CH1_CC_MATCH_1 = "0b0000000000";
+ parameter CH1_CC_MATCH_2 = "0b0000000000";
+ parameter CH1_CC_MATCH_3 = "0b0000000000";
+ parameter CH1_CC_MATCH_4 = "0b0000000000";
+ parameter CH1_CDR_CNT4SEL = "0b00";
+ parameter CH1_CDR_CNT8SEL = "0b00";
+ parameter CH1_CTC_BYPASS = "0b0";
+ parameter CH1_DCOATDCFG = "0b00";
+ parameter CH1_DCOATDDLY = "0b00";
+ parameter CH1_DCOBYPSATD = "0b0";
+ parameter CH1_DCOCALDIV = "0b000";
+ parameter CH1_DCOCTLGI = "0b000";
+ parameter CH1_DCODISBDAVOID = "0b0";
+ parameter CH1_DCOFLTDAC = "0b00";
+ parameter CH1_DCOFTNRG = "0b000";
+ parameter CH1_DCOIOSTUNE = "0b000";
+ parameter CH1_DCOITUNE = "0b00";
+ parameter CH1_DCOITUNE4LSB = "0b000";
+ parameter CH1_DCOIUPDNX2 = "0b0";
+ parameter CH1_DCONUOFLSB = "0b000";
+ parameter CH1_DCOSCALEI = "0b00";
+ parameter CH1_DCOSTARTVAL = "0b000";
+ parameter CH1_DCOSTEP = "0b00";
+ parameter CH1_DEC_BYPASS = "0b0";
+ parameter CH1_ENABLE_CG_ALIGN = "0b0";
+ parameter CH1_ENC_BYPASS = "0b0";
+ parameter CH1_FF_RX_F_CLK_DIS = "0b0";
+ parameter CH1_FF_RX_H_CLK_EN = "0b0";
+ parameter CH1_FF_TX_F_CLK_DIS = "0b0";
+ parameter CH1_FF_TX_H_CLK_EN = "0b0";
+ parameter CH1_GE_AN_ENABLE = "0b0";
+ parameter CH1_INVERT_RX = "0b0";
+ parameter CH1_INVERT_TX = "0b0";
+ parameter CH1_LDR_CORE2TX_SEL = "0b0";
+ parameter CH1_LDR_RX2CORE_SEL = "0b0";
+ parameter CH1_LEQ_OFFSET_SEL = "0b0";
+ parameter CH1_LEQ_OFFSET_TRIM = "0b000";
+ parameter CH1_LSM_DISABLE = "0b0";
+ parameter CH1_MATCH_2_ENABLE = "0b0";
+ parameter CH1_MATCH_4_ENABLE = "0b0";
+ parameter CH1_MIN_IPG_CNT = "0b00";
+ parameter CH1_PCIE_EI_EN = "0b0";
+ parameter CH1_PCIE_MODE = "0b0";
+ parameter CH1_PCS_DET_TIME_SEL = "0b00";
+ parameter CH1_PDEN_SEL = "0b0";
+ parameter CH1_PRBS_ENABLE = "0b0";
+ parameter CH1_PRBS_LOCK = "0b0";
+ parameter CH1_PRBS_SELECTION = "0b0";
+ parameter CH1_RATE_MODE_RX = "0b0";
+ parameter CH1_RATE_MODE_TX = "0b0";
+ parameter CH1_RCV_DCC_EN = "0b0";
+ parameter CH1_REG_BAND_OFFSET = "0b0000";
+ parameter CH1_REG_BAND_SEL = "0b000000";
+ parameter CH1_REG_IDAC_EN = "0b0";
+ parameter CH1_REG_IDAC_SEL = "0b0000000000";
+ parameter CH1_REQ_EN = "0b0";
+ parameter CH1_REQ_LVL_SET = "0b00";
+ parameter CH1_RIO_MODE = "0b0";
+ parameter CH1_RLOS_SEL = "0b0";
+ parameter CH1_RPWDNB = "0b0";
+ parameter CH1_RTERM_RX = "0b00000";
+ parameter CH1_RTERM_TX = "0b00000";
+ parameter CH1_RXIN_CM = "0b00";
+ parameter CH1_RXTERM_CM = "0b00";
+ parameter CH1_RX_DCO_CK_DIV = "0b000";
+ parameter CH1_RX_DIV11_SEL = "0b0";
+ parameter CH1_RX_GEAR_BYPASS = "0b0";
+ parameter CH1_RX_GEAR_MODE = "0b0";
+ parameter CH1_RX_LOS_CEQ = "0b00";
+ parameter CH1_RX_LOS_EN = "0b0";
+ parameter CH1_RX_LOS_HYST_EN = "0b0";
+ parameter CH1_RX_LOS_LVL = "0b000";
+ parameter CH1_RX_RATE_SEL = "0b0000";
+ parameter CH1_RX_SB_BYPASS = "0b0";
+ parameter CH1_SB_BYPASS = "0b0";
+ parameter CH1_SEL_SD_RX_CLK = "0b0";
+ parameter CH1_TDRV_DAT_SEL = "0b00";
+ parameter CH1_TDRV_POST_EN = "0b0";
+ parameter CH1_TDRV_PRE_EN = "0b0";
+ parameter CH1_TDRV_SLICE0_CUR = "0b000";
+ parameter CH1_TDRV_SLICE0_SEL = "0b00";
+ parameter CH1_TDRV_SLICE1_CUR = "0b000";
+ parameter CH1_TDRV_SLICE1_SEL = "0b00";
+ parameter CH1_TDRV_SLICE2_CUR = "0b00";
+ parameter CH1_TDRV_SLICE2_SEL = "0b00";
+ parameter CH1_TDRV_SLICE3_CUR = "0b00";
+ parameter CH1_TDRV_SLICE3_SEL = "0b00";
+ parameter CH1_TDRV_SLICE4_CUR = "0b00";
+ parameter CH1_TDRV_SLICE4_SEL = "0b00";
+ parameter CH1_TDRV_SLICE5_CUR = "0b00";
+ parameter CH1_TDRV_SLICE5_SEL = "0b00";
+ parameter CH1_TPWDNB = "0b0";
+ parameter CH1_TX_CM_SEL = "0b00";
+ parameter CH1_TX_DIV11_SEL = "0b0";
+ parameter CH1_TX_GEAR_BYPASS = "0b0";
+ parameter CH1_TX_GEAR_MODE = "0b0";
+ parameter CH1_TX_POST_SIGN = "0b0";
+ parameter CH1_TX_PRE_SIGN = "0b0";
+ parameter CH1_UC_MODE = "0b0";
+ parameter CH1_UDF_COMMA_A = "0b0000000000";
+ parameter CH1_UDF_COMMA_B = "0b0000000000";
+ parameter CH1_UDF_COMMA_MASK = "0b0000000000";
+ parameter CH1_WA_BYPASS = "0b0";
+ parameter CH1_WA_MODE = "0b0";
+ parameter D_BITCLK_FROM_ND_EN = "0b0";
+ parameter D_BITCLK_LOCAL_EN = "0b0";
+ parameter D_BITCLK_ND_EN = "0b0";
+ parameter D_BUS8BIT_SEL = "0b0";
+ parameter D_CDR_LOL_SET = "0b00";
+ parameter D_CMUSETBIASI = "0b00";
+ parameter D_CMUSETI4CPP = "0b0000";
+ parameter D_CMUSETI4CPZ = "0b0000";
+ parameter D_CMUSETI4VCO = "0b00";
+ parameter D_CMUSETICP4P = "0b00";
+ parameter D_CMUSETICP4Z = "0b000";
+ parameter D_CMUSETINITVCT = "0b00";
+ parameter D_CMUSETISCL4VCO = "0b000";
+ parameter D_CMUSETP1GM = "0b000";
+ parameter D_CMUSETP2AGM = "0b000";
+ parameter D_CMUSETZGM = "0b000";
+ parameter D_DCO_CALIB_TIME_SEL = "0b00";
+ parameter D_HIGH_MARK = "0b0000";
+ parameter D_IB_PWDNB = "0b0";
+ parameter D_ISETLOS = "0b00000000";
+ parameter D_LOW_MARK = "0b0000";
+ parameter D_MACROPDB = "0b0";
+ parameter D_PD_ISET = "0b00";
+ parameter D_PLL_LOL_SET = "0b00";
+ parameter D_REFCK_MODE = "0b000";
+ parameter D_REQ_ISET = "0b000";
+ parameter D_RG_EN = "0b0";
+ parameter D_RG_SET = "0b00";
+ parameter D_SETICONST_AUX = "0b00";
+ parameter D_SETICONST_CH = "0b00";
+ parameter D_SETIRPOLY_AUX = "0b00";
+ parameter D_SETIRPOLY_CH = "0b00";
+ parameter D_SETPLLRC = "0b000000";
+ parameter D_SYNC_LOCAL_EN = "0b0";
+ parameter D_SYNC_ND_EN = "0b0";
+ parameter D_TXPLL_PWDNB = "0b0";
+ parameter D_TX_VCO_CK_DIV = "0b000";
+ parameter D_XGE_MODE = "0b0";
+
+// These parameters don't do anything but are
+// needed for compatibility with Diamond
+ parameter D_TX_MAX_RATE = "2.5";
+ parameter D_RX_MAX_RATE = "2.5";
+ parameter CH0_TXAMPLITUDE = "0d1300";
+ parameter CH1_TXAMPLITUDE = "0d1300";
+ parameter CH0_PROTOCOL = "8B10B";
+ parameter CH1_PROTOCOL = "8B10B";
+ parameter CH0_CDR_MAX_RATE = "2.5";
+ parameter CH1_CDR_MAX_RATE = "2.5";
+endmodule
+
+(* blackbox *)
+module EXTREFB (
+ input REFCLKP, REFCLKN,
+ output REFCLKO
+);
+ parameter REFCK_PWDNB = "0b0";
+ parameter REFCK_RTERM = "0b0";
+ parameter REFCK_DCBIAS_EN = "0b0";
+endmodule
+
+(* blackbox *)
+module PCSCLKDIV (
+ input CLKI, RST, SEL2, SEL1, SEL0,
+ output CDIV1, CDIVX
+);
+ parameter GSR = "DISABLED";
+endmodule
diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
index 48162a4d..6ab4b69f 100644
--- a/techlibs/ecp5/cells_map.v
+++ b/techlibs/ecp5/cells_map.v
@@ -7,46 +7,49 @@ module \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .C
module \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
-module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFSE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
-module \$__DFFSE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_PN0 (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_PN1 (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
module \$__DFFSE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
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
+// 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
+
`ifndef NO_LUT
module \$lut (A, Y);
parameter WIDTH = 0;
diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
index 1700694e..1e4002ee 100644
--- a/techlibs/ecp5/cells_sim.v
+++ b/techlibs/ecp5/cells_sim.v
@@ -57,7 +57,7 @@ module TRELLIS_RAM16X2 (
input RAD0, RAD1, RAD2, RAD3,
output DO0, DO1
);
- parameter WCKMUX = "WCK";
+ parameter WCKMUX = "WCK";
parameter WREMUX = "WRE";
parameter INITVAL_0 = 16'h0000;
parameter INITVAL_1 = 16'h0000;
@@ -104,7 +104,7 @@ module TRELLIS_DPR16X4 (
input [3:0] RAD,
output [3:0] DO
);
- parameter WCKMUX = "WCK";
+ parameter WCKMUX = "WCK";
parameter WREMUX = "WRE";
parameter [63:0] INITVAL = 64'h0000000000000000;
@@ -203,13 +203,14 @@ endmodule
// ---------------------------------------
-module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q);
+module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
parameter GSR = "ENABLED";
parameter [127:0] CEMUX = "1";
parameter CLKMUX = "CLK";
parameter LSRMUX = "LSR";
parameter SRMODE = "LSR_OVER_CE";
parameter REGSET = "RESET";
+ parameter [127:0] LSRMODE = "LSR";
reg muxce;
always @(*)
@@ -222,8 +223,13 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q);
wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
-
- localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0;
+ wire srval;
+ generate
+ if (LSRMODE == "PRLD")
+ assign srval = M;
+ else
+ assign srval = (REGSET == "SET") ? 1'b1 : 1'b0;
+ endgenerate
initial Q = srval;
@@ -257,7 +263,7 @@ assign O = I;
endmodule
// ---------------------------------------
-
+(* keep *)
module TRELLIS_IO(
inout B,
input I,
@@ -265,16 +271,18 @@ module TRELLIS_IO(
output O
);
parameter DIR = "INPUT";
+ reg T_pd;
+ always @(*) if (T === 1'bz) T_pd <= 1'b0; else T_pd <= T;
generate
if (DIR == "INPUT") begin
assign B = 1'bz;
assign O = B;
end else if (DIR == "OUTPUT") begin
- assign B = T ? 1'bz : I;
+ assign B = T_pd ? 1'bz : I;
assign O = 1'bx;
- end else if (DIR == "INOUT") begin
- assign B = T ? 1'bz : I;
+ end else if (DIR == "BIDIR") begin
+ assign B = T_pd ? 1'bz : I;
assign O = B;
end else begin
ERROR_UNKNOWN_IO_MODE error();
@@ -337,6 +345,8 @@ module TRELLIS_SLICE(
parameter REG1_SD = "0";
parameter REG0_REGSET = "RESET";
parameter REG1_REGSET = "RESET";
+ parameter REG0_LSRMODE = "LSR";
+ parameter REG1_LSRMODE = "LSR";
parameter [127:0] CCU2_INJECT1_0 = "NO";
parameter [127:0] CCU2_INJECT1_1 = "NO";
parameter WREMUX = "WRE";
@@ -426,10 +436,11 @@ module TRELLIS_SLICE(
.CLKMUX(CLKMUX),
.LSRMUX(LSRMUX),
.SRMODE(SRMODE),
- .REGSET(REG0_REGSET)
+ .REGSET(REG0_REGSET),
+ .LSRMODE(REG0_LSRMODE)
) ff_0 (
.CLK(CLK), .LSR(LSR), .CE(CE),
- .DI(muxdi0),
+ .DI(muxdi0), .M(M0),
.Q(Q0)
);
TRELLIS_FF #(
@@ -438,11 +449,128 @@ module TRELLIS_SLICE(
.CLKMUX(CLKMUX),
.LSRMUX(LSRMUX),
.SRMODE(SRMODE),
- .REGSET(REG1_REGSET)
+ .REGSET(REG1_REGSET),
+ .LSRMODE(REG1_LSRMODE)
) ff_1 (
.CLK(CLK), .LSR(LSR), .CE(CE),
- .DI(muxdi1),
+ .DI(muxdi1), .M(M1),
.Q(Q1)
);
endmodule
+(* blackbox *)
+module DP16KD(
+ input DIA17, DIA16, DIA15, DIA14, DIA13, DIA12, DIA11, DIA10, DIA9, DIA8, DIA7, DIA6, DIA5, DIA4, DIA3, DIA2, DIA1, DIA0,
+ input ADA13, ADA12, ADA11, ADA10, ADA9, ADA8, ADA7, ADA6, ADA5, ADA4, ADA3, ADA2, ADA1, ADA0,
+ input CEA, OCEA, CLKA, WEA, RSTA,
+ input CSA2, CSA1, CSA0,
+ output DOA17, DOA16, DOA15, DOA14, DOA13, DOA12, DOA11, DOA10, DOA9, DOA8, DOA7, DOA6, DOA5, DOA4, DOA3, DOA2, DOA1, DOA0,
+
+ input DIB17, DIB16, DIB15, DIB14, DIB13, DIB12, DIB11, DIB10, DIB9, DIB8, DIB7, DIB6, DIB5, DIB4, DIB3, DIB2, DIB1, DIB0,
+ input ADB13, ADB12, ADB11, ADB10, ADB9, ADB8, ADB7, ADB6, ADB5, ADB4, ADB3, ADB2, ADB1, ADB0,
+ input CEB, OCEB, CLKB, WEB, RSTB,
+ 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
+
+// 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)
+ );
+endmodule
diff --git a/techlibs/ecp5/dram.txt b/techlibs/ecp5/dram.txt
index b3252fa9..b9435742 100644
--- a/techlibs/ecp5/dram.txt
+++ b/techlibs/ecp5/dram.txt
@@ -13,4 +13,5 @@ endbram
match $__TRELLIS_DPR16X4
make_outreg
+ min wports 1
endmatch
diff --git a/techlibs/ecp5/ecp5_ffinit.cc b/techlibs/ecp5/ecp5_ffinit.cc
new file mode 100644
index 00000000..dbd16cac
--- /dev/null
+++ b/techlibs/ecp5/ecp5_ffinit.cc
@@ -0,0 +1,203 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018-19 David Shah <david@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
+
+struct Ecp5FfinitPass : public Pass {
+ Ecp5FfinitPass() : Pass("ecp5_ffinit", "ECP5: handle FF init values") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ecp5_ffinit [options] [selection]\n");
+ log("\n");
+ log("Remove init values for FF output signals when equal to reset value.\n");
+ log("If reset is not used, set the reset value to the init value, otherwise\n");
+ log("unmap out the reset (if not an async reset).\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing ECP5_FFINIT pass (implement FF init values).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ log("Handling FF init values in %s.\n", log_id(module));
+
+ SigMap sigmap(module);
+ pool<Wire*> init_wires;
+ dict<SigBit, State> initbits;
+ dict<SigBit, SigBit> initbit_to_wire;
+ pool<SigBit> handled_initbits;
+
+ for (auto wire : module->selected_wires())
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec wirebits = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ init_wires.insert(wire);
+
+ for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
+ {
+ SigBit bit = wirebits[i];
+ State val = initval[i];
+
+ if (val != State::S0 && val != State::S1)
+ continue;
+
+ if (initbits.count(bit)) {
+ if (initbits.at(bit) != val) {
+ log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n",
+ log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val),
+ log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit)));
+ initbits.at(bit) = State::Sx;
+ }
+ continue;
+ }
+
+ initbits[bit] = val;
+ initbit_to_wire[bit] = SigBit(wire, i);
+ }
+ }
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type != "\\TRELLIS_FF")
+ continue;
+ SigSpec sig_d = cell->getPort("\\DI");
+ SigSpec sig_q = cell->getPort("\\Q");
+ SigSpec sig_lsr = cell->getPort("\\LSR");
+
+ if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
+ continue;
+
+ SigBit bit_d = sigmap(sig_d[0]);
+ SigBit bit_q = sigmap(sig_q[0]);
+
+ std::string regset = "RESET";
+ if (cell->hasParam("\\REGSET"))
+ regset = cell->getParam("\\REGSET").decode_string();
+ State resetState;
+ if (regset == "SET")
+ resetState = State::S1;
+ else if (regset == "RESET")
+ resetState = State::S0;
+ else
+ log_error("FF cell %s has illegal REGSET value %s.\n",
+ log_id(cell), regset.c_str());
+
+ if (!initbits.count(bit_q))
+ continue;
+
+ State val = initbits.at(bit_q);
+
+ if (val == State::Sx)
+ continue;
+
+ log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type),
+ log_signal(bit_q), val != State::S0 ? '1' : '0');
+ // Initval is the same as the reset state. Matches hardware, nowt more to do
+ if (val == resetState) {
+ handled_initbits.insert(bit_q);
+ continue;
+ }
+
+ if (GetSize(sig_lsr) >= 1 && sig_lsr[0] != State::S0) {
+ std::string srmode = "LSR_OVER_CE";
+ if (cell->hasParam("\\SRMODE"))
+ srmode = cell->getParam("\\SRMODE").decode_string();
+ if (srmode == "ASYNC") {
+ log("Async reset value %c for FF cell %s inconsistent with init value %c.\n",
+ resetState != State::S0 ? '1' : '0', log_id(cell), val != State::S0 ? '1' : '0');
+ } else {
+ SigBit bit_lsr = sigmap(sig_lsr[0]);
+ Wire *new_bit_d = module->addWire(NEW_ID);
+ if (resetState == State::S0) {
+ module->addAndnotGate(NEW_ID, bit_d, bit_lsr, new_bit_d);
+ } else {
+ module->addOrGate(NEW_ID, bit_d, bit_lsr, new_bit_d);
+ }
+
+ cell->setPort("\\DI", new_bit_d);
+ cell->setPort("\\LSR", State::S0);
+
+ if(cell->hasPort("\\CE")) {
+ std::string cemux = "CE";
+ if (cell->hasParam("\\CEMUX"))
+ cemux = cell->getParam("\\CEMUX").decode_string();
+ SigSpec sig_ce = cell->getPort("\\CE");
+ if (GetSize(sig_ce) >= 1) {
+ SigBit bit_ce = sigmap(sig_ce[0]);
+ Wire *new_bit_ce = module->addWire(NEW_ID);
+ if (cemux == "INV")
+ module->addAndnotGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce);
+ else
+ module->addOrGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce);
+ cell->setPort("\\CE", new_bit_ce);
+ }
+ }
+ cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET"));
+ handled_initbits.insert(bit_q);
+ }
+ } else {
+ cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET"));
+ handled_initbits.insert(bit_q);
+ }
+ }
+
+ for (auto wire : init_wires)
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec wirebits = sigmap(wire);
+ Const &initval = wire->attributes.at("\\init");
+ bool remove_attribute = true;
+
+ for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) {
+ if (handled_initbits.count(wirebits[i]))
+ initval[i] = State::Sx;
+ else if (initval[i] != State::Sx)
+ remove_attribute = false;
+ }
+
+ if (remove_attribute)
+ wire->attributes.erase("\\init");
+ }
+ }
+ }
+} Ecp5FfinitPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ecp5/latches_map.v b/techlibs/ecp5/latches_map.v
new file mode 100644
index 00000000..c28f88cf
--- /dev/null
+++ b/techlibs/ecp5/latches_map.v
@@ -0,0 +1,11 @@
+module \$_DLATCH_N_ (E, D, Q);
+ wire [1023:0] _TECHMAP_DO_ = "simplemap; opt";
+ input E, D;
+ output Q = !E ? D : Q;
+endmodule
+
+module \$_DLATCH_P_ (E, D, Q);
+ wire [1023:0] _TECHMAP_DO_ = "simplemap; opt";
+ input E, D;
+ output Q = E ? D : Q;
+endmodule
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc
index a13dd8d4..4b889d67 100644
--- a/techlibs/ecp5/synth_ecp5.cc
+++ b/techlibs/ecp5/synth_ecp5.cc
@@ -189,7 +189,7 @@ struct SynthEcp5Pass : public ScriptPass
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH_ECP5 pass.\n");
log_push();
@@ -203,7 +203,7 @@ struct SynthEcp5Pass : public ScriptPass
{
if (check_label("begin"))
{
- run("read_verilog -lib +/ecp5/cells_sim.v");
+ run("read_verilog -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}
@@ -222,11 +222,8 @@ struct SynthEcp5Pass : public ScriptPass
if (!nobram && check_label("bram", "(skip if -nobram)"))
{
- //TODO
-#if 0
- run("memory_bram -rules +/ecp5/brams.txt");
+ run("memory_bram -rules +/ecp5/bram.txt");
run("techmap -map +/ecp5/brams_map.v");
-#endif
}
if (!nodram && check_label("dram", "(skip if -nodram)"))
@@ -258,10 +255,7 @@ struct SynthEcp5Pass : public ScriptPass
run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
- // TODO
-#if 0
run("ecp5_ffinit");
-#endif
}
if (check_label("map_luts"))
@@ -269,14 +263,11 @@ struct SynthEcp5Pass : public ScriptPass
if (abc2 || help_mode) {
run("abc", " (only if -abc2)");
}
- //TODO
-#if 0
run("techmap -map +/ecp5/latches_map.v");
-#endif
if (nomux)
- run("abc -lut 4");
+ run("abc -lut 4 -dress");
else
- run("abc -lut 4:7");
+ run("abc -lut 4:7 -dress");
run("clean");
}
diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc
index 679d7eff..2f82def7 100644
--- a/techlibs/gowin/Makefile.inc
+++ b/techlibs/gowin/Makefile.inc
@@ -3,4 +3,5 @@ OBJS += techlibs/gowin/synth_gowin.o
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v))
+$(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v))
diff --git a/techlibs/gowin/arith_map.v b/techlibs/gowin/arith_map.v
new file mode 100644
index 00000000..e15de642
--- /dev/null
+++ b/techlibs/gowin/arith_map.v
@@ -0,0 +1,59 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 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
+ * 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_gw1n_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 _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 = {CO, CI};
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
+ ALU #(.ALU_MODE(32'b0))
+ alu(.I0(AA[i]),
+ .I1(BB[i]),
+ .I3(1'b0),
+ .CIN(C[i]),
+ .COUT(CO[i]),
+ .SUM(Y[i])
+ );
+ end endgenerate
+ assign X = AA ^ BB;
+endmodule
+
diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v
index 94794262..14441c2f 100644
--- a/techlibs/gowin/cells_sim.v
+++ b/techlibs/gowin/cells_sim.v
@@ -57,3 +57,9 @@ endmodule
module GSR (input GSRI);
wire GSRO = GSRI;
endmodule
+
+module ALU (input I0, input I1, input I3, input CIN, output COUT, output SUM);
+ parameter [3:0] ALU_MODE = 0; // default 0 = ADD
+ assign {COUT, SUM} = CIN + I1 + I0;
+endmodule // alu
+
diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc
index 793f345b..9a3fcdbb 100644
--- a/techlibs/gowin/synth_gowin.cc
+++ b/techlibs/gowin/synth_gowin.cc
@@ -49,6 +49,12 @@ struct SynthGowinPass : 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(" -nobram\n");
+ log(" do not use BRAM cells in output netlist\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log("\n");
@@ -59,13 +65,15 @@ struct SynthGowinPass : public ScriptPass
}
string top_opt, vout_file;
- bool retime;
+ bool retime, flatten, nobram;
void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
vout_file = "";
retime = false;
+ flatten = true;
+ nobram = true;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -96,12 +104,20 @@ struct SynthGowinPass : public ScriptPass
retime = true;
continue;
}
+ if (args[argidx] == "-nobram") {
+ nobram = true;
+ continue;
+ }
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH_GOWIN pass.\n");
log_push();
@@ -119,7 +135,7 @@ struct SynthGowinPass : public ScriptPass
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}
- if (check_label("flatten"))
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
{
run("proc");
run("flatten");
@@ -131,13 +147,18 @@ struct SynthGowinPass : public ScriptPass
{
run("synth -run coarse");
}
-
+ if (!nobram && check_label("bram", "(skip if -nobram)"))
+ {
+ run("memory_bram -rules +/gowin/bram.txt");
+ run("techmap -map +/gowin/brams_map.v");
+ }
if (check_label("fine"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
- run("techmap");
+ run("techmap -map +/techmap.v -map +/gowin/arith_map.v");
+ run("opt -fine");
run("clean -purge");
run("splitnets -ports");
run("setundef -undriven -zero");
diff --git a/techlibs/greenpak4/cells_map.v b/techlibs/greenpak4/cells_map.v
index b971a51f..51c85183 100644
--- a/techlibs/greenpak4/cells_map.v
+++ b/techlibs/greenpak4/cells_map.v
@@ -112,14 +112,14 @@ module GP_OBUFT(input IN, input OE, output OUT);
endmodule
module \$lut (A, Y);
- parameter WIDTH = 0;
- parameter LUT = 0;
+ parameter WIDTH = 0;
+ parameter LUT = 0;
- input [WIDTH-1:0] A;
- output Y;
+ input [WIDTH-1:0] A;
+ output Y;
- generate
- if (WIDTH == 1) begin
+ generate
+ if (WIDTH == 1) begin
if(LUT == 2'b01) begin
GP_INV _TECHMAP_REPLACE_ (.OUT(Y), .IN(A[0]) );
end
@@ -127,22 +127,22 @@ module \$lut (A, Y);
GP_2LUT #(.INIT({2'b00, LUT})) _TECHMAP_REPLACE_ (.OUT(Y),
.IN0(A[0]), .IN1(1'b0));
end
- end else
- if (WIDTH == 2) begin
- GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
- .IN0(A[0]), .IN1(A[1]));
- end else
- if (WIDTH == 3) begin
- GP_3LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
- .IN0(A[0]), .IN1(A[1]), .IN2(A[2]));
- end else
- if (WIDTH == 4) begin
- GP_4LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
- .IN0(A[0]), .IN1(A[1]), .IN2(A[2]), .IN3(A[3]));
- end else begin
- wire _TECHMAP_FAIL_ = 1;
- end
- endgenerate
+ end else
+ if (WIDTH == 2) begin
+ GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
+ .IN0(A[0]), .IN1(A[1]));
+ end else
+ if (WIDTH == 3) begin
+ GP_3LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
+ .IN0(A[0]), .IN1(A[1]), .IN2(A[2]));
+ end else
+ if (WIDTH == 4) begin
+ GP_4LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y),
+ .IN0(A[0]), .IN1(A[1]), .IN2(A[2]), .IN3(A[3]));
+ end else begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ endgenerate
endmodule
module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP);
diff --git a/techlibs/greenpak4/synth_greenpak4.cc b/techlibs/greenpak4/synth_greenpak4.cc
index b91d5273..eeb001b4 100644
--- a/techlibs/greenpak4/synth_greenpak4.cc
+++ b/techlibs/greenpak4/synth_greenpak4.cc
@@ -120,7 +120,7 @@ struct SynthGreenPAK4Pass : public ScriptPass
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
if (part != "SLG46140V" && part != "SLG46620V" && part != "SLG46621V")
log_cmd_error("Invalid part name: '%s'\n", part.c_str());
diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc
index 14761c6c..723b59d6 100644
--- a/techlibs/ice40/Makefile.inc
+++ b/techlibs/ice40/Makefile.inc
@@ -1,8 +1,10 @@
OBJS += techlibs/ice40/synth_ice40.o
+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
diff --git a/techlibs/ice40/brams_map.v b/techlibs/ice40/brams_map.v
index 19a61d73..ad3bccd2 100644
--- a/techlibs/ice40/brams_map.v
+++ b/techlibs/ice40/brams_map.v
@@ -7,8 +7,8 @@ module \$__ICE40_RAM4K (
input [10:0] WADDR,
input [15:0] MASK, WDATA
);
- parameter integer READ_MODE = 0;
- parameter integer WRITE_MODE = 0;
+ parameter [1:0] READ_MODE = 0;
+ parameter [1:0] WRITE_MODE = 0;
parameter [0:0] NEGCLK_R = 0;
parameter [0:0] NEGCLK_W = 0;
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index e0a07af3..62a28364 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -326,6 +326,8 @@ module SB_RAM40_4K (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_FILE = "";
+
`ifndef BLACKBOX
wire [15:0] WMASK_I;
wire [15:0] RMASK_I;
@@ -408,24 +410,27 @@ module SB_RAM40_4K (
reg [15:0] memory [0:255];
initial begin
- for (i=0; i<16; i=i+1) begin
- memory[ 0*16 + i] <= INIT_0[16*i +: 16];
- memory[ 1*16 + i] <= INIT_1[16*i +: 16];
- memory[ 2*16 + i] <= INIT_2[16*i +: 16];
- memory[ 3*16 + i] <= INIT_3[16*i +: 16];
- memory[ 4*16 + i] <= INIT_4[16*i +: 16];
- memory[ 5*16 + i] <= INIT_5[16*i +: 16];
- memory[ 6*16 + i] <= INIT_6[16*i +: 16];
- memory[ 7*16 + i] <= INIT_7[16*i +: 16];
- memory[ 8*16 + i] <= INIT_8[16*i +: 16];
- memory[ 9*16 + i] <= INIT_9[16*i +: 16];
- memory[10*16 + i] <= INIT_A[16*i +: 16];
- memory[11*16 + i] <= INIT_B[16*i +: 16];
- memory[12*16 + i] <= INIT_C[16*i +: 16];
- memory[13*16 + i] <= INIT_D[16*i +: 16];
- memory[14*16 + i] <= INIT_E[16*i +: 16];
- memory[15*16 + i] <= INIT_F[16*i +: 16];
- end
+ if (INIT_FILE != "")
+ $readmemh(INIT_FILE, memory);
+ else
+ for (i=0; i<16; i=i+1) begin
+ memory[ 0*16 + i] = INIT_0[16*i +: 16];
+ memory[ 1*16 + i] = INIT_1[16*i +: 16];
+ memory[ 2*16 + i] = INIT_2[16*i +: 16];
+ memory[ 3*16 + i] = INIT_3[16*i +: 16];
+ memory[ 4*16 + i] = INIT_4[16*i +: 16];
+ memory[ 5*16 + i] = INIT_5[16*i +: 16];
+ memory[ 6*16 + i] = INIT_6[16*i +: 16];
+ memory[ 7*16 + i] = INIT_7[16*i +: 16];
+ memory[ 8*16 + i] = INIT_8[16*i +: 16];
+ memory[ 9*16 + i] = INIT_9[16*i +: 16];
+ memory[10*16 + i] = INIT_A[16*i +: 16];
+ memory[11*16 + i] = INIT_B[16*i +: 16];
+ memory[12*16 + i] = INIT_C[16*i +: 16];
+ memory[13*16 + i] = INIT_D[16*i +: 16];
+ memory[14*16 + i] = INIT_E[16*i +: 16];
+ memory[15*16 + i] = INIT_F[16*i +: 16];
+ end
end
always @(posedge WCLK) begin
@@ -485,6 +490,8 @@ module SB_RAM40_4KNR (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_FILE = "";
+
SB_RAM40_4K #(
.WRITE_MODE(WRITE_MODE),
.READ_MODE (READ_MODE ),
@@ -503,7 +510,8 @@ module SB_RAM40_4KNR (
.INIT_C (INIT_C ),
.INIT_D (INIT_D ),
.INIT_E (INIT_E ),
- .INIT_F (INIT_F )
+ .INIT_F (INIT_F ),
+ .INIT_FILE (INIT_FILE )
) RAM (
.RDATA(RDATA),
.RCLK (~RCLKN),
@@ -547,6 +555,8 @@ module SB_RAM40_4KNW (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_FILE = "";
+
SB_RAM40_4K #(
.WRITE_MODE(WRITE_MODE),
.READ_MODE (READ_MODE ),
@@ -565,7 +575,8 @@ module SB_RAM40_4KNW (
.INIT_C (INIT_C ),
.INIT_D (INIT_D ),
.INIT_E (INIT_E ),
- .INIT_F (INIT_F )
+ .INIT_F (INIT_F ),
+ .INIT_FILE (INIT_FILE )
) RAM (
.RDATA(RDATA),
.RCLK (RCLK ),
@@ -609,6 +620,8 @@ module SB_RAM40_4KNRNW (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_FILE = "";
+
SB_RAM40_4K #(
.WRITE_MODE(WRITE_MODE),
.READ_MODE (READ_MODE ),
@@ -627,7 +640,8 @@ module SB_RAM40_4KNRNW (
.INIT_C (INIT_C ),
.INIT_D (INIT_D ),
.INIT_E (INIT_E ),
- .INIT_F (INIT_F )
+ .INIT_F (INIT_F ),
+ .INIT_FILE (INIT_FILE )
) RAM (
.RDATA(RDATA),
.RCLK (~RCLKN),
@@ -867,59 +881,6 @@ module SB_WARMBOOT (
);
endmodule
-// UltraPlus feature cells
-(* blackbox *)
-module SB_MAC16 (
- input CLK,
- input CE,
- input [15:0] C,
- input [15:0] A,
- input [15:0] B,
- input [15:0] D,
- input AHOLD,
- input BHOLD,
- input CHOLD,
- input DHOLD,
- input IRSTTOP,
- input IRSTBOT,
- input ORSTTOP,
- input ORSTBOT,
- input OLOADTOP,
- input OLOADBOT,
- input ADDSUBTOP,
- input ADDSUBBOT,
- input OHOLDTOP,
- input OHOLDBOT,
- input CI,
- input ACCUMCI,
- input SIGNEXTIN,
- output [31:0] O,
- output CO,
- output ACCUMCO,
- output SIGNEXTOUT
-);
-parameter NEG_TRIGGER = 1'b0;
-parameter C_REG = 1'b0;
-parameter A_REG = 1'b0;
-parameter B_REG = 1'b0;
-parameter D_REG = 1'b0;
-parameter TOP_8x8_MULT_REG = 1'b0;
-parameter BOT_8x8_MULT_REG = 1'b0;
-parameter PIPELINE_16x16_MULT_REG1 = 1'b0;
-parameter PIPELINE_16x16_MULT_REG2 = 1'b0;
-parameter TOPOUTPUT_SELECT = 2'b00;
-parameter TOPADDSUB_LOWERINPUT = 2'b00;
-parameter TOPADDSUB_UPPERINPUT = 1'b0;
-parameter TOPADDSUB_CARRYSELECT = 2'b00;
-parameter BOTOUTPUT_SELECT = 2'b00;
-parameter BOTADDSUB_LOWERINPUT = 2'b00;
-parameter BOTADDSUB_UPPERINPUT = 1'b0;
-parameter BOTADDSUB_CARRYSELECT = 2'b00;
-parameter MODE_8x8 = 1'b0;
-parameter A_SIGNED = 1'b0;
-parameter B_SIGNED = 1'b0;
-endmodule
-
module SB_SPRAM256KA (
input [13:0] ADDRESS,
input [15:0] DATAIN,
@@ -928,6 +889,7 @@ module SB_SPRAM256KA (
output reg [15:0] DATAOUT
);
`ifndef BLACKBOX
+`ifndef EQUIV
reg [15:0] mem [0:16383];
wire off = SLEEP || !POWEROFF;
integer i;
@@ -954,6 +916,7 @@ module SB_SPRAM256KA (
end
end
`endif
+`endif
endmodule
(* blackbox *)
@@ -1252,3 +1215,171 @@ module SB_IO_OD (
endgenerate
`endif
endmodule
+
+module SB_MAC16 (
+ input CLK, CE,
+ input [15:0] C, A, B, D,
+ input AHOLD, BHOLD, CHOLD, DHOLD,
+ input IRSTTOP, IRSTBOT,
+ input ORSTTOP, ORSTBOT,
+ input OLOADTOP, OLOADBOT,
+ input ADDSUBTOP, ADDSUBBOT,
+ input OHOLDTOP, OHOLDBOT,
+ input CI, ACCUMCI, SIGNEXTIN,
+ output [31:0] O,
+ output CO, ACCUMCO, SIGNEXTOUT
+);
+ parameter [0:0] NEG_TRIGGER = 0;
+ parameter [0:0] C_REG = 0;
+ parameter [0:0] A_REG = 0;
+ parameter [0:0] B_REG = 0;
+ parameter [0:0] D_REG = 0;
+ parameter [0:0] TOP_8x8_MULT_REG = 0;
+ parameter [0:0] BOT_8x8_MULT_REG = 0;
+ parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0;
+ parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0;
+ parameter [1:0] TOPOUTPUT_SELECT = 0;
+ parameter [1:0] TOPADDSUB_LOWERINPUT = 0;
+ parameter [0:0] TOPADDSUB_UPPERINPUT = 0;
+ parameter [1:0] TOPADDSUB_CARRYSELECT = 0;
+ parameter [1:0] BOTOUTPUT_SELECT = 0;
+ parameter [1:0] BOTADDSUB_LOWERINPUT = 0;
+ parameter [0:0] BOTADDSUB_UPPERINPUT = 0;
+ parameter [1:0] BOTADDSUB_CARRYSELECT = 0;
+ parameter [0:0] MODE_8x8 = 0;
+ parameter [0:0] A_SIGNED = 0;
+ parameter [0:0] B_SIGNED = 0;
+
+ wire clock = CLK ^ NEG_TRIGGER;
+
+ // internal wires, compare Figure on page 133 of ICE Technology Library 3.0 and Fig 2 on page 2 of Lattice TN1295-DSP
+ // http://www.latticesemi.com/~/media/LatticeSemi/Documents/TechnicalBriefs/SBTICETechnologyLibrary201608.pdf
+ // https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/AD/DSPFunctionUsageGuideforICE40Devices.ashx
+ wire [15:0] iA, iB, iC, iD;
+ wire [15:0] iF, iJ, iK, iG;
+ wire [31:0] iL, iH;
+ wire [15:0] iW, iX, iP, iQ;
+ wire [15:0] iY, iZ, iR, iS;
+ wire HCI, LCI, LCO;
+
+ // Regs C and A
+ reg [15:0] rC, rA;
+ always @(posedge clock, posedge IRSTTOP) begin
+ if (IRSTTOP) begin
+ rC <= 0;
+ rA <= 0;
+ end else if (CE) begin
+ if (!CHOLD) rC <= C;
+ if (!AHOLD) rA <= A;
+ end
+ end
+ assign iC = C_REG ? rC : C;
+ assign iA = A_REG ? rA : A;
+
+ // Regs B and D
+ reg [15:0] rB, rD;
+ always @(posedge clock, posedge IRSTBOT) begin
+ if (IRSTBOT) begin
+ rB <= 0;
+ rD <= 0;
+ end else if (CE) begin
+ if (!BHOLD) rB <= B;
+ if (!DHOLD) rD <= D;
+ end
+ end
+ assign iB = B_REG ? rB : B;
+ assign iD = D_REG ? rD : D;
+
+ // Multiplier Stage
+ 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 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;
+
+ // Regs F and J
+ reg [15:0] rF, rJ;
+ always @(posedge clock, posedge IRSTTOP) begin
+ if (IRSTTOP) begin
+ rF <= 0;
+ rJ <= 0;
+ end else if (CE) begin
+ rF <= p_Ah_Bh;
+ if (!MODE_8x8) rJ <= p_Al_Bh;
+ end
+ end
+ assign iF = TOP_8x8_MULT_REG ? rF : p_Ah_Bh;
+ assign iJ = PIPELINE_16x16_MULT_REG1 ? rJ : p_Al_Bh;
+
+ // Regs K and G
+ reg [15:0] rK, rG;
+ always @(posedge clock, posedge IRSTBOT) begin
+ if (IRSTBOT) begin
+ rK <= 0;
+ rG <= 0;
+ end else if (CE) begin
+ if (!MODE_8x8) rK <= p_Ah_Bl;
+ rG <= p_Al_Bl;
+ end
+ end
+ assign iK = PIPELINE_16x16_MULT_REG1 ? rK : p_Ah_Bl;
+ assign iG = BOT_8x8_MULT_REG ? rG : p_Al_Bl;
+
+ // Adder Stage
+ assign iL = iG + (iK << 8) + (iJ << 8) + (iF << 16);
+
+ // Reg H
+ reg [31:0] rH;
+ always @(posedge clock, posedge IRSTBOT) begin
+ if (IRSTBOT) begin
+ rH <= 0;
+ end else if (CE) begin
+ if (!MODE_8x8) rH <= iL;
+ end
+ end
+ assign iH = PIPELINE_16x16_MULT_REG2 ? rH : iL;
+
+ // Hi Output Stage
+ wire [15:0] XW, Oh;
+ reg [15:0] rQ;
+ assign iW = TOPADDSUB_UPPERINPUT ? iC : iQ;
+ assign iX = (TOPADDSUB_LOWERINPUT == 0) ? iA : (TOPADDSUB_LOWERINPUT == 1) ? iF : (TOPADDSUB_LOWERINPUT == 2) ? iH[31:16] : {16{iZ[15]}};
+ assign {ACCUMCO, XW} = iX + (iW ^ {16{ADDSUBTOP}}) + HCI;
+ assign CO = ACCUMCO ^ ADDSUBTOP;
+ assign iP = OLOADTOP ? iC : XW ^ {16{ADDSUBTOP}};
+ always @(posedge clock, posedge ORSTTOP) begin
+ if (ORSTTOP) begin
+ rQ <= 0;
+ end else if (CE) begin
+ if (!OHOLDTOP) rQ <= iP;
+ end
+ end
+ assign iQ = rQ;
+ assign Oh = (TOPOUTPUT_SELECT == 0) ? iP : (TOPOUTPUT_SELECT == 1) ? iQ : (TOPOUTPUT_SELECT == 2) ? iF : iH[31:16];
+ assign HCI = (TOPADDSUB_CARRYSELECT == 0) ? 1'b0 : (TOPADDSUB_CARRYSELECT == 1) ? 1'b1 : (TOPADDSUB_CARRYSELECT == 2) ? LCO : LCO ^ ADDSUBBOT;
+ assign SIGNEXTOUT = iX[15];
+
+ // Lo Output Stage
+ wire [15:0] YZ, Ol;
+ reg [15:0] rS;
+ assign iY = BOTADDSUB_UPPERINPUT ? iD : iS;
+ assign iZ = (BOTADDSUB_LOWERINPUT == 0) ? iB : (BOTADDSUB_LOWERINPUT == 1) ? iG : (BOTADDSUB_LOWERINPUT == 2) ? iH[15:0] : {16{SIGNEXTIN}};
+ assign {LCO, YZ} = iZ + (iY ^ {16{ADDSUBBOT}}) + LCI;
+ assign iR = OLOADBOT ? iD : YZ ^ {16{ADDSUBBOT}};
+ always @(posedge clock, posedge ORSTBOT) begin
+ if (ORSTBOT) begin
+ rS <= 0;
+ end else if (CE) begin
+ if (!OHOLDBOT) rS <= iR;
+ end
+ end
+ assign iS = rS;
+ assign Ol = (BOTOUTPUT_SELECT == 0) ? iR : (BOTOUTPUT_SELECT == 1) ? iS : (BOTOUTPUT_SELECT == 2) ? iG : iH[15:0];
+ assign LCI = (BOTADDSUB_CARRYSELECT == 0) ? 1'b0 : (BOTADDSUB_CARRYSELECT == 1) ? 1'b1 : (BOTADDSUB_CARRYSELECT == 2) ? ACCUMCI : CI;
+ assign O = {Oh, Ol};
+endmodule
diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc
new file mode 100644
index 00000000..4fa6b079
--- /dev/null
+++ b/techlibs/ice40/ice40_braminit.cc
@@ -0,0 +1,159 @@
+/*
+ * 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>
+#include <bitset>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+static void run_ice40_braminit(Module *module)
+{
+ for (auto cell : module->selected_cells())
+ {
+ uint16_t mem[256];
+
+ /* Only consider cells we're interested in */
+ if (cell->type != "\\SB_RAM40_4K" &&
+ cell->type != "\\SB_RAM40_4KNR" &&
+ cell->type != "\\SB_RAM40_4KNW" &&
+ cell->type != "\\SB_RAM40_4KNRNW")
+ continue;
+ if (!cell->hasParam("\\INIT_FILE"))
+ continue;
+ std::string init_file = cell->getParam("\\INIT_FILE").decode_string();
+ cell->unsetParam("\\INIT_FILE");
+ if (init_file == "")
+ continue;
+
+ /* Open file */
+ log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str());
+
+ std::ifstream f;
+ f.open(init_file.c_str());
+ if (f.fail()) {
+ log("Can not open file `%s`.\n", init_file.c_str());
+ continue;
+ }
+
+ /* Defaults to 0 */
+ memset(mem, 0x00, sizeof(mem));
+
+ /* Process each line */
+ bool in_comment = false;
+ int cursor = 0;
+
+ while (!f.eof())
+ {
+ std::string line, token;
+ std::getline(f, line);
+
+ for (int i = 0; i < GetSize(line); i++)
+ {
+ if (in_comment && line.substr(i, 2) == "*/") {
+ line[i] = ' ';
+ line[i+1] = ' ';
+ in_comment = false;
+ continue;
+ }
+ if (!in_comment && line.substr(i, 2) == "/*")
+ in_comment = true;
+ if (in_comment)
+ line[i] = ' ';
+ }
+
+ while (1)
+ {
+ bool set_cursor = false;
+ long value;
+
+ token = next_token(line, " \t\r\n");
+ if (token.empty() || token.substr(0, 2) == "//")
+ break;
+
+ if (token[0] == '@') {
+ token = token.substr(1);
+ set_cursor = true;
+ }
+
+ const char *nptr = token.c_str();
+ char *endptr;
+ value = strtol(nptr, &endptr, 16);
+ if (!*nptr || *endptr) {
+ log("Can not parse %s `%s` for %s.\n",
+ set_cursor ? "address" : "value",
+ nptr, token.c_str()
+ );
+ continue;
+ }
+
+ if (set_cursor)
+ cursor = value;
+ else if (cursor >= 0 && cursor < 256)
+ mem[cursor++] = value;
+ else
+ log("Attempt to initialize non existent address %d\n", cursor);
+ }
+ }
+
+ /* Set attributes */
+ const char *hex = "0123456789ABCDEF";
+ for (int i=0; i<16; i++) {
+ std::string val = "";
+ for (int j=15; j>=0; j--)
+ val += std::bitset<16>(mem[i*16+j]).to_string();
+ cell->setParam("\\INIT_" + std::string(1, hex[i]), RTLIL::Const::from_string(val));
+ }
+ }
+}
+
+struct Ice40BRAMInitPass : public Pass {
+ Ice40BRAMInitPass() : Pass("ice40_braminit", "iCE40: perform SB_RAM40_4K initialization from file") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ice40_braminit\n");
+ log("\n");
+ log("This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE\n");
+ log("parameter and converts it into the required INIT_x attributes\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing ICE40_BRAMINIT pass.\n");
+
+ 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_braminit(module);
+ }
+} Ice40BRAMInitPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/ice40_ffssr.cc b/techlibs/ice40/ice40_ffssr.cc
index 668df09d..a7649d7a 100644
--- a/techlibs/ice40/ice40_ffssr.cc
+++ b/techlibs/ice40/ice40_ffssr.cc
@@ -81,6 +81,9 @@ struct Ice40FfssrPass : public Pass {
for (auto cell : ff_cells)
{
+ if (cell->get_bool_attribute("\\dont_touch"))
+ continue;
+
SigSpec sig_d = cell->getPort("\\D");
if (GetSize(sig_d) < 1)
diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc
index 16274005..f528607d 100644
--- a/techlibs/ice40/ice40_opt.cc
+++ b/techlibs/ice40/ice40_opt.cc
@@ -33,7 +33,7 @@ static SigBit get_bit_or_zero(const SigSpec &sig)
return sig[0];
}
-static void run_ice40_opts(Module *module, bool unlut_mode)
+static void run_ice40_opts(Module *module)
{
pool<SigBit> optimized_co;
vector<Cell*> sb_lut_cells;
@@ -95,9 +95,6 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
sigmap.apply(inbits);
- if (unlut_mode)
- goto remap_lut;
-
if (optimized_co.count(inbits[0])) goto remap_lut;
if (optimized_co.count(inbits[1])) goto remap_lut;
if (optimized_co.count(inbits[2])) goto remap_lut;
@@ -152,14 +149,10 @@ struct Ice40OptPass : public Pass {
log(" opt_clean\n");
log(" while <changed design>\n");
log("\n");
- log("When called with the option -unlut, this command will transform all already\n");
- log("mapped SB_LUT4 cells back to logic.\n");
- log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string opt_expr_args = "-mux_undef -undriven";
- bool unlut_mode = false;
log_header(design, "Executing ICE40_OPT pass (performing simple optimizations).\n");
log_push();
@@ -170,10 +163,6 @@ struct Ice40OptPass : public Pass {
opt_expr_args += " -full";
continue;
}
- if (args[argidx] == "-unlut") {
- unlut_mode = true;
- continue;
- }
break;
}
extra_args(args, argidx, design);
@@ -184,7 +173,7 @@ struct Ice40OptPass : public Pass {
log_header(design, "Running ICE40 specific optimizations.\n");
for (auto module : design->selected_modules())
- run_ice40_opts(module, unlut_mode);
+ run_ice40_opts(module);
Pass::call(design, "opt_expr " + opt_expr_args);
Pass::call(design, "opt_merge");
diff --git a/techlibs/ice40/ice40_unlut.cc b/techlibs/ice40/ice40_unlut.cc
new file mode 100644
index 00000000..2428a8e7
--- /dev/null
+++ b/techlibs/ice40/ice40_unlut.cc
@@ -0,0 +1,106 @@
+/*
+ * 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 b0687e5e..8899bfcc 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -63,15 +63,28 @@ 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");
log(" -nodffe\n");
log(" do not use SB_DFFE* cells in output netlist\n");
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("\n");
log(" -nobram\n");
log(" do not use SB_RAM40_4K* cells in output netlist\n");
log("\n");
+ log(" -dsp\n");
+ log(" use iCE40 UltraPlus DSP cells for large arithmetic\n");
+ log("\n");
+ log(" -noabc\n");
+ log(" use built-in Yosys LUT techmapping instead of abc\n");
+ log("\n");
log(" -abc2\n");
log(" run two passes of 'abc' for slightly improved logic density\n");
log("\n");
@@ -86,7 +99,8 @@ struct SynthIce40Pass : public ScriptPass
}
string top_opt, blif_file, edif_file, json_file;
- bool nocarry, nodffe, nobram, flatten, retime, abc2, vpr;
+ bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
+ int min_ce_use;
void clear_flags() YS_OVERRIDE
{
@@ -96,9 +110,13 @@ struct SynthIce40Pass : public ScriptPass
json_file = "";
nocarry = false;
nodffe = false;
+ min_ce_use = -1;
nobram = false;
+ dsp = false;
flatten = true;
retime = false;
+ relut = false;
+ noabc = false;
abc2 = false;
vpr = false;
}
@@ -147,6 +165,10 @@ struct SynthIce40Pass : public ScriptPass
retime = true;
continue;
}
+ if (args[argidx] == "-relut") {
+ relut = true;
+ continue;
+ }
if (args[argidx] == "-nocarry") {
nocarry = true;
continue;
@@ -155,10 +177,22 @@ struct SynthIce40Pass : public ScriptPass
nodffe = true;
continue;
}
+ if (args[argidx] == "-dffe_min_ce_use" && argidx+1 < args.size()) {
+ min_ce_use = std::stoi(args[++argidx]);
+ continue;
+ }
if (args[argidx] == "-nobram") {
nobram = true;
continue;
}
+ if (args[argidx] == "-dsp") {
+ dsp = true;
+ continue;
+ }
+ if (args[argidx] == "-noabc") {
+ noabc = true;
+ continue;
+ }
if (args[argidx] == "-abc2") {
abc2 = true;
continue;
@@ -172,7 +206,7 @@ struct SynthIce40Pass : public ScriptPass
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH_ICE40 pass.\n");
log_push();
@@ -188,11 +222,11 @@ struct SynthIce40Pass : public ScriptPass
{
run("read_verilog -lib +/ice40/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ run("proc");
}
if (flatten && check_label("flatten", "(unless -noflatten)"))
{
- run("proc");
run("flatten");
run("tribuf -logic");
run("deminout");
@@ -200,20 +234,41 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("coarse"))
{
- run("synth -run coarse");
+ run("opt_expr");
+ run("opt_clean");
+ run("check");
+ run("opt");
+ run("wreduce");
+ run("share");
+ run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
+ run("opt_expr");
+ run("opt_clean");
+ if (help_mode || dsp)
+ run("ice40_dsp", "(if -dsp)");
+ run("alumacc");
+ run("opt");
+ run("fsm");
+ run("opt -fast");
+ run("memory -nomap");
+ run("opt_clean");
}
if (!nobram && check_label("bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/ice40/brams.txt");
run("techmap -map +/ice40/brams_map.v");
+ run("ice40_braminit");
}
- if (check_label("fine"))
+ if (check_label("map"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
+ }
+
+ if (check_label("map_gates"))
+ {
if (nocarry)
run("techmap");
else
@@ -228,6 +283,10 @@ struct SynthIce40Pass : public ScriptPass
run("dffsr2dff");
if (!nodffe)
run("dff2dffe -direct-match $_DFF_*");
+ if (min_ce_use >= 0) {
+ run("opt_merge");
+ run(stringf("dff2dffe -unmap-mince %d", min_ce_use));
+ }
run("techmap -D NO_LUT -map +/ice40/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
@@ -243,8 +302,18 @@ struct SynthIce40Pass : public ScriptPass
run("ice40_opt", "(only if -abc2)");
}
run("techmap -map +/ice40/latches_map.v");
- run("abc -lut 4");
+ if (noabc || help_mode) {
+ run("simplemap", " (only if -noabc)");
+ run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
+ }
+ if (!noabc) {
+ run("abc -dress -lut 4", "(skip if -noabc)");
+ }
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)");
+ }
}
if (check_label("map_cells"))
diff --git a/techlibs/ice40/tests/.gitignore b/techlibs/ice40/tests/.gitignore
index b58f9ad4..12028655 100644
--- a/techlibs/ice40/tests/.gitignore
+++ b/techlibs/ice40/tests/.gitignore
@@ -1,2 +1,11 @@
-test_ffs_[01][01][01][01][01]_*
-test_bram_[0-9]*
+/test_ffs_[01][01][01][01][01]_*
+/test_bram_[0-9]*
+/test_dsp_model
+/test_dsp_model.vcd
+/test_dsp_model_ref.v
+/test_dsp_model_uut.v
+/test_dsp_map
+/test_dsp_map.vcd
+/test_dsp_map_tb.v
+/test_dsp_map_top.v
+/test_dsp_map_syn.v
diff --git a/techlibs/ice40/tests/test_dsp_map.sh b/techlibs/ice40/tests/test_dsp_map.sh
new file mode 100644
index 00000000..3f7f134e
--- /dev/null
+++ b/techlibs/ice40/tests/test_dsp_map.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+set -ex
+
+for iter in {1..100}
+do
+ SZA=$(( 3 + $RANDOM % 13 ))
+ SZB=$(( 3 + $RANDOM % 13 ))
+ SZO=$(( 3 + $RANDOM % 29 ))
+
+ C0=clk$(( $RANDOM & 1))
+ C1=clk$(( $RANDOM & 1))
+ C2=clk$(( $RANDOM & 1))
+ C3=clk$(( $RANDOM & 1))
+
+ E0=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
+ E1=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
+ E2=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
+ E3=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
+
+ SP=$( test $(( $RANDOM & 1 )) -eq 0 && echo S || echo P )
+
+ RC=$( test $(( $RANDOM & 1 )) -eq 0 && echo "reset" || echo "!reset" )
+ RV="32'h$( echo $RANDOM | md5sum | cut -c1-8 )"
+
+ cat > test_dsp_map_top.v << EOT
+module top (
+ input clk0, clk1, reset,
+ input [$SZA:0] A,
+ input [$SZB:0] B,
+ output [$SZO:0] O
+);
+ reg [15:0] AA, BB;
+ reg [31:0] P, S;
+
+ always @($E0 $C0) AA <= A;
+ always @($E1 $C1) BB <= B;
+ always @($E2 $C2) P <= AA * BB;
+ always @($E3 $C3) S <= $RC ? $RV : S + P;
+ assign O = $SP;
+endmodule
+EOT
+
+ cat > test_dsp_map_tb.v << EOT
+\`timescale 1ns / 1ps
+module testbench;
+ reg clk1, clk0, reset;
+ reg [$SZA:0] A;
+ reg [$SZB:0] B;
+
+ wire [$SZO:0] O_top, O_syn;
+
+ top top_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_top));
+ syn syn_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_syn));
+
+ initial begin
+ // \$dumpfile("test_dsp_map.vcd");
+ // \$dumpvars(0, testbench);
+
+ #2;
+ clk0 = 0;
+ clk1 = 0;
+ reset = 1;
+ reset = $RC;
+ A = 0;
+ B = 0;
+
+ repeat (3) begin
+ #2; clk0 = ~clk0;
+ #2; clk0 = ~clk0;
+ #2; clk1 = ~clk1;
+ #2; clk1 = ~clk1;
+ end
+
+ repeat (100) begin
+ #2;
+ A = \$urandom;
+ B = \$urandom;
+ reset = \$urandom & \$urandom & \$urandom & \$urandom;
+ if (\$urandom & 1) begin
+ #2; clk0 = ~clk0;
+ #2; clk0 = ~clk0;
+ end else begin
+ #2; clk1 = ~clk1;
+ #2; clk1 = ~clk1;
+ end
+ #2;
+ if (O_top !== O_syn) begin
+ \$display("ERROR: O_top=%b O_syn=%b", O_top, O_syn);
+ \$stop;
+ end
+ // \$display("OK O_top=O_syn=%b", O_top);
+ end
+
+ \$display("Test passed.");
+ \$finish;
+ end
+endmodule
+EOT
+
+ ../../../yosys -p 'read_verilog test_dsp_map_top.v; synth_ice40 -dsp; rename top syn; write_verilog test_dsp_map_syn.v'
+ iverilog -o test_dsp_map -s testbench test_dsp_map_tb.v test_dsp_map_top.v test_dsp_map_syn.v ../cells_sim.v
+ vvp -N test_dsp_map
+done
+
+: ""
+: "#### All tests passed. ####"
+: ""
diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh
new file mode 100644
index 00000000..1bc0cc68
--- /dev/null
+++ b/techlibs/ice40/tests/test_dsp_model.sh
@@ -0,0 +1,11 @@
+#!/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
+for tb in testbench \
+ testbench_comb_8x8_A testbench_comb_8x8_B testbench_comb_16x16 \
+ testbench_seq_16x16_A testbench_seq_16x16_B
+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
+done
diff --git a/techlibs/ice40/tests/test_dsp_model.v b/techlibs/ice40/tests/test_dsp_model.v
new file mode 100644
index 00000000..594bd4ad
--- /dev/null
+++ b/techlibs/ice40/tests/test_dsp_model.v
@@ -0,0 +1,342 @@
+`timescale 1ns / 1ps
+
+module testbench;
+ parameter [0:0] NEG_TRIGGER = 0;
+ parameter [0:0] C_REG = 0;
+ parameter [0:0] A_REG = 0;
+ parameter [0:0] B_REG = 0;
+ parameter [0:0] D_REG = 0;
+ parameter [0:0] TOP_8x8_MULT_REG = 0;
+ parameter [0:0] BOT_8x8_MULT_REG = 0;
+ parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0;
+ parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0;
+ parameter [1:0] TOPOUTPUT_SELECT = 0;
+ parameter [1:0] TOPADDSUB_LOWERINPUT = 0;
+ parameter [0:0] TOPADDSUB_UPPERINPUT = 1;
+ parameter [1:0] TOPADDSUB_CARRYSELECT = 0;
+ parameter [1:0] BOTOUTPUT_SELECT = 0;
+ parameter [1:0] BOTADDSUB_LOWERINPUT = 0;
+ parameter [0:0] BOTADDSUB_UPPERINPUT = 1;
+ parameter [1:0] BOTADDSUB_CARRYSELECT = 0;
+ parameter [0:0] MODE_8x8 = 0;
+ parameter [0:0] A_SIGNED = 0;
+ parameter [0:0] B_SIGNED = 0;
+
+ reg CLK, CE;
+ reg [15:0] C, A, B, D;
+ reg AHOLD, BHOLD, CHOLD, DHOLD;
+ reg IRSTTOP, IRSTBOT;
+ reg ORSTTOP, ORSTBOT;
+ reg OLOADTOP, OLOADBOT;
+ reg ADDSUBTOP, ADDSUBBOT;
+ reg OHOLDTOP, OHOLDBOT;
+ reg CI, ACCUMCI, SIGNEXTIN;
+
+ output [31:0] REF_O, UUT_O;
+ output REF_CO, REF_ACCUMCO, REF_SIGNEXTOUT;
+ output UUT_CO, UUT_ACCUMCO, UUT_SIGNEXTOUT;
+
+ integer errcount = 0;
+
+ task clkcycle;
+ begin
+ #5;
+ CLK = ~CLK;
+ #10;
+ CLK = ~CLK;
+ #2;
+ if (REF_O !== UUT_O) begin
+ $display("ERROR at %1t: REF_O=%b UUT_O=%b DIFF=%b", $time, REF_O, UUT_O, REF_O ^ UUT_O);
+ errcount = errcount + 1;
+ end
+ if (REF_CO !== UUT_CO) begin
+ $display("ERROR at %1t: REF_CO=%b UUT_CO=%b", $time, REF_CO, UUT_CO);
+ errcount = errcount + 1;
+ end
+ if (REF_ACCUMCO !== UUT_ACCUMCO) begin
+ $display("ERROR at %1t: REF_ACCUMCO=%b UUT_ACCUMCO=%b", $time, REF_ACCUMCO, UUT_ACCUMCO);
+ errcount = errcount + 1;
+ end
+ if (REF_SIGNEXTOUT !== UUT_SIGNEXTOUT) begin
+ $display("ERROR at %1t: REF_SIGNEXTOUT=%b UUT_SIGNEXTOUT=%b", $time, REF_SIGNEXTOUT, UUT_SIGNEXTOUT);
+ errcount = errcount + 1;
+ end
+ #3;
+ end
+ endtask
+
+ initial begin
+ $dumpfile("test_dsp_model.vcd");
+ $dumpvars(0, testbench);
+
+ #2;
+ CLK = NEG_TRIGGER;
+ CE = 1;
+ {C, A, B, D} = 0;
+ {AHOLD, BHOLD, CHOLD, DHOLD} = 0;
+ {OLOADTOP, OLOADBOT} = 0;
+ {ADDSUBTOP, ADDSUBBOT} = 0;
+ {OHOLDTOP, OHOLDBOT} = 0;
+ {CI, ACCUMCI, SIGNEXTIN} = 0;
+
+ {IRSTTOP, IRSTBOT} = ~0;
+ {ORSTTOP, ORSTBOT} = ~0;
+
+ #3;
+ {IRSTTOP, IRSTBOT} = 0;
+ {ORSTTOP, ORSTBOT} = 0;
+
+ repeat (300) begin
+ clkcycle;
+
+ A = $urandom;
+ B = $urandom;
+ C = $urandom;
+ D = $urandom;
+
+ {AHOLD, BHOLD, CHOLD, DHOLD} = $urandom & $urandom & $urandom;
+ {OLOADTOP, OLOADBOT} = $urandom & $urandom & $urandom;
+ {ADDSUBTOP, ADDSUBBOT} = $urandom & $urandom & $urandom;
+ {OHOLDTOP, OHOLDBOT} = $urandom & $urandom & $urandom;
+ {CI, ACCUMCI, SIGNEXTIN} = $urandom & $urandom & $urandom;
+
+ {IRSTTOP, IRSTBOT} = $urandom & $urandom & $urandom;
+ {ORSTTOP, ORSTBOT} = $urandom & $urandom & $urandom;
+ end
+
+ if (errcount == 0) begin
+ $display("All tests passed.");
+ $finish;
+ end else begin
+ $display("Caught %1d errors.", errcount);
+ $stop;
+ end
+ end
+
+ SB_MAC16 #(
+ .NEG_TRIGGER (NEG_TRIGGER ),
+ .C_REG (C_REG ),
+ .A_REG (A_REG ),
+ .B_REG (B_REG ),
+ .D_REG (D_REG ),
+ .TOP_8x8_MULT_REG (TOP_8x8_MULT_REG ),
+ .BOT_8x8_MULT_REG (BOT_8x8_MULT_REG ),
+ .PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1),
+ .PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2),
+ .TOPOUTPUT_SELECT (TOPOUTPUT_SELECT ),
+ .TOPADDSUB_LOWERINPUT (TOPADDSUB_LOWERINPUT ),
+ .TOPADDSUB_UPPERINPUT (TOPADDSUB_UPPERINPUT ),
+ .TOPADDSUB_CARRYSELECT (TOPADDSUB_CARRYSELECT ),
+ .BOTOUTPUT_SELECT (BOTOUTPUT_SELECT ),
+ .BOTADDSUB_LOWERINPUT (BOTADDSUB_LOWERINPUT ),
+ .BOTADDSUB_UPPERINPUT (BOTADDSUB_UPPERINPUT ),
+ .BOTADDSUB_CARRYSELECT (BOTADDSUB_CARRYSELECT ),
+ .MODE_8x8 (MODE_8x8 ),
+ .A_SIGNED (A_SIGNED ),
+ .B_SIGNED (B_SIGNED )
+ ) ref (
+ .CLK (CLK ),
+ .CE (CE ),
+ .C (C ),
+ .A (A ),
+ .B (B ),
+ .D (D ),
+ .AHOLD (AHOLD ),
+ .BHOLD (BHOLD ),
+ .CHOLD (CHOLD ),
+ .DHOLD (DHOLD ),
+ .IRSTTOP (IRSTTOP ),
+ .IRSTBOT (IRSTBOT ),
+ .ORSTTOP (ORSTTOP ),
+ .ORSTBOT (ORSTBOT ),
+ .OLOADTOP (OLOADTOP ),
+ .OLOADBOT (OLOADBOT ),
+ .ADDSUBTOP (ADDSUBTOP ),
+ .ADDSUBBOT (ADDSUBBOT ),
+ .OHOLDTOP (OHOLDTOP ),
+ .OHOLDBOT (OHOLDBOT ),
+ .CI (CI ),
+ .ACCUMCI (ACCUMCI ),
+ .SIGNEXTIN (SIGNEXTIN ),
+ .O (REF_O ),
+ .CO (REF_CO ),
+ .ACCUMCO (REF_ACCUMCO ),
+ .SIGNEXTOUT (REF_SIGNEXTOUT)
+ );
+
+ SB_MAC16_UUT #(
+ .NEG_TRIGGER (NEG_TRIGGER ),
+ .C_REG (C_REG ),
+ .A_REG (A_REG ),
+ .B_REG (B_REG ),
+ .D_REG (D_REG ),
+ .TOP_8x8_MULT_REG (TOP_8x8_MULT_REG ),
+ .BOT_8x8_MULT_REG (BOT_8x8_MULT_REG ),
+ .PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1),
+ .PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2),
+ .TOPOUTPUT_SELECT (TOPOUTPUT_SELECT ),
+ .TOPADDSUB_LOWERINPUT (TOPADDSUB_LOWERINPUT ),
+ .TOPADDSUB_UPPERINPUT (TOPADDSUB_UPPERINPUT ),
+ .TOPADDSUB_CARRYSELECT (TOPADDSUB_CARRYSELECT ),
+ .BOTOUTPUT_SELECT (BOTOUTPUT_SELECT ),
+ .BOTADDSUB_LOWERINPUT (BOTADDSUB_LOWERINPUT ),
+ .BOTADDSUB_UPPERINPUT (BOTADDSUB_UPPERINPUT ),
+ .BOTADDSUB_CARRYSELECT (BOTADDSUB_CARRYSELECT ),
+ .MODE_8x8 (MODE_8x8 ),
+ .A_SIGNED (A_SIGNED ),
+ .B_SIGNED (B_SIGNED )
+ ) uut (
+ .CLK (CLK ),
+ .CE (CE ),
+ .C (C ),
+ .A (A ),
+ .B (B ),
+ .D (D ),
+ .AHOLD (AHOLD ),
+ .BHOLD (BHOLD ),
+ .CHOLD (CHOLD ),
+ .DHOLD (DHOLD ),
+ .IRSTTOP (IRSTTOP ),
+ .IRSTBOT (IRSTBOT ),
+ .ORSTTOP (ORSTTOP ),
+ .ORSTBOT (ORSTBOT ),
+ .OLOADTOP (OLOADTOP ),
+ .OLOADBOT (OLOADBOT ),
+ .ADDSUBTOP (ADDSUBTOP ),
+ .ADDSUBBOT (ADDSUBBOT ),
+ .OHOLDTOP (OHOLDTOP ),
+ .OHOLDBOT (OHOLDBOT ),
+ .CI (CI ),
+ .ACCUMCI (ACCUMCI ),
+ .SIGNEXTIN (SIGNEXTIN ),
+ .O (UUT_O ),
+ .CO (UUT_CO ),
+ .ACCUMCO (UUT_ACCUMCO ),
+ .SIGNEXTOUT (UUT_SIGNEXTOUT)
+ );
+endmodule
+
+module testbench_comb_8x8_A;
+ 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 (0)
+ ) testbench ();
+endmodule
+
+module testbench_comb_8x8_B;
+ 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 (0)
+ ) testbench ();
+endmodule
+
+module testbench_comb_16x16;
+ 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 (0)
+ ) testbench ();
+endmodule
+
+module testbench_seq_16x16_A;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (1),
+ .A_REG (1),
+ .B_REG (1),
+ .D_REG (1),
+ .TOP_8x8_MULT_REG (1),
+ .BOT_8x8_MULT_REG (1),
+ .PIPELINE_16x16_MULT_REG1 (1),
+ .PIPELINE_16x16_MULT_REG2 (1),
+ .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 (0)
+ ) testbench ();
+endmodule
+
+module testbench_seq_16x16_B;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (1),
+ .A_REG (1),
+ .B_REG (1),
+ .D_REG (1),
+ .TOP_8x8_MULT_REG (1),
+ .BOT_8x8_MULT_REG (1),
+ .PIPELINE_16x16_MULT_REG1 (1),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (1), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (1), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (0),
+ .B_SIGNED (0)
+ ) testbench ();
+endmodule
diff --git a/techlibs/intel/common/brams_map.v b/techlibs/intel/common/brams_map.v
index fae4af2a..d0f07c1d 100644
--- a/techlibs/intel/common/brams_map.v
+++ b/techlibs/intel/common/brams_map.v
@@ -2,8 +2,8 @@ module \$__M9K_ALTSYNCRAM_SINGLEPORT_FULL (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1A
parameter CFG_ABITS = 8;
parameter CFG_DBITS = 36;
- parameter ABITS = "1";
- parameter DBITS = "1";
+ parameter ABITS = 1;
+ parameter DBITS = 1;
parameter CLKPOL2 = 1;
parameter CLKPOL3 = 1;
@@ -63,21 +63,21 @@ module \$__M9K_ALTSYNCRAM_SINGLEPORT_FULL (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1A
.width_byteena_a (1), // Forced value
.numwords_b ( NUMWORDS ),
.numwords_a ( NUMWORDS ),
- .widthad_b ( CFG_ABITS ),
- .width_b ( CFG_DBITS ),
- .widthad_a ( CFG_ABITS ),
- .width_a ( CFG_DBITS )
+ .widthad_b ( CFG_DBITS ),
+ .width_b ( CFG_ABITS ),
+ .widthad_a ( CFG_DBITS ),
+ .width_a ( CFG_ABITS )
) _TECHMAP_REPLACE_ (
.data_a(B1DATA),
.address_a(B1ADDR),
.wren_a(B1EN),
.rden_a(A1EN),
.q_a(A1DATA),
- .data_b(1'b0),
+ .data_b(B1DATA),
.address_b(0),
.wren_b(1'b0),
.rden_b(1'b0),
- .q_b(1'b0),
+ .q_b(),
.clock0(CLK2),
.clock1(1'b1), // Unused in single port mode
.clocken0(1'b1),
diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v
index b3a11272..49e36aa2 100644
--- a/techlibs/intel/cycloneive/arith_map.v
+++ b/techlibs/intel/cycloneive/arith_map.v
@@ -32,7 +32,7 @@ module fa
wire VCC;
assign VCC = 1'b1;
-
+
cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x),
.dataa(a_c),
.datab(b_c),
@@ -40,7 +40,7 @@ module fa
.datad(VCC));
defparam syn__05_.lut_mask = 16'b1001011010010110;
defparam syn__05_.sum_lutc_input = "datac";
-
+
cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t),
.dataa(cin_c),
.datab(b_c),
@@ -48,11 +48,11 @@ module fa
.datad(VCC));
defparam syn__06_.lut_mask = 16'b1110000011100000;
defparam syn__06_.sum_lutc_input = "datac";
-
+
endmodule // fa
module f_stage();
-
+
endmodule // f_stage
module f_end();
@@ -88,7 +88,7 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO);
.cin_c(C[0]),
.cout_t(C0[1]),
.sum_x(Y[0]));
-
+
genvar i;
generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice
cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i]));
diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v
index bd60d4e1..f8d142bc 100644
--- a/techlibs/intel/cyclonev/cells_map.v
+++ b/techlibs/intel/cyclonev/cells_map.v
@@ -76,7 +76,7 @@ module \$lut (A, Y);
wire VCC;
wire GND;
assign {VCC,GND} = {1'b1,1'b0};
-
+
generate
if (WIDTH == 1) begin
assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
@@ -151,7 +151,7 @@ module \$lut (A, Y);
TODO: There's not a just 7-input function on Cyclone V, see the following note:
**Extended LUT Mode**
Use extended LUT mode to implement a specific set of 7-input functions. The set must
- be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs.
+ be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs.
[source](Device Interfaces and Integration Basics for Cyclone V Devices).
end*/
else
diff --git a/techlibs/intel/cyclonev/cells_sim.v b/techlibs/intel/cyclonev/cells_sim.v
index 5ecdabcf..fa27c2c8 100644
--- a/techlibs/intel/cyclonev/cells_sim.v
+++ b/techlibs/intel/cyclonev/cells_sim.v
@@ -54,7 +54,7 @@ module cyclonev_lcell_comb
// Internal variables
// Sub mask for fragmented LUTs
wire [15:0] mask_a, mask_b, mask_c, mask_d;
- // Independant output for fragmented LUTs
+ // Independent output for fragmented LUTs
wire output_0, output_1, output_2, output_3;
// Extended mode uses mux to define the output
wire mux_0, mux_1;
diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc
index d74f295e..0f1d7a7b 100644
--- a/techlibs/intel/synth_intel.cc
+++ b/techlibs/intel/synth_intel.cc
@@ -131,8 +131,8 @@ struct SynthIntelPass : public ScriptPass {
nobram = true;
continue;
}
- if (args[argidx] == "-flatten") {
- flatten = true;
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
continue;
}
if (args[argidx] == "-retime") {
diff --git a/techlibs/sf2/Makefile.inc b/techlibs/sf2/Makefile.inc
new file mode 100644
index 00000000..cc3054ac
--- /dev/null
+++ b/techlibs/sf2/Makefile.inc
@@ -0,0 +1,8 @@
+
+OBJS += techlibs/sf2/synth_sf2.o
+OBJS += techlibs/sf2/sf2_iobs.o
+
+$(eval $(call add_share_file,share/sf2,techlibs/sf2/arith_map.v))
+$(eval $(call add_share_file,share/sf2,techlibs/sf2/cells_map.v))
+$(eval $(call add_share_file,share/sf2,techlibs/sf2/cells_sim.v))
+
diff --git a/techlibs/sf2/arith_map.v b/techlibs/sf2/arith_map.v
new file mode 100644
index 00000000..462d3ce5
--- /dev/null
+++ b/techlibs/sf2/arith_map.v
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ *
+ */
+
+
+// nothing here yet
diff --git a/techlibs/sf2/cells_map.v b/techlibs/sf2/cells_map.v
new file mode 100644
index 00000000..6ad7807d
--- /dev/null
+++ b/techlibs/sf2/cells_map.v
@@ -0,0 +1,82 @@
+module \$_DFF_N_ (input D, C, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+module \$_DFF_P_ (input D, C, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+module \$_DFF_NN0_ (input D, C, R, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+module \$_DFF_NN1_ (input D, C, R, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+module \$_DFF_NP0_ (input D, C, R, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+module \$_DFF_NP1_ (input D, C, R, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+module \$_DFF_PN0_ (input D, C, R, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+module \$_DFF_PN1_ (input D, C, R, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+module \$_DFF_PP0_ (input D, C, R, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+module \$_DFF_PP1_ (input D, C, R, output Q);
+ SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
+endmodule
+
+// module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
+// module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
+//
+// module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
+// module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
+//
+// module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
+// module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
+// module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
+// module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
+//
+// module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
+// module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
+// module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
+// module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); 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
+ CFG1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]));
+ end else
+ if (WIDTH == 2) begin
+ CFG2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]));
+ end else
+ if (WIDTH == 3) begin
+ CFG3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2]));
+ end else
+ if (WIDTH == 4) begin
+ CFG4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ end else begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ endgenerate
+endmodule
+`endif
diff --git a/techlibs/sf2/cells_sim.v b/techlibs/sf2/cells_sim.v
new file mode 100644
index 00000000..c62748b1
--- /dev/null
+++ b/techlibs/sf2/cells_sim.v
@@ -0,0 +1,327 @@
+// https://coredocs.s3.amazonaws.com/Libero/12_0_0/Tool/sf2_mlg.pdf
+
+module ADD2 (
+
+ input A, B,
+ output Y
+);
+ assign Y = A & B;
+endmodule
+
+module ADD3 (
+ input A, B, C,
+ output Y
+);
+ assign Y = A & B & C;
+endmodule
+
+module ADD4 (
+ input A, B, C, D,
+ output Y
+);
+ assign Y = A & B & C & D;
+endmodule
+
+module CFG1 (
+ output Y,
+ input A
+);
+ parameter [1:0] INIT = 2'h0;
+ assign Y = INIT >> A;
+endmodule
+
+module CFG2 (
+ output Y,
+ input A,
+ input B
+);
+ parameter [3:0] INIT = 4'h0;
+ assign Y = INIT >> {B, A};
+endmodule
+
+module CFG3 (
+ output Y,
+ input A,
+ input B,
+ input C
+);
+ parameter [7:0] INIT = 8'h0;
+ assign Y = INIT >> {C, B, A};
+endmodule
+
+module CFG4 (
+ output Y,
+ input A,
+ input B,
+ input C,
+ input D
+);
+ parameter [15:0] INIT = 16'h0;
+ assign Y = INIT >> {D, C, B, A};
+endmodule
+
+module BUFF (
+ input A,
+ output Y
+);
+ assign Y = A;
+endmodule
+
+module BUFD (
+ input A,
+ output Y
+);
+ assign Y = A;
+endmodule
+
+module CLKINT (
+ input A,
+ output Y
+);
+ assign Y = A;
+endmodule
+
+module CLKINT_PRESERVE (
+ input A,
+ output Y
+);
+ assign Y = A;
+endmodule
+
+module GCLKINT (
+ input A, EN,
+ output Y
+);
+ assign Y = A & EN;
+endmodule
+
+module RCLKINT (
+ input A,
+ output Y
+);
+ assign Y = A;
+endmodule
+
+module RGCLKINT (
+ input A, EN,
+ output Y
+);
+ assign Y = A & EN;
+endmodule
+
+module SLE (
+ output Q,
+ input ADn,
+ input ALn,
+ input CLK,
+ input D,
+ input LAT,
+ input SD,
+ input EN,
+ input SLn
+);
+ reg q_latch, q_ff;
+
+ always @(posedge CLK, negedge ALn) begin
+ if (!ALn) begin
+ q_ff <= !ADn;
+ end else if (EN) begin
+ if (!SLn)
+ q_ff <= SD;
+ else
+ q_ff <= D;
+ end
+ end
+
+ always @* begin
+ if (!ALn) begin
+ q_latch <= !ADn;
+ end else if (CLK && EN) begin
+ if (!SLn)
+ q_ff <= SD;
+ else
+ q_ff <= D;
+ end
+ end
+
+ assign Q = LAT ? q_latch : q_ff;
+endmodule
+
+// module AR1
+// module FCEND_BUFF
+// module FCINIT_BUFF
+// module FLASH_FREEZE
+// module OSCILLATOR
+// module SYSRESET
+// module SYSCTRL_RESET_STATUS
+// module LIVE_PROBE_FB
+// module GCLKBUF
+// module GCLKBUF_DIFF
+// module GCLKBIBUF
+// module DFN1
+// module DFN1C0
+// module DFN1E1
+// module DFN1E1C0
+// module DFN1E1P0
+// module DFN1P0
+// module DLN1
+// module DLN1C0
+// module DLN1P0
+
+module INV (
+ input A,
+ output Y
+);
+ assign Y = !A;
+endmodule
+
+module INVD (
+ input A,
+ output Y
+);
+ assign Y = !A;
+endmodule
+
+module MX2 (
+ input A, B, S,
+ output Y
+);
+ assign Y = S ? B : A;
+endmodule
+
+module MX4 (
+ input D0, D1, D2, D3, S0, S1,
+ output Y
+);
+ assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0);
+endmodule
+
+module NAND2 (
+ input A, B,
+ output Y
+);
+ assign Y = !(A & B);
+endmodule
+
+module NAND3 (
+ input A, B, C,
+ output Y
+);
+ assign Y = !(A & B & C);
+endmodule
+
+module NAND4 (
+ input A, B, C, D,
+ output Y
+);
+ assign Y = !(A & B & C & D);
+endmodule
+
+module NOR2 (
+ input A, B,
+ output Y
+);
+ assign Y = !(A | B);
+endmodule
+
+module NOR3 (
+ input A, B, C,
+ output Y
+);
+ assign Y = !(A | B | C);
+endmodule
+
+module NOR4 (
+ input A, B, C, D,
+ output Y
+);
+ assign Y = !(A | B | C | D);
+endmodule
+
+module OR2 (
+ input A, B,
+ output Y
+);
+ assign Y = A | B;
+endmodule
+
+module OR3 (
+ input A, B, C,
+ output Y
+);
+ assign Y = A | B | C;
+endmodule
+
+module OR4 (
+ input A, B, C, D,
+ output Y
+);
+ assign Y = A | B | C | D;
+endmodule
+
+module XOR2 (
+ input A, B,
+ output Y
+);
+ assign Y = A ^ B;
+endmodule
+
+module XOR3 (
+ input A, B, C,
+ output Y
+);
+ assign Y = A ^ B ^ C;
+endmodule
+
+module XOR4 (
+ input A, B, C, D,
+ output Y
+);
+ assign Y = A ^ B ^ C ^ D;
+endmodule
+
+module XOR8 (
+ input A, B, C, D, E, F, G, H,
+ output Y
+);
+ assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H;
+endmodule
+
+// module UJTAG
+// module BIBUF
+// module BIBUF_DIFF
+// module CLKBIBUF
+
+module CLKBUF (
+ input PAD,
+ output Y
+);
+ assign Y = PAD;
+endmodule
+
+// module CLKBUF_DIFF
+
+module INBUF (
+ input PAD,
+ output Y
+);
+ assign Y = PAD;
+endmodule
+
+// module INBUF_DIFF
+
+module OUTBUF (
+ input D,
+ output PAD
+);
+ assign PAD = D;
+endmodule
+
+// module OUTBUF_DIFF
+// module TRIBUFF
+// module TRIBUFF_DIFF
+// module DDR_IN
+// module DDR_OUT
+// module RAM1K18
+// module RAM64x18
+// module MACC
diff --git a/techlibs/sf2/sf2_iobs.cc b/techlibs/sf2/sf2_iobs.cc
new file mode 100644
index 00000000..3d43332e
--- /dev/null
+++ b/techlibs/sf2/sf2_iobs.cc
@@ -0,0 +1,197 @@
+/*
+ * 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
+
+static void handle_iobufs(Module *module, bool clkbuf_mode)
+{
+ SigMap sigmap(module);
+
+ pool<SigBit> clk_bits;
+ pool<SigBit> handled_io_bits;
+ dict<SigBit, SigBit> rewrite_bits;
+ vector<pair<Cell*, SigBit>> pad_bits;
+
+ for (auto cell : module->cells())
+ {
+ if (clkbuf_mode && cell->type == "\\SLE") {
+ for (auto bit : sigmap(cell->getPort("\\CLK")))
+ clk_bits.insert(bit);
+ }
+ if (cell->type.in("\\INBUF", "\\OUTBUF", "\\TRIBUFF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF",
+ "\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUFF_DIFF", "\\CLKBUF_DIFF",
+ "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF")) {
+ for (auto bit : sigmap(cell->getPort("\\PAD")))
+ handled_io_bits.insert(bit);
+ }
+ }
+
+ for (auto wire : vector<Wire*>(module->wires()))
+ {
+ if (!wire->port_input && !wire->port_output)
+ continue;
+
+ for (int index = 0; index < GetSize(wire); index++)
+ {
+ SigBit bit(wire, index);
+ SigBit canonical_bit = sigmap(bit);
+
+ if (handled_io_bits.count(canonical_bit))
+ continue;
+
+ if (wire->port_input && wire->port_output)
+ log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit));
+
+ IdString buf_type, buf_port;
+
+ if (wire->port_output) {
+ buf_type = "\\OUTBUF";
+ buf_port = "\\D";
+ } else if (clkbuf_mode && clk_bits.count(canonical_bit)) {
+ buf_type = "\\CLKBUF";
+ buf_port = "\\Y";
+ } else {
+ buf_type = "\\INBUF";
+ buf_port = "\\Y";
+ }
+
+ Cell *c = module->addCell(NEW_ID, buf_type);
+ SigBit new_bit = module->addWire(NEW_ID);
+ c->setPort(buf_port, new_bit);
+ 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("\\PAD", it.second);
+}
+
+static void handle_clkint(Module *module)
+{
+ SigMap sigmap(module);
+
+ pool<SigBit> clk_bits;
+ vector<SigBit> handled_clk_bits;
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type == "\\SLE") {
+ for (auto bit : sigmap(cell->getPort("\\CLK")))
+ clk_bits.insert(bit);
+ }
+ if (cell->type.in("\\CLKBUF", "\\CLKBIBUF", "\\CLKBUF_DIFF", "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF",
+ "\\CLKINT", "\\CLKINT_PRESERVE", "\\GCLKINT", "\\RCLKINT", "\\RGCLKINT")) {
+ for (auto bit : sigmap(cell->getPort("\\Y")))
+ handled_clk_bits.push_back(bit);
+ }
+ }
+
+ for (auto bit : handled_clk_bits)
+ clk_bits.erase(bit);
+
+ for (auto cell : vector<Cell*>(module->cells()))
+ for (auto &conn : cell->connections())
+ {
+ if (!cell->output(conn.first))
+ continue;
+
+ SigSpec sig = conn.second;
+ bool did_something = false;
+
+ for (auto &bit : sig) {
+ SigBit canonical_bit = sigmap(bit);
+ if (clk_bits.count(canonical_bit)) {
+ Cell *c = module->addCell(NEW_ID, "\\CLKINT");
+ SigBit new_bit = module->addWire(NEW_ID);
+ c->setPort("\\A", new_bit);
+ c->setPort("\\Y", bit);
+ log("Added %s cell %s for clock signal %s.\n", log_id(c->type), log_id(c), log_signal(bit));
+ clk_bits.erase(canonical_bit);
+ did_something = true;
+ bit = new_bit;
+ }
+ }
+
+ if (did_something)
+ cell->setPort(conn.first, sig);
+ }
+
+ for (auto bit : clk_bits)
+ log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit));
+}
+
+struct Sf2IobsPass : public Pass {
+ Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" sf2_iobs [options] [selection]\n");
+ log("\n");
+ log("Add SF2 I/O buffers and global buffers to top module as needed.\n");
+ log("\n");
+ log(" -clkbuf\n");
+ log(" Insert PAD->global_net clock buffers\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool clkbuf_mode = false;
+
+ log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-clkbuf") {
+ clkbuf_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ Module *module = design->top_module();
+
+ if (module == nullptr)
+ log_cmd_error("No top module found.\n");
+
+ handle_iobufs(module, clkbuf_mode);
+ handle_clkint(module);
+ }
+} Sf2IobsPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc
new file mode 100644
index 00000000..0924df7a
--- /dev/null
+++ b/techlibs/sf2/synth_sf2.cc
@@ -0,0 +1,246 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SynthSf2Pass : public ScriptPass
+{
+ SynthSf2Pass() : ScriptPass("synth_sf2", "synthesis for SmartFusion2 and IGLOO2 FPGAs") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_sf2 [options]\n");
+ log("\n");
+ log("This command runs synthesis for SmartFusion2 and IGLOO2 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(" -vlog <file>\n");
+ log(" write the design to the specified Verilog 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(" -noiobs\n");
+ log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n");
+ log("\n");
+ log(" -clkbuf\n");
+ log(" insert direct PAD->global_net buffers\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, vlog_file, json_file;
+ bool flatten, retime, iobs, clkbuf;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ edif_file = "";
+ vlog_file = "";
+ json_file = "";
+ flatten = true;
+ retime = false;
+ iobs = true;
+ clkbuf = 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] == "-vlog" && argidx+1 < args.size()) {
+ vlog_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;
+ }
+ if (args[argidx] == "-noiobs") {
+ iobs = false;
+ continue;
+ }
+ if (args[argidx] == "-clkbuf") {
+ clkbuf = 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_SF2 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 +/sf2/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("fine"))
+ {
+ run("opt -fast -mux_undef -undriven -fine");
+ run("memory_map");
+ run("opt -undriven -fine");
+ run("techmap -map +/techmap.v -map +/sf2/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 +/sf2/cells_map.v");
+ run("opt_expr -mux_undef");
+ run("simplemap");
+ // run("sf2_ffinit");
+ // run("sf2_ffssr");
+ // run("sf2_opt -full");
+ }
+
+ if (check_label("map_luts"))
+ {
+ run("abc -lut 4");
+ run("clean");
+ }
+
+ if (check_label("map_cells"))
+ {
+ run("techmap -map +/sf2/cells_map.v");
+ run("clean");
+ }
+
+ if (check_label("map_iobs"))
+ {
+ if (help_mode)
+ run("sf2_iobs [-clkbuf]", "(unless -noiobs)");
+ else if (iobs)
+ run(clkbuf ? "sf2_iobs -clkbuf" : "sf2_iobs");
+ 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 -gndvccy %s", help_mode ? "<file-name>" : edif_file.c_str()));
+ }
+
+ if (check_label("vlog"))
+ {
+ if (!vlog_file.empty() || help_mode)
+ run(stringf("write_verilog %s", help_mode ? "<file-name>" : vlog_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()));
+ }
+ }
+} SynthSf2Pass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 887ea27d..d68f03bb 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -28,7 +28,8 @@ $(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/arith_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut2lut.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_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v
index 03719659..09a5f07e 100644
--- a/techlibs/xilinx/arith_map.v
+++ b/techlibs/xilinx/arith_map.v
@@ -17,6 +17,9 @@
*
*/
+// ============================================================================
+// LCU
+
(* techmap_celltype = "$lcu" *)
module _80_xilinx_lcu (P, G, CI, CO);
parameter WIDTH = 2;
@@ -28,10 +31,78 @@ module _80_xilinx_lcu (P, G, CI, CO);
wire _TECHMAP_FAIL_ = WIDTH <= 2;
+ genvar i;
+
+`ifdef _CLB_CARRY
+
+ localparam CARRY4_COUNT = (WIDTH + 3) / 4;
+ localparam MAX_WIDTH = CARRY4_COUNT * 4;
+ localparam PAD_WIDTH = MAX_WIDTH - WIDTH;
+
+ wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G};
+ wire [MAX_WIDTH-1:0] C = CO;
+
+ generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
+
+ // Partially occupied CARRY4
+ if ((i+1)*4 > WIDTH) begin
+
+ // First one
+ if (i == 0) begin
+ CARRY4 carry4_1st_part
+ (
+ .CYINIT(CI),
+ .CI (1'd0),
+ .DI (G [(Y_WIDTH - 1):i*4]),
+ .S (S [(Y_WIDTH - 1):i*4]),
+ .CO (CO[(Y_WIDTH - 1):i*4]),
+ );
+ // Another one
+ end else begin
+ CARRY4 carry4_part
+ (
+ .CYINIT(1'd0),
+ .CI (C [i*4 - 1]),
+ .DI (G [(Y_WIDTH - 1):i*4]),
+ .S (S [(Y_WIDTH - 1):i*4]),
+ .CO (CO[(Y_WIDTH - 1):i*4]),
+ );
+ end
+
+ // Fully occupied CARRY4
+ end else begin
+
+ // First one
+ if (i == 0) begin
+ CARRY4 carry4_1st_full
+ (
+ .CYINIT(CI),
+ .CI (1'd0),
+ .DI (G [((i+1)*4 - 1):i*4]),
+ .S (S [((i+1)*4 - 1):i*4]),
+ .CO (CO[((i+1)*4 - 1):i*4]),
+ );
+ // Another one
+ end else begin
+ CARRY4 carry4_full
+ (
+ .CYINIT(1'd0),
+ .CI (C [i*4 - 1]),
+ .DI (G [((i+1)*4 - 1):i*4]),
+ .S (S [((i+1)*4 - 1):i*4]),
+ .CO (CO[((i+1)*4 - 1):i*4]),
+ );
+ end
+
+ end
+
+ end endgenerate
+
+`elsif _EXPLICIT_CARRY
+
wire [WIDTH-1:0] C = {CO, CI};
wire [WIDTH-1:0] S = P & ~G;
- genvar i;
generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
MUXCY muxcy (
.CI(C[i]),
@@ -40,8 +111,28 @@ module _80_xilinx_lcu (P, G, CI, CO);
.O(CO[i])
);
end endgenerate
+
+`else
+
+ wire [WIDTH-1:0] C = {CO, CI};
+ wire [WIDTH-1:0] S = P & ~G;
+
+ generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
+ MUXCY muxcy (
+ .CI(C[i]),
+ .DI(G[i]),
+ .S(S[i]),
+ .O(CO[i])
+ );
+ end endgenerate
+`endif
+
endmodule
+
+// ============================================================================
+// ALU
+
(* techmap_celltype = "$alu" *)
module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
parameter A_SIGNED = 0;
@@ -49,6 +140,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
parameter A_WIDTH = 1;
parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
+ parameter _TECHMAP_CONSTVAL_CI_ = 0;
+ parameter _TECHMAP_CONSTMSK_CI_ = 0;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
@@ -66,16 +159,189 @@ module _80_xilinx_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] P = AA ^ BB;
- wire [Y_WIDTH-1:0] G = AA & BB;
- wire [Y_WIDTH-1:0] C = {CO, CI};
- wire [Y_WIDTH-1:0] S = P & ~G;
+ genvar i;
+
+`ifdef _CLB_CARRY
+
+ localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4;
+ localparam MAX_WIDTH = CARRY4_COUNT * 4;
+ localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH;
+
+ wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB};
+ wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB};
+
+ wire [MAX_WIDTH-1:0] C = CO;
genvar i;
+ generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
+
+ // Partially occupied CARRY4
+ if ((i+1)*4 > Y_WIDTH) begin
+
+ // First one
+ if (i == 0) begin
+ CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_part
+ (
+ .CYINIT(CI),
+ .CI (1'd0),
+ .DI (DI[(Y_WIDTH - 1):i*4]),
+ .S (S [(Y_WIDTH - 1):i*4]),
+ .O (Y [(Y_WIDTH - 1):i*4]),
+ .CO (CO[(Y_WIDTH - 1):i*4])
+ );
+ // Another one
+ end else begin
+ CARRY4 carry4_part
+ (
+ .CYINIT(1'd0),
+ .CI (C [i*4 - 1]),
+ .DI (DI[(Y_WIDTH - 1):i*4]),
+ .S (S [(Y_WIDTH - 1):i*4]),
+ .O (Y [(Y_WIDTH - 1):i*4]),
+ .CO (CO[(Y_WIDTH - 1):i*4])
+ );
+ end
+
+ // Fully occupied CARRY4
+ end else begin
+
+ // First one
+ if (i == 0) begin
+ CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_full
+ (
+ .CYINIT(CI),
+ .CI (1'd0),
+ .DI (DI[((i+1)*4 - 1):i*4]),
+ .S (S [((i+1)*4 - 1):i*4]),
+ .O (Y [((i+1)*4 - 1):i*4]),
+ .CO (CO[((i+1)*4 - 1):i*4])
+ );
+ // Another one
+ end else begin
+ CARRY4 carry4_full
+ (
+ .CYINIT(1'd0),
+ .CI (C [i*4 - 1]),
+ .DI (DI[((i+1)*4 - 1):i*4]),
+ .S (S [((i+1)*4 - 1):i*4]),
+ .O (Y [((i+1)*4 - 1):i*4]),
+ .CO (CO[((i+1)*4 - 1):i*4])
+ );
+ end
+
+ end
+
+ end endgenerate
+
+`elsif _EXPLICIT_CARRY
+
+ wire [Y_WIDTH-1:0] S = AA ^ BB;
+ wire [Y_WIDTH-1:0] DI = AA & BB;
+
+ wire CINIT;
+ // Carry chain.
+ //
+ // VPR requires that the carry chain never hit the fabric. The CO input
+ // to this techmap is the carry outputs for synthesis, e.g. might hit the
+ // fabric.
+ //
+ // So we maintain two wire sets, CO_CHAIN is the carry that is for VPR,
+ // e.g. off fabric dedicated chain. CO is the carry outputs that are
+ // available to the fabric.
+ wire [Y_WIDTH-1:0] CO_CHAIN;
+ wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT};
+
+ // If carry chain is being initialized to a constant, techmap the constant
+ // source. Otherwise techmap the fabric source.
+ generate for (i = 0; i < 1; i = i + 1) begin:slice
+ CARRY0 #(.CYINIT_FABRIC(1)) carry(
+ .CI_INIT(CI),
+ .DI(DI[0]),
+ .S(S[0]),
+ .CO_CHAIN(CO_CHAIN[0]),
+ .CO_FABRIC(CO[0]),
+ .O(Y[0])
+ );
+ end endgenerate
+
+ generate for (i = 1; i < Y_WIDTH-1; i = i + 1) begin:slice
+ if(i % 4 == 0) begin
+ CARRY0 carry (
+ .CI(C[i]),
+ .DI(DI[i]),
+ .S(S[i]),
+ .CO_CHAIN(CO_CHAIN[i]),
+ .CO_FABRIC(CO[i]),
+ .O(Y[i])
+ );
+ end
+ else
+ begin
+ CARRY carry (
+ .CI(C[i]),
+ .DI(DI[i]),
+ .S(S[i]),
+ .CO_CHAIN(CO_CHAIN[i]),
+ .CO_FABRIC(CO[i]),
+ .O(Y[i])
+ );
+ end
+ end endgenerate
+
+ generate for (i = Y_WIDTH-1; i < Y_WIDTH; i = i + 1) begin:slice
+ if(i % 4 == 0) begin
+ CARRY0 top_of_carry (
+ .CI(C[i]),
+ .DI(DI[i]),
+ .S(S[i]),
+ .CO_CHAIN(CO_CHAIN[i]),
+ .O(Y[i])
+ );
+ end
+ else
+ begin
+ CARRY top_of_carry (
+ .CI(C[i]),
+ .DI(DI[i]),
+ .S(S[i]),
+ .CO_CHAIN(CO_CHAIN[i]),
+ .O(Y[i])
+ );
+ end
+ // Turns out CO_FABRIC and O both use [ABCD]MUX, so provide
+ // a non-congested path to output the top of the carry chain.
+ // Registering the output of the CARRY block would solve this, but not
+ // all designs do that.
+ if((i+1) % 4 == 0) begin
+ CARRY0 carry_output (
+ .CI(CO_CHAIN[i]),
+ .DI(0),
+ .S(0),
+ .O(CO[i])
+ );
+ end
+ else
+ begin
+ CARRY carry_output (
+ .CI(CO_CHAIN[i]),
+ .DI(0),
+ .S(0),
+ .O(CO[i])
+ );
+ end
+ end endgenerate
+
+`else
+
+ wire [Y_WIDTH-1:0] S = AA ^ BB;
+ wire [Y_WIDTH-1:0] DI = AA & BB;
+
+ wire [Y_WIDTH-1:0] C = {CO, CI};
+
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
MUXCY muxcy (
.CI(C[i]),
- .DI(G[i]),
+ .DI(DI[i]),
.S(S[i]),
.O(CO[i])
);
@@ -86,6 +352,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
);
end endgenerate
- assign X = P;
+`endif
+
+ assign X = S;
endmodule
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index 0771be0b..d5801c0f 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -1,86 +1,20 @@
+/*
+ * 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.
+ *
+ */
-module \$_DFF_N_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
-module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
-
-module \$_DFFE_NP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
-module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
-
-module \$_DFF_NN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
-module \$_DFF_NP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
-module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _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), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|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 #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|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 #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|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), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|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(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); 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
- LUT1 #(.INIT(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]));
- end else
- if (WIDTH == 3) begin
- LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]));
- 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]));
- 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]));
- 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]));
- 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]));
- 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]));
- end else begin
- wire _TECHMAP_FAIL_ = 1;
- end
- endgenerate
-endmodule
-`endif
+// Empty for now
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index eba17ac9..ff5ff072 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -1,3 +1,21 @@
+/*
+ * 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.
+ *
+ */
// See Xilinx UG953 and UG474 for a description of the cell types below.
// http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf
@@ -104,6 +122,29 @@ module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
assign CO[3] = S[3] ? CO[2] : DI[3];
endmodule
+`ifdef _EXPLICIT_CARRY
+
+module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
+ parameter CYINIT_FABRIC = 0;
+ wire CI_COMBINE;
+ if(CYINIT_FABRIC) begin
+ assign CI_COMBINE = CI_INIT;
+ end else begin
+ assign CI_COMBINE = CI;
+ end
+ assign CO_CHAIN = S ? CI_COMBINE : DI;
+ assign CO_FABRIC = S ? CI_COMBINE : DI;
+ assign O = S ^ CI_COMBINE;
+endmodule
+
+module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S);
+ assign CO_CHAIN = S ? CI : DI;
+ assign CO_FABRIC = S ? CI : DI;
+ assign O = S ^ CI;
+endmodule
+
+`endif
+
module FDRE (output reg Q, input C, CE, D, R);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -156,6 +197,30 @@ module FDPE (output reg Q, input C, CE, D, PRE);
endcase endgenerate
endmodule
+module FDRE_1 (output reg Q, input C, CE, D, R);
+ parameter [0:0] INIT = 1'b0;
+ initial Q <= INIT;
+ always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
+endmodule
+
+module FDSE_1 (output reg Q, input C, CE, D, S);
+ parameter [0:0] INIT = 1'b1;
+ initial Q <= INIT;
+ always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
+endmodule
+
+module FDCE_1 (output reg Q, input C, CE, D, CLR);
+ parameter [0:0] INIT = 1'b0;
+ initial Q <= INIT;
+ always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
+endmodule
+
+module FDPE_1 (output reg Q, input C, CE, D, PRE);
+ parameter [0:0] INIT = 1'b1;
+ initial Q <= INIT;
+ always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
+endmodule
+
module RAM64X1D (
output DPO, SPO,
input D, WCLK, WE,
diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh
index c7ad1604..56520ea1 100644
--- a/techlibs/xilinx/cells_xtra.sh
+++ b/techlibs/xilinx/cells_xtra.sh
@@ -1,13 +1,14 @@
#!/bin/bash
set -e
-libdir="/opt/Xilinx/Vivado/2015.4/data/verilog/src"
+libdir="/opt/Xilinx/Vivado/2018.1/data/verilog/src"
function xtract_cell_decl()
{
for dir in $libdir/xeclib $libdir/retarget; do
[ -f $dir/$1.v ] || continue
- egrep '^\s*((end)?module|parameter|input|output|(end)?function|(end)?task)' $dir/$1.v |
+ [ -z "$2" ] || echo $2
+ egrep '^\s*((end)?module|parameter|input|inout|output|(end)?function|(end)?task)' $dir/$1.v |
sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d;
s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/;
s/\s+$//; s/,$/;/; /input|output|parameter/ s/[^;]$/&;/; s/\s+/ /g;
@@ -37,10 +38,10 @@ function xtract_cell_decl()
xtract_cell_decl BUFMR
xtract_cell_decl BUFMRCE
xtract_cell_decl BUFR
- xtract_cell_decl CAPTUREE2
+ xtract_cell_decl CAPTUREE2 "(* keep *)"
# xtract_cell_decl CARRY4
xtract_cell_decl CFGLUT5
- xtract_cell_decl DCIRESET
+ xtract_cell_decl DCIRESET "(* keep *)"
xtract_cell_decl DNA_PORT
xtract_cell_decl DSP48E1
xtract_cell_decl EFUSE_USR
@@ -67,10 +68,10 @@ function xtract_cell_decl()
xtract_cell_decl IBUFDS_GTE2
xtract_cell_decl IBUFDS_IBUFDISABLE
xtract_cell_decl IBUFDS_INTERMDISABLE
- xtract_cell_decl ICAPE2
+ xtract_cell_decl ICAPE2 "(* keep *)"
xtract_cell_decl IDDR
xtract_cell_decl IDDR_2CLK
- xtract_cell_decl IDELAYCTRL
+ xtract_cell_decl IDELAYCTRL "(* keep *)"
xtract_cell_decl IDELAYE2
xtract_cell_decl IN_FIFO
xtract_cell_decl IOBUF
@@ -112,9 +113,10 @@ function xtract_cell_decl()
xtract_cell_decl PHY_CONTROL
xtract_cell_decl PLLE2_ADV
xtract_cell_decl PLLE2_BASE
+ 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
@@ -123,7 +125,7 @@ function xtract_cell_decl()
xtract_cell_decl RAM32X1S_1
xtract_cell_decl RAM32X2S
xtract_cell_decl RAM64M
- # xtract_cell_decl RAM64X1D
+ xtract_cell_decl RAM64X1D
xtract_cell_decl RAM64X1S
xtract_cell_decl RAM64X1S_1
xtract_cell_decl RAM64X2S
@@ -135,7 +137,7 @@ function xtract_cell_decl()
xtract_cell_decl ROM64X1
xtract_cell_decl SRL16E
xtract_cell_decl SRLC32E
- xtract_cell_decl STARTUPE2
+ xtract_cell_decl STARTUPE2 "(* keep *)"
xtract_cell_decl USR_ACCESSE2
xtract_cell_decl XADC
} > cells_xtra.new
diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v
index a2dd01ad..497518d3 100644
--- a/techlibs/xilinx/cells_xtra.v
+++ b/techlibs/xilinx/cells_xtra.v
@@ -114,6 +114,7 @@ module BUFR (...);
parameter SIM_DEVICE = "7SERIES";
endmodule
+(* keep *)
module CAPTUREE2 (...);
parameter ONESHOT = "TRUE";
input CAP;
@@ -130,6 +131,7 @@ module CFGLUT5 (...);
input CDI, CE, CLK;
endmodule
+(* keep *)
module DCIRESET (...);
output LOCKED;
input RST;
@@ -2102,6 +2104,7 @@ module IBUFDS_INTERMDISABLE (...);
input INTERMDISABLE;
endmodule
+(* keep *)
module ICAPE2 (...);
parameter [31:0] DEVICE_ID = 32'h04244093;
parameter ICAP_WIDTH = "X32";
@@ -2149,6 +2152,7 @@ module IDDR_2CLK (...);
input S;
endmodule
+(* keep *)
module IDELAYCTRL (...);
parameter SIM_DEVICE = "7SERIES";
output RDY;
@@ -2225,6 +2229,7 @@ module IOBUF (...);
parameter IOSTANDARD = "DEFAULT";
parameter SLEW = "SLOW";
output O;
+ inout IO;
input I, T;
endmodule
@@ -2236,6 +2241,7 @@ module IOBUF_DCIEN (...);
parameter SLEW = "SLOW";
parameter USE_IBUFDISABLE = "TRUE";
output O;
+ inout IO;
input DCITERMDISABLE;
input I;
input IBUFDISABLE;
@@ -2250,6 +2256,7 @@ module IOBUF_INTERMDISABLE (...);
parameter SLEW = "SLOW";
parameter USE_IBUFDISABLE = "TRUE";
output O;
+ inout IO;
input I;
input IBUFDISABLE;
input INTERMDISABLE;
@@ -2263,6 +2270,7 @@ module IOBUFDS (...);
parameter IOSTANDARD = "DEFAULT";
parameter SLEW = "SLOW";
output O;
+ inout IO, IOB;
input I, T;
endmodule
@@ -2275,6 +2283,8 @@ module IOBUFDS_DCIEN (...);
parameter SLEW = "SLOW";
parameter USE_IBUFDISABLE = "TRUE";
output O;
+ inout IO;
+ inout IOB;
input DCITERMDISABLE;
input I;
input IBUFDISABLE;
@@ -2288,6 +2298,8 @@ module IOBUFDS_DIFF_OUT (...);
parameter IOSTANDARD = "DEFAULT";
output O;
output OB;
+ inout IO;
+ inout IOB;
input I;
input TM;
input TS;
@@ -2302,6 +2314,8 @@ module IOBUFDS_DIFF_OUT_DCIEN (...);
parameter USE_IBUFDISABLE = "TRUE";
output O;
output OB;
+ inout IO;
+ inout IOB;
input DCITERMDISABLE;
input I;
input IBUFDISABLE;
@@ -2318,6 +2332,8 @@ module IOBUFDS_DIFF_OUT_INTERMDISABLE (...);
parameter USE_IBUFDISABLE = "TRUE";
output O;
output OB;
+ inout IO;
+ inout IOB;
input I;
input IBUFDISABLE;
input INTERMDISABLE;
@@ -2381,6 +2397,7 @@ module ISERDESE2 (...);
endmodule
module KEEPER (...);
+ inout O;
endmodule
module LDCE (...);
@@ -3044,6 +3061,630 @@ module PLLE2_BASE (...);
input RST;
endmodule
+(* keep *)
+module PS7 (...);
+ output DMA0DAVALID;
+ output DMA0DRREADY;
+ output DMA0RSTN;
+ output DMA1DAVALID;
+ output DMA1DRREADY;
+ output DMA1RSTN;
+ output DMA2DAVALID;
+ output DMA2DRREADY;
+ output DMA2RSTN;
+ output DMA3DAVALID;
+ output DMA3DRREADY;
+ output DMA3RSTN;
+ output EMIOCAN0PHYTX;
+ output EMIOCAN1PHYTX;
+ output EMIOENET0GMIITXEN;
+ output EMIOENET0GMIITXER;
+ output EMIOENET0MDIOMDC;
+ output EMIOENET0MDIOO;
+ output EMIOENET0MDIOTN;
+ output EMIOENET0PTPDELAYREQRX;
+ output EMIOENET0PTPDELAYREQTX;
+ output EMIOENET0PTPPDELAYREQRX;
+ output EMIOENET0PTPPDELAYREQTX;
+ output EMIOENET0PTPPDELAYRESPRX;
+ output EMIOENET0PTPPDELAYRESPTX;
+ output EMIOENET0PTPSYNCFRAMERX;
+ output EMIOENET0PTPSYNCFRAMETX;
+ output EMIOENET0SOFRX;
+ output EMIOENET0SOFTX;
+ output EMIOENET1GMIITXEN;
+ output EMIOENET1GMIITXER;
+ output EMIOENET1MDIOMDC;
+ output EMIOENET1MDIOO;
+ output EMIOENET1MDIOTN;
+ output EMIOENET1PTPDELAYREQRX;
+ output EMIOENET1PTPDELAYREQTX;
+ output EMIOENET1PTPPDELAYREQRX;
+ output EMIOENET1PTPPDELAYREQTX;
+ output EMIOENET1PTPPDELAYRESPRX;
+ output EMIOENET1PTPPDELAYRESPTX;
+ output EMIOENET1PTPSYNCFRAMERX;
+ output EMIOENET1PTPSYNCFRAMETX;
+ output EMIOENET1SOFRX;
+ output EMIOENET1SOFTX;
+ output EMIOI2C0SCLO;
+ output EMIOI2C0SCLTN;
+ output EMIOI2C0SDAO;
+ output EMIOI2C0SDATN;
+ output EMIOI2C1SCLO;
+ output EMIOI2C1SCLTN;
+ output EMIOI2C1SDAO;
+ output EMIOI2C1SDATN;
+ output EMIOPJTAGTDO;
+ output EMIOPJTAGTDTN;
+ output EMIOSDIO0BUSPOW;
+ output EMIOSDIO0CLK;
+ output EMIOSDIO0CMDO;
+ output EMIOSDIO0CMDTN;
+ output EMIOSDIO0LED;
+ output EMIOSDIO1BUSPOW;
+ output EMIOSDIO1CLK;
+ output EMIOSDIO1CMDO;
+ output EMIOSDIO1CMDTN;
+ output EMIOSDIO1LED;
+ output EMIOSPI0MO;
+ output EMIOSPI0MOTN;
+ output EMIOSPI0SCLKO;
+ output EMIOSPI0SCLKTN;
+ output EMIOSPI0SO;
+ output EMIOSPI0SSNTN;
+ output EMIOSPI0STN;
+ output EMIOSPI1MO;
+ output EMIOSPI1MOTN;
+ output EMIOSPI1SCLKO;
+ output EMIOSPI1SCLKTN;
+ output EMIOSPI1SO;
+ output EMIOSPI1SSNTN;
+ output EMIOSPI1STN;
+ output EMIOTRACECTL;
+ output EMIOUART0DTRN;
+ output EMIOUART0RTSN;
+ output EMIOUART0TX;
+ output EMIOUART1DTRN;
+ output EMIOUART1RTSN;
+ output EMIOUART1TX;
+ output EMIOUSB0VBUSPWRSELECT;
+ output EMIOUSB1VBUSPWRSELECT;
+ output EMIOWDTRSTO;
+ output EVENTEVENTO;
+ output MAXIGP0ARESETN;
+ output MAXIGP0ARVALID;
+ output MAXIGP0AWVALID;
+ output MAXIGP0BREADY;
+ output MAXIGP0RREADY;
+ output MAXIGP0WLAST;
+ output MAXIGP0WVALID;
+ output MAXIGP1ARESETN;
+ output MAXIGP1ARVALID;
+ output MAXIGP1AWVALID;
+ output MAXIGP1BREADY;
+ output MAXIGP1RREADY;
+ output MAXIGP1WLAST;
+ output MAXIGP1WVALID;
+ output SAXIACPARESETN;
+ output SAXIACPARREADY;
+ output SAXIACPAWREADY;
+ output SAXIACPBVALID;
+ output SAXIACPRLAST;
+ output SAXIACPRVALID;
+ output SAXIACPWREADY;
+ output SAXIGP0ARESETN;
+ output SAXIGP0ARREADY;
+ output SAXIGP0AWREADY;
+ output SAXIGP0BVALID;
+ output SAXIGP0RLAST;
+ output SAXIGP0RVALID;
+ output SAXIGP0WREADY;
+ output SAXIGP1ARESETN;
+ output SAXIGP1ARREADY;
+ output SAXIGP1AWREADY;
+ output SAXIGP1BVALID;
+ output SAXIGP1RLAST;
+ output SAXIGP1RVALID;
+ output SAXIGP1WREADY;
+ output SAXIHP0ARESETN;
+ output SAXIHP0ARREADY;
+ output SAXIHP0AWREADY;
+ output SAXIHP0BVALID;
+ output SAXIHP0RLAST;
+ output SAXIHP0RVALID;
+ output SAXIHP0WREADY;
+ output SAXIHP1ARESETN;
+ output SAXIHP1ARREADY;
+ output SAXIHP1AWREADY;
+ output SAXIHP1BVALID;
+ output SAXIHP1RLAST;
+ output SAXIHP1RVALID;
+ output SAXIHP1WREADY;
+ output SAXIHP2ARESETN;
+ output SAXIHP2ARREADY;
+ output SAXIHP2AWREADY;
+ output SAXIHP2BVALID;
+ output SAXIHP2RLAST;
+ output SAXIHP2RVALID;
+ output SAXIHP2WREADY;
+ output SAXIHP3ARESETN;
+ output SAXIHP3ARREADY;
+ output SAXIHP3AWREADY;
+ output SAXIHP3BVALID;
+ output SAXIHP3RLAST;
+ output SAXIHP3RVALID;
+ output SAXIHP3WREADY;
+ output [11:0] MAXIGP0ARID;
+ output [11:0] MAXIGP0AWID;
+ output [11:0] MAXIGP0WID;
+ output [11:0] MAXIGP1ARID;
+ output [11:0] MAXIGP1AWID;
+ output [11:0] MAXIGP1WID;
+ output [1:0] DMA0DATYPE;
+ output [1:0] DMA1DATYPE;
+ output [1:0] DMA2DATYPE;
+ output [1:0] DMA3DATYPE;
+ output [1:0] EMIOUSB0PORTINDCTL;
+ output [1:0] EMIOUSB1PORTINDCTL;
+ output [1:0] EVENTSTANDBYWFE;
+ output [1:0] EVENTSTANDBYWFI;
+ output [1:0] MAXIGP0ARBURST;
+ output [1:0] MAXIGP0ARLOCK;
+ output [1:0] MAXIGP0ARSIZE;
+ output [1:0] MAXIGP0AWBURST;
+ output [1:0] MAXIGP0AWLOCK;
+ output [1:0] MAXIGP0AWSIZE;
+ output [1:0] MAXIGP1ARBURST;
+ output [1:0] MAXIGP1ARLOCK;
+ output [1:0] MAXIGP1ARSIZE;
+ output [1:0] MAXIGP1AWBURST;
+ output [1:0] MAXIGP1AWLOCK;
+ output [1:0] MAXIGP1AWSIZE;
+ output [1:0] SAXIACPBRESP;
+ output [1:0] SAXIACPRRESP;
+ output [1:0] SAXIGP0BRESP;
+ output [1:0] SAXIGP0RRESP;
+ output [1:0] SAXIGP1BRESP;
+ output [1:0] SAXIGP1RRESP;
+ output [1:0] SAXIHP0BRESP;
+ output [1:0] SAXIHP0RRESP;
+ output [1:0] SAXIHP1BRESP;
+ output [1:0] SAXIHP1RRESP;
+ output [1:0] SAXIHP2BRESP;
+ output [1:0] SAXIHP2RRESP;
+ output [1:0] SAXIHP3BRESP;
+ output [1:0] SAXIHP3RRESP;
+ output [28:0] IRQP2F;
+ output [2:0] EMIOSDIO0BUSVOLT;
+ output [2:0] EMIOSDIO1BUSVOLT;
+ output [2:0] EMIOSPI0SSON;
+ output [2:0] EMIOSPI1SSON;
+ output [2:0] EMIOTTC0WAVEO;
+ output [2:0] EMIOTTC1WAVEO;
+ output [2:0] MAXIGP0ARPROT;
+ output [2:0] MAXIGP0AWPROT;
+ output [2:0] MAXIGP1ARPROT;
+ output [2:0] MAXIGP1AWPROT;
+ output [2:0] SAXIACPBID;
+ output [2:0] SAXIACPRID;
+ output [2:0] SAXIHP0RACOUNT;
+ output [2:0] SAXIHP1RACOUNT;
+ output [2:0] SAXIHP2RACOUNT;
+ output [2:0] SAXIHP3RACOUNT;
+ output [31:0] EMIOTRACEDATA;
+ output [31:0] FTMTP2FDEBUG;
+ output [31:0] MAXIGP0ARADDR;
+ output [31:0] MAXIGP0AWADDR;
+ output [31:0] MAXIGP0WDATA;
+ output [31:0] MAXIGP1ARADDR;
+ output [31:0] MAXIGP1AWADDR;
+ output [31:0] MAXIGP1WDATA;
+ output [31:0] SAXIGP0RDATA;
+ output [31:0] SAXIGP1RDATA;
+ output [3:0] EMIOSDIO0DATAO;
+ output [3:0] EMIOSDIO0DATATN;
+ output [3:0] EMIOSDIO1DATAO;
+ output [3:0] EMIOSDIO1DATATN;
+ output [3:0] FCLKCLK;
+ output [3:0] FCLKRESETN;
+ output [3:0] FTMTF2PTRIGACK;
+ output [3:0] FTMTP2FTRIG;
+ output [3:0] MAXIGP0ARCACHE;
+ output [3:0] MAXIGP0ARLEN;
+ output [3:0] MAXIGP0ARQOS;
+ output [3:0] MAXIGP0AWCACHE;
+ output [3:0] MAXIGP0AWLEN;
+ output [3:0] MAXIGP0AWQOS;
+ output [3:0] MAXIGP0WSTRB;
+ output [3:0] MAXIGP1ARCACHE;
+ output [3:0] MAXIGP1ARLEN;
+ output [3:0] MAXIGP1ARQOS;
+ output [3:0] MAXIGP1AWCACHE;
+ output [3:0] MAXIGP1AWLEN;
+ output [3:0] MAXIGP1AWQOS;
+ output [3:0] MAXIGP1WSTRB;
+ output [5:0] SAXIGP0BID;
+ output [5:0] SAXIGP0RID;
+ output [5:0] SAXIGP1BID;
+ output [5:0] SAXIGP1RID;
+ output [5:0] SAXIHP0BID;
+ output [5:0] SAXIHP0RID;
+ output [5:0] SAXIHP0WACOUNT;
+ output [5:0] SAXIHP1BID;
+ output [5:0] SAXIHP1RID;
+ output [5:0] SAXIHP1WACOUNT;
+ output [5:0] SAXIHP2BID;
+ output [5:0] SAXIHP2RID;
+ output [5:0] SAXIHP2WACOUNT;
+ output [5:0] SAXIHP3BID;
+ output [5:0] SAXIHP3RID;
+ output [5:0] SAXIHP3WACOUNT;
+ output [63:0] EMIOGPIOO;
+ output [63:0] EMIOGPIOTN;
+ output [63:0] SAXIACPRDATA;
+ output [63:0] SAXIHP0RDATA;
+ output [63:0] SAXIHP1RDATA;
+ output [63:0] SAXIHP2RDATA;
+ output [63:0] SAXIHP3RDATA;
+ output [7:0] EMIOENET0GMIITXD;
+ output [7:0] EMIOENET1GMIITXD;
+ output [7:0] SAXIHP0RCOUNT;
+ output [7:0] SAXIHP0WCOUNT;
+ output [7:0] SAXIHP1RCOUNT;
+ output [7:0] SAXIHP1WCOUNT;
+ output [7:0] SAXIHP2RCOUNT;
+ output [7:0] SAXIHP2WCOUNT;
+ output [7:0] SAXIHP3RCOUNT;
+ output [7:0] SAXIHP3WCOUNT;
+ inout DDRCASB;
+ inout DDRCKE;
+ inout DDRCKN;
+ inout DDRCKP;
+ inout DDRCSB;
+ inout DDRDRSTB;
+ inout DDRODT;
+ inout DDRRASB;
+ inout DDRVRN;
+ inout DDRVRP;
+ inout DDRWEB;
+ inout PSCLK;
+ inout PSPORB;
+ inout PSSRSTB;
+ inout [14:0] DDRA;
+ inout [2:0] DDRBA;
+ inout [31:0] DDRDQ;
+ inout [3:0] DDRDM;
+ inout [3:0] DDRDQSN;
+ inout [3:0] DDRDQSP;
+ inout [53:0] MIO;
+ input DMA0ACLK;
+ input DMA0DAREADY;
+ input DMA0DRLAST;
+ input DMA0DRVALID;
+ input DMA1ACLK;
+ input DMA1DAREADY;
+ input DMA1DRLAST;
+ input DMA1DRVALID;
+ input DMA2ACLK;
+ input DMA2DAREADY;
+ input DMA2DRLAST;
+ input DMA2DRVALID;
+ input DMA3ACLK;
+ input DMA3DAREADY;
+ input DMA3DRLAST;
+ input DMA3DRVALID;
+ input EMIOCAN0PHYRX;
+ input EMIOCAN1PHYRX;
+ input EMIOENET0EXTINTIN;
+ input EMIOENET0GMIICOL;
+ input EMIOENET0GMIICRS;
+ input EMIOENET0GMIIRXCLK;
+ input EMIOENET0GMIIRXDV;
+ input EMIOENET0GMIIRXER;
+ input EMIOENET0GMIITXCLK;
+ input EMIOENET0MDIOI;
+ input EMIOENET1EXTINTIN;
+ input EMIOENET1GMIICOL;
+ input EMIOENET1GMIICRS;
+ input EMIOENET1GMIIRXCLK;
+ input EMIOENET1GMIIRXDV;
+ input EMIOENET1GMIIRXER;
+ input EMIOENET1GMIITXCLK;
+ input EMIOENET1MDIOI;
+ input EMIOI2C0SCLI;
+ input EMIOI2C0SDAI;
+ input EMIOI2C1SCLI;
+ input EMIOI2C1SDAI;
+ input EMIOPJTAGTCK;
+ input EMIOPJTAGTDI;
+ input EMIOPJTAGTMS;
+ input EMIOSDIO0CDN;
+ input EMIOSDIO0CLKFB;
+ input EMIOSDIO0CMDI;
+ input EMIOSDIO0WP;
+ input EMIOSDIO1CDN;
+ input EMIOSDIO1CLKFB;
+ input EMIOSDIO1CMDI;
+ input EMIOSDIO1WP;
+ input EMIOSPI0MI;
+ input EMIOSPI0SCLKI;
+ input EMIOSPI0SI;
+ input EMIOSPI0SSIN;
+ input EMIOSPI1MI;
+ input EMIOSPI1SCLKI;
+ input EMIOSPI1SI;
+ input EMIOSPI1SSIN;
+ input EMIOSRAMINTIN;
+ input EMIOTRACECLK;
+ input EMIOUART0CTSN;
+ input EMIOUART0DCDN;
+ input EMIOUART0DSRN;
+ input EMIOUART0RIN;
+ input EMIOUART0RX;
+ input EMIOUART1CTSN;
+ input EMIOUART1DCDN;
+ input EMIOUART1DSRN;
+ input EMIOUART1RIN;
+ input EMIOUART1RX;
+ input EMIOUSB0VBUSPWRFAULT;
+ input EMIOUSB1VBUSPWRFAULT;
+ input EMIOWDTCLKI;
+ input EVENTEVENTI;
+ input FPGAIDLEN;
+ input FTMDTRACEINCLOCK;
+ input FTMDTRACEINVALID;
+ input MAXIGP0ACLK;
+ input MAXIGP0ARREADY;
+ input MAXIGP0AWREADY;
+ input MAXIGP0BVALID;
+ input MAXIGP0RLAST;
+ input MAXIGP0RVALID;
+ input MAXIGP0WREADY;
+ input MAXIGP1ACLK;
+ input MAXIGP1ARREADY;
+ input MAXIGP1AWREADY;
+ input MAXIGP1BVALID;
+ input MAXIGP1RLAST;
+ input MAXIGP1RVALID;
+ input MAXIGP1WREADY;
+ input SAXIACPACLK;
+ input SAXIACPARVALID;
+ input SAXIACPAWVALID;
+ input SAXIACPBREADY;
+ input SAXIACPRREADY;
+ input SAXIACPWLAST;
+ input SAXIACPWVALID;
+ input SAXIGP0ACLK;
+ input SAXIGP0ARVALID;
+ input SAXIGP0AWVALID;
+ input SAXIGP0BREADY;
+ input SAXIGP0RREADY;
+ input SAXIGP0WLAST;
+ input SAXIGP0WVALID;
+ input SAXIGP1ACLK;
+ input SAXIGP1ARVALID;
+ input SAXIGP1AWVALID;
+ input SAXIGP1BREADY;
+ input SAXIGP1RREADY;
+ input SAXIGP1WLAST;
+ input SAXIGP1WVALID;
+ input SAXIHP0ACLK;
+ input SAXIHP0ARVALID;
+ input SAXIHP0AWVALID;
+ input SAXIHP0BREADY;
+ input SAXIHP0RDISSUECAP1EN;
+ input SAXIHP0RREADY;
+ input SAXIHP0WLAST;
+ input SAXIHP0WRISSUECAP1EN;
+ input SAXIHP0WVALID;
+ input SAXIHP1ACLK;
+ input SAXIHP1ARVALID;
+ input SAXIHP1AWVALID;
+ input SAXIHP1BREADY;
+ input SAXIHP1RDISSUECAP1EN;
+ input SAXIHP1RREADY;
+ input SAXIHP1WLAST;
+ input SAXIHP1WRISSUECAP1EN;
+ input SAXIHP1WVALID;
+ input SAXIHP2ACLK;
+ input SAXIHP2ARVALID;
+ input SAXIHP2AWVALID;
+ input SAXIHP2BREADY;
+ input SAXIHP2RDISSUECAP1EN;
+ input SAXIHP2RREADY;
+ input SAXIHP2WLAST;
+ input SAXIHP2WRISSUECAP1EN;
+ input SAXIHP2WVALID;
+ input SAXIHP3ACLK;
+ input SAXIHP3ARVALID;
+ input SAXIHP3AWVALID;
+ input SAXIHP3BREADY;
+ input SAXIHP3RDISSUECAP1EN;
+ input SAXIHP3RREADY;
+ input SAXIHP3WLAST;
+ input SAXIHP3WRISSUECAP1EN;
+ input SAXIHP3WVALID;
+ input [11:0] MAXIGP0BID;
+ input [11:0] MAXIGP0RID;
+ input [11:0] MAXIGP1BID;
+ input [11:0] MAXIGP1RID;
+ input [19:0] IRQF2P;
+ input [1:0] DMA0DRTYPE;
+ input [1:0] DMA1DRTYPE;
+ input [1:0] DMA2DRTYPE;
+ input [1:0] DMA3DRTYPE;
+ input [1:0] MAXIGP0BRESP;
+ input [1:0] MAXIGP0RRESP;
+ input [1:0] MAXIGP1BRESP;
+ input [1:0] MAXIGP1RRESP;
+ input [1:0] SAXIACPARBURST;
+ input [1:0] SAXIACPARLOCK;
+ input [1:0] SAXIACPARSIZE;
+ input [1:0] SAXIACPAWBURST;
+ input [1:0] SAXIACPAWLOCK;
+ input [1:0] SAXIACPAWSIZE;
+ input [1:0] SAXIGP0ARBURST;
+ input [1:0] SAXIGP0ARLOCK;
+ input [1:0] SAXIGP0ARSIZE;
+ input [1:0] SAXIGP0AWBURST;
+ input [1:0] SAXIGP0AWLOCK;
+ input [1:0] SAXIGP0AWSIZE;
+ input [1:0] SAXIGP1ARBURST;
+ input [1:0] SAXIGP1ARLOCK;
+ input [1:0] SAXIGP1ARSIZE;
+ input [1:0] SAXIGP1AWBURST;
+ input [1:0] SAXIGP1AWLOCK;
+ input [1:0] SAXIGP1AWSIZE;
+ input [1:0] SAXIHP0ARBURST;
+ input [1:0] SAXIHP0ARLOCK;
+ input [1:0] SAXIHP0ARSIZE;
+ input [1:0] SAXIHP0AWBURST;
+ input [1:0] SAXIHP0AWLOCK;
+ input [1:0] SAXIHP0AWSIZE;
+ input [1:0] SAXIHP1ARBURST;
+ input [1:0] SAXIHP1ARLOCK;
+ input [1:0] SAXIHP1ARSIZE;
+ input [1:0] SAXIHP1AWBURST;
+ input [1:0] SAXIHP1AWLOCK;
+ input [1:0] SAXIHP1AWSIZE;
+ input [1:0] SAXIHP2ARBURST;
+ input [1:0] SAXIHP2ARLOCK;
+ input [1:0] SAXIHP2ARSIZE;
+ input [1:0] SAXIHP2AWBURST;
+ input [1:0] SAXIHP2AWLOCK;
+ input [1:0] SAXIHP2AWSIZE;
+ input [1:0] SAXIHP3ARBURST;
+ input [1:0] SAXIHP3ARLOCK;
+ input [1:0] SAXIHP3ARSIZE;
+ input [1:0] SAXIHP3AWBURST;
+ input [1:0] SAXIHP3AWLOCK;
+ input [1:0] SAXIHP3AWSIZE;
+ input [2:0] EMIOTTC0CLKI;
+ input [2:0] EMIOTTC1CLKI;
+ input [2:0] SAXIACPARID;
+ input [2:0] SAXIACPARPROT;
+ input [2:0] SAXIACPAWID;
+ input [2:0] SAXIACPAWPROT;
+ input [2:0] SAXIACPWID;
+ input [2:0] SAXIGP0ARPROT;
+ input [2:0] SAXIGP0AWPROT;
+ input [2:0] SAXIGP1ARPROT;
+ input [2:0] SAXIGP1AWPROT;
+ input [2:0] SAXIHP0ARPROT;
+ input [2:0] SAXIHP0AWPROT;
+ input [2:0] SAXIHP1ARPROT;
+ input [2:0] SAXIHP1AWPROT;
+ input [2:0] SAXIHP2ARPROT;
+ input [2:0] SAXIHP2AWPROT;
+ input [2:0] SAXIHP3ARPROT;
+ input [2:0] SAXIHP3AWPROT;
+ input [31:0] FTMDTRACEINDATA;
+ input [31:0] FTMTF2PDEBUG;
+ input [31:0] MAXIGP0RDATA;
+ input [31:0] MAXIGP1RDATA;
+ input [31:0] SAXIACPARADDR;
+ input [31:0] SAXIACPAWADDR;
+ input [31:0] SAXIGP0ARADDR;
+ input [31:0] SAXIGP0AWADDR;
+ input [31:0] SAXIGP0WDATA;
+ input [31:0] SAXIGP1ARADDR;
+ input [31:0] SAXIGP1AWADDR;
+ input [31:0] SAXIGP1WDATA;
+ input [31:0] SAXIHP0ARADDR;
+ input [31:0] SAXIHP0AWADDR;
+ input [31:0] SAXIHP1ARADDR;
+ input [31:0] SAXIHP1AWADDR;
+ input [31:0] SAXIHP2ARADDR;
+ input [31:0] SAXIHP2AWADDR;
+ input [31:0] SAXIHP3ARADDR;
+ input [31:0] SAXIHP3AWADDR;
+ input [3:0] DDRARB;
+ input [3:0] EMIOSDIO0DATAI;
+ input [3:0] EMIOSDIO1DATAI;
+ input [3:0] FCLKCLKTRIGN;
+ input [3:0] FTMDTRACEINATID;
+ input [3:0] FTMTF2PTRIG;
+ input [3:0] FTMTP2FTRIGACK;
+ input [3:0] SAXIACPARCACHE;
+ input [3:0] SAXIACPARLEN;
+ input [3:0] SAXIACPARQOS;
+ input [3:0] SAXIACPAWCACHE;
+ input [3:0] SAXIACPAWLEN;
+ input [3:0] SAXIACPAWQOS;
+ input [3:0] SAXIGP0ARCACHE;
+ input [3:0] SAXIGP0ARLEN;
+ input [3:0] SAXIGP0ARQOS;
+ input [3:0] SAXIGP0AWCACHE;
+ input [3:0] SAXIGP0AWLEN;
+ input [3:0] SAXIGP0AWQOS;
+ input [3:0] SAXIGP0WSTRB;
+ input [3:0] SAXIGP1ARCACHE;
+ input [3:0] SAXIGP1ARLEN;
+ input [3:0] SAXIGP1ARQOS;
+ input [3:0] SAXIGP1AWCACHE;
+ input [3:0] SAXIGP1AWLEN;
+ input [3:0] SAXIGP1AWQOS;
+ input [3:0] SAXIGP1WSTRB;
+ input [3:0] SAXIHP0ARCACHE;
+ input [3:0] SAXIHP0ARLEN;
+ input [3:0] SAXIHP0ARQOS;
+ input [3:0] SAXIHP0AWCACHE;
+ input [3:0] SAXIHP0AWLEN;
+ input [3:0] SAXIHP0AWQOS;
+ input [3:0] SAXIHP1ARCACHE;
+ input [3:0] SAXIHP1ARLEN;
+ input [3:0] SAXIHP1ARQOS;
+ input [3:0] SAXIHP1AWCACHE;
+ input [3:0] SAXIHP1AWLEN;
+ input [3:0] SAXIHP1AWQOS;
+ input [3:0] SAXIHP2ARCACHE;
+ input [3:0] SAXIHP2ARLEN;
+ input [3:0] SAXIHP2ARQOS;
+ input [3:0] SAXIHP2AWCACHE;
+ input [3:0] SAXIHP2AWLEN;
+ input [3:0] SAXIHP2AWQOS;
+ input [3:0] SAXIHP3ARCACHE;
+ input [3:0] SAXIHP3ARLEN;
+ input [3:0] SAXIHP3ARQOS;
+ input [3:0] SAXIHP3AWCACHE;
+ input [3:0] SAXIHP3AWLEN;
+ input [3:0] SAXIHP3AWQOS;
+ input [4:0] SAXIACPARUSER;
+ input [4:0] SAXIACPAWUSER;
+ input [5:0] SAXIGP0ARID;
+ input [5:0] SAXIGP0AWID;
+ input [5:0] SAXIGP0WID;
+ input [5:0] SAXIGP1ARID;
+ input [5:0] SAXIGP1AWID;
+ input [5:0] SAXIGP1WID;
+ input [5:0] SAXIHP0ARID;
+ input [5:0] SAXIHP0AWID;
+ input [5:0] SAXIHP0WID;
+ input [5:0] SAXIHP1ARID;
+ input [5:0] SAXIHP1AWID;
+ input [5:0] SAXIHP1WID;
+ input [5:0] SAXIHP2ARID;
+ input [5:0] SAXIHP2AWID;
+ input [5:0] SAXIHP2WID;
+ input [5:0] SAXIHP3ARID;
+ input [5:0] SAXIHP3AWID;
+ input [5:0] SAXIHP3WID;
+ input [63:0] EMIOGPIOI;
+ input [63:0] SAXIACPWDATA;
+ input [63:0] SAXIHP0WDATA;
+ input [63:0] SAXIHP1WDATA;
+ input [63:0] SAXIHP2WDATA;
+ input [63:0] SAXIHP3WDATA;
+ input [7:0] EMIOENET0GMIIRXD;
+ input [7:0] EMIOENET1GMIIRXD;
+ input [7:0] SAXIACPWSTRB;
+ input [7:0] SAXIHP0WSTRB;
+ input [7:0] SAXIHP1WSTRB;
+ input [7:0] SAXIHP2WSTRB;
+ input [7:0] SAXIHP3WSTRB;
+endmodule
+
module PULLDOWN (...);
output O;
endmodule
@@ -3052,6 +3693,17 @@ 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;
@@ -3142,6 +3794,13 @@ 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;
@@ -3204,6 +3863,7 @@ module SRLC32E (...);
input CE, CLK, D;
endmodule
+(* keep *)
module STARTUPE2 (...);
parameter PROG_USR = "FALSE";
parameter real SIM_CCLK_FREQ = 0.0;
diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v
new file mode 100644
index 00000000..13beaa6a
--- /dev/null
+++ b/techlibs/xilinx/ff_map.v
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ *
+ */
+
+// ============================================================================
+// FF mapping
+
+`ifndef _NO_FFS
+
+module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
+module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
+
+module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
+module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
+
+module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
+module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
+module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
+module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
+
+module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
+module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
+module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
+module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
+
+`endif
+
diff --git a/techlibs/xilinx/lut2lut.v b/techlibs/xilinx/lut2lut.v
deleted file mode 100644
index 061ad204..00000000
--- a/techlibs/xilinx/lut2lut.v
+++ /dev/null
@@ -1,65 +0,0 @@
-module LUT1(output O, input I0);
- parameter [1:0] INIT = 0;
- \$lut #(
- .WIDTH(1),
- .LUT(INIT)
- ) _TECHMAP_REPLACE_ (
- .A(I0),
- .Y(O)
- );
-endmodule
-
-module LUT2(output O, input I0, I1);
- parameter [3:0] INIT = 0;
- \$lut #(
- .WIDTH(2),
- .LUT(INIT)
- ) _TECHMAP_REPLACE_ (
- .A({I1, I0}),
- .Y(O)
- );
-endmodule
-
-module LUT3(output O, input I0, I1, I2);
- parameter [7:0] INIT = 0;
- \$lut #(
- .WIDTH(3),
- .LUT(INIT)
- ) _TECHMAP_REPLACE_ (
- .A({I2, I1, I0}),
- .Y(O)
- );
-endmodule
-
-module LUT4(output O, input I0, I1, I2, I3);
- parameter [15:0] INIT = 0;
- \$lut #(
- .WIDTH(4),
- .LUT(INIT)
- ) _TECHMAP_REPLACE_ (
- .A({I3, I2, I1, I0}),
- .Y(O)
- );
-endmodule
-
-module LUT5(output O, input I0, I1, I2, I3, I4);
- parameter [31:0] INIT = 0;
- \$lut #(
- .WIDTH(5),
- .LUT(INIT)
- ) _TECHMAP_REPLACE_ (
- .A({I4, I3, I2, I1, I0}),
- .Y(O)
- );
-endmodule
-
-module LUT6(output O, input I0, I1, I2, I3, I4, I5);
- parameter [63:0] INIT = 0;
- \$lut #(
- .WIDTH(6),
- .LUT(INIT)
- ) _TECHMAP_REPLACE_ (
- .A({I5, I4, I3, I2, I1, I0}),
- .Y(O)
- );
-endmodule
diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v
new file mode 100644
index 00000000..d07c59de
--- /dev/null
+++ b/techlibs/xilinx/lut_map.v
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ */
+
+// ============================================================================
+// LUT mapping
+
+`ifndef _NO_LUTS
+
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+
+ input [WIDTH-1:0] A;
+ output Y;
+
+ generate
+ if (WIDTH == 1) begin
+ LUT1 #(.INIT(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]));
+ end else
+ if (WIDTH == 3) begin
+ LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]));
+ 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]));
+ 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]));
+ 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]));
+ 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]));
+ 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]));
+ end else begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ endgenerate
+endmodule
+
+`endif
+
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 590fe61d..805ae8e6 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -63,6 +63,12 @@ struct SynthXilinxPass : public Pass
log(" generate an output netlist (and BLIF file) suitable for VPR\n");
log(" (this feature is experimental and incomplete)\n");
log("\n");
+ log(" -nobram\n");
+ log(" disable infering of block rams\n");
+ log("\n");
+ log(" -nodram\n");
+ log(" disable infering of distributed rams\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");
@@ -90,11 +96,11 @@ struct SynthXilinxPass : public Pass
log(" coarse:\n");
log(" synth -run coarse\n");
log("\n");
- log(" bram:\n");
+ log(" bram: (only executed when '-nobram' is not given)\n");
log(" memory_bram -rules +/xilinx/brams.txt\n");
log(" techmap -map +/xilinx/brams_map.v\n");
log("\n");
- log(" dram:\n");
+ log(" dram: (only executed when '-nodram' is not given)\n");
log(" memory_bram -rules +/xilinx/drams.txt\n");
log(" techmap -map +/xilinx/drams_map.v\n");
log("\n");
@@ -104,16 +110,18 @@ struct SynthXilinxPass : public Pass
log(" dffsr2dff\n");
log(" dff2dffe\n");
log(" opt -full\n");
- log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n");
+ log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n");
log(" opt -fast\n");
log("\n");
log(" map_luts:\n");
- log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n");
+ log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n");
+ log(" abc -lut 5 [-dff] (with '-vpr' only!)\n");
log(" clean\n");
log("\n");
log(" map_cells:\n");
- log(" techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode)\n");
- log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT\n");
+ log(" techmap -map +/xilinx/cells_map.v\n");
+ log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n");
+ log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n");
log(" clean\n");
log("\n");
log(" check:\n");
@@ -137,6 +145,8 @@ struct SynthXilinxPass : public Pass
bool flatten = false;
bool retime = false;
bool vpr = false;
+ bool nobram = false;
+ bool nodram = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -173,12 +183,20 @@ struct SynthXilinxPass : public Pass
vpr = true;
continue;
}
+ if (args[argidx] == "-nobram") {
+ nobram = true;
+ continue;
+ }
+ if (args[argidx] == "-nodram") {
+ nodram = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
bool active = run_from.empty();
@@ -187,9 +205,18 @@ struct SynthXilinxPass : public Pass
if (check_label(active, run_from, run_to, "begin"))
{
- Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v");
+ if (vpr) {
+ Pass::call(design, "read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
+ } else {
+ Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v");
+ }
+
Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v");
- Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v");
+
+ if (!nobram) {
+ Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v");
+ }
+
Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
}
@@ -206,14 +233,18 @@ struct SynthXilinxPass : public Pass
if (check_label(active, run_from, run_to, "bram"))
{
- Pass::call(design, "memory_bram -rules +/xilinx/brams.txt");
- Pass::call(design, "techmap -map +/xilinx/brams_map.v");
+ if (!nobram) {
+ Pass::call(design, "memory_bram -rules +/xilinx/brams.txt");
+ Pass::call(design, "techmap -map +/xilinx/brams_map.v");
+ }
}
if (check_label(active, run_from, run_to, "dram"))
{
- Pass::call(design, "memory_bram -rules +/xilinx/drams.txt");
- Pass::call(design, "techmap -map +/xilinx/drams_map.v");
+ if (!nodram) {
+ Pass::call(design, "memory_bram -rules +/xilinx/drams.txt");
+ Pass::call(design, "techmap -map +/xilinx/drams_map.v");
+ }
}
if (check_label(active, run_from, run_to, "fine"))
@@ -223,7 +254,14 @@ struct SynthXilinxPass : public Pass
Pass::call(design, "dffsr2dff");
Pass::call(design, "dff2dffe");
Pass::call(design, "opt -full");
- Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v");
+
+ if (vpr) {
+ Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v -D _EXPLICIT_CARRY");
+ } else {
+ Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v");
+ }
+
+ Pass::call(design, "hierarchy -check");
Pass::call(design, "opt -fast");
}
@@ -231,15 +269,14 @@ struct SynthXilinxPass : public Pass
{
Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
Pass::call(design, "clean");
+ Pass::call(design, "techmap -map +/xilinx/lut_map.v");
}
if (check_label(active, run_from, run_to, "map_cells"))
{
- if (vpr)
- Pass::call(design, "techmap -D NO_LUT -map +/xilinx/cells_map.v");
- else
- Pass::call(design, "techmap -map +/xilinx/cells_map.v");
- Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT");
+ Pass::call(design, "techmap -map +/xilinx/cells_map.v");
+ Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
+ "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
Pass::call(design, "clean");
}
@@ -253,7 +290,7 @@ struct SynthXilinxPass : public Pass
if (check_label(active, run_from, run_to, "edif"))
{
if (!edif_file.empty())
- Pass::call(design, stringf("write_edif %s", edif_file.c_str()));
+ Pass::call(design, stringf("write_edif -pvector bra %s", edif_file.c_str()));
}
if (check_label(active, run_from, run_to, "blif"))
{
diff --git a/tests/aiger/and.aag b/tests/aiger/and.aag
new file mode 100644
index 00000000..d1ef2c5a
--- /dev/null
+++ b/tests/aiger/and.aag
@@ -0,0 +1,5 @@
+aag 3 2 0 1 1
+2
+4
+6
+6 2 4
diff --git a/tests/aiger/and.aig b/tests/aiger/and.aig
new file mode 100644
index 00000000..da0fa071
--- /dev/null
+++ b/tests/aiger/and.aig
@@ -0,0 +1,3 @@
+aig 3 2 0 1 1
+6
+ \ No newline at end of file
diff --git a/tests/aiger/buffer.aag b/tests/aiger/buffer.aag
new file mode 100644
index 00000000..94a6fb1e
--- /dev/null
+++ b/tests/aiger/buffer.aag
@@ -0,0 +1,3 @@
+aag 1 1 0 1 0
+2
+2
diff --git a/tests/aiger/buffer.aig b/tests/aiger/buffer.aig
new file mode 100644
index 00000000..0c715fde
--- /dev/null
+++ b/tests/aiger/buffer.aig
@@ -0,0 +1,2 @@
+aig 1 1 0 1 0
+2
diff --git a/tests/aiger/cnt1.aag b/tests/aiger/cnt1.aag
new file mode 100644
index 00000000..ce4f28fc
--- /dev/null
+++ b/tests/aiger/cnt1.aag
@@ -0,0 +1,3 @@
+aag 1 0 1 0 0 1
+2 3
+2
diff --git a/tests/aiger/cnt1.aig b/tests/aiger/cnt1.aig
new file mode 100644
index 00000000..8d0ba13b
--- /dev/null
+++ b/tests/aiger/cnt1.aig
@@ -0,0 +1,3 @@
+aig 1 0 1 0 0 1
+3
+2
diff --git a/tests/aiger/cnt1e.aag b/tests/aiger/cnt1e.aag
new file mode 100644
index 00000000..6db3f0ff
--- /dev/null
+++ b/tests/aiger/cnt1e.aag
@@ -0,0 +1,8 @@
+aag 5 1 1 0 3 1
+2
+4 10
+4
+6 5 3
+8 4 2
+10 9 7
+b0 AIGER_NEVER
diff --git a/tests/aiger/cnt1e.aig b/tests/aiger/cnt1e.aig
new file mode 100644
index 00000000..d8d159f1
--- /dev/null
+++ b/tests/aiger/cnt1e.aig
@@ -0,0 +1,4 @@
+aig 5 1 1 0 3 1
+10
+4
+b0 AIGER_NEVER
diff --git a/tests/aiger/empty.aag b/tests/aiger/empty.aag
new file mode 100644
index 00000000..40c0f00c
--- /dev/null
+++ b/tests/aiger/empty.aag
@@ -0,0 +1 @@
+aag 0 0 0 0 0
diff --git a/tests/aiger/empty.aig b/tests/aiger/empty.aig
new file mode 100644
index 00000000..a28373cd
--- /dev/null
+++ b/tests/aiger/empty.aig
@@ -0,0 +1 @@
+aig 0 0 0 0 0
diff --git a/tests/aiger/false.aag b/tests/aiger/false.aag
new file mode 100644
index 00000000..421e64a9
--- /dev/null
+++ b/tests/aiger/false.aag
@@ -0,0 +1,2 @@
+aag 0 0 0 1 0
+0
diff --git a/tests/aiger/false.aig b/tests/aiger/false.aig
new file mode 100644
index 00000000..ad7d039f
--- /dev/null
+++ b/tests/aiger/false.aig
@@ -0,0 +1,2 @@
+aig 0 0 0 1 0
+0
diff --git a/tests/aiger/halfadder.aag b/tests/aiger/halfadder.aag
new file mode 100644
index 00000000..5bf54d38
--- /dev/null
+++ b/tests/aiger/halfadder.aag
@@ -0,0 +1,14 @@
+aag 7 2 0 2 3
+2
+4
+6
+12
+6 13 15
+12 2 4
+14 3 5
+i0 x
+i1 y
+o0 s
+o1 c
+c
+half adder
diff --git a/tests/aiger/halfadder.aig b/tests/aiger/halfadder.aig
new file mode 100644
index 00000000..83727ee6
--- /dev/null
+++ b/tests/aiger/halfadder.aig
@@ -0,0 +1,9 @@
+aig 5 2 0 2 3
+10
+6
+i0 x
+i1 y
+o0 s
+o1 c
+c
+half adder
diff --git a/tests/aiger/inverter.aag b/tests/aiger/inverter.aag
new file mode 100644
index 00000000..ff7c2854
--- /dev/null
+++ b/tests/aiger/inverter.aag
@@ -0,0 +1,3 @@
+aag 1 1 0 1 0
+2
+3
diff --git a/tests/aiger/inverter.aig b/tests/aiger/inverter.aig
new file mode 100644
index 00000000..525d8239
--- /dev/null
+++ b/tests/aiger/inverter.aig
@@ -0,0 +1,2 @@
+aig 1 1 0 1 0
+3
diff --git a/tests/aiger/notcnt1.aag b/tests/aiger/notcnt1.aag
new file mode 100644
index 00000000..e92815f2
--- /dev/null
+++ b/tests/aiger/notcnt1.aag
@@ -0,0 +1,4 @@
+aag 1 0 1 0 0 1
+2 3
+3
+b0 AIGER_NEVER
diff --git a/tests/aiger/notcnt1.aig b/tests/aiger/notcnt1.aig
new file mode 100644
index 00000000..f8a667f1
--- /dev/null
+++ b/tests/aiger/notcnt1.aig
@@ -0,0 +1,4 @@
+aig 1 0 1 0 0 1
+3
+3
+b0 AIGER_NEVER
diff --git a/tests/aiger/notcnt1e.aag b/tests/aiger/notcnt1e.aag
new file mode 100644
index 00000000..141c864f
--- /dev/null
+++ b/tests/aiger/notcnt1e.aag
@@ -0,0 +1,8 @@
+aag 5 1 1 0 3 1
+2
+4 10
+5
+6 5 3
+8 4 2
+10 9 7
+b0 AIGER_NEVER
diff --git a/tests/aiger/notcnt1e.aig b/tests/aiger/notcnt1e.aig
new file mode 100644
index 00000000..7c85a729
--- /dev/null
+++ b/tests/aiger/notcnt1e.aig
@@ -0,0 +1,4 @@
+aig 5 1 1 0 3 1
+10
+5
+b0 AIGER_NEVER
diff --git a/tests/aiger/or.aag b/tests/aiger/or.aag
new file mode 100644
index 00000000..f780e339
--- /dev/null
+++ b/tests/aiger/or.aag
@@ -0,0 +1,5 @@
+aag 3 2 0 1 1
+2
+4
+7
+6 3 5
diff --git a/tests/aiger/or.aig b/tests/aiger/or.aig
new file mode 100644
index 00000000..75c9e448
--- /dev/null
+++ b/tests/aiger/or.aig
@@ -0,0 +1,3 @@
+aig 3 2 0 1 1
+7
+ \ No newline at end of file
diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh
new file mode 100755
index 00000000..e0a34f02
--- /dev/null
+++ b/tests/aiger/run-test.sh
@@ -0,0 +1,24 @@
+#!/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
+
+echo "===== AAG ======"
+${MAKE:-make} -f ../tools/autotest.mk $seed *.aag EXTRA_FLAGS="-f aiger"
+
+echo "===== AIG ======"
+exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.aig EXTRA_FLAGS="-f aiger"
diff --git a/tests/aiger/toggle-re.aag b/tests/aiger/toggle-re.aag
new file mode 100644
index 00000000..b662bb38
--- /dev/null
+++ b/tests/aiger/toggle-re.aag
@@ -0,0 +1,14 @@
+aag 7 2 1 2 4
+2
+4
+6 8
+6
+7
+8 4 10
+10 13 15
+12 2 6
+14 3 7
+i0 enable
+i1 reset
+o0 Q
+o1 !Q
diff --git a/tests/aiger/toggle-re.aig b/tests/aiger/toggle-re.aig
new file mode 100644
index 00000000..9d6730f2
--- /dev/null
+++ b/tests/aiger/toggle-re.aig
@@ -0,0 +1,8 @@
+aig 7 2 1 2 4
+14
+6
+7
+i0 enable
+i1 reset
+o0 Q
+o1 !Q
diff --git a/tests/aiger/toggle.aag b/tests/aiger/toggle.aag
new file mode 100644
index 00000000..09651012
--- /dev/null
+++ b/tests/aiger/toggle.aag
@@ -0,0 +1,4 @@
+aag 1 0 1 2 0
+2 3
+2
+3
diff --git a/tests/aiger/toggle.aig b/tests/aiger/toggle.aig
new file mode 100644
index 00000000..b69e21aa
--- /dev/null
+++ b/tests/aiger/toggle.aig
@@ -0,0 +1,4 @@
+aig 1 0 1 2 0
+3
+2
+3
diff --git a/tests/aiger/true.aag b/tests/aiger/true.aag
new file mode 100644
index 00000000..36689364
--- /dev/null
+++ b/tests/aiger/true.aag
@@ -0,0 +1,2 @@
+aag 0 0 0 1 0
+1
diff --git a/tests/aiger/true.aig b/tests/aiger/true.aig
new file mode 100644
index 00000000..10086f38
--- /dev/null
+++ b/tests/aiger/true.aig
@@ -0,0 +1,2 @@
+aig 0 0 0 1 0
+1
diff --git a/tests/asicworld/code_hdl_models_misc1.v b/tests/asicworld/code_hdl_models_misc1.v
deleted file mode 100644
index e3d9d5d6..00000000
--- a/tests/asicworld/code_hdl_models_misc1.v
+++ /dev/null
@@ -1,22 +0,0 @@
-module misc1 (a,b,c,d,y);
-input a, b,c,d;
-output y;
-
-wire net1,net2,net3;
-
-supply1 vdd;
-supply0 vss;
-
-// y = !((a+b+c).d)
-
-pmos p1 (vdd,net1,a);
-pmos p2 (net1,net2,b);
-pmos p3 (net2,y,c);
-pmos p4 (vdd,y,d);
-
-nmos n1 (vss,net3,a);
-nmos n2 (vss,net3,b);
-nmos n3 (vss,net3,c);
-nmos n4 (net3,y,d);
-
-endmodule
diff --git a/tests/asicworld/code_hdl_models_mux21_switch.v b/tests/asicworld/code_hdl_models_mux21_switch.v
deleted file mode 100644
index 519c07fc..00000000
--- a/tests/asicworld/code_hdl_models_mux21_switch.v
+++ /dev/null
@@ -1,22 +0,0 @@
-//-----------------------------------------------------
-// Design Name : mux21_switch
-// File Name : mux21_switch.v
-// Function : 2:1 Mux using Switch Primitives
-// Coder : Deepak Kumar Tala
-//-----------------------------------------------------
-module mux21_switch (out, ctrl, in1, in2);
-
- output out;
- input ctrl, in1, in2;
- wire w;
-
- supply1 power;
- supply0 ground;
-
- pmos N1 (w, power, ctrl);
- nmos N2 (w, ground, ctrl);
-
- cmos C1 (out, in1, w, ctrl);
- cmos C2 (out, in2, ctrl, w);
-
-endmodule
diff --git a/tests/asicworld/code_hdl_models_nand_switch.v b/tests/asicworld/code_hdl_models_nand_switch.v
deleted file mode 100644
index 1ccdd3a7..00000000
--- a/tests/asicworld/code_hdl_models_nand_switch.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module nand_switch(a,b,out);
-input a,b;
-output out;
-
-supply0 vss;
-supply1 vdd;
-wire net1;
-
-pmos p1 (vdd,out,a);
-pmos p2 (vdd,out,b);
-nmos n1 (vss,net1,a);
-nmos n2 (net1,out,b);
-
-endmodule \ No newline at end of file
diff --git a/tests/asicworld/code_hdl_models_t_gate_switch.v b/tests/asicworld/code_hdl_models_t_gate_switch.v
deleted file mode 100644
index 5a7e0eaf..00000000
--- a/tests/asicworld/code_hdl_models_t_gate_switch.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module t_gate_switch (L,R,nC,C);
- inout L;
- inout R;
- input nC;
- input C;
-
- //Syntax: keyword unique_name (drain. source, gate);
- pmos p1 (L,R,nC);
- nmos p2 (L,R,C);
-
-endmodule
diff --git a/tests/asicworld/run-test.sh b/tests/asicworld/run-test.sh
index d5708c45..c22ab692 100755
--- a/tests/asicworld/run-test.sh
+++ b/tests/asicworld/run-test.sh
@@ -11,4 +11,4 @@ do
done
shift "$((OPTIND-1))"
-exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS="-e" *.v
+exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS+="-e" *.v
diff --git a/tests/asicworld/xfirrtl b/tests/asicworld/xfirrtl
new file mode 100644
index 00000000..08bf4ccd
--- /dev/null
+++ b/tests/asicworld/xfirrtl
@@ -0,0 +1,23 @@
+# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures.
+code_hdl_models_arbiter.v error: reg rst; cannot be driven by primitives or continuous assignment.
+code_hdl_models_clk_div_45.v yosys issue: 2nd PMUXTREE pass yields: ERROR: Negative edge clock on FF clk_div_45.$procdff$49.
+code_hdl_models_d_ff_gates.v combinational loop
+code_hdl_models_d_latch_gates.v combinational loop
+code_hdl_models_dff_async_reset.v $adff
+code_hdl_models_tff_async_reset.v $adff
+code_hdl_models_uart.v $adff
+code_tidbits_asyn_reset.v $adff
+code_tidbits_reg_seq_example.v $adff
+code_verilog_tutorial_always_example.v empty module
+code_verilog_tutorial_escape_id.v make_id issues (name begins with a digit)
+code_verilog_tutorial_explicit.v firrtl backend bug (empty module)
+code_verilog_tutorial_first_counter.v error: reg rst; cannot be driven by primitives or continuous assignment.
+code_verilog_tutorial_fsm_full.v error: reg reset; cannot be driven by primitives or continuous assignment.
+code_verilog_tutorial_if_else.v empty module (everything is under 'always @ (posedge clk)')
+[code_verilog_tutorial_n_out_primitive.v empty module
+code_verilog_tutorial_parallel_if.v empty module (everything is under 'always @ (posedge clk)')
+code_verilog_tutorial_simple_function.v empty module (no hardware)
+code_verilog_tutorial_simple_if.v empty module (everything is under 'always @ (posedge clk)')
+code_verilog_tutorial_task_global.v empty module (everything is under 'always @ (posedge clk)')
+code_verilog_tutorial_v2k_reg.v empty module
+code_verilog_tutorial_which_clock.v $adff
diff --git a/tests/errors/syntax_err01.v b/tests/errors/syntax_err01.v
new file mode 100644
index 00000000..68e9b1d5
--- /dev/null
+++ b/tests/errors/syntax_err01.v
@@ -0,0 +1,4 @@
+module a;
+integer [31:0]w;
+endmodule
+
diff --git a/tests/errors/syntax_err02.v b/tests/errors/syntax_err02.v
new file mode 100644
index 00000000..c72e976a
--- /dev/null
+++ b/tests/errors/syntax_err02.v
@@ -0,0 +1,7 @@
+module a;
+task to (
+ input integer [3:0]x
+);
+endtask
+endmodule
+
diff --git a/tests/errors/syntax_err03.v b/tests/errors/syntax_err03.v
new file mode 100644
index 00000000..6eec44ad
--- /dev/null
+++ b/tests/errors/syntax_err03.v
@@ -0,0 +1,7 @@
+module a;
+task to (
+ input [3]x
+);
+endtask
+endmodule
+
diff --git a/tests/errors/syntax_err04.v b/tests/errors/syntax_err04.v
new file mode 100644
index 00000000..d488e5db
--- /dev/null
+++ b/tests/errors/syntax_err04.v
@@ -0,0 +1,4 @@
+module a;
+wire [3]x;
+endmodule
+
diff --git a/tests/errors/syntax_err05.v b/tests/errors/syntax_err05.v
new file mode 100644
index 00000000..8a1f1153
--- /dev/null
+++ b/tests/errors/syntax_err05.v
@@ -0,0 +1,4 @@
+module a;
+input x[2:0];
+endmodule
+
diff --git a/tests/errors/syntax_err06.v b/tests/errors/syntax_err06.v
new file mode 100644
index 00000000..b35a1dea
--- /dev/null
+++ b/tests/errors/syntax_err06.v
@@ -0,0 +1,6 @@
+module a;
+initial
+begin : label1
+end: label2
+endmodule
+
diff --git a/tests/errors/syntax_err07.v b/tests/errors/syntax_err07.v
new file mode 100644
index 00000000..62bcc6b3
--- /dev/null
+++ b/tests/errors/syntax_err07.v
@@ -0,0 +1,6 @@
+module a;
+wire [5:0]x;
+wire [3:0]y;
+assign y = (4)55;
+endmodule
+
diff --git a/tests/errors/syntax_err08.v b/tests/errors/syntax_err08.v
new file mode 100644
index 00000000..d41bfd6c
--- /dev/null
+++ b/tests/errors/syntax_err08.v
@@ -0,0 +1,6 @@
+module a;
+wire [5:0]x;
+wire [3:0]y;
+assign y = x 55;
+endmodule
+
diff --git a/tests/errors/syntax_err09.v b/tests/errors/syntax_err09.v
new file mode 100644
index 00000000..1e472eb9
--- /dev/null
+++ b/tests/errors/syntax_err09.v
@@ -0,0 +1,3 @@
+module a(input wire x = 1'b0);
+endmodule
+
diff --git a/tests/errors/syntax_err10.v b/tests/errors/syntax_err10.v
new file mode 100644
index 00000000..d3280405
--- /dev/null
+++ b/tests/errors/syntax_err10.v
@@ -0,0 +1,3 @@
+module a;
+parameter integer [2:0]x=0;
+endmodule
diff --git a/tests/errors/syntax_err11.v b/tests/errors/syntax_err11.v
new file mode 100644
index 00000000..f3cde9df
--- /dev/null
+++ b/tests/errors/syntax_err11.v
@@ -0,0 +1,3 @@
+module a;
+parameter integer real x=0;
+endmodule
diff --git a/tests/errors/syntax_err12.v b/tests/errors/syntax_err12.v
new file mode 100644
index 00000000..f9b5d5b0
--- /dev/null
+++ b/tests/errors/syntax_err12.v
@@ -0,0 +1,7 @@
+interface iface;
+endinterface
+
+module a (
+ iface x = 1'b0
+);
+endmodule
diff --git a/tests/errors/syntax_err13.v b/tests/errors/syntax_err13.v
new file mode 100644
index 00000000..b5c942fc
--- /dev/null
+++ b/tests/errors/syntax_err13.v
@@ -0,0 +1,4 @@
+module a #(p = 0)
+();
+endmodule
+
diff --git a/tests/liberty/.gitignore b/tests/liberty/.gitignore
new file mode 100644
index 00000000..e6ec49c4
--- /dev/null
+++ b/tests/liberty/.gitignore
@@ -0,0 +1,2 @@
+*.log
+test.ys
diff --git a/tests/liberty/busdef.lib b/tests/liberty/busdef.lib
new file mode 100644
index 00000000..b5e3d50b
--- /dev/null
+++ b/tests/liberty/busdef.lib
@@ -0,0 +1,81 @@
+/********************************************/
+/* */
+/* Supergate cell library for Bench marking */
+/* */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley */
+/* */
+/* Process: none */
+/* */
+/* Date : 02-11-2018 */
+/* Version: 1.0 */
+/* */
+/********************************************/
+
+library(supergate) {
+ technology (cmos);
+ revision : 1.0;
+
+ time_unit : "1ps";
+ pulling_resistance_unit : "1kohm";
+ voltage_unit : "1V";
+ current_unit : "1uA";
+
+ capacitive_load_unit(1,ff);
+
+ default_inout_pin_cap : 7.0;
+ default_input_pin_cap : 7.0;
+ default_output_pin_cap : 0.0;
+ default_fanout_load : 1.0;
+
+ default_wire_load_capacitance : 0.1;
+ default_wire_load_resistance : 1.0e-3;
+ default_wire_load_area : 0.0;
+
+ nom_process : 1.0;
+ nom_temperature : 25.0;
+ nom_voltage : 1.2;
+
+ delay_model : generic_cmos;
+
+ type( IO_bus_3_to_0 ) {
+ base_type : array ;
+ data_type : bit ;
+ bit_width : 4;
+ bit_from : 3 ;
+ bit_to : 0 ;
+ downto : true ;
+ }
+
+ cell (SRAM) {
+ area : 1 ;
+ memory() {
+ type : ram;
+ address_width : 4;
+ word_width : 4;
+ }
+ pin(CE1) {
+ direction : input;
+ capacitance : 0.021;
+ max_transition : 1.024;
+ switch_pin : true;
+ }
+ bus(I1) {
+ bus_type : IO_bus_3_to_0 ;
+ direction : input;
+ pin (I1[3:0]) {
+ timing() {
+ related_pin : "CE1" ;
+ timing_type : setup_rising ;
+ rise_constraint (scalar) {
+ values("0.0507786");
+ }
+ fall_constraint (scalar) {
+ values("0.0507786");
+ }
+ }
+ }
+ }
+ }
+
+} /* end */
diff --git a/tests/liberty/normal.lib b/tests/liberty/normal.lib
new file mode 100644
index 00000000..4621194d
--- /dev/null
+++ b/tests/liberty/normal.lib
@@ -0,0 +1,359 @@
+/********************************************/
+/* */
+/* Supergate cell library for Bench marking */
+/* */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley */
+/* */
+/* Process: none */
+/* */
+/* Date : 02-11-2018 */
+/* Version: 1.0 */
+/* */
+/********************************************/
+
+library(supergate) {
+ technology (cmos);
+ revision : 1.0;
+
+ time_unit : "1ps";
+ pulling_resistance_unit : "1kohm";
+ voltage_unit : "1V";
+ current_unit : "1uA";
+
+ capacitive_load_unit(1,ff);
+
+ default_inout_pin_cap : 7.0;
+ default_input_pin_cap : 7.0;
+ default_output_pin_cap : 0.0;
+ default_fanout_load : 1.0;
+
+ default_wire_load_capacitance : 0.1;
+ default_wire_load_resistance : 1.0e-3;
+ default_wire_load_area : 0.0;
+
+ nom_process : 1.0;
+ nom_temperature : 25.0;
+ nom_voltage : 1.2;
+
+ delay_model : generic_cmos;
+
+ /* Inverter */
+ cell (inv) {
+ area : 1;
+ pin(A) {
+ direction : input;
+ }
+
+ pin(Y) {
+ direction : output;
+ function : "A'";
+ }
+ }
+
+ /* tri-state inverter */
+ cell (tri_inv) {
+ area : 4;
+ pin(A) {
+ direction : input;
+ }
+ pin(S) {
+ direction : input;
+ }
+ pin(Z) {
+ direction : output;
+ function : "A'";
+ three_State : "S'";
+ }
+ }
+
+ cell (buffer) {
+ area : 5;
+ pin(A) {
+ direction : input;
+ }
+ pin(Y) {
+ direction : output;
+ function : "A";
+ }
+ }
+
+ /* 2-input NAND gate */
+ cell (nand2) {
+ area : 3;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "(A * B)'";
+ }
+ }
+
+ /* 2-input NOR gate */
+ cell (nor2) {
+ area : 3;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "(A + B)'";
+ }
+ }
+
+ /* 2-input XOR */
+ cell (xor2) {
+ area : 6;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "(A *B') + (A' * B)";
+ }
+ }
+
+ /* 2-input inverting MUX */
+ cell (imux2) {
+ area : 5;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(S) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "( (A * S) + (B * S') )'";
+ }
+ }
+
+ /* D-type flip-flop with asynchronous reset and preset */
+ cell (dff) {
+ area : 6;
+ ff("IQ", "IQN") {
+ next_state : "D";
+ clocked_on : "CLK";
+ clear : "RESET";
+ preset : "PRESET";
+ clear_preset_var1 : L;
+ clear_preset_var2 : L;
+ }
+ pin(D) {
+ direction : input;
+ }
+ pin(CLK) {
+ direction : input;
+ }
+ pin(RESET) {
+ direction : input;
+ }
+ pin(PRESET) {
+ direction : input;
+ }
+ pin(Q) {
+ direction: output;
+ function : "IQ";
+ timing() {
+ timing_type : rising_edge;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "CLK";
+ }
+ timing () {
+ timing_type : clear;
+ timing_sense : positive_unate;
+ intrinsic_fall : 75;
+ related_pin : "RESET";
+ }
+ timing () {
+ timing_type : preset;
+ timing_sense : negative_unate;
+ intrinsic_rise : 75;
+ related_pin : "PRESET";
+ }
+ }
+ pin(QN) {
+ direction: output;
+ function : "IQN";
+ timing() {
+ timing_type : rising_edge;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "CLK";
+ }
+ timing () {
+ timing_type : preset;
+ timing_sense : negative_unate;
+ intrinsic_rise : 75;
+ related_pin : "RESET";
+ }
+ timing () {
+ timing_type : clear;
+ timing_sense : positive_unate;
+ intrinsic_fall : 75;
+ related_pin : "PRESET";
+ }
+ }
+ }
+
+ /* Latch */
+ cell(latch) {
+ area : 5;
+ latch ("IQ","IQN") {
+ enable : "G";
+ data_in : "D";
+ }
+
+ pin(D) {
+ direction : input;
+ }
+ pin(G) {
+ direction : input;
+ }
+
+ pin(Q) {
+ direction : output;
+ function : "IQ";
+ internal_node : "Q";
+
+ timing() {
+ timing_type : rising_edge;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "G";
+ }
+
+ timing() {
+ timing_sense : positive_unate;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "D";
+ }
+ }
+
+ pin(QN) {
+ direction : output;
+ function : "IQN";
+ internal_node : "QN";
+
+ timing() {
+ timing_type : rising_edge;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "G";
+ }
+
+ timing() {
+ timing_sense : negative_unate;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "D";
+ }
+ }
+ }
+
+ /* 3 input AND-OR-INVERT gate */
+ cell (aoi211) {
+ area : 3;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(C) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "((A * B) + C)'";
+ }
+ }
+
+
+ /* 3 input OR-AND-INVERT gate */
+ cell (oai211) {
+ area : 3;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(C) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "((A + B) * C)'";
+ }
+ }
+
+ /* half adder */
+ cell (halfadder) {
+ area : 5;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(C) {
+ direction : output;
+ function : "(A * B)";
+ }
+ pin(Y) {
+ direction: output;
+ function : "(A *B') + (A' * B)";
+ }
+ }
+
+ /* full adder */
+ cell (fulladder) {
+ area : 8;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(CI) {
+ direction : input;
+ }
+ pin(CO) {
+ direction : output;
+ function : "(((A * B)+(B * CI))+(CI * A))";
+ }
+ pin(Y) {
+ direction: output;
+ function : "((A^B)^CI)";
+ }
+ }
+
+} /* end */
diff --git a/tests/liberty/processdefs.lib b/tests/liberty/processdefs.lib
new file mode 100644
index 00000000..37a6bbaf
--- /dev/null
+++ b/tests/liberty/processdefs.lib
@@ -0,0 +1,48 @@
+/********************************************/
+/* */
+/* Supergate cell library for Bench marking */
+/* */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley */
+/* */
+/* Process: none */
+/* */
+/* Date : 25-03-2019 */
+/* Version: 1.0 */
+/* */
+/********************************************/
+
+library(processdefs) {
+ technology (cmos);
+ revision : 1.0;
+
+ time_unit : "1ps";
+ pulling_resistance_unit : "1kohm";
+ voltage_unit : "1V";
+ current_unit : "1uA";
+
+ capacitive_load_unit(1,ff);
+
+ default_inout_pin_cap : 7.0;
+ default_input_pin_cap : 7.0;
+ default_output_pin_cap : 0.0;
+ default_fanout_load : 1.0;
+
+ default_wire_load_capacitance : 0.1;
+ default_wire_load_resistance : 1.0e-3;
+ default_wire_load_area : 0.0;
+
+ nom_process : 1.0;
+ nom_temperature : 25.0;
+ nom_voltage : 1.2;
+
+ delay_model : generic_cmos;
+
+ define_cell_area(bond_pads,pad_slots)
+ input_voltage(cmos) {
+ vil : 0.3 * VDD ;
+ vih : 0.7 * VDD ;
+ vimin : -0.5 ;
+ vimax : VDD + 0.5 ;
+ }
+}
diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh
new file mode 100755
index 00000000..7e2ed237
--- /dev/null
+++ b/tests/liberty/run-test.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -e
+
+for x in *.lib; do
+ echo "Running $x.."
+ echo "read_verilog small.v" > test.ys
+ echo "synth -top small" >> test.ys
+ echo "dfflibmap -liberty ${x}" >> test.ys
+ ../../yosys -ql ${x%.lib}.log -s test.ys
+done
diff --git a/tests/liberty/semicolextra.lib b/tests/liberty/semicolextra.lib
new file mode 100644
index 00000000..6a7fa77c
--- /dev/null
+++ b/tests/liberty/semicolextra.lib
@@ -0,0 +1,48 @@
+/*
+
+ Test case for https://www.reddit.com/r/yosys/comments/b5texg/yosys_fails_to_parse_apparentlycorrect_liberty/
+
+ fall_constraint (SETUP_HOLD) formatting.
+
+*/
+
+library(supergate) {
+ technology (cmos);
+ revision : 1.0;
+
+ cell (DFF) {
+ cell_footprint : dff;
+ area : 50;
+ pin(D) {
+ direction : input;
+ capacitance : 0.002;
+ timing() {
+ related_pin : "CK";
+ timing_type : setup_rising;
+
+ fall_constraint (SETUP_HOLD) { values ("0.4000, 0.3000, 0.2000, 0.1000, 0.0000", \
+ "0.4000, 0.3000, 0.2000, 0.1000, 0.000", \
+ "0.5000, 0.4000, 0.3000, 0.2000, 0.0000", \
+ "0.7000, 0.6000, 0.5000, 0.4000, 0.2000", \
+ "1.0000, 1.0000, 0.9000, 0.8000, 0.6000"); };
+ }
+ }
+
+ pin(CK) {
+ direction : input;
+ clock : true;
+ capacitance : 0.00290;
+ }
+
+ ff(IQ,IQN) {
+ clocked_on : "CK";
+ next_state : "D";
+ }
+ pin(Q) {
+ direction : output;
+ capacitance : 0.003;
+ max_capacitance : 0.3;
+ }
+ cell_leakage_power : 0.3;
+ }
+}
diff --git a/tests/liberty/semicolmissing.lib b/tests/liberty/semicolmissing.lib
new file mode 100644
index 00000000..f7c20750
--- /dev/null
+++ b/tests/liberty/semicolmissing.lib
@@ -0,0 +1,72 @@
+/********************************************/
+/* */
+/* Supergate cell library for Bench marking */
+/* */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley */
+/* */
+/* Process: none */
+/* */
+/* Date : 24-03-2019 */
+/* Version: 1.0 */
+/* Version: 1.1 - Removed semicolons in */
+/* full adder */
+/* */
+/********************************************/
+
+/*
+ semi colon is missing in full-adder specification
+ some TSMC liberty files are formatted this way..
+*/
+
+library(supergate) {
+ technology (cmos);
+ revision : 1.0;
+
+ time_unit : "1ps";
+ pulling_resistance_unit : "1kohm";
+ voltage_unit : "1V";
+ current_unit : "1uA";
+
+ capacitive_load_unit(1,ff);
+
+ default_inout_pin_cap : 7.0;
+ default_input_pin_cap : 7.0;
+ default_output_pin_cap : 0.0;
+ default_fanout_load : 1.0;
+
+ default_wire_load_capacitance : 0.1;
+ default_wire_load_resistance : 1.0e-3;
+ default_wire_load_area : 0.0;
+
+ nom_process : 1.0;
+ nom_temperature : 25.0;
+ nom_voltage : 1.2;
+
+ delay_model : generic_cmos;
+
+ /* full adder */
+ cell (fulladder) {
+ area : 8
+ pin(A) {
+ direction : input
+ }
+ pin(B) {
+ direction : input
+ }
+ pin(CI) {
+ direction : input
+ }
+ pin(CO) {
+ direction : output
+ function : "(((A * B)+(B * CI))+(CI * A))"
+ }
+ pin(Y) {
+ direction: output
+ function : "((A^B)^CI)"
+ }
+ }
+
+} /* end */
+
+
diff --git a/tests/liberty/small.v b/tests/liberty/small.v
new file mode 100644
index 00000000..bd94be4f
--- /dev/null
+++ b/tests/liberty/small.v
@@ -0,0 +1,16 @@
+/** small, meaningless design to test loading of liberty files */
+
+module small
+(
+ input clk,
+ output reg[7:0] count
+);
+
+initial count = 0;
+
+always @ (posedge clk)
+begin
+ count <= count + 1'b1;
+end
+
+endmodule
diff --git a/tests/lut/.gitignore b/tests/lut/.gitignore
new file mode 100644
index 00000000..397b4a76
--- /dev/null
+++ b/tests/lut/.gitignore
@@ -0,0 +1 @@
+*.log
diff --git a/tests/lut/check_map.ys b/tests/lut/check_map.ys
new file mode 100644
index 00000000..46854e82
--- /dev/null
+++ b/tests/lut/check_map.ys
@@ -0,0 +1,6 @@
+simplemap
+equiv_opt -assert techmap -D LUT_WIDTH=4 -map +/cmp2lut.v
+design -load postopt
+equiv_opt -assert techmap -D LUT_WIDTH=4 -map +/gate2lut.v
+design -load postopt
+select -assert-count 0 t:* t:$lut %d
diff --git a/tests/lut/map_and.v b/tests/lut/map_and.v
new file mode 100644
index 00000000..68ae33fd
--- /dev/null
+++ b/tests/lut/map_and.v
@@ -0,0 +1,5 @@
+module top(...);
+ input a, b;
+ output y;
+ assign y = a&b;
+endmodule
diff --git a/tests/lut/map_cmp.v b/tests/lut/map_cmp.v
new file mode 100644
index 00000000..5e413f89
--- /dev/null
+++ b/tests/lut/map_cmp.v
@@ -0,0 +1,29 @@
+module top(...);
+ input [3: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 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 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 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;
+endmodule
diff --git a/tests/lut/map_mux.v b/tests/lut/map_mux.v
new file mode 100644
index 00000000..ccecf302
--- /dev/null
+++ b/tests/lut/map_mux.v
@@ -0,0 +1,5 @@
+module top(...);
+ input a, b, s;
+ output y;
+ assign y = s?a:b;
+endmodule
diff --git a/tests/lut/map_not.v b/tests/lut/map_not.v
new file mode 100644
index 00000000..38599741
--- /dev/null
+++ b/tests/lut/map_not.v
@@ -0,0 +1,5 @@
+module top(...);
+ input a;
+ output y;
+ assign y = ~a;
+endmodule
diff --git a/tests/lut/map_or.v b/tests/lut/map_or.v
new file mode 100644
index 00000000..8b8c5518
--- /dev/null
+++ b/tests/lut/map_or.v
@@ -0,0 +1,5 @@
+module top(...);
+ input a, b;
+ output y;
+ assign y = a|b;
+endmodule
diff --git a/tests/lut/map_xor.v b/tests/lut/map_xor.v
new file mode 100644
index 00000000..708a0578
--- /dev/null
+++ b/tests/lut/map_xor.v
@@ -0,0 +1,5 @@
+module top(...);
+ input a, b;
+ output y;
+ assign y = a^b;
+endmodule
diff --git a/tests/lut/run-test.sh b/tests/lut/run-test.sh
new file mode 100755
index 00000000..207417fa
--- /dev/null
+++ b/tests/lut/run-test.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -e
+for x in *.v; do
+ echo "Running $x.."
+ ../../yosys -q -s check_map.ys -l ${x%.v}.log $x
+done
diff --git a/tests/opt/.gitignore b/tests/opt/.gitignore
new file mode 100644
index 00000000..397b4a76
--- /dev/null
+++ b/tests/opt/.gitignore
@@ -0,0 +1 @@
+*.log
diff --git a/tests/opt/opt_expr_cmp.v b/tests/opt/opt_expr_cmp.v
new file mode 100644
index 00000000..5aff4b80
--- /dev/null
+++ b/tests/opt/opt_expr_cmp.v
@@ -0,0 +1,40 @@
+module top(...);
+ input [3:0] a;
+
+ output o1_1 = 4'b0000 > a;
+ output o1_2 = 4'b0000 <= a;
+ output o1_3 = 4'b1111 < a;
+ output o1_4 = 4'b1111 >= a;
+ output o1_5 = a < 4'b0000;
+ output o1_6 = a >= 4'b0000;
+ output o1_7 = a > 4'b1111;
+ output o1_8 = a <= 4'b1111;
+
+ output o2_1 = 4'sb0000 > $signed(a);
+ output o2_2 = 4'sb0000 <= $signed(a);
+ output o2_3 = $signed(a) < 4'sb0000;
+ output o2_4 = $signed(a) >= 4'sb0000;
+
+ output o3_1 = 4'b0100 > a;
+ output o3_2 = 4'b0100 <= a;
+ output o3_3 = a < 4'b0100;
+ output o3_4 = a >= 4'b0100;
+
+ output o4_1 = 5'b10000 > a;
+ output o4_2 = 5'b10000 >= a;
+ output o4_3 = 5'b10000 < a;
+ output o4_4 = 5'b10000 <= a;
+ output o4_5 = a < 5'b10000;
+ output o4_6 = a <= 5'b10000;
+ output o4_7 = a > 5'b10000;
+ output o4_8 = a >= 5'b10000;
+
+ output o5_1 = 5'b10100 > a;
+ output o5_2 = 5'b10100 >= a;
+ output o5_3 = 5'b10100 < a;
+ output o5_4 = 5'b10100 <= a;
+ output o5_5 = a < 5'b10100;
+ output o5_6 = a <= 5'b10100;
+ output o5_7 = a > 5'b10100;
+ output o5_8 = a >= 5'b10100;
+endmodule
diff --git a/tests/opt/opt_expr_cmp.ys b/tests/opt/opt_expr_cmp.ys
new file mode 100644
index 00000000..214ce8b1
--- /dev/null
+++ b/tests/opt/opt_expr_cmp.ys
@@ -0,0 +1,4 @@
+read_verilog opt_expr_cmp.v
+equiv_opt -assert opt_expr -fine
+design -load postopt
+select -assert-count 0 t:$gt t:$ge t:$lt t:$le
diff --git a/tests/opt/opt_ff.v b/tests/opt/opt_ff.v
new file mode 100644
index 00000000..a01b64b6
--- /dev/null
+++ b/tests/opt/opt_ff.v
@@ -0,0 +1,21 @@
+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
new file mode 100644
index 00000000..704c7acf
--- /dev/null
+++ b/tests/opt/opt_ff.ys
@@ -0,0 +1,3 @@
+read_verilog opt_ff.v
+synth_ice40
+ice40_unlut
diff --git a/tests/opt/opt_lut.v b/tests/opt/opt_lut.v
new file mode 100644
index 00000000..b13db367
--- /dev/null
+++ b/tests/opt/opt_lut.v
@@ -0,0 +1,18 @@
+module top(
+ input [8:0] a,
+ input [8:0] b,
+ output [8:0] o1,
+ output [2:0] o2,
+ input [2:0] c,
+ input [2:0] d,
+ output [2:0] o3,
+ output [2:0] o4,
+ input s
+);
+
+assign o1 = (s ? 0 : a + b);
+assign o2 = (s ? a : a - b);
+assign o3 = (s ? 4'b1111 : d + c);
+assign o4 = (s ? d : c - d);
+
+endmodule
diff --git a/tests/opt/opt_lut.ys b/tests/opt/opt_lut.ys
new file mode 100644
index 00000000..59b12c35
--- /dev/null
+++ b/tests/opt/opt_lut.ys
@@ -0,0 +1,4 @@
+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
diff --git a/tests/opt/opt_lut_elim.il b/tests/opt/opt_lut_elim.il
new file mode 100644
index 00000000..75675d98
--- /dev/null
+++ b/tests/opt/opt_lut_elim.il
@@ -0,0 +1,19 @@
+module \test
+ wire input 1 \i
+
+ wire output 2 \o1
+ cell $lut $1
+ parameter \LUT 16'0110100110010110
+ parameter \WIDTH 4
+ connect \A { \i 3'000 }
+ connect \Y \o1
+ end
+
+ wire output 2 \o2
+ cell $lut $2
+ parameter \LUT 16'0110100010010110
+ parameter \WIDTH 4
+ connect \A { \i 3'000 }
+ connect \Y \o2
+ end
+end
diff --git a/tests/opt/opt_lut_elim.ys b/tests/opt/opt_lut_elim.ys
new file mode 100644
index 00000000..8e5e23ae
--- /dev/null
+++ b/tests/opt/opt_lut_elim.ys
@@ -0,0 +1,3 @@
+read_ilang opt_lut_elim.il
+opt_lut
+select -assert-count 0 t:$lut
diff --git a/tests/opt/opt_lut_port.il b/tests/opt/opt_lut_port.il
new file mode 100644
index 00000000..7eb71890
--- /dev/null
+++ b/tests/opt/opt_lut_port.il
@@ -0,0 +1,18 @@
+module $1
+ wire width 4 input 2 \_0_
+ wire output 4 \_1_
+ wire input 3 \_2_
+ wire output 1 \o
+ cell $lut \_3_
+ parameter \LUT 16'0011000000000011
+ parameter \WIDTH 4
+ connect \A { \_0_ [3] \o 2'00 }
+ connect \Y \_1_
+ end
+ cell $lut \_4_
+ parameter \LUT 4'0001
+ parameter \WIDTH 4
+ connect \A { 3'000 \_2_ }
+ connect \Y \o
+ end
+end
diff --git a/tests/opt/opt_lut_port.ys b/tests/opt/opt_lut_port.ys
new file mode 100644
index 00000000..3cb4ecb2
--- /dev/null
+++ b/tests/opt/opt_lut_port.ys
@@ -0,0 +1,3 @@
+read_ilang opt_lut_port.il
+opt_lut
+select -assert-count 2 t:$lut
diff --git a/tests/opt/run-test.sh b/tests/opt/run-test.sh
new file mode 100755
index 00000000..44ce7e67
--- /dev/null
+++ b/tests/opt/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/dff_init.v b/tests/simple/dff_init.v
new file mode 100644
index 00000000..be947042
--- /dev/null
+++ b/tests/simple/dff_init.v
@@ -0,0 +1,42 @@
+module dff0_test(n1, n1_inv, clk);
+ input clk;
+ output n1;
+ reg n1 = 32'd0;
+ output n1_inv;
+ always @(posedge clk)
+ n1 <= n1_inv;
+ assign n1_inv = ~n1;
+endmodule
+
+module dff1_test(n1, n1_inv, clk);
+ input clk;
+ (* init = 32'd1 *)
+ output n1;
+ reg n1 = 32'd1;
+ output n1_inv;
+ always @(posedge clk)
+ n1 <= n1_inv;
+ assign n1_inv = ~n1;
+endmodule
+
+module dff0a_test(n1, n1_inv, clk);
+ input clk;
+ (* init = 32'd0 *) // Must be consistent with reg initialiser below
+ output n1;
+ reg n1 = 32'd0;
+ output n1_inv;
+ always @(posedge clk)
+ n1 <= n1_inv;
+ assign n1_inv = ~n1;
+endmodule
+
+module dff1a_test(n1, n1_inv, clk);
+ input clk;
+ (* init = 32'd1 *) // Must be consistent with reg initialiser below
+ output n1;
+ reg n1 = 32'd1;
+ output n1_inv;
+ always @(posedge clk)
+ n1 <= n1_inv;
+ assign n1_inv = ~n1;
+endmodule
diff --git a/tests/simple/generate.v b/tests/simple/generate.v
index 24eb4462..3c55682c 100644
--- a/tests/simple/generate.v
+++ b/tests/simple/generate.v
@@ -90,5 +90,61 @@ generate
endcase
end
endgenerate
+endmodule
+
+// ------------------------------------------
+
+module gen_test4(a, b);
+
+input [3:0] a;
+output [3:0] b;
+
+genvar i;
+generate
+ for (i=0; i < 3; i=i+1) begin : foo
+ localparam PREV = i - 1;
+ wire temp;
+ if (i == 0)
+ assign temp = a[0];
+ else
+ assign temp = foo[PREV].temp & a[i];
+ assign b[i] = temp;
+ end
+endgenerate
+endmodule
+
+// ------------------------------------------
+
+module gen_test5(input_bits, out);
+
+parameter WIDTH = 256;
+parameter CHUNK = 4;
+input [WIDTH-1:0] input_bits;
+output out;
+
+genvar step, i, j;
+generate
+ for (step = 1; step <= WIDTH; step = step * CHUNK) begin : steps
+ localparam PREV = step / CHUNK;
+ localparam DIM = WIDTH / step;
+ for (i = 0; i < DIM; i = i + 1) begin : outer
+ localparam LAST_START = i * CHUNK;
+ for (j = 0; j < CHUNK; j = j + 1) begin : inner
+ wire temp;
+ if (step == 1)
+ assign temp = input_bits[i];
+ else if (j == 0)
+ assign temp = steps[PREV].outer[LAST_START].val;
+ else
+ assign temp
+ = steps[step].outer[i].inner[j-1].temp
+ & steps[PREV].outer[LAST_START + j].val;
+ end
+ wire val;
+ assign val = steps[step].outer[i].inner[CHUNK - 1].temp;
+ end
+ end
+endgenerate
+assign out = steps[WIDTH].outer[0].val;
endmodule
diff --git a/tests/simple/hierdefparam.v b/tests/simple/hierdefparam.v
index ff92c38b..c9368ca7 100644
--- a/tests/simple/hierdefparam.v
+++ b/tests/simple/hierdefparam.v
@@ -1,3 +1,5 @@
+`default_nettype none
+
module hierdefparam_top(input [7:0] A, output [7:0] Y);
generate begin:foo
hierdefparam_a mod_a(.A(A), .Y(Y));
diff --git a/tests/simple/task_func.v b/tests/simple/task_func.v
index fa50c1d5..f6e902f6 100644
--- a/tests/simple/task_func.v
+++ b/tests/simple/task_func.v
@@ -120,3 +120,22 @@ module task_func_test04(input [7:0] in, output [7:0] out1, out2, out3, out4);
assign out3 = test3(in);
assign out4 = test4(in);
endmodule
+
+// -------------------------------------------------------------------
+
+// https://github.com/YosysHQ/yosys/issues/857
+module task_func_test05(data_in,data_out,clk);
+ output reg data_out;
+ input data_in;
+ input clk;
+
+ task myTask;
+ output out;
+ input in;
+ out = in;
+ endtask
+
+ always @(posedge clk) begin
+ myTask(data_out,data_in);
+ end
+endmodule
diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl
new file mode 100644
index 00000000..50d69351
--- /dev/null
+++ b/tests/simple/xfirrtl
@@ -0,0 +1,26 @@
+# 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
+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
+macros.v drops modules
+mem2reg.v drops modules
+mem_arst.v $adff
+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
+scopes.v original verilog issues ( -x where x isn't declared signed)
+sincos.v $adff
+specify.v no code (empty module generates error
+subbytes.v $adff
+task_func.v drops modules
+values.v combinational loop
+vloghammer.v combinational loop
+wreduce.v original verilog issues ( -x where x isn't declared signed)
diff --git a/tests/sva/basic01.sv b/tests/sva/basic01.sv
index 74ab9343..d5ad497d 100644
--- a/tests/sva/basic01.sv
+++ b/tests/sva/basic01.sv
@@ -6,7 +6,7 @@ module top (input logic clock, ctrl);
write <= ctrl;
ready <= write;
end
-
+
a_rw: assert property ( @(posedge clock) !(read && write) );
`ifdef FAIL
a_wr: assert property ( @(posedge clock) write |-> ready );
diff --git a/tests/sva/extnets.sv b/tests/sva/extnets.sv
new file mode 100644
index 00000000..47312de7
--- /dev/null
+++ b/tests/sva/extnets.sv
@@ -0,0 +1,22 @@
+module top(input i, output o);
+ A A();
+ B B();
+ assign A.i = i;
+ assign o = B.o;
+ always @* assert(o == i);
+endmodule
+
+module A;
+ wire i, y;
+`ifdef FAIL
+ assign B.x = i;
+`else
+ assign B.x = !i;
+`endif
+ assign y = !B.y;
+endmodule
+
+module B;
+ wire x, y, o;
+ assign y = x, o = A.y;
+endmodule
diff --git a/tests/svinterfaces/.gitignore b/tests/svinterfaces/.gitignore
new file mode 100644
index 00000000..a5b7927d
--- /dev/null
+++ b/tests/svinterfaces/.gitignore
@@ -0,0 +1,8 @@
+/a.out
+/dut_result.txt
+/reference_result.txt
+/*.diff
+/*.log_stderr
+/*.log_stdout
+/*_ref_syn.v
+/*_syn.v
diff --git a/tests/svinterfaces/run-test.sh b/tests/svinterfaces/run-test.sh
new file mode 100755
index 00000000..86567d1c
--- /dev/null
+++ b/tests/svinterfaces/run-test.sh
@@ -0,0 +1,6 @@
+#/bin/bash -e
+
+
+
+./runone.sh svinterface1
+./runone.sh svinterface_at_top
diff --git a/tests/svinterfaces/runone.sh b/tests/svinterfaces/runone.sh
new file mode 100755
index 00000000..0adecc79
--- /dev/null
+++ b/tests/svinterfaces/runone.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+
+TESTNAME=$1
+
+STDOUTFILE=${TESTNAME}.log_stdout
+STDERRFILE=${TESTNAME}.log_stderr
+
+echo "" > $STDOUTFILE
+echo "" > $STDERRFILE
+
+echo -n "Test: ${TESTNAME} -> "
+
+$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE >> $STDERRFILE
+$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE >> $STDERRFILE
+
+rm -f a.out reference_result.txt dut_result.txt
+
+set -e
+
+iverilog -g2012 ${TESTNAME}_syn.v
+iverilog -g2012 ${TESTNAME}_ref_syn.v
+
+set +e
+iverilog -g2012 ${TESTNAME}_tb.v ${TESTNAME}_ref_syn.v
+./a.out
+mv output.txt reference_result.txt
+if [ -f ${TESTNAME}_wrapper.v ] ; then
+ iverilog -g2012 ${TESTNAME}_tb_wrapper.v ${TESTNAME}_syn.v
+else
+ iverilog -g2012 ${TESTNAME}_tb.v ${TESTNAME}_syn.v
+fi
+./a.out
+mv output.txt dut_result.txt
+
+diff reference_result.txt dut_result.txt > ${TESTNAME}.diff
+RET=$?
+if [ "$RET" != "0" ] ; then
+ echo "ERROR!"
+ exit -1
+fi
+
+echo "ok"
+exit 0
diff --git a/tests/svinterfaces/svinterface1.sv b/tests/svinterfaces/svinterface1.sv
new file mode 100644
index 00000000..6d60b488
--- /dev/null
+++ b/tests/svinterfaces/svinterface1.sv
@@ -0,0 +1,117 @@
+
+
+module TopModule(
+ input logic clk,
+ input logic rst,
+ output logic [21:0] outOther,
+ input logic [1:0] sig,
+ input logic flip,
+ output logic [1:0] sig_out,
+ output logic [15:0] passThrough);
+
+ MyInterface #(.WIDTH(4)) MyInterfaceInstance();
+
+ SubModule1 u_SubModule1 (
+ .clk(clk),
+ .rst(rst),
+ .u_MyInterface(MyInterfaceInstance),
+ .outOther(outOther),
+ .sig (sig)
+ );
+
+ assign sig_out = MyInterfaceInstance.mysig_out;
+
+
+ assign MyInterfaceInstance.setting = flip;
+
+ assign passThrough = MyInterfaceInstance.passThrough;
+
+endmodule
+
+interface MyInterface #(
+ parameter WIDTH = 3)(
+ );
+
+ logic setting;
+ logic [WIDTH-1:0] other_setting;
+
+ logic [1:0] mysig_out;
+
+ logic [15:0] passThrough;
+
+ modport submodule1 (
+ input setting,
+ output other_setting,
+ output mysig_out,
+ output passThrough
+ );
+
+ modport submodule2 (
+ input setting,
+ output other_setting,
+ input mysig_out,
+ output passThrough
+ );
+
+endinterface
+
+
+module SubModule1(
+ input logic clk,
+ input logic rst,
+ MyInterface.submodule1 u_MyInterface,
+ input logic [1:0] sig,
+ output logic [21:0] outOther
+
+ );
+
+ always_ff @(posedge clk or posedge rst)
+ if(rst)
+ u_MyInterface.mysig_out <= 0;
+ else begin
+ if(u_MyInterface.setting)
+ u_MyInterface.mysig_out <= sig;
+ else
+ u_MyInterface.mysig_out <= ~sig;
+ end
+
+ MyInterface #(.WIDTH(22)) MyInterfaceInstanceInSub();
+
+ SubModule2 u_SubModule2 (
+ .clk(clk),
+ .rst(rst),
+ .u_MyInterfaceInSub2(u_MyInterface),
+ .u_MyInterfaceInSub3(MyInterfaceInstanceInSub)
+ );
+
+ assign outOther = MyInterfaceInstanceInSub.other_setting;
+
+ assign MyInterfaceInstanceInSub.setting = 0;
+ assign MyInterfaceInstanceInSub.mysig_out = sig;
+
+endmodule
+
+module SubModule2(
+
+ input logic clk,
+ input logic rst,
+ MyInterface.submodule2 u_MyInterfaceInSub2,
+ MyInterface.submodule2 u_MyInterfaceInSub3
+
+ );
+
+ always_comb begin
+ if (u_MyInterfaceInSub3.mysig_out == 2'b00)
+ u_MyInterfaceInSub3.other_setting[21:0] = 1000;
+ else if (u_MyInterfaceInSub3.mysig_out == 2'b01)
+ u_MyInterfaceInSub3.other_setting[21:0] = 2000;
+ else if (u_MyInterfaceInSub3.mysig_out == 2'b10)
+ u_MyInterfaceInSub3.other_setting[21:0] = 3000;
+ else
+ u_MyInterfaceInSub3.other_setting[21:0] = 4000;
+ end
+
+ assign u_MyInterfaceInSub2.passThrough[7:0] = 124;
+ assign u_MyInterfaceInSub2.passThrough[15:8] = 200;
+
+endmodule
diff --git a/tests/svinterfaces/svinterface1_ref.v b/tests/svinterfaces/svinterface1_ref.v
new file mode 100644
index 00000000..b119f403
--- /dev/null
+++ b/tests/svinterfaces/svinterface1_ref.v
@@ -0,0 +1,107 @@
+
+module TopModule(
+ input logic clk,
+ input logic rst,
+ input logic [1:0] sig,
+ input logic flip,
+ output logic [15:0] passThrough,
+ output logic [21:0] outOther,
+ output logic [1:0] sig_out);
+
+
+ logic MyInterfaceInstance_setting;
+ logic [3:0] MyInterfaceInstance_other_setting;
+ logic [1:0] MyInterfaceInstance_mysig_out;
+
+ SubModule1 u_SubModule1 (
+ .clk(clk),
+ .rst(rst),
+ .u_MyInterface_setting(MyInterfaceInstance_setting),
+ .u_MyInterface_mysig_out(MyInterfaceInstance_mysig_out),
+ .u_MyInterface_other_setting(MyInterfaceInstance_other_setting),
+ .outOther(outOther),
+ .passThrough (passThrough),
+ .sig (sig)
+ );
+
+ assign sig_out = MyInterfaceInstance_mysig_out;
+
+
+ assign MyInterfaceInstance_setting = flip;
+
+endmodule
+
+
+module SubModule1(
+ input logic clk,
+ input logic rst,
+ input logic u_MyInterface_setting,
+ output logic [3:0] u_MyInterface_other_setting,
+ output logic [1:0] u_MyInterface_mysig_out,
+ output logic [21:0] outOther,
+ input logic [1:0] sig,
+ output logic [15:0] passThrough
+ );
+
+ always @(posedge clk or posedge rst)
+ if(rst)
+ u_MyInterface_mysig_out <= 0;
+ else begin
+ if(u_MyInterface_setting)
+ u_MyInterface_mysig_out <= sig;
+ else
+ u_MyInterface_mysig_out <= ~sig;
+ end
+
+ logic MyInterfaceInstanceInSub_setting;
+ logic [21:0] MyInterfaceInstanceInSub_other_setting;
+ logic [1:0] MyInterfaceInstanceInSub_mysig_out;
+
+
+ SubModule2 u_SubModule2 (
+ .clk(clk),
+ .rst(rst),
+ .u_MyInterfaceInSub2_setting(u_MyInterface_setting),
+ .u_MyInterfaceInSub2_mysig_out(u_MyInterface_mysig_out),
+ .u_MyInterfaceInSub2_other_setting(u_MyInterface_other_setting),
+ .u_MyInterfaceInSub3_setting(MyInterfaceInstanceInSub_setting),
+ .u_MyInterfaceInSub3_mysig_out(MyInterfaceInstanceInSub_mysig_out),
+ .u_MyInterfaceInSub3_other_setting(MyInterfaceInstanceInSub_other_setting),
+ .passThrough (passThrough)
+ );
+ assign outOther = MyInterfaceInstanceInSub_other_setting;
+
+ assign MyInterfaceInstanceInSub_setting = 0;
+ assign MyInterfaceInstanceInSub_mysig_out = sig;
+
+endmodule
+
+module SubModule2(
+
+ input logic clk,
+ input logic rst,
+ input logic u_MyInterfaceInSub2_setting,
+ output logic [3:0] u_MyInterfaceInSub2_other_setting,
+ input logic [1:0] u_MyInterfaceInSub2_mysig_out,
+ input logic u_MyInterfaceInSub3_setting,
+ output logic [21:0] u_MyInterfaceInSub3_other_setting,
+ input logic [1:0] u_MyInterfaceInSub3_mysig_out,
+ output logic [15:0] passThrough
+
+ );
+
+ always @(u_MyInterfaceInSub3_mysig_out) begin
+ if (u_MyInterfaceInSub3_mysig_out == 2'b00)
+ u_MyInterfaceInSub3_other_setting[21:0] = 1000;
+ else if (u_MyInterfaceInSub3_mysig_out == 2'b01)
+ u_MyInterfaceInSub3_other_setting[21:0] = 2000;
+ else if (u_MyInterfaceInSub3_mysig_out == 2'b10)
+ u_MyInterfaceInSub3_other_setting[21:0] = 3000;
+ else
+ u_MyInterfaceInSub3_other_setting[21:0] = 4000;
+ end
+
+ assign passThrough[7:0] = 124;
+ assign passThrough[15:8] = 200;
+
+endmodule
diff --git a/tests/svinterfaces/svinterface1_tb.v b/tests/svinterfaces/svinterface1_tb.v
new file mode 100644
index 00000000..44c3b5f6
--- /dev/null
+++ b/tests/svinterfaces/svinterface1_tb.v
@@ -0,0 +1,57 @@
+`timescale 1ns/10ps
+
+module svinterface1_tb;
+
+
+ logic clk;
+ logic rst;
+ logic [21:0] outOther;
+ logic [1:0] sig;
+ logic [1:0] sig_out;
+ logic flip;
+ logic [15:0] passThrough;
+ integer outfile;
+
+ TopModule u_dut (
+ .clk(clk),
+ .rst(rst),
+ .outOther(outOther),
+ .sig(sig),
+ .flip(flip),
+ .passThrough(passThrough),
+ .sig_out(sig_out)
+ );
+
+ initial begin
+ clk = 0;
+ while(1) begin
+ clk = ~clk;
+ #50;
+ end
+ end
+
+ initial begin
+ outfile = $fopen("output.txt");
+ rst = 1;
+ sig = 0;
+ flip = 0;
+ @(posedge clk);
+ #(2);
+ rst = 0;
+ @(posedge clk);
+ for(int j=0;j<2;j++) begin
+ for(int i=0;i<20;i++) begin
+ #(2);
+ flip = j;
+ sig = i;
+ @(posedge clk);
+ end
+ end
+ $finish;
+ end
+
+ always @(negedge clk) begin
+ $fdisplay(outfile, "%d %d %d", outOther, sig_out, passThrough);
+ end
+
+endmodule
diff --git a/tests/svinterfaces/svinterface_at_top.sv b/tests/svinterfaces/svinterface_at_top.sv
new file mode 100644
index 00000000..b5aa8c8f
--- /dev/null
+++ b/tests/svinterfaces/svinterface_at_top.sv
@@ -0,0 +1,125 @@
+
+
+module TopModule(
+ input logic clk,
+ input logic rst,
+ output logic [21:0] outOther,
+ input logic [1:0] sig,
+ input logic flip,
+ output logic [1:0] sig_out,
+ MyInterface.submodule1 interfaceInstanceAtTop,
+ output logic [15:0] passThrough);
+
+ MyInterface #(.WIDTH(4)) MyInterfaceInstance();
+
+ SubModule1 u_SubModule1 (
+ .clk(clk),
+ .rst(rst),
+ .u_MyInterface(MyInterfaceInstance),
+ .u_MyInterfaceFromTop(interfaceInstanceAtTop),
+ .outOther(outOther),
+ .sig (sig)
+ );
+
+ assign sig_out = MyInterfaceInstance.mysig_out;
+
+
+ assign MyInterfaceInstance.setting = flip;
+
+ assign passThrough = MyInterfaceInstance.passThrough;
+
+endmodule
+
+interface MyInterface #(
+ parameter WIDTH = 3)(
+ );
+
+ logic setting;
+ logic [WIDTH-1:0] other_setting;
+
+ logic [1:0] mysig_out;
+
+ logic [15:0] passThrough;
+
+ modport submodule1 (
+ input setting,
+ output other_setting,
+ output mysig_out,
+ output passThrough
+ );
+
+ modport submodule2 (
+ input setting,
+ output other_setting,
+ input mysig_out,
+ output passThrough
+ );
+
+endinterface
+
+
+module SubModule1(
+ input logic clk,
+ input logic rst,
+ MyInterface.submodule1 u_MyInterface,
+ MyInterface.submodule1 u_MyInterfaceFromTop,
+ input logic [1:0] sig,
+ output logic [21:0] outOther
+
+ );
+
+
+ always_ff @(posedge clk or posedge rst)
+ if(rst)
+ u_MyInterface.mysig_out <= 0;
+ else begin
+ if(u_MyInterface.setting)
+ u_MyInterface.mysig_out <= sig;
+ else
+ u_MyInterface.mysig_out <= ~sig;
+ end
+
+ MyInterface #(.WIDTH(22)) MyInterfaceInstanceInSub();
+
+ SubModule2 u_SubModule2 (
+ .clk(clk),
+ .rst(rst),
+ .u_MyInterfaceFromTopDown(u_MyInterfaceFromTop),
+ .u_MyInterfaceInSub2(u_MyInterface),
+ .u_MyInterfaceInSub3(MyInterfaceInstanceInSub)
+ );
+
+ assign outOther = MyInterfaceInstanceInSub.other_setting;
+
+ assign MyInterfaceInstanceInSub.setting = 0;
+ assign MyInterfaceInstanceInSub.mysig_out = sig;
+
+endmodule
+
+module SubModule2(
+
+ input logic clk,
+ input logic rst,
+ MyInterface.submodule2 u_MyInterfaceInSub2,
+ MyInterface.submodule1 u_MyInterfaceFromTopDown,
+ MyInterface.submodule2 u_MyInterfaceInSub3
+
+ );
+
+ assign u_MyInterfaceFromTopDown.mysig_out = u_MyInterfaceFromTop.setting ? 10 : 20;
+
+ always_comb begin
+ if (u_MyInterfaceInSub3.mysig_out == 2'b00)
+ u_MyInterfaceInSub3.other_setting[21:0] = 1000;
+ else if (u_MyInterfaceInSub3.mysig_out == 2'b01)
+ u_MyInterfaceInSub3.other_setting[21:0] = 2000;
+ else if (u_MyInterfaceInSub3.mysig_out == 2'b10)
+ u_MyInterfaceInSub3.other_setting[21:0] = 3000;
+ else
+ u_MyInterfaceInSub3.other_setting[21:0] = 4000;
+ end
+
+ assign u_MyInterfaceInSub2.passThrough[7:0] = 124;
+ assign u_MyInterfaceInSub2.passThrough[15:8] = 200;
+
+endmodule
diff --git a/tests/svinterfaces/svinterface_at_top_ref.v b/tests/svinterfaces/svinterface_at_top_ref.v
new file mode 100644
index 00000000..7b54a26d
--- /dev/null
+++ b/tests/svinterfaces/svinterface_at_top_ref.v
@@ -0,0 +1,120 @@
+
+module TopModule(
+ input logic clk,
+ input logic rst,
+ input logic [1:0] sig,
+ input logic flip,
+ output logic [15:0] passThrough,
+ output logic [21:0] outOther,
+ input logic interfaceInstanceAtTop_setting,
+ output logic [2:0] interfaceInstanceAtTop_other_setting,
+ output logic [1:0] interfaceInstanceAtTop_mysig_out,
+ output logic [15:0] interfaceInstanceAtTop_passThrough,
+ output logic [1:0] sig_out);
+
+
+ logic MyInterfaceInstance_setting;
+ logic [3:0] MyInterfaceInstance_other_setting;
+ logic [1:0] MyInterfaceInstance_mysig_out;
+
+ SubModule1 u_SubModule1 (
+ .clk(clk),
+ .rst(rst),
+ .u_MyInterface_setting(MyInterfaceInstance_setting),
+ .u_MyInterface_mysig_out(MyInterfaceInstance_mysig_out),
+ .u_MyInterface_other_setting(MyInterfaceInstance_other_setting),
+ .u_MyInterfaceFromTop_setting(interfaceInstanceAtTop_setting),
+ .u_MyInterfaceFromTop_other_setting(interfaceInstanceAtTop_other_setting),
+ .u_MyInterfaceFromTop_mysig_out(interfaceInstanceAtTop_mysig_out),
+ .u_MyInterfaceFromTop_passThrough(interfaceInstanceAtTop_passThrough),
+ .outOther(outOther),
+ .passThrough (passThrough),
+ .sig (sig)
+ );
+
+ assign sig_out = MyInterfaceInstance_mysig_out;
+
+
+ assign MyInterfaceInstance_setting = flip;
+
+endmodule
+
+
+module SubModule1(
+ input logic clk,
+ input logic rst,
+ input logic u_MyInterface_setting,
+ output logic [3:0] u_MyInterface_other_setting,
+ output logic [1:0] u_MyInterface_mysig_out,
+ output logic [21:0] outOther,
+ input logic [1:0] sig,
+ input logic u_MyInterfaceFromTop_setting,
+ output logic [2:0] u_MyInterfaceFromTop_other_setting,
+ output logic [1:0] u_MyInterfaceFromTop_mysig_out,
+ output logic [14:0] u_MyInterfaceFromTop_passThrough,
+ output logic [15:0] passThrough
+ );
+
+ always @(posedge clk or posedge rst)
+ if(rst)
+ u_MyInterface_mysig_out <= 0;
+ else begin
+ if(u_MyInterface_setting)
+ u_MyInterface_mysig_out <= sig;
+ else
+ u_MyInterface_mysig_out <= ~sig;
+ end
+
+ logic MyInterfaceInstanceInSub_setting;
+ logic [21:0] MyInterfaceInstanceInSub_other_setting;
+ logic [1:0] MyInterfaceInstanceInSub_mysig_out;
+
+ assign u_MyInterfaceFromTop_mysig_out = u_MyInterfaceFromTop_setting ? 10 : 20;
+
+ SubModule2 u_SubModule2 (
+ .clk(clk),
+ .rst(rst),
+ .u_MyInterfaceInSub2_setting(u_MyInterface_setting),
+ .u_MyInterfaceInSub2_mysig_out(u_MyInterface_mysig_out),
+ .u_MyInterfaceInSub2_other_setting(u_MyInterface_other_setting),
+ .u_MyInterfaceInSub3_setting(MyInterfaceInstanceInSub_setting),
+ .u_MyInterfaceInSub3_mysig_out(MyInterfaceInstanceInSub_mysig_out),
+ .u_MyInterfaceInSub3_other_setting(MyInterfaceInstanceInSub_other_setting),
+ .passThrough (passThrough)
+ );
+ assign outOther = MyInterfaceInstanceInSub_other_setting;
+
+ assign MyInterfaceInstanceInSub_setting = 0;
+ assign MyInterfaceInstanceInSub_mysig_out = sig;
+
+endmodule
+
+module SubModule2(
+
+ input logic clk,
+ input logic rst,
+ input logic u_MyInterfaceInSub2_setting,
+ output logic [3:0] u_MyInterfaceInSub2_other_setting,
+ input logic [1:0] u_MyInterfaceInSub2_mysig_out,
+ input logic u_MyInterfaceInSub3_setting,
+ output logic [21:0] u_MyInterfaceInSub3_other_setting,
+ input logic [1:0] u_MyInterfaceInSub3_mysig_out,
+ output logic [15:0] passThrough
+
+ );
+
+ always @(u_MyInterfaceInSub3_mysig_out) begin
+ if (u_MyInterfaceInSub3_mysig_out == 2'b00)
+ u_MyInterfaceInSub3_other_setting[21:0] = 1000;
+ else if (u_MyInterfaceInSub3_mysig_out == 2'b01)
+ u_MyInterfaceInSub3_other_setting[21:0] = 2000;
+ else if (u_MyInterfaceInSub3_mysig_out == 2'b10)
+ u_MyInterfaceInSub3_other_setting[21:0] = 3000;
+ else
+ u_MyInterfaceInSub3_other_setting[21:0] = 4000;
+ end
+
+ assign passThrough[7:0] = 124;
+ assign passThrough[15:8] = 200;
+
+endmodule
diff --git a/tests/svinterfaces/svinterface_at_top_tb.v b/tests/svinterfaces/svinterface_at_top_tb.v
new file mode 100644
index 00000000..bf37a148
--- /dev/null
+++ b/tests/svinterfaces/svinterface_at_top_tb.v
@@ -0,0 +1,68 @@
+`timescale 1ns/10ps
+
+module svinterface_at_top_tb;
+
+
+ logic clk;
+ logic rst;
+ logic [21:0] outOther;
+ logic [1:0] sig;
+ logic [1:0] sig_out;
+ logic flip;
+ logic [15:0] passThrough;
+ integer outfile;
+
+ logic interfaceInstanceAtTop_setting;
+ logic [2:0] interfaceInstanceAtTop_other_setting;
+ logic [1:0] interfaceInstanceAtTop_mysig_out;
+ logic [15:0] interfaceInstanceAtTop_passThrough;
+
+
+ TopModule u_dut (
+ .clk(clk),
+ .rst(rst),
+ .outOther(outOther),
+ .sig(sig),
+ .flip(flip),
+ .passThrough(passThrough),
+ .interfaceInstanceAtTop_setting(interfaceInstanceAtTop_setting),
+ .interfaceInstanceAtTop_other_setting(interfaceInstanceAtTop_other_setting),
+ .interfaceInstanceAtTop_mysig_out(interfaceInstanceAtTop_mysig_out),
+ .interfaceInstanceAtTop_passThrough(interfaceInstanceAtTop_passThrough),
+ .sig_out(sig_out)
+ );
+
+ initial begin
+ clk = 0;
+ while(1) begin
+ clk = ~clk;
+ #50;
+ end
+ end
+
+ initial begin
+ outfile = $fopen("output.txt");
+ rst = 1;
+ interfaceInstanceAtTop_setting = 0;
+ sig = 0;
+ flip = 0;
+ @(posedge clk);
+ #(2);
+ rst = 0;
+ @(posedge clk);
+ for(int j=0;j<2;j++) begin
+ for(int i=0;i<20;i++) begin
+ #(2);
+ flip = j;
+ sig = i;
+ @(posedge clk);
+ end
+ end
+ $finish;
+ end
+
+ always @(negedge clk) begin
+ $fdisplay(outfile, "%d %d %d %d", outOther, sig_out, passThrough, interfaceInstanceAtTop_mysig_out);
+ end
+
+endmodule
diff --git a/tests/svinterfaces/svinterface_at_top_tb_wrapper.v b/tests/svinterfaces/svinterface_at_top_tb_wrapper.v
new file mode 100644
index 00000000..b344a7b8
--- /dev/null
+++ b/tests/svinterfaces/svinterface_at_top_tb_wrapper.v
@@ -0,0 +1,68 @@
+`timescale 1ns/10ps
+
+module svinterface_at_top_tb_wrapper;
+
+
+ logic clk;
+ logic rst;
+ logic [21:0] outOther;
+ logic [1:0] sig;
+ logic [1:0] sig_out;
+ logic flip;
+ logic [15:0] passThrough;
+ integer outfile;
+
+ logic interfaceInstanceAtTop_setting;
+ logic [2:0] interfaceInstanceAtTop_other_setting;
+ logic [1:0] interfaceInstanceAtTop_mysig_out;
+ logic [15:0] interfaceInstanceAtTop_passThrough;
+
+
+ TopModule u_dut (
+ .clk(clk),
+ .rst(rst),
+ .outOther(outOther),
+ .sig(sig),
+ .flip(flip),
+ .passThrough(passThrough),
+ .\interfaceInstanceAtTop.setting (interfaceInstanceAtTop_setting),
+ .\interfaceInstanceAtTop.other_setting (interfaceInstanceAtTop_other_setting),
+ .\interfaceInstanceAtTop.mysig_out (interfaceInstanceAtTop_mysig_out),
+ .\interfaceInstanceAtTop.passThrough (interfaceInstanceAtTop_passThrough),
+ .sig_out(sig_out)
+ );
+
+ initial begin
+ clk = 0;
+ while(1) begin
+ clk = ~clk;
+ #50;
+ end
+ end
+
+ initial begin
+ outfile = $fopen("output.txt");
+ rst = 1;
+ sig = 0;
+ interfaceInstanceAtTop_setting = 0;
+ flip = 0;
+ @(posedge clk);
+ #(2);
+ rst = 0;
+ @(posedge clk);
+ for(int j=0;j<2;j++) begin
+ for(int i=0;i<20;i++) begin
+ #(2);
+ flip = j;
+ sig = i;
+ @(posedge clk);
+ end
+ end
+ $finish;
+ end
+
+ always @(negedge clk) begin
+ $fdisplay(outfile, "%d %d %d %d", outOther, sig_out, passThrough, interfaceInstanceAtTop_mysig_out);
+ end
+
+endmodule
diff --git a/tests/svinterfaces/svinterface_at_top_wrapper.v b/tests/svinterfaces/svinterface_at_top_wrapper.v
new file mode 100644
index 00000000..64f906c0
--- /dev/null
+++ b/tests/svinterfaces/svinterface_at_top_wrapper.v
@@ -0,0 +1,33 @@
+`timescale 1ns/10ps
+
+module svinterface_at_top_wrapper(
+ input logic clk,
+ input logic rst,
+ output logic [21:0] outOther,
+ input logic [1:0] sig,
+ output logic [1:0] sig_out,
+ input logic flip,
+ output logic [15:0] passThrough,
+
+ input logic interfaceInstanceAtTop_setting,
+ output logic [2:0] interfaceInstanceAtTop_other_setting,
+ output logic [1:0] interfaceInstanceAtTop_mysig_out,
+ output logic [15:0] interfaceInstanceAtTop_passThrough,
+ );
+
+
+ TopModule u_dut (
+ .clk(clk),
+ .rst(rst),
+ .outOther(outOther),
+ .sig(sig),
+ .flip(flip),
+ .passThrough(passThrough),
+ .\interfaceInstanceAtTop.setting(interfaceInstanceAtTop_setting),
+ .\interfaceInstanceAtTop.other_setting(interfaceInstanceAtTop_other_setting),
+ .\interfaceInstanceAtTop.mysig_out(interfaceInstanceAtTop_mysig_out),
+ .\interfaceInstanceAtTop.passThrough(interfaceInstanceAtTop_passThrough),
+ .sig_out(sig_out)
+ );
+
+endmodule
diff --git a/tests/tools/autotest.mk b/tests/tools/autotest.mk
index c6867892..e0f2bcdc 100644
--- a/tests/tools/autotest.mk
+++ b/tests/tools/autotest.mk
@@ -1,7 +1,7 @@
-EXTRA_FLAGS=
-SEED=
-
+# Don't bother defining default values for SEED and EXTRA_FLAGS.
+# Their "natural" default values should be sufficient,
+# and they may be overridden in the environment.
ifneq ($(strip $(SEED)),)
SEEDOPT=-S$(SEED)
endif
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index d6216244..f3dac504 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -8,7 +8,7 @@ verbose=false
keeprunning=false
makejmode=false
frontend="verilog"
-backend_opts="-noattr -noexpr"
+backend_opts="-noattr -noexpr -siminit"
autotb_opts=""
include_opts=""
xinclude_opts=""
@@ -17,12 +17,18 @@ scriptfiles=""
scriptopt=""
toolsdir="$(cd $(dirname $0); pwd)"
warn_iverilog_git=false
+# The following are used in verilog to firrtl regression tests.
+# Typically these will be passed as environment variables:
+#EXTRA_FLAGS="--firrtl2verilog 'java -cp /.../firrtl/utils/bin/firrtl.jar firrtl.Driver'"
+# The tests are skipped if firrtl2verilog is the empty string (the default).
+firrtl2verilog=""
+xfirrtl="../xfirrtl"
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:-: opt; do
case "$opt" in
x)
use_xsim=true ;;
@@ -43,7 +49,7 @@ while getopts xmGl:wkjvref:s:p:n:S:I: opt; do
r)
backend_opts="$backend_opts -norename" ;;
e)
- backend_opts="$( echo " $backend_opts " | sed 's, -noexpr ,,; s,^ ,,; s, $,,;'; )" ;;
+ backend_opts="$( echo " $backend_opts " | sed 's, -noexpr , ,; s,^ ,,; s, $,,;'; )" ;;
f)
frontend="$OPTARG" ;;
s)
@@ -59,8 +65,24 @@ 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" ;;
+ -)
+ case "${OPTARG}" in
+ xfirrtl)
+ xfirrtl="${!OPTIND}"
+ OPTIND=$(( $OPTIND + 1 ))
+ ;;
+ firrtl2verilog)
+ firrtl2verilog="${!OPTIND}"
+ OPTIND=$(( $OPTIND + 1 ))
+ ;;
+ *)
+ if [ "$OPTERR" == 1 ] && [ "${optspec:0:1}" != ":" ]; then
+ echo "Unknown option --${OPTARG}" >&2
+ fi
+ ;;
+ esac;;
*)
- echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] verilog-files\n" >&2
+ echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [--xfirrtl FIRRTL test exclude file] [--firrtl2verilog command to generate verilog from firrtl] verilog-files\n" >&2
exit 1
esac
done
@@ -86,8 +108,9 @@ shift $((OPTIND - 1))
for fn
do
- bn=${fn%.v}
- if [ "$bn" == "$fn" ]; then
+ bn=${fn%.*}
+ ext=${fn##*.}
+ if [[ "$ext" != "v" ]] && [[ "$ext" != "aag" ]] && [[ "$ext" != "aig" ]]; then
echo "Invalid argument: $fn" >&2
exit 1
fi
@@ -109,7 +132,13 @@ do
fn=$(basename $fn)
bn=$(basename $bn)
- egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.v
+ rm -f ${bn}_ref.fir
+ if [[ "$ext" == "v" ]]; then
+ egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
+ else
+ "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn}
+ frontend="verilog"
+ fi
if [ ! -f ../${bn}_tb.v ]; then
"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v
@@ -117,7 +146,8 @@ do
cp ../${bn}_tb.v ${bn}_tb.v
fi
if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi
- compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs
+ compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \
+ "$toolsdir"/../../techlibs/common/simlib.v
if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
test_count=0
@@ -148,6 +178,13 @@ do
else
test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.v
test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.v
+ if [ -n "$firrtl2verilog" ]; then
+ if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then
+ "$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.v
+ $firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v
+ test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v
+ fi
+ fi
fi
touch ../${bn}.log
}
@@ -160,14 +197,18 @@ do
( set -ex; body; ) > ${bn}.err 2>&1
fi
+ did_firrtl=""
+ if [ -f ${bn}.out/${bn}_ref.fir ]; then
+ did_firrtl="+FIRRTL "
+ fi
if [ -f ${bn}.log ]; then
mv ${bn}.err ${bn}.log
- echo "${status_prefix}-> ok"
+ echo "${status_prefix}${did_firrtl}-> ok"
elif [ -f ${bn}.skip ]; then
mv ${bn}.err ${bn}.skip
echo "${status_prefix}-> skip"
else
- echo "${status_prefix}-> ERROR!"
+ echo "${status_prefix}${did_firrtl}-> ERROR!"
if $warn_iverilog_git; then
echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of Icarus Verilog."
fi
diff --git a/tests/various/hierarchy.sh b/tests/various/hierarchy.sh
new file mode 100644
index 00000000..d33a247b
--- /dev/null
+++ b/tests/various/hierarchy.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+# Simple test of hierarchy -auto-top.
+
+set -e
+
+echo -n " TOP first - "
+../../yosys -s - <<- EOY | grep "Automatically selected TOP as design top module"
+ read_verilog << EOV
+ module TOP(a, y);
+ input a;
+ output [31:0] y;
+
+ aoi12 p [31:0] (a, y);
+ endmodule
+
+ module aoi12(a, y);
+ input a;
+ output y;
+ assign y = ~a;
+ endmodule
+ EOV
+ hierarchy -auto-top
+EOY
+
+echo -n " TOP last - "
+../../yosys -s - <<- EOY | grep "Automatically selected TOP as design top module"
+ read_verilog << EOV
+ module aoi12(a, y);
+ input a;
+ output y;
+ assign y = ~a;
+ endmodule
+
+ module TOP(a, y);
+ input a;
+ output [31:0] y;
+
+ aoi12 foo (a, y);
+ endmodule
+ EOV
+ hierarchy -auto-top
+EOY
+
+echo -n " no explicit top - "
+../../yosys -s - <<- EOY | grep "Automatically selected noTop as design top module."
+ read_verilog << EOV
+ module aoi12(a, y);
+ input a;
+ output y;
+ assign y = ~a;
+ endmodule
+
+ module noTop(a, y);
+ input a;
+ output [31:0] y;
+ endmodule
+ EOV
+ hierarchy -auto-top
+EOY
diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh
index 67e1beb2..d49553ed 100755
--- a/tests/various/run-test.sh
+++ b/tests/various/run-test.sh
@@ -1,6 +1,14 @@
-#!/bin/bash
+#!/usr/bin/env bash
set -e
for x in *.ys; do
echo "Running $x.."
../../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