summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAhmed Irfan <irfan@levert.(none)>2015-04-03 16:38:07 +0200
committerAhmed Irfan <irfan@levert.(none)>2015-04-03 16:38:07 +0200
commitbdf6b2b19ab2206f5957ad5b2ec582c2730d45ee (patch)
tree1d02541701054a1c3b1cdb66478d0cbc31c2d38f
parent8acdd90bc918b780ad45cdac42b3baf84d2cc476 (diff)
parent4b4490761949e738dee54bdfc52e080e0a5c9067 (diff)
Merge branch 'master' of https://github.com/cliffordwolf/yosys
-rw-r--r--.gitignore8
-rw-r--r--CHANGELOG132
-rw-r--r--CodingReadme320
-rw-r--r--Makefile201
-rw-r--r--README65
-rw-r--r--backends/blif/blif.cc152
-rw-r--r--backends/btor/btor.cc8
-rw-r--r--backends/edif/edif.cc27
-rw-r--r--backends/ilang/ilang_backend.cc116
-rw-r--r--backends/intersynth/intersynth.cc3
-rw-r--r--backends/json/Makefile.inc3
-rw-r--r--backends/json/json.cc407
-rw-r--r--backends/smt2/.gitignore1
-rw-r--r--backends/smt2/Makefile.inc3
-rw-r--r--backends/smt2/smt2.cc711
-rw-r--r--backends/smt2/test_cells.sh55
-rw-r--r--backends/spice/spice.cc8
-rw-r--r--backends/verilog/verilog_backend.cc158
-rw-r--r--backends/verilog/verilog_backend.h38
-rw-r--r--frontends/ast/ast.cc35
-rw-r--r--frontends/ast/ast.h28
-rw-r--r--frontends/ast/dpicall.cc12
-rw-r--r--frontends/ast/genrtlil.cc134
-rw-r--r--frontends/ast/simplify.cc378
-rw-r--r--frontends/ilang/.gitignore8
-rw-r--r--frontends/ilang/Makefile.inc22
-rw-r--r--frontends/ilang/ilang_frontend.cc6
-rw-r--r--frontends/ilang/ilang_lexer.l (renamed from frontends/ilang/lexer.l)6
-rw-r--r--frontends/ilang/ilang_parser.y (renamed from frontends/ilang/parser.y)5
-rw-r--r--frontends/liberty/liberty.cc1
-rw-r--r--frontends/verific/build_amd64.txt1
-rw-r--r--frontends/verific/verific.cc25
-rw-r--r--frontends/verilog/.gitignore8
-rw-r--r--frontends/verilog/Makefile.inc24
-rw-r--r--frontends/verilog/const2ast.cc16
-rw-r--r--frontends/verilog/preproc.cc9
-rw-r--r--frontends/verilog/verilog_frontend.cc60
-rw-r--r--frontends/verilog/verilog_frontend.h5
-rw-r--r--frontends/verilog/verilog_lexer.l (renamed from frontends/verilog/lexer.l)51
-rw-r--r--frontends/verilog/verilog_parser.y (renamed from frontends/verilog/parser.y)136
-rw-r--r--frontends/vhdl2verilog/vhdl2verilog.cc45
-rw-r--r--kernel/bitpattern.h89
-rw-r--r--kernel/calc.cc2
-rw-r--r--kernel/celltypes.h122
-rw-r--r--kernel/consteval.h24
-rw-r--r--kernel/cost.h84
-rw-r--r--kernel/driver.cc388
-rw-r--r--kernel/hashlib.h887
-rw-r--r--kernel/log.cc228
-rw-r--r--kernel/log.h63
-rw-r--r--kernel/macc.h69
-rw-r--r--kernel/modtools.h194
-rw-r--r--kernel/register.cc92
-rw-r--r--kernel/register.h10
-rw-r--r--kernel/rtlil.cc490
-rw-r--r--kernel/rtlil.h668
-rw-r--r--kernel/satgen.h282
-rw-r--r--kernel/sigtools.h30
-rw-r--r--kernel/utils.h36
-rw-r--r--kernel/yosys.cc479
-rw-r--r--kernel/yosys.h173
-rw-r--r--libs/ezsat/ezminisat.cc15
-rw-r--r--libs/ezsat/ezminisat.h2
-rw-r--r--libs/ezsat/ezsat.cc202
-rw-r--r--libs/ezsat/ezsat.h11
-rw-r--r--libs/sha1/sha1.cpp113
-rw-r--r--libs/sha1/sha1.h46
-rw-r--r--libs/subcircuit/subcircuit.cc4
-rw-r--r--manual/APPNOTE_010_Verilog_to_BLIF.tex6
-rw-r--r--manual/APPNOTE_011_Design_Investigation/cmos_00.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/cmos_01.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/example_00.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/example_01.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/example_02.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/example_03.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/memdemo_00.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/memdemo_01.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/splice.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/submod_00.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/submod_01.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/submod_02.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/submod_03.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/sumprod_00.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/sumprod_01.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/sumprod_02.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/sumprod_03.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/sumprod_04.dot2
-rw-r--r--manual/APPNOTE_011_Design_Investigation/sumprod_05.dot2
-rw-r--r--manual/CHAPTER_Appnotes.tex25
-rw-r--r--manual/CHAPTER_Auxprogs.tex6
-rw-r--r--manual/CHAPTER_CellLib.tex12
-rw-r--r--manual/CHAPTER_Prog.tex21
-rw-r--r--manual/CHAPTER_Prog/.gitignore3
-rw-r--r--manual/CHAPTER_Prog/stubnets.cc12
-rw-r--r--manual/PRESENTATION_ExAdv.tex2
-rw-r--r--manual/PRESENTATION_ExOth/axis_master.v2
-rw-r--r--manual/PRESENTATION_ExSyn.tex6
-rw-r--r--manual/PRESENTATION_Intro.tex67
-rw-r--r--manual/PRESENTATION_Prog.tex92
-rw-r--r--manual/PRESENTATION_Prog/.gitignore1
-rw-r--r--manual/PRESENTATION_Prog/my_cmd.cc9
-rw-r--r--manual/command-reference-manual.tex1636
-rw-r--r--manual/manual.tex5
-rwxr-xr-xmanual/presentation.sh4
-rw-r--r--manual/presentation.tex4
-rw-r--r--misc/create_vcxsrc.sh54
-rw-r--r--misc/example.cc21
-rw-r--r--misc/yosys-config.in (renamed from yosys-config.in)16
-rw-r--r--misc/yosysjs/demo01.html197
-rw-r--r--misc/yosysjs/demo02.html102
-rw-r--r--misc/yosysjs/demo03.html103
-rw-r--r--misc/yosysjs/yosysjs.js223
-rw-r--r--passes/abc/abc.cc720
-rw-r--r--passes/abc/blifparse.cc10
-rw-r--r--passes/abc/blifparse.h7
-rw-r--r--passes/cmds/Makefile.inc3
-rw-r--r--passes/cmds/add.cc8
-rw-r--r--passes/cmds/check.cc154
-rw-r--r--passes/cmds/connect.cc4
-rw-r--r--passes/cmds/connwrappers.cc4
-rw-r--r--passes/cmds/copy.cc4
-rw-r--r--passes/cmds/cover.cc25
-rw-r--r--passes/cmds/delete.cc16
-rw-r--r--passes/cmds/logcmd.cc (renamed from passes/cmds/log.cc)4
-rw-r--r--passes/cmds/plugin.cc9
-rw-r--r--passes/cmds/rename.cc21
-rw-r--r--passes/cmds/scatter.cc4
-rw-r--r--passes/cmds/scc.cc59
-rw-r--r--passes/cmds/select.cc223
-rw-r--r--passes/cmds/setattr.cc6
-rw-r--r--passes/cmds/setundef.cc4
-rw-r--r--passes/cmds/show.cc94
-rw-r--r--passes/cmds/splice.cc33
-rw-r--r--passes/cmds/splitnets.cc6
-rw-r--r--passes/cmds/stat.cc242
-rw-r--r--passes/cmds/tee.cc8
-rw-r--r--passes/cmds/trace.cc17
-rw-r--r--passes/cmds/write_file.cc8
-rw-r--r--passes/equiv/Makefile.inc9
-rw-r--r--passes/equiv/equiv_add.cc89
-rw-r--r--passes/equiv/equiv_induct.cc241
-rw-r--r--passes/equiv/equiv_make.cc474
-rw-r--r--passes/equiv/equiv_miter.cc343
-rw-r--r--passes/equiv/equiv_remove.cc83
-rw-r--r--passes/equiv/equiv_simple.cc358
-rw-r--r--passes/equiv/equiv_status.cc94
-rw-r--r--passes/fsm/fsm.cc14
-rw-r--r--passes/fsm/fsm_detect.cc6
-rw-r--r--passes/fsm/fsm_expand.cc6
-rw-r--r--passes/fsm/fsm_export.cc9
-rw-r--r--passes/fsm/fsm_extract.cc22
-rw-r--r--passes/fsm/fsm_info.cc4
-rw-r--r--passes/fsm/fsm_map.cc15
-rw-r--r--passes/fsm/fsm_opt.cc18
-rw-r--r--passes/fsm/fsm_recode.cc55
-rw-r--r--passes/fsm/fsmdata.h15
-rw-r--r--passes/hierarchy/hierarchy.cc183
-rw-r--r--passes/hierarchy/submod.cc8
-rw-r--r--passes/memory/Makefile.inc1
-rw-r--r--passes/memory/memory.cc17
-rw-r--r--passes/memory/memory_bram.cc1174
-rw-r--r--passes/memory/memory_collect.cc130
-rw-r--r--passes/memory/memory_dff.cc16
-rw-r--r--passes/memory/memory_map.cc32
-rw-r--r--passes/memory/memory_share.cc33
-rw-r--r--passes/memory/memory_unpack.cc8
-rw-r--r--passes/opt/Makefile.inc3
-rw-r--r--passes/opt/opt.cc23
-rw-r--r--passes/opt/opt_clean.cc149
-rw-r--r--passes/opt/opt_const.cc103
-rw-r--r--passes/opt/opt_muxtree.cc349
-rw-r--r--passes/opt/opt_reduce.cc32
-rw-r--r--passes/opt/opt_rmdff.cc12
-rw-r--r--passes/opt/opt_share.cc31
-rw-r--r--passes/opt/share.cc489
-rw-r--r--passes/opt/wreduce.cc105
-rw-r--r--passes/proc/Makefile.inc1
-rw-r--r--passes/proc/proc.cc9
-rw-r--r--passes/proc/proc_arst.cc19
-rw-r--r--passes/proc/proc_clean.cc15
-rw-r--r--passes/proc/proc_dff.cc18
-rw-r--r--passes/proc/proc_dlatch.cc308
-rw-r--r--passes/proc/proc_init.cc8
-rw-r--r--passes/proc/proc_mux.cc18
-rw-r--r--passes/proc/proc_rmdead.cc8
-rw-r--r--passes/sat/eval.cc32
-rw-r--r--passes/sat/expose.cc20
-rw-r--r--passes/sat/freduce.cc60
-rw-r--r--passes/sat/miter.cc6
-rw-r--r--passes/sat/sat.cc417
-rw-r--r--passes/techmap/Makefile.inc13
-rw-r--r--passes/techmap/alumacc.cc92
-rw-r--r--passes/techmap/dff2dffe.cc337
-rw-r--r--passes/techmap/dfflibmap.cc113
-rw-r--r--passes/techmap/extract.cc534
-rw-r--r--passes/techmap/hilomap.cc10
-rw-r--r--passes/techmap/iopadmap.cc23
-rw-r--r--passes/techmap/libparse.cc45
-rw-r--r--passes/techmap/libparse.h2
-rw-r--r--passes/techmap/maccmap.cc84
-rw-r--r--passes/techmap/simplemap.cc121
-rw-r--r--passes/techmap/simplemap.h48
-rw-r--r--passes/techmap/techmap.cc140
-rw-r--r--passes/tests/test_abcloop.cc44
-rw-r--r--passes/tests/test_autotb.cc31
-rw-r--r--passes/tests/test_cell.cc165
-rw-r--r--techlibs/cmos/cmos_cells.v15
-rw-r--r--techlibs/common/Makefile.inc34
-rw-r--r--techlibs/common/cells.lib108
-rw-r--r--techlibs/common/simcells.v38
-rw-r--r--techlibs/common/simlib.v238
-rw-r--r--techlibs/common/synth.cc54
-rw-r--r--techlibs/common/techmap.v58
-rw-r--r--techlibs/ice40/Makefile.inc6
-rw-r--r--techlibs/ice40/cells_map.v32
-rw-r--r--techlibs/ice40/cells_sim.v12
-rw-r--r--techlibs/ice40/synth_ice40.cc161
-rw-r--r--techlibs/xilinx/Makefile.inc10
-rw-r--r--techlibs/xilinx/arith_map.v91
-rw-r--r--techlibs/xilinx/brams.txt101
-rw-r--r--techlibs/xilinx/brams_map.v267
-rw-r--r--techlibs/xilinx/cells.v53
-rw-r--r--techlibs/xilinx/cells_map.v84
-rw-r--r--techlibs/xilinx/cells_sim.v158
-rw-r--r--techlibs/xilinx/example_basys3/README16
-rw-r--r--techlibs/xilinx/example_basys3/example.v21
-rw-r--r--techlibs/xilinx/example_basys3/example.xdc21
-rw-r--r--techlibs/xilinx/example_basys3/run.sh4
-rw-r--r--techlibs/xilinx/example_basys3/run_prog.tcl4
-rw-r--r--techlibs/xilinx/example_basys3/run_vivado.tcl9
-rw-r--r--techlibs/xilinx/example_basys3/run_yosys.ys2
-rw-r--r--techlibs/xilinx/example_mojo_counter/README10
-rw-r--r--techlibs/xilinx/example_mojo_counter/example.sh18
-rw-r--r--techlibs/xilinx/example_mojo_counter/example.ucf14
-rw-r--r--techlibs/xilinx/example_mojo_counter/example.v14
-rw-r--r--techlibs/xilinx/example_sim_counter/counter.v12
-rw-r--r--techlibs/xilinx/example_sim_counter/counter_tb.v61
-rw-r--r--techlibs/xilinx/example_sim_counter/run_sim.sh23
-rw-r--r--techlibs/xilinx/example_zed_counter/README10
-rw-r--r--techlibs/xilinx/example_zed_counter/example.sh18
-rw-r--r--techlibs/xilinx/example_zed_counter/example.ucf14
-rw-r--r--techlibs/xilinx/example_zed_counter/example.v14
-rw-r--r--techlibs/xilinx/synth_xilinx.cc132
-rw-r--r--techlibs/xilinx/tests/.gitignore3
-rw-r--r--techlibs/xilinx/tests/bram1.sh63
-rw-r--r--techlibs/xilinx/tests/bram1.v24
-rw-r--r--techlibs/xilinx/tests/bram1_tb.v116
-rw-r--r--tests/asicworld/code_hdl_models_dlatch_reset.v30
-rw-r--r--tests/asicworld/code_hdl_models_ram_sp_ar_sw.v58
-rw-r--r--tests/asicworld/code_hdl_models_ram_sp_sr_sw.v62
-rw-r--r--tests/bram/.gitignore1
-rw-r--r--tests/bram/generate.py264
-rw-r--r--tests/bram/run-single.sh12
-rwxr-xr-xtests/bram/run-test.sh32
-rw-r--r--tests/fsm/generate.py146
-rw-r--r--tests/realmath/generate.py99
-rwxr-xr-xtests/realmath/run-test.sh2
-rw-r--r--tests/share/generate.py92
-rwxr-xr-xtests/share/run-test.sh2
-rw-r--r--tests/simple/memory.v23
-rw-r--r--tests/simple/muxtree.v11
-rw-r--r--tests/simple/task_func.v36
-rw-r--r--tests/techmap/mem_simple_4x1_map.v5
-rwxr-xr-xtests/tools/autotest.sh2
-rw-r--r--tests/tools/cmp_tbdata.c2
-rwxr-xr-xtests/tools/vcdcd.pl4
266 files changed, 18443 insertions, 4671 deletions
diff --git a/.gitignore b/.gitignore
index 803e1302..2b6f032e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,9 +11,17 @@
/qtcreator.creator.user
/Makefile.conf
/abc
+/viz.js
/yosys
+/yosys.exe
+/yosys.js
/yosys-abc
+/yosys-abc.exe
/yosys-config
/yosys-filterlib
+/yosys-filterlib.exe
/kernel/version_*.cc
/share
+/yosys-win32-mxebin-*
+/yosys-win32-vcxsrc-*
+/yosysjs-*
diff --git a/CHANGELOG b/CHANGELOG
index 35695729..3efbe109 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,15 +1,133 @@
-List of changes and major improvements between releases
+List of major changes and improvements between releases
=======================================================
-Yosys 0.3.0 .. Yoys 0.3.0+
---------------------------
+Yosys 0.4 .. Yosys 0.5
+----------------------
+
+ * API changes
+ - Added log_warning()
+ - Added eval_select_args() and eval_select_op()
+ - Added cell->known(), cell->input(portname), cell->output(portname)
+ - Skip blackbox modules in design->selected_modules()
+ - Replaced std::map<> and std::set<> with dict<> and pool<>
+ - New SigSpec::extend() is what used to be SigSpec::extend_u0()
+ - Added YS_OVERRIDE, YS_FINAL, YS_ATTRIBUTE, YS_NORETURN
+
+ * Cell library changes
+ - Added flip-flops with enable ($dffe etc.)
+ - Added $equiv cells for equivalence checking framework
+
+ * Various
+ - Updated ABC to hg rev 61ad5f908c03
+ - Added clock domain partitioning to ABC pass
+ - Improved plugin building (see "yosys-config --build")
+ - Added ENABLE_NDEBUG Makefile flag for high-performance builds
+ - Added "yosys -d", "yosys -L" and other driver improvements
+ - Added support for multi-bit (array) cell ports to "write_edif"
+ - Now printing most output to stdout, not stderr
+ - Added "onehot" attribute (set by "fsm_map")
+ - Various performance improvements
+ - Vastly improved Xilinx flow
+ - Added "make unsintall"
+
+ * Equivalence checking
+ - Added equivalence checking commands:
+ equiv_make equiv_simple equiv_status
+ equiv_induct equiv_miter
+ equiv_add equiv_remove
+
+ * Block RAM support:
+ - Added "memory_bram" command
+ - Added BRAM support to Xilinx flow
+
+ * Other New Commands and Options
+ - Added "dff2dffe"
+ - Added "fsm -encfile"
+ - Added "dfflibmap -prepare"
+ - Added "write_blid -unbuf -undef -blackbox"
+ - Added "write_smt2" for writing SMT-LIBv2 files
+ - Added "test_cell -w -muxdiv"
+ - Added "select -read"
+
+
+Yosys 0.3.0 .. Yosys 0.4
+------------------------
- ... TBD ...
+ * Platform Support
+ - Added support for mxe-based cross-builds for win32
+ - Added sourcecode-export as VisualStudio project
+ - Added experimental EMCC (JavaScript) support
+ * Verilog Frontend
+ - Added -sv option for SystemVerilog (and automatic *.sv file support)
+ - Added support for real-valued constants and constant expressions
+ - Added support for non-standard "via_celltype" attribute on task/func
+ - Added support for non-standard "module mod_name(...);" syntax
+ - Added support for non-standard """ macro bodies
+ - Added support for array with more than one dimension
+ - Added support for $readmemh and $readmemb
+ - Added support for DPI functions
-Yosys 0.2.0 .. Yoys 0.3.0
+ * Changes in internal cell library
+ - Added $shift and $shiftx cell types
+ - Added $alu, $lcu, $fa and $macc cell types
+ - Removed $bu0 and $safe_pmux cell types
+ - $mem/$memwr WR_EN input is now a per-data-bit enable signal
+ - Added $_NAND_ $_NOR_ $_XNOR_ $_AOI3_ $_OAI3_ $_AOI4_ $_OAI4_
+ - Renamed ports of $lut cells (from I->O to A->Y)
+ - Renamed $_INV_ to $_NOT_
+
+ * Changes for simple synthesis flows
+ - There is now a "synth" command with a recommended default script
+ - Many improvements in synthesis of arithmetic functions to gates
+ - Multiplieres and adders with many operands are using carry-save adder trees
+ - Remaining adders are now implemented using Brent–Kung carry look-ahead adders
+ - Various new high-level optimizations on RTL netlist
+ - Various improvements in FSM optimization
+ - Updated ABC to hg 5b5af75f1dda (from 2014-11-07)
+
+ * Changes in internal APIs and RTLIL
+ - Added log_id() and log_cell() helper functions
+ - Added function-like cell creation helpers
+ - Added GetSize() function (like .size() but with int)
+ - Major refactoring of RTLIL::Module and related classes
+ - Major refactoring of RTLIL::SigSpec and related classes
+ - Now RTLIL::IdString is essentially an int
+ - Added macros for code coverage counters
+ - Added some Makefile magic for pretty make logs
+ - Added "kernel/yosys.h" with all the core definitions
+ - Chanded a lot of code from FILE* to c++ streams
+ - Added RTLIL::Monitor API and "trace" command
+ - Added "Yosys" C++ namespace
+
+ * Changes relevant to SAT solving
+ - Added ezSAT::keep_cnf() and ezSAT::non_incremental()
+ - Added native ezSAT support for vector shift ops
+ - Updated MiniSAT to git 37dc6c67e2 (from 2013-09-25)
+
+ * New commands (or large improvements to commands)
+ - Added "synth" command with default script
+ - Added "share" (finally some real resource sharing)
+ - Added "memory_share" (reduce number of ports on memories)
+ - Added "wreduce" and "alumacc" commands
+ - Added "opt -keepdc -fine -full -fast"
+ - Added some "test_*" commands
+
+ * Various other changes
+ - Added %D and %c select operators
+ - Added support for labels in yosys scripts
+ - Added support for here-documents in yosys scripts
+ - Support "+/" prefix for files from proc_share_dir
+ - Added "autoidx" statement to ilang language
+ - Switched from "yosys-svgviewer" to "xdot"
+ - Renamed "stdcells.v" to "techmap.v"
+ - Various bug fixes and small improvements
+ - Improved welcome and bye messages
+
+
+Yosys 0.2.0 .. Yosys 0.3.0
--------------------------
* Driver program and overall behavior:
@@ -59,8 +177,8 @@ Yosys 0.2.0 .. Yoys 0.3.0
- Various build fixes for OSX (Darwin) and OpenBSD
-Yosys 0.1.0 .. Yoys 0.2.0
--------------------------
+Yosys 0.1.0 .. Yosys 0.2.0
+--------------------------
* Changes to the driver program:
- Added "yosys -h" and "yosys -H"
diff --git a/CodingReadme b/CodingReadme
index 8f515e1f..54ea368e 100644
--- a/CodingReadme
+++ b/CodingReadme
@@ -1,31 +1,209 @@
+This file contains some very brief documentation on things like programming APIs.
+Also consult the Yosys manual and the section about programming in the presentation.
+(Both can be downloaded as PDF from the yosys webpage.)
+
+--snip-- only the lines below this mark are included in the yosys manual --snip--
Getting Started
===============
-Reading List
-------------
+Outline of a Yosys command
+--------------------------
+
+Here is a the C++ code for a "hello_world" Yosys command (hello.cc):
+
+ #include "kernel/yosys.h"
+
+ USING_YOSYS_NAMESPACE
+ PRIVATE_NAMESPACE_BEGIN
+
+ struct HelloWorldPass : public Pass {
+ HelloWorldPass() : Pass("hello_world") { }
+ virtual void execute(vector<string>, Design*) {
+ log("Hello World!\n");
+ }
+ } HelloWorldPass;
+
+ PRIVATE_NAMESPACE_END
+
+This can be built into a Yosys module using the following command:
+
+ yosys-config --exec --cxx --cxxflags --ldflags -o hello.so -shared hello.cc --ldlibs
+
+Or short:
+
+ yosys-config --build hello.so hello.cc
+
+And then executed using the following command:
+
+ yosys -m hello.so -p hello_world
+
+
+Yosys Data Structures
+---------------------
+
+Here is a short list of data structures that you should make yourself familiar
+with before you write C++ code for Yosys. The following data structures are all
+defined when "kernel/yosys.h" is included and USING_YOSYS_NAMESPACE is used.
+
+ 1. Yosys Container Classes
+
+Yosys uses dict<K, T> and pool<T> as main container classes. dict<K, T> is
+essentially a replacement for std::unordered_map<K, T> and pool<T> is a
+replacement for std::unordered_set<T>. The main characteristics are:
+
+ - dict<K, T> and pool<T> are about 2x faster than the std containers
+
+ - references to elements in a dict<K, T> or pool<T> are invalidated by
+ insert and remove operations (similar to std::vector<T> on push_back()).
+
+ - some iterators are invalidated by erase(). specifically, iterators
+ that have not passed the erased element yet are invalidated. (erase()
+ itself returns valid iterator to the next element.)
+
+ - no iterators are invalidated by insert(). elements are inserted at
+ begin(). i.e. only a new iterator that starts at begin() will see the
+ inserted elements.
+
+ - the method .count(key, iterator) is like .count(key) but only
+ considers elements that can be reached via the iterator.
+
+ - iterators can be compared. it1 < it2 means that the position of t2
+ can be reached via t1 but not vice versa.
+
+ - the method .sort() can be used to sort the elements in the container
+ the container stays sorted until elements are added or removed.
+
+ - dict<K, T> and pool<T> will have the same order of iteration across
+ all compilers, standard libraries and architectures.
+
+In addition to dict<K, T> and pool<T> there is also an idict<K> that
+creates a bijective map from K to the integers. For example:
+
+ idict<string, 42> si;
+ log("%d\n", si("hello")); // will print 42
+ log("%d\n", si("world")); // will print 43
+ log("%d\n", si.at("world")); // will print 43
+ log("%d\n", si.at("dummy")); // will throw exception
+ log("%s\n", si[42].c_str())); // will print hello
+ log("%s\n", si[43].c_str())); // will print world
+ log("%s\n", si[44].c_str())); // will throw exception
+
+It is not possible to remove elements from an idict.
-To write Yosys C++ code you need to know at least the following classes in kernel/rtlil.h:
+ 2. Standard STL data types
+
+In Yosys we use std::vector<T> and std::string whenever applicable. When
+dict<K, T> and pool<T> are not suitable then std::map<K, T> and std::set<T>
+are used instead.
+
+The types std::vector<T> and std::string are also available as vector<T>
+and string in the Yosys namespace.
+
+ 3. RTLIL objects
+
+The current design (essentially a collection of modules, each defined by a
+netlist) is stored in memory using RTLIL object (declared in kernel/rtlil.h,
+automatically included by kernel/yosys.h). You should glance over at least
+the declarations for the following types in kernel/rtlil.h:
+
+ RTLIL::IdString
+ This is a handle for an identifier (e.g. cell or wire name).
+ It feels a lot like a std::string, but is only a single int
+ in size. (The actual string is stored in a global lookup
+ table.)
+
+ RTLIL::SigBit
+ A single signal bit. I.e. either a constant state (0, 1,
+ x, z) or a single bit from a wire.
+
+ RTLIL::SigSpec
+ Essentially a vector of SigBits.
RTLIL::Wire
RTLIL::Cell
+ The building blocks of the netlist in a module.
+
RTLIL::Module
- RTLIL::SigSpec
+ RTLIL::Design
+ The module is a container with connected cells and wires
+ in it. The design is a container with modules in it.
+
+All this types are also available without the RTLIL:: prefix in the Yosys
+namespace.
+
+ 4. SigMap and other Helper Classes
+
+There are a couple of additional helper classes that are in wide use
+in Yosys. Most importantly there is SigMap (declared in kernel/sigtools.h).
+
+When a design has many wires in it that are connected to each other, then a
+single signal bit can have multiple valid names. The SigMap object can be used
+to map SigSpecs or SigBits to unique SigSpecs and SigBits that consistently
+only use one wire from such a group of connected wires. For example:
+
+ SigBit a = module->addWire(NEW_ID);
+ SigBit b = module->addWire(NEW_ID);
+ module->connect(a, b);
+
+ log("%d\n", a == b); // will print 0
+
+ SigMap sigmap(module);
+ log("%d\n", sigmap(a) == sigmap(b)); // will print 1
+
+
+Using the RTLIL Netlist Format
+------------------------------
+
+In the RTLIL netlist format the cell ports contain SigSpecs that point to the
+Wires. There are no references in the other direction. This has two direct
+consequences:
+
+(1) It is very easy to go from cells to wires but hard to go in the other way.
+
+(2) There is no danger in removing cells from the netlists, but removing wires
+can break the netlist format when there are still references to the wire
+somewhere in the netlist.
+
+The solution to (1) is easy: Create custom indexes that allow you to make fast
+lookups for the wire-to-cell direction. You can either use existing generic
+index structures to do that (such as the ModIndex class) or write your own
+index. For many application it is simplest to construct a custom index. For
+example:
+
+ SigMap sigmap(module);
+ dict<SigBit, Cell*> sigbit_to_driver_index;
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections())
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sigbit_to_driver_index[bit] = cell;
+
+Regarding (2): There is a general theme in Yosys that you don't remove wires
+from the design. You can rename them, unconnect them, but you do not actually remove
+the Wire object from the module. Instead you let the "clean" command take care
+of the dangling wires. On the other hand it is safe to remove cells (as long as
+you make sure this does not invalidate a custom index you are using in your code).
+
+
+Example Code
+------------
The following yosys commands are a good starting point if you are looking for examples
of how to use the Yosys API:
- passes/opt/wreduce.cc
- passes/techmap/maccmap.cc
+ manual/CHAPTER_Prog/stubnets.cc
+ manual/PRESENTATION_Prog/my_cmd.cc
Notes on the existing codebase
------------------------------
For historical reasons not all parts of Yosys adhere to the current coding
-styles. When adding code to existing parts of the system, adhere to this guide
+style. When adding code to existing parts of the system, adhere to this guide
for the new code instead of trying to mimic the style of the surrounding code.
@@ -58,15 +236,58 @@ C++ Langugage
-------------
Yosys is written in C++11. At the moment only constructs supported by
-gcc 4.6 is allowed in Yosys code. This will change in future releases.
+gcc 4.6 are allowed in Yosys code. This will change in future releases.
In general Yosys uses "int" instead of "size_t". To avoid compiler
-warnings for implicit type casts, always use "SIZE(foobar)" instead
-of "foobar.size()". (the macro SIZE() is defined by kernel/yosys.h)
+warnings for implicit type casts, always use "GetSize(foobar)" instead
+of "foobar.size()". (GetSize() is defined in kernel/yosys.h)
Use range-based for loops whenever applicable.
+--snap-- only the lines above this mark are included in the yosys manual --snap--
+
+
+Creating the Visual Studio Template Project
+===========================================
+
+1. Create an empty Visual C++ Win32 Console App project
+
+ Microsoft Visual Studio Express 2013 for Windows Desktop
+ Open New Project Wizard (File -> New Project..)
+
+ Project Name: YosysVS
+ Solution Name: YosysVS
+ [X] Create directory for solution
+ [ ] Add to source control
+
+ [X] Console applications
+ [X] Empty Projcect
+ [ ] SDL checks
+
+2. Open YosysVS Project Properties
+
+ Select Configuration: All Configurations
+
+ C/C++ -> General -> Additional Include Directories
+ Add: ..\yosys
+
+ C/C++ -> Preprocessor -> Preprocessor Definitions
+ Add: _YOSYS_;_CRT_SECURE_NO_WARNINGS
+
+3. Resulting file system tree:
+
+ YosysVS/
+ YosysVS/YosysVS
+ YosysVS/YosysVS/YosysVS.vcxproj
+ YosysVS/YosysVS/YosysVS.vcxproj.filters
+ YosysVS/YosysVS.sdf
+ YosysVS/YosysVS.sln
+ YosysVS/YosysVS.v12.suo
+
+4. Zip YosysVS as YosysVS-Tpl-v1.zip
+
+
Checklist for adding internal cell types
========================================
@@ -96,50 +317,45 @@ Update the CHANGELOG file:
vi CHANGELOG
-Run all tests with "make config-{clang-debug,gcc-debug,gcc-4.6,release}":
+Update and check documentation:
cd ~yosys
- make clean
- make test vloghtb
- make install
-
- cd ~yosys-bigsim
- make clean
- make full
+ make update-manual
+ make manual
+ - sanity check the figures in the appnotes and presentation
+ - if there are any odd things -> investigate
+ - make cosmetic changes to the .tex files if necessary
- cd ~vloghammer
- make purge
- make gen_issues gen_samples
- make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" FULL=1 world
- chromium-browser report.html
+ cd ~yosys
+ vi README CodingReadme
+ - is the information provided in those file still up to date
Then with default config setting:
cd ~yosys
- ./yosys -p 'proc; show' tests/simple/fiedler-cooley.v
- ./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v
+ make vgtest
cd ~yosys
- make manual
- - sanity check the figures in the appnotes and presentation
- - if there are any odd things -> investigate
- - make cosmetic changes to the .tex files if necessary
-
-
-Also with default config setting:
+ ./yosys -p 'proc; show' tests/simple/fiedler-cooley.v
+ ./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v
+ ./yosys -p 'synth; show' tests/simple/fiedler-cooley.v
+ ./yosys -p 'synth_xilinx -top up3down5; show' tests/simple/fiedler-cooley.v
cd ~yosys/techlibs/cmos
bash testbench.sh
- cd ~yosys/techlibs/xilinx/example_sim_counter
- bash run_sim.sh
+ cd ~yosys/techlibs/xilinx/example_basys3
+ bash run.sh
+
+
+Test building plugins with various of the standard passes:
- cd ~yosys/techlibs/xilinx/example_mojo_counter
- bash example.sh
+ yosys-config --build test.so equiv_simple.cc
+ - also check the code examples in CodingReadme
-Finally if a current verific library is available:
+And if a version of the verific library is currently available:
cd ~yosys
cat frontends/verific/build_amd64.txt
@@ -149,12 +365,22 @@ Finally if a current verific library is available:
../../yosys test_navre.ys
-Release candiate:
+Finally run all tests with "make config-{clang,gcc,gcc-4.6}":
- - create branch yosys-x.y.z-rc and push to github
- - contact the usual suspects per mail and ask them to test
- - post on the reddit and ask people to test
- - commit KISS fixes to the -rc branch if necessary
+ cd ~yosys
+ make clean
+ make test
+ make vloghtb
+ make install
+
+ cd ~yosys-bigsim
+ make clean
+ make full
+
+ cd ~vloghammer
+ make purge gen_issues gen_samples
+ make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" REPORT_FULL=1 world
+ chromium-browser report.html
Release:
@@ -166,7 +392,6 @@ Release:
- push tag to github
- post changelog on github
- post short release note on reddit
- - delete -rc branch from github
Updating the website:
@@ -183,12 +408,3 @@ Updating the website:
git commit -am update
make push
-
-In master branch:
-
- git merge {release-tag}
- - set version to x.y.z+ in Makefile
- - add section "Yosys x.y.z .. x.y.z+" to CHANGELOG
- git commit --amend -am "Yosys x.y.z+"
-
-
diff --git a/Makefile b/Makefile
index 5a75320c..405870b6 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ CONFIG := clang
# CONFIG := gcc
# CONFIG := gcc-4.6
# CONFIG := emcc
+# CONFIG := mxe
# features (the more the better)
ENABLE_TCL := 1
@@ -10,41 +11,53 @@ ENABLE_ABC := 1
ENABLE_PLUGINS := 1
ENABLE_READLINE := 1
ENABLE_VERIFIC := 0
+ENABLE_COVER := 1
# other configuration flags
ENABLE_GPROF := 0
+ENABLE_NDEBUG := 0
DESTDIR := /usr/local
INSTALL_SUDO :=
+TARGET_BINDIR := $(DESTDIR)/bin
+TARGET_DATDIR := $(DESTDIR)/share/yosys
+
+EXE =
OBJS =
GENFILES =
+EXTRA_OBJS =
EXTRA_TARGETS =
-TARGETS = yosys yosys-config
+TARGETS = yosys$(EXE) yosys-config
PRETTY = 1
SMALL = 0
all: top-all
-CXXFLAGS = -Wall -Wextra -ggdb -I"$(shell pwd)" -MD -DYOSYS_SRC='"$(shell pwd)"' -D_YOSYS_ -fPIC -I${DESTDIR}/include
-LDFLAGS = -L${DESTDIR}/lib
+YOSYS_SRC := $(shell pwd)
+CXXFLAGS = -Wall -Wextra -ggdb -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(DESTDIR)/include
+LDFLAGS = -L$(DESTDIR)/lib
LDLIBS = -lstdc++ -lm
-QMAKE = qmake-qt4
SED = sed
+BISON = bison
ifeq (Darwin,$(findstring Darwin,$(shell uname)))
- # add macports include and library path to search directories, don't use '-rdynamic' and '-lrt':
- CXXFLAGS += -I/opt/local/include
- LDFLAGS += -L/opt/local/lib
- QMAKE = qmake
+ # add macports/homebrew include and library path to search directories, don't use '-rdynamic' and '-lrt':
+ CXXFLAGS += -I/opt/local/include -I/usr/local/opt/readline/include
+ LDFLAGS += -L/opt/local/lib -L/usr/local/opt/readline/lib
+ # add homebrew's libffi include and library path
+ CXXFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --cflags libffi)
+ LDFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --libs libffi)
+ # use bison installed by homebrew if available
+ BISON = $(shell (brew list bison | grep -m1 "bin/bison") || echo bison)
SED = gsed
else
LDFLAGS += -rdynamic
LDLIBS += -lrt
endif
-YOSYS_VER := 0.3.0+$(shell test -d .git && { git log --author=clifford@clifford.at --oneline ca125bf41.. | wc -l; })
+YOSYS_VER := 0.5+$(shell test -d .git && { git log --author=clifford@clifford.at --oneline c3c9fbfb8c678.. | wc -l; })
GIT_REV := $(shell git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
@@ -54,8 +67,9 @@ 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 = 4d547a5e065b
+ABCREV = 61ad5f908c03
ABCPULL = 1
+ABCMKARGS = # CC="$(CXX)" CXX="$(CXX)"
define newline
@@ -81,8 +95,42 @@ CXXFLAGS += -std=gnu++0x -Os
else ifeq ($(CONFIG),emcc)
CXX = emcc
-CXXFLAGS += -std=c++11 -Os -Wno-warn-absolute-paths
-CXXFLAGS := $(filter-out -ggdb,$(CXXFLAGS))
+CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS))
+EMCCFLAGS := -Os -Wno-warn-absolute-paths
+EMCCFLAGS += --memory-init-file 0 --embed-file share -s NO_EXIT_RUNTIME=1
+EMCCFLAGS += -s EXPORTED_FUNCTIONS="['_main','_run','_prompt','_errmsg']"
+EMCCFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1
+# https://github.com/kripken/emscripten/blob/master/src/settings.js
+CXXFLAGS += $(EMCCFLAGS)
+LDFLAGS += $(EMCCFLAGS)
+LDLIBS =
+EXE = .js
+
+TARGETS := $(filter-out yosys-config,$(TARGETS))
+EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip
+
+viz.js:
+ wget -O viz.js.part https://github.com/mdaines/viz.js/releases/download/0.0.3/viz.js
+ mv viz.js.part viz.js
+
+yosysjs-$(YOSYS_VER).zip: yosys.js viz.js misc/yosysjs/*
+ rm -rf yosysjs-$(YOSYS_VER) yosysjs-$(YOSYS_VER).zip
+ mkdir -p yosysjs-$(YOSYS_VER)
+ cp viz.js misc/yosysjs/* yosys.js yosysjs-$(YOSYS_VER)/
+ zip -r yosysjs-$(YOSYS_VER).zip yosysjs-$(YOSYS_VER)
+
+yosys.html: misc/yosys.html
+ $(P) cp misc/yosys.html yosys.html
+
+else ifeq ($(CONFIG),mxe)
+CXX = /usr/local/src/mxe/usr/bin/i686-pc-mingw32-gcc
+CXXFLAGS += -std=gnu++0x -Os -D_POSIX_SOURCE
+CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
+LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
+LDLIBS := $(filter-out -lrt,$(LDLIBS))
+ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -x c++ -fpermissive -w"
+ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" READLINE=0 CC="$(CXX)" CXX="$(CXX)"
+EXE = .exe
else ifneq ($(CONFIG),none)
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.6, emcc, none)
@@ -91,6 +139,9 @@ endif
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
LDLIBS += -lreadline
+ifeq ($(CONFIG),mxe)
+LDLIBS += -lpdcurses
+endif
endif
ifeq ($(ENABLE_PLUGINS),1)
@@ -99,7 +150,7 @@ LDLIBS += $(shell pkg-config --silence-errors --libs libffi || echo -lffi) -ldl
endif
ifeq ($(ENABLE_TCL),1)
-TCL_VERSION ?= tcl8.5
+TCL_VERSION ?= tcl$(shell echo 'puts [info tclversion]' | tclsh)
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
LDLIBS += -l$(TCL_VERSION)
@@ -110,9 +161,13 @@ CXXFLAGS += -pg
LDFLAGS += -pg
endif
+ifeq ($(ENABLE_NDEBUG),1)
+CXXFLAGS := -O3 -DNDEBUG $(filter-out -Os,$(CXXFLAGS))
+endif
+
ifeq ($(ENABLE_ABC),1)
CXXFLAGS += -DYOSYS_ENABLE_ABC
-TARGETS += yosys-abc
+TARGETS += yosys-abc$(EXE)
endif
ifeq ($(ENABLE_VERIFIC),1)
@@ -122,11 +177,26 @@ CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABL
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS))
endif
+ifeq ($(ENABLE_COVER),1)
+CXXFLAGS += -DYOSYS_ENABLE_COVER
+endif
+
+define add_share_file
+EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2)))
+$(subst //,/,$(1)/$(notdir $(2))): $(2)
+ $$(P) mkdir -p $(1)
+ $$(Q) cp $(2) $(subst //,/,$(1)/$(notdir $(2)))
+endef
+
+define add_include_file
+$(eval $(call add_share_file,$(dir share/include/$(1)),$(1)))
+endef
+
ifeq ($(PRETTY), 1)
P_STATUS = 0
P_OFFSET = 0
-P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
-P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
+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 = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@";
Q = @
S = -s
@@ -137,7 +207,26 @@ Q =
S =
endif
+$(eval $(call add_include_file,kernel/yosys.h))
+$(eval $(call add_include_file,kernel/hashlib.h))
+$(eval $(call add_include_file,kernel/log.h))
+$(eval $(call add_include_file,kernel/rtlil.h))
+$(eval $(call add_include_file,kernel/register.h))
+$(eval $(call add_include_file,kernel/celltypes.h))
+$(eval $(call add_include_file,kernel/consteval.h))
+$(eval $(call add_include_file,kernel/sigtools.h))
+$(eval $(call add_include_file,kernel/modtools.h))
+$(eval $(call add_include_file,kernel/macc.h))
+$(eval $(call add_include_file,kernel/utils.h))
+$(eval $(call add_include_file,kernel/satgen.h))
+$(eval $(call add_include_file,libs/ezsat/ezsat.h))
+$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
+$(eval $(call add_include_file,libs/sha1/sha1.h))
+$(eval $(call add_include_file,passes/fsm/fsmdata.h))
+$(eval $(call add_include_file,backends/ilang/ilang_backend.h))
+
OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
+kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o
OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o
@@ -192,8 +281,8 @@ top-all: $(TARGETS) $(EXTRA_TARGETS)
@echo " Build successful."
@echo ""
-yosys: $(OBJS)
- $(P) $(CXX) -o yosys $(LDFLAGS) $(OBJS) $(LDLIBS)
+yosys$(EXE): $(OBJS)
+ $(P) $(CXX) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
%.o: %.cc
$(P) $(CXX) -o $@ -c $(CXXFLAGS) $<
@@ -203,15 +292,16 @@ yosys: $(OBJS)
kernel/version_$(GIT_REV).cc: Makefile
$(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
- $(Q) echo "extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(CXX) ` \
- $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1` $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))\";" > kernel/version_$(GIT_REV).cc
+ $(Q) echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(notdir $(CXX)) ` \
+ $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1` $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))\"; }" > kernel/version_$(GIT_REV).cc
-yosys-config: yosys-config.in
- $(P) $(SED) -e 's,@CXX@,$(CXX),;' -e 's,@CXXFLAGS@,$(CXXFLAGS),;' -e 's,@LDFLAGS@,$(LDFLAGS),;' -e 's,@LDLIBS@,$(LDLIBS),;' \
- -e 's,@BINDIR@,$(DESTDIR)/bin,;' -e 's,@DATDIR@,$(DESTDIR)/share/yosys,;' < yosys-config.in > yosys-config
+yosys-config: misc/yosys-config.in
+ $(P) $(SED) -e 's,@CXXFLAGS@,$(subst -I"$(YOSYS_SRC)",-I"$(TARGET_DATDIR)/include",$(CXXFLAGS)),;' \
+ -e 's,@CXX@,$(CXX),;' -e 's,@LDFLAGS@,$(LDFLAGS),;' -e 's,@LDLIBS@,$(LDLIBS),;' \
+ -e 's,@BINDIR@,$(TARGET_BINDIR),;' -e 's,@DATDIR@,$(TARGET_DATDIR),;' < misc/yosys-config.in > yosys-config
$(Q) chmod +x yosys-config
-abc/abc-$(ABCREV):
+abc/abc-$(ABCREV)$(EXE):
$(P)
ifneq ($(ABCREV),default)
$(Q) if ( cd abc 2> /dev/null && hg identify; ) | grep -q +; then \
@@ -219,20 +309,20 @@ ifneq ($(ABCREV),default)
fi
$(Q) if test "`cd abc 2> /dev/null && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
- echo "Pulling ABC from bitbucket.org:"; \
+ echo "Pulling ABC from bitbucket.org:"; set -x; \
test -d abc || hg clone https://bitbucket.org/alanmi/abc abc; \
- cd abc && hg pull && hg update -r $(ABCREV); \
+ cd abc && $(MAKE) DEP= clean && hg pull && hg update -r $(ABCREV); \
fi
endif
$(Q) rm -f abc/abc-[0-9a-f]*
- $(Q) cd abc && $(MAKE) $(S) PROG="abc-$(ABCREV)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: "
+ $(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) PROG="abc-$(ABCREV)$(EXE)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: "
ifeq ($(ABCREV),default)
-.PHONY: abc/abc-$(ABCREV)
+.PHONY: abc/abc-$(ABCREV)$(EXE)
endif
-yosys-abc: abc/abc-$(ABCREV)
- $(P) cp abc/abc-$(ABCREV) yosys-abc
+yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
+ $(P) cp abc/abc-$(ABCREV)$(EXE) yosys-abc$(EXE)
test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && bash run-test.sh
@@ -243,6 +333,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/fsm && bash run-test.sh
+cd tests/techmap && bash run-test.sh
+cd tests/memories && bash run-test.sh
+ +cd tests/bram && bash run-test.sh
+cd tests/various && bash run-test.sh
+cd tests/sat && bash run-test.sh
@echo ""
@@ -252,7 +343,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
vgtest: $(TARGETS) $(EXTRA_TARGETS)
- $(VALGRIND) ./yosys -p 'setattr -mod -unset top; hierarchy; proc; opt; memory -nomap; opt -fine; techmap; opt' $$( ls tests/simple/*.v | grep -v repwhile.v )
+ $(VALGRIND) ./yosys -p 'setattr -mod -unset top; synth' $$( ls tests/simple/*.v | grep -v repwhile.v )
@echo ""
@echo " Passed \"make vgtest\"."
@echo ""
@@ -269,6 +360,13 @@ install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)/share/yosys
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)/share/yosys/.
+uninstall:
+ $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)/bin/,$(notdir $(TARGETS)))
+ $(INSTALL_SUDO) rm -rvf $(DESTDIR)/share/yosys/
+
+update-manual: $(TARGETS) $(EXTRA_TARGETS)
+ cd manual && ../yosys -p 'help -write-tex-command-reference-manual'
+
manual: $(TARGETS) $(EXTRA_TARGETS)
cd manual && bash appnotes.sh
cd manual && bash presentation.sh
@@ -277,13 +375,13 @@ manual: $(TARGETS) $(EXTRA_TARGETS)
clean:
rm -rf share
cd manual && bash clean.sh
- rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS)
+ rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
clean-abc:
- make -C abc clean
- rm -f yosys-abc abc/abc-[0-9a-f]*
+ $(MAKE) -C abc DEP= clean
+ rm -f yosys-abc$(EXE) abc/abc-[0-9a-f]*
mrproper: clean
git clean -xdf
@@ -295,6 +393,29 @@ qtcreator:
{ echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes
touch qtcreator.config qtcreator.creator
+vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
+ rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
+ set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \
+ echo "Analyse: $$f" >&2; cpp -std=gnu++0x -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
+ bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV)
+ echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc
+ zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc
+ zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
+ rm -f srcfiles.txt kernel/version.cc
+
+ifeq ($(CONFIG),mxe)
+mxebin: $(TARGETS) $(EXTRA_TARGETS)
+ rm -rf yosys-win32-mxebin-$(YOSYS_VER){,.zip}
+ mkdir -p yosys-win32-mxebin-$(YOSYS_VER)
+ cp -r yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/
+ifeq ($(ENABLE_ABC),1)
+ cp -r yosys-abc.exe abc/lib/x86/pthreadVC2.dll yosys-win32-mxebin-$(YOSYS_VER)/
+endif
+ echo -en 'This is Yosys $(YOSYS_VER) for Win32.\r\n' > yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
+ echo -en 'Documentation at http://www.clifford.at/yosys/.\r\n' >> yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
+ zip -r yosys-win32-mxebin-$(YOSYS_VER).zip yosys-win32-mxebin-$(YOSYS_VER)/
+endif
+
config-clean: clean
rm -f Makefile.conf
@@ -314,6 +435,12 @@ config-emcc: clean
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo 'ENABLE_READLINE := 0' >> Makefile.conf
+config-mxe: clean
+ echo 'CONFIG := mxe' > Makefile.conf
+ echo 'ENABLE_TCL := 0' >> Makefile.conf
+ echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
+ echo 'ENABLE_READLINE := 0' >> Makefile.conf
+
config-gprof: clean
echo 'CONFIG := gcc' > Makefile.conf
echo 'ENABLE_GPROF := 1' >> Makefile.conf
@@ -321,6 +448,12 @@ config-gprof: clean
config-sudo:
echo "INSTALL_SUDO := sudo" >> Makefile.conf
+echo-yosys-ver:
+ @echo "$(YOSYS_VER)"
+
+echo-git-rev:
+ @echo "$(GIT_REV)"
+
-include libs/*/*.d
-include frontends/*/*.d
-include passes/*/*.d
diff --git a/README b/README
index d7f5aaa4..856f6079 100644
--- a/README
+++ b/README
@@ -3,7 +3,7 @@
| |
| yosys -- Yosys Open SYnthesis Suite |
| |
- | Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |
+ | Copyright (C) 2012 - 2015 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 |
@@ -55,12 +55,13 @@ Xdot (graphviz) is used by the "show" command in yosys to display schematics.
For example on Ubuntu Linux 14.04 LTS the following commands will install all
prerequisites for building yosys:
- $ yosys_deps="build-essential clang bison flex libreadline-dev
- tcl8.5-dev libffi-dev git mercurial graphviz xdot"
+ $ yosys_deps="build-essential clang bison flex libreadline-dev gawk
+ tcl-dev libffi-dev git mercurial graphviz xdot pkg-config"
$ sudo apt-get install $yosys_deps
-There are also pre-compiled packages for Yosys on Ubuntu. Visit the Yosys
-download page to learn more about this:
+There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well
+as a source distribution for Visual Studio. Visit the Yosys download page for
+more information:
http://www.clifford.at/yosys/download.html
@@ -248,11 +249,19 @@ Verilog Attributes and non-standard features
is strongly recommended instead).
- The "nomem2reg" attribute on modules or arrays prohibits the
- automatic early conversion of arrays to separate registers.
+ automatic early conversion of arrays to separate registers. This
+ is potentially dangerous. Usually the front-end has good reasons
+ for converting an array to a list of registers. Prohibiting this
+ step will likely result in incorrect synthesis results.
- The "mem2reg" attribute on modules or arrays forces the early
conversion of arrays to separate registers.
+- The "nomeminit" attribute on modules or arrays prohibits the
+ creation of initialized memories. This effectively puts "mem2reg"
+ on all memories that are written to in an "initial" block and
+ are not ROMs.
+
- The "nolatches" attribute on modules or always-blocks
prohibits the generation of logic-loops for latches. Instead
all not explicitly assigned values default to x-bits. This does
@@ -264,6 +273,9 @@ Verilog Attributes and non-standard features
temporary variable within an always block. This is mostly used internally
by yosys to synthesize verilog functions and access arrays.
+- The "onehot" attribute on wires mark them as onehot 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
that have the same ports as the real thing but do not contain information
on the internal configuration. This modules are only used by the synthesis
@@ -273,6 +285,11 @@ Verilog Attributes and non-standard features
- 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.
+ Setting the "keep" attribute on a module has the same effect as setting it
+ on all instances of the module.
+
+- The "keep_hierarchy" attribute on cells and modules keeps the "flatten"
+ command from flattening the indicated cells and modules.
- The "init" attribute on wires is set by the frontend when a register is
initialized "FPGA-style" with 'reg foo = val'. It can be used during synthesis
@@ -289,7 +306,7 @@ Verilog Attributes and non-standard features
by adding an empty {* *} statement.)
- Modules can be declared with "module mod_name(...);" (with three dots
- instead of a list of moudle ports). With this syntax it is sufficient
+ instead of a list of module ports). With this syntax it is sufficient
to simply declare a module port as 'input' or 'output' in the module
body.
@@ -354,40 +371,8 @@ from SystemVerilog:
- The "assert" statement from SystemVerilog is supported in its most basic
form. In module context: "assert property (<expression>);" and within an
- always block: "assert(<expression>);". It is transformed to a $assert cell
- that is supported by the "sat" and "write_btor" commands.
+ always block: "assert(<expression>);". It is transformed to a $assert cell.
- The keywords "always_comb", "always_ff" and "always_latch", "logic" and
"bit" are supported.
-
-Roadmap / Large-scale TODOs
-===========================
-
-- Technology mapping for real-world applications
- - Improve Xilinx FGPA synthesis (RAMB, CARRY4, SLR, etc.)
-
-- Implement SAT-based formal equivialence checker
- - Write equiv pass based on hint-based register mapping
-
-- Re-implement Verilog frontend (far future)
- - cleaner (easier to use, harder to use wrong) AST format
- - pipeline of well structured AST transformations
- - true contextual name lookup
-
-
-Other Unsorted TODOs
-====================
-
-- Implement missing Verilog 2005 features:
-
- - Support for real (float) const. expressions and parameters
- - ROM modeling using $readmemh/$readmemb in "initial" blocks
- - Ignore what needs to be ignored (e.g. drive and charge strengths)
- - Check standard vs. implementation to identify missing features
-
-- Miscellaneous TODO items:
-
- - Add brief source code documentation to most passes and kernel code
- - Implement mux-to-tribuf pass and rebalance mixed mux/tribuf trees
-
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index ee12546c..f6aac0b4 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -28,6 +28,9 @@
#include "kernel/log.h"
#include <string>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct BlifDumperConfig
{
bool icells_mode;
@@ -35,11 +38,14 @@ struct BlifDumperConfig
bool impltf_mode;
bool gates_mode;
bool param_mode;
+ bool attr_mode;
+ bool blackbox_mode;
std::string buf_type, buf_in, buf_out;
- std::string true_type, true_out, false_type, false_out;
+ std::map<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::IdString>> unbuf_types;
+ std::string true_type, true_out, false_type, false_out, undef_type, undef_out;
- BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false) { }
+ BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false) { }
};
struct BlifDumper
@@ -69,8 +75,11 @@ struct BlifDumper
const char *cstr(RTLIL::SigBit sig)
{
- if (sig.wire == NULL)
- return sig == RTLIL::State::S1 ? "$true" : "$false";
+ if (sig.wire == NULL) {
+ if (sig == RTLIL::State::S0) return config->false_type == "-" ? config->false_out.c_str() : "$false";
+ if (sig == RTLIL::State::S1) return config->true_type == "-" ? config->true_out.c_str() : "$true";
+ return config->undef_type == "-" ? config->undef_out.c_str() : "$undef";
+ }
std::string str = RTLIL::unescape_id(sig.wire->name);
for (size_t i = 0; i < str.size(); i++)
@@ -95,6 +104,26 @@ struct BlifDumper
return "subckt";
}
+ void dump_params(const char *command, dict<IdString, Const> &params)
+ {
+ for (auto &param : params) {
+ f << stringf("%s %s ", command, RTLIL::id2cstr(param.first));
+ if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
+ std::string str = param.second.decode_string();
+ f << stringf("\"");
+ for (char ch : str)
+ if (ch == '"' || ch == '\\')
+ f << stringf("\\%c", ch);
+ else if (ch < 32 || ch >= 127)
+ f << stringf("\\%03o", ch);
+ else
+ f << stringf("%c", ch);
+ f << stringf("\"\n");
+ } else
+ f << stringf("%s\n", param.second.as_string().c_str());
+ }
+ }
+
void dump()
{
f << stringf("\n");
@@ -126,23 +155,44 @@ struct BlifDumper
}
f << stringf("\n");
+ if (module->get_bool_attribute("\\blackbox")) {
+ f << stringf(".blackbox\n");
+ f << stringf(".end\n");
+ return;
+ }
+
if (!config->impltf_mode) {
- if (!config->false_type.empty())
- f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
- config->false_type.c_str(), config->false_out.c_str());
- else
+ if (!config->false_type.empty()) {
+ if (config->false_type != "-")
+ f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
+ config->false_type.c_str(), config->false_out.c_str());
+ } else
f << stringf(".names $false\n");
- if (!config->true_type.empty())
- f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
- config->true_type.c_str(), config->true_out.c_str());
- else
+ if (!config->true_type.empty()) {
+ if (config->true_type != "-")
+ f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
+ config->true_type.c_str(), config->true_out.c_str());
+ } else
f << stringf(".names $true\n1\n");
+ if (!config->undef_type.empty()) {
+ if (config->undef_type != "-")
+ f << stringf(".%s %s %s=$undef\n", subckt_or_gate(config->undef_type),
+ config->undef_type.c_str(), config->undef_out.c_str());
+ } else
+ f << stringf(".names $undef\n");
}
for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
+ if (config->unbuf_types.count(cell->type)) {
+ auto portnames = config->unbuf_types.at(cell->type);
+ f << stringf(".names %s %s\n1 1\n",
+ cstr(cell->getPort(portnames.first)), cstr(cell->getPort(portnames.second)));
+ continue;
+ }
+
if (!config->icells_mode && cell->type == "$_NOT_") {
f << stringf(".names %s %s\n0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\Y")));
@@ -191,21 +241,21 @@ struct BlifDumper
auto &inputs = cell->getPort("\\A");
auto width = cell->parameters.at("\\WIDTH").as_int();
log_assert(inputs.size() == width);
- for (int i = 0; i < inputs.size(); i++) {
+ for (int i = width-1; i >= 0; i--) {
f << stringf(" %s", cstr(inputs.extract(i, 1)));
}
auto &output = cell->getPort("\\Y");
log_assert(output.size() == 1);
f << stringf(" %s", cstr(output));
f << stringf("\n");
- auto mask = cell->parameters.at("\\LUT").as_string();
- for (int i = 0; i < (1 << width); i++) {
- if (mask[i] == '0') continue;
- for (int j = width-1; j >= 0; j--) {
- f << ((i>>j)&1 ? '1' : '0');
+ RTLIL::SigSpec mask = cell->parameters.at("\\LUT");
+ for (int i = 0; i < (1 << width); i++)
+ if (mask[i] == RTLIL::S1) {
+ for (int j = width-1; j >= 0; j--) {
+ f << ((i>>j)&1 ? '1' : '0');
+ }
+ f << " 1\n";
}
- f << stringf(" %c\n", mask[i]);
- }
continue;
}
@@ -220,23 +270,10 @@ struct BlifDumper
}
f << stringf("\n");
+ if (config->attr_mode)
+ dump_params(".attr", cell->attributes);
if (config->param_mode)
- for (auto &param : cell->parameters) {
- f << stringf(".param %s ", RTLIL::id2cstr(param.first));
- if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
- std::string str = param.second.decode_string();
- f << stringf("\"");
- for (char ch : str)
- if (ch == '"' || ch == '\\')
- f << stringf("\\%c", ch);
- else if (ch < 32 || ch >= 127)
- f << stringf("\\%03o", ch);
- else
- f << stringf("%c", ch);
- f << stringf("\"\n");
- } else
- f << stringf("%s\n", param.second.as_string().c_str());
- }
+ dump_params(".param", cell->parameters);
}
for (auto &conn : module->connections())
@@ -276,9 +313,17 @@ struct BlifBackend : public Backend {
log(" -buf <cell-type> <in-port> <out-port>\n");
log(" use cells of type <cell-type> with the specified port names for buffers\n");
log("\n");
+ log(" -unbuf <cell-type> <in-port> <out-port>\n");
+ log(" replace buffer cells with the specified name and port names with\n");
+ log(" a .names statement that models a buffer\n");
+ log("\n");
log(" -true <cell-type> <out-port>\n");
log(" -false <cell-type> <out-port>\n");
- log(" use the specified cell types to drive nets that are constant 1 or 0\n");
+ log(" -undef <cell-type> <out-port>\n");
+ log(" use the specified cell types to drive nets that are constant 1, 0, or\n");
+ log(" undefined. when '-' is used as <cell-type>, then <out-port> specifies\n");
+ log(" the wire name to be used for the constant signal and no cell driving\n");
+ log(" that wire is generated.\n");
log("\n");
log("The following options can be useful when the generated file is not going to be\n");
log("read by a BLIF parser but a custom tool. It is recommended to not name the output\n");
@@ -296,11 +341,17 @@ struct BlifBackend : public Backend {
log(" do not generate buffers for connected wires. instead use the\n");
log(" non-standard .conn statement.\n");
log("\n");
+ log(" -attr\n");
+ log(" use the non-standard .attr statement to write cell attributes\n");
+ log("\n");
log(" -param\n");
- log(" use the non-standard .param statement to write module parameters\n");
+ log(" use the non-standard .param statement to write cell parameters\n");
+ log("\n");
+ log(" -blackbox\n");
+ log(" write blackbox cells with .blackbox statement.\n");
log("\n");
log(" -impltf\n");
- log(" do not write definitions for the $true and $false wires.\n");
+ log(" do not write definitions for the $true, $false and $undef wires.\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
@@ -326,6 +377,13 @@ struct BlifBackend : public Backend {
config.buf_out = args[++argidx];
continue;
}
+ if (args[argidx] == "-unbuf" && argidx+3 < args.size()) {
+ RTLIL::IdString unbuf_type = RTLIL::escape_id(args[++argidx]);
+ RTLIL::IdString unbuf_in = RTLIL::escape_id(args[++argidx]);
+ RTLIL::IdString unbuf_out = RTLIL::escape_id(args[++argidx]);
+ config.unbuf_types[unbuf_type] = std::pair<RTLIL::IdString, RTLIL::IdString>(unbuf_in, unbuf_out);
+ continue;
+ }
if (args[argidx] == "-true" && argidx+2 < args.size()) {
config.true_type = args[++argidx];
config.true_out = args[++argidx];
@@ -336,6 +394,11 @@ struct BlifBackend : public Backend {
config.false_out = args[++argidx];
continue;
}
+ if (args[argidx] == "-undef" && argidx+2 < args.size()) {
+ config.undef_type = args[++argidx];
+ config.undef_out = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-icells") {
config.icells_mode = true;
continue;
@@ -352,6 +415,14 @@ struct BlifBackend : public Backend {
config.param_mode = true;
continue;
}
+ if (args[argidx] == "-attr") {
+ config.attr_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-blackbox") {
+ config.blackbox_mode = true;
+ continue;
+ }
if (args[argidx] == "-impltf") {
config.impltf_mode = true;
continue;
@@ -372,7 +443,7 @@ struct BlifBackend : public Backend {
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
- if (module->get_bool_attribute("\\blackbox"))
+ if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode)
continue;
if (module->processes.size() != 0)
@@ -397,3 +468,4 @@ struct BlifBackend : public Backend {
}
} BlifBackend;
+PRIVATE_NAMESPACE_END
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 8ce5bb5e..c8fbf8d6 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -30,6 +30,9 @@
#include <string>
#include <math.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct BtorDumperConfig
{
bool subckt_mode;
@@ -476,7 +479,7 @@ struct BtorDumper
log_assert(!(cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" ||
cell->type == "$ge" || cell->type == "$gt") || output_width == 1);
bool l1_signed = cell->parameters.at(RTLIL::IdString("\\A_SIGNED")).as_bool();
- bool l2_signed = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
+ bool l2_signed YS_ATTRIBUTE(unused) = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
@@ -817,7 +820,7 @@ struct BtorDumper
int input_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
log_assert(input->size() == input_width);
int input_line = dump_sigspec(input, input_width);
- const RTLIL::SigSpec* output = &cell->getPort(RTLIL::IdString("\\Y"));
+ const RTLIL::SigSpec* output YS_ATTRIBUTE(unused) = &cell->getPort(RTLIL::IdString("\\Y"));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
log_assert(output->size() == output_width);
int offset = cell->parameters.at(RTLIL::IdString("\\OFFSET")).as_int();
@@ -1057,3 +1060,4 @@ struct BtorBackend : public Backend {
}
} BtorBackend;
+PRIVATE_NAMESPACE_END
diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc
index ccedd91d..b089be14 100644
--- a/backends/edif/edif.cc
+++ b/backends/edif/edif.cc
@@ -27,6 +27,9 @@
#include "kernel/log.h"
#include <string>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str()
#define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false).c_str()
@@ -108,7 +111,7 @@ struct EdifBackend : public Backend {
log_header("Executing EDIF backend.\n");
std::string top_module_name;
- std::map<RTLIL::IdString, std::set<RTLIL::IdString>> lib_cell_ports;
+ std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
CellTypes ct(design);
EdifNames edif_names;
@@ -147,12 +150,8 @@ struct EdifBackend : public Backend {
RTLIL::Cell *cell = cell_it.second;
if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
lib_cell_ports[cell->type];
- for (auto p : cell->connections()) {
- if (p.second.size() > 1)
- log_error("Found multi-bit port %s on library cell %s.%s (%s): not supported in EDIF backend!\n",
- RTLIL::id2cstr(p.first), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
- lib_cell_ports[cell->type].insert(p.first);
- }
+ for (auto p : cell->connections())
+ lib_cell_ports[cell->type][p.first] = GetSize(p.second);
}
}
}
@@ -195,12 +194,15 @@ struct EdifBackend : public Backend {
for (auto &port_it : cell_it.second) {
const char *dir = "INOUT";
if (ct.cell_known(cell_it.first)) {
- if (!ct.cell_output(cell_it.first, port_it))
+ if (!ct.cell_output(cell_it.first, port_it.first))
dir = "INPUT";
- else if (!ct.cell_input(cell_it.first, port_it))
+ else if (!ct.cell_input(cell_it.first, port_it.first))
dir = "OUTPUT";
}
- *f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it), dir);
+ if (port_it.second == 1)
+ *f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it.first), dir);
+ else
+ *f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEF(port_it.first), port_it.second, dir);
}
*f << stringf(" )\n");
*f << stringf(" )\n");
@@ -300,12 +302,12 @@ struct EdifBackend : public Backend {
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
hex_string = std::string(digit_str) + hex_string;
}
- *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), hex_string.c_str());
+ *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(p.first), GetSize(p.second.bits), hex_string.c_str());
}
*f << stringf(")\n");
for (auto &p : cell->connections()) {
RTLIL::SigSpec sig = sigmap(p.second);
- for (int i = 0; i < SIZE(sig); i++)
+ for (int i = 0; i < GetSize(sig); i++)
if (sig.size() == 1)
net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)));
else
@@ -345,3 +347,4 @@ struct EdifBackend : public Backend {
}
} EdifBackend;
+PRIVATE_NAMESPACE_END
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
index 48d818d7..814d3e8f 100644
--- a/backends/ilang/ilang_backend.cc
+++ b/backends/ilang/ilang_backend.cc
@@ -26,7 +26,9 @@
#include "kernel/yosys.h"
#include <errno.h>
+USING_YOSYS_NAMESPACE
using namespace ILANG_BACKEND;
+YOSYS_NAMESPACE_BEGIN
void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint)
{
@@ -101,7 +103,7 @@ void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
dump_sigchunk(f, sig.as_chunk(), autoint);
} else {
f << stringf("{ ");
- for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
+ for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
dump_sigchunk(f, *it, false);
f << stringf(" ");
}
@@ -111,11 +113,9 @@ void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
{
- std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(wire->attributes.begin(), wire->attributes.end());
-
- for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
- f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
- dump_const(f, it->second);
+ for (auto &it : wire->attributes) {
+ f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
+ dump_const(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "wire ", indent.c_str());
@@ -136,11 +136,9 @@ void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::
void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory)
{
- std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(memory->attributes.begin(), memory->attributes.end());
-
- for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
- f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
- dump_const(f, it->second);
+ for (auto &it : memory->attributes) {
+ f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
+ dump_const(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "memory ", indent.c_str());
@@ -148,29 +146,27 @@ void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL
f << stringf("width %d ", memory->width);
if (memory->size != 0)
f << stringf("size %d ", memory->size);
+ if (memory->start_offset != 0)
+ f << stringf("offset %d ", memory->start_offset);
f << stringf("%s\n", memory->name.c_str());
}
void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
{
- std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(cell->attributes.begin(), cell->attributes.end());
- std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_parameters(cell->parameters.begin(), cell->parameters.end());
- std::map<RTLIL::IdString, RTLIL::SigSpec, RTLIL::sort_by_id_str> sorted_connections(cell->connections().begin(), cell->connections().end());
-
- for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
- f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
- dump_const(f, it->second);
+ for (auto &it : cell->attributes) {
+ f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
+ dump_const(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
- for (auto it = sorted_parameters.begin(); it != sorted_parameters.end(); it++) {
- f << stringf("%s parameter%s %s ", indent.c_str(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it->first.c_str());
- dump_const(f, it->second);
+ for (auto &it : cell->parameters) {
+ f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str());
+ dump_const(f, it.second);
f << stringf("\n");
}
- for (auto it = sorted_connections.begin(); it != sorted_connections.end(); it++) {
- f << stringf("%s connect %s ", indent.c_str(), it->first.c_str());
- dump_sigspec(f, it->second);
+ for (auto &it : cell->connections()) {
+ f << stringf("%s connect %s ", indent.c_str(), it.first.c_str());
+ dump_sigspec(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "end\n", indent.c_str());
@@ -178,7 +174,7 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
void ILANG_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs)
{
- for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
+ for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it)
{
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, it->first);
@@ -187,13 +183,13 @@ void ILANG_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, con
f << stringf("\n");
}
- for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
+ for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
dump_proc_switch(f, indent, *it);
}
void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw)
{
- for (auto it = sw->attributes.begin(); it != sw->attributes.end(); it++) {
+ for (auto it = sw->attributes.begin(); it != sw->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
@@ -203,7 +199,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
dump_sigspec(f, sw->signal);
f << stringf("\n");
- for (auto it = sw->cases.begin(); it != sw->cases.end(); it++)
+ for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it)
{
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
@@ -235,7 +231,7 @@ void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
case RTLIL::STi: f << stringf("init\n"); break;
}
- for (auto it = sy->actions.begin(); it != sy->actions.end(); it++) {
+ for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) {
f << stringf("%s update ", indent.c_str());
dump_sigspec(f, it->first);
f << stringf(" ");
@@ -246,14 +242,14 @@ void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
void ILANG_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc)
{
- for (auto it = proc->attributes.begin(); it != proc->attributes.end(); it++) {
+ for (auto it = proc->attributes.begin(); it != proc->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
f << stringf("%s" "process %s\n", indent.c_str(), proc->name.c_str());
dump_proc_case_body(f, indent + " ", &proc->root_case);
- for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
+ for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
dump_proc_sync(f, indent + " ", *it);
f << stringf("%s" "end\n", indent.c_str());
}
@@ -274,7 +270,7 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (print_header)
{
- for (auto it = module->attributes.begin(); it != module->attributes.end(); it++) {
+ for (auto it = module->attributes.begin(); it != module->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
@@ -285,56 +281,36 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (print_body)
{
- std::vector<RTLIL::Wire*> sorted_wires;
for (auto it : module->wires())
- sorted_wires.push_back(it);
- std::sort(sorted_wires.begin(), sorted_wires.end(), RTLIL::sort_by_name_str<RTLIL::Wire>());
-
- std::vector<RTLIL::Memory*> sorted_memories;
- for (auto it : module->memories)
- sorted_memories.push_back(it.second);
- std::sort(sorted_memories.begin(), sorted_memories.end(), RTLIL::sort_by_name_str<RTLIL::Memory>());
-
- std::vector<RTLIL::Cell*> sorted_cells;
- for (auto it : module->cells())
- sorted_cells.push_back(it);
- std::sort(sorted_cells.begin(), sorted_cells.end(), RTLIL::sort_by_name_str<RTLIL::Cell>());
-
- std::vector<RTLIL::Process*> sorted_processes;
- for (auto it : module->processes)
- sorted_processes.push_back(it.second);
- std::sort(sorted_processes.begin(), sorted_processes.end(), RTLIL::sort_by_name_str<RTLIL::Process>());
-
- for (auto it : sorted_wires)
if (!only_selected || design->selected(module, it)) {
if (only_selected)
f << stringf("\n");
dump_wire(f, indent + " ", it);
}
- for (auto it : sorted_memories)
- if (!only_selected || design->selected(module, it)) {
+ for (auto it : module->memories)
+ if (!only_selected || design->selected(module, it.second)) {
if (only_selected)
f << stringf("\n");
- dump_memory(f, indent + " ", it);
+ dump_memory(f, indent + " ", it.second);
}
- for (auto it : sorted_cells)
+ for (auto it : module->cells())
if (!only_selected || design->selected(module, it)) {
if (only_selected)
f << stringf("\n");
dump_cell(f, indent + " ", it);
}
- for (auto it : sorted_processes)
- if (!only_selected || design->selected(module, it)) {
+ for (auto it : module->processes)
+ if (!only_selected || design->selected(module, it.second)) {
if (only_selected)
f << stringf("\n");
- dump_proc(f, indent + " ", it);
+ dump_proc(f, indent + " ", it.second);
}
bool first_conn_line = true;
- for (auto it = module->connections().begin(); it != module->connections().end(); it++) {
+ for (auto it = module->connections().begin(); it != module->connections().end(); ++it) {
bool show_conn = !only_selected;
if (only_selected) {
RTLIL::SigSpec sigs = it->first;
@@ -360,11 +336,13 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
{
+#ifndef NDEBUG
int init_autoidx = autoidx;
+#endif
if (!flag_m) {
int count_selected_mods = 0;
- for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
if (design->selected_whole_module(it->first))
flag_m = true;
if (design->selected(it->second))
@@ -380,7 +358,7 @@ void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
f << stringf("autoidx %d\n", autoidx);
}
- for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
if (!only_selected || design->selected(it->second)) {
if (only_selected)
f << stringf("\n");
@@ -391,6 +369,9 @@ void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
log_assert(init_autoidx == autoidx);
}
+YOSYS_NAMESPACE_END
+PRIVATE_NAMESPACE_BEGIN
+
struct IlangBackend : public Backend {
IlangBackend() : Backend("ilang", "write design to ilang file") { }
virtual void help()
@@ -423,6 +404,8 @@ struct IlangBackend : public Backend {
}
extra_args(f, filename, args, argidx);
+ design->sort();
+
log("Output filename: %s\n", filename.c_str());
*f << stringf("# Generated by %s\n", yosys_version_str);
ILANG_BACKEND::dump_design(*f, design, selected, true, false);
@@ -447,10 +430,10 @@ struct DumpPass : public Pass {
log(" -n\n");
log(" only dump the module headers if the entire module is selected\n");
log("\n");
- log(" -outfile <filename>\n");
+ log(" -o <filename>\n");
log(" write to the specified file.\n");
log("\n");
- log(" -append <filename>\n");
+ log(" -a <filename>\n");
log(" like -outfile but append instead of overwrite\n");
log("\n");
}
@@ -463,12 +446,12 @@ struct DumpPass : public Pass {
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
- if (arg == "-outfile" && argidx+1 < args.size()) {
+ if ((arg == "-o" || arg == "-outfile") && argidx+1 < args.size()) {
filename = args[++argidx];
append = false;
continue;
}
- if (arg == "-append" && argidx+1 < args.size()) {
+ if ((arg == "-a" || arg == "-append") && argidx+1 < args.size()) {
filename = args[++argidx];
append = true;
continue;
@@ -510,3 +493,4 @@ struct DumpPass : public Pass {
}
} DumpPass;
+PRIVATE_NAMESPACE_END
diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc
index 8502d90f..6d4731e7 100644
--- a/backends/intersynth/intersynth.cc
+++ b/backends/intersynth/intersynth.cc
@@ -24,6 +24,8 @@
#include "kernel/log.h"
#include <string>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
static std::string netname(std::set<std::string> &conntypes_code, std::set<std::string> &celltypes_code, std::set<std::string> &constcells_code, RTLIL::SigSpec sig)
{
@@ -215,3 +217,4 @@ struct IntersynthBackend : public Backend {
}
} IntersynthBackend;
+PRIVATE_NAMESPACE_END
diff --git a/backends/json/Makefile.inc b/backends/json/Makefile.inc
new file mode 100644
index 00000000..a463daf9
--- /dev/null
+++ b/backends/json/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += backends/json/json.o
+
diff --git a/backends/json/json.cc b/backends/json/json.cc
new file mode 100644
index 00000000..7d73fb11
--- /dev/null
+++ b/backends/json/json.cc
@@ -0,0 +1,407 @@
+/*
+ * 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/rtlil.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/log.h"
+#include <string>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct JsonWriter
+{
+ std::ostream &f;
+ bool use_selection;
+
+ Design *design;
+ Module *module;
+
+ SigMap sigmap;
+ int sigidcounter;
+ dict<SigBit, string> sigids;
+
+ JsonWriter(std::ostream &f, bool use_selection) : f(f), use_selection(use_selection) { }
+
+ string get_string(string str)
+ {
+ string newstr = "\"";
+ for (char c : str) {
+ if (c == '\\')
+ newstr += c;
+ newstr += c;
+ }
+ return newstr + "\"";
+ }
+
+ string get_name(IdString name)
+ {
+ return get_string(RTLIL::unescape_id(name));
+ }
+
+ string get_bits(SigSpec sig)
+ {
+ bool first = true;
+ string str = "[";
+ for (auto bit : sigmap(sig)) {
+ str += first ? " " : ", ";
+ first = false;
+ if (sigids.count(bit) == 0) {
+ string &s = sigids[bit];
+ if (bit.wire == nullptr) {
+ if (bit == State::S0) s = "\"0\"";
+ else if (bit == State::S1) s = "\"1\"";
+ else if (bit == State::Sz) s = "\"z\"";
+ else s = "\"x\"";
+ } else
+ s = stringf("%d", sigidcounter++);
+ }
+ str += sigids[bit];
+ }
+ return str + " ]";
+ }
+
+ void write_parameters(const dict<IdString, Const> &parameters)
+ {
+ bool first = true;
+ for (auto &param : parameters) {
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s: ", get_name(param.first).c_str());
+ if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
+ f << get_string(param.second.decode_string());
+ else if (GetSize(param.second.bits) > 32)
+ f << get_string(param.second.as_string());
+ else
+ f << stringf("%d", param.second.as_int());
+ first = false;
+ }
+ }
+
+ void write_module(Module *module_)
+ {
+ module = module_;
+ log_assert(module->design == design);
+ sigmap.set(module);
+ sigids.clear();
+
+ // reserve 0 and 1 to avoid confusion with "0" and "1"
+ sigidcounter = 2;
+
+ f << stringf(" %s: {\n", get_name(module->name).c_str());
+
+ f << stringf(" \"ports\": {");
+ bool first = true;
+ for (auto n : module->ports) {
+ Wire *w = module->wire(n);
+ if (use_selection && !module->selected(w))
+ continue;
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s: {\n", get_name(n).c_str());
+ f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
+ f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
+ f << stringf(" }");
+ first = false;
+ }
+ f << stringf("\n },\n");
+
+ f << stringf(" \"cells\": {");
+ first = true;
+ for (auto c : module->cells()) {
+ if (use_selection && !module->selected(c))
+ continue;
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s: {\n", get_name(c->name).c_str());
+ f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
+ f << stringf(" \"type\": %s,\n", get_name(c->type).c_str());
+ f << stringf(" \"parameters\": {");
+ write_parameters(c->parameters);
+ f << stringf("\n },\n");
+ f << stringf(" \"attributes\": {");
+ write_parameters(c->attributes);
+ f << stringf("\n },\n");
+ f << stringf(" \"connections\": {");
+ bool first2 = true;
+ for (auto &conn : c->connections()) {
+ f << stringf("%s\n", first2 ? "" : ",");
+ f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
+ first2 = false;
+ }
+ f << stringf("\n }\n");
+ f << stringf(" }");
+ first = false;
+ }
+ f << stringf("\n },\n");
+
+ f << stringf(" \"netnames\": {");
+ first = true;
+ for (auto w : module->wires()) {
+ if (use_selection && !module->selected(w))
+ continue;
+ f << stringf("%s\n", first ? "" : ",");
+ f << stringf(" %s: {\n", get_name(w->name).c_str());
+ f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
+ f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
+ f << stringf(" \"attributes\": {");
+ write_parameters(w->attributes);
+ f << stringf("\n }\n");
+ f << stringf(" }");
+ first = false;
+ }
+ f << stringf("\n }\n");
+
+ f << stringf(" }");
+ }
+
+ void write_design(Design *design_)
+ {
+ design = design_;
+ f << stringf("{\n");
+ f << stringf(" \"creator\": %s,\n", get_string(yosys_version_str).c_str());
+ f << stringf(" \"modules\": {\n");
+ vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
+ bool first_module = true;
+ for (auto mod : modules) {
+ if (!first_module)
+ f << stringf(",\n");
+ write_module(mod);
+ first_module = false;
+ }
+ f << stringf("\n }\n");
+ f << stringf("}\n");
+ }
+};
+
+struct JsonBackend : public Backend {
+ JsonBackend() : Backend("json", "write design to a JSON file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_json [options] [filename]\n");
+ log("\n");
+ log("Write a JSON netlist of the current design.\n");
+ log("\n");
+ log("The general syntax of the JSON output created by this command is as follows:\n");
+ log("\n");
+ log(" {\n");
+ log(" \"modules\": {\n");
+ log(" <module_name>: {\n");
+ log(" \"ports\": {\n");
+ log(" <port_name>: <port_details>,\n");
+ log(" ...\n");
+ log(" },\n");
+ log(" \"cells\": {\n");
+ log(" <cell_name>: <cell_details>,\n");
+ log(" ...\n");
+ log(" },\n");
+ log(" \"netnames\": {\n");
+ log(" <net_name>: <net_details>,\n");
+ log(" ...\n");
+ log(" }\n");
+ log(" }\n");
+ log(" }\n");
+ log(" }\n");
+ log("\n");
+ log("Where <port_details> is:\n");
+ log("\n");
+ log(" {\n");
+ log(" \"direction\": <\"input\" | \"output\" | \"inout\">,\n");
+ log(" \"bits\": <bit_vector>\n");
+ log(" }\n");
+ log("\n");
+ log("And <cell_details> is:\n");
+ log("\n");
+ log(" {\n");
+ log(" \"hide_name\": <1 | 0>,\n");
+ log(" \"type\": <cell_type>,\n");
+ log(" \"parameters\": {\n");
+ log(" <parameter_name>: <parameter_value>,\n");
+ log(" ...\n");
+ log(" },\n");
+ log(" \"attributes\": {\n");
+ log(" <attribute_name>: <attribute_value>,\n");
+ log(" ...\n");
+ log(" },\n");
+ log(" \"connections\": {\n");
+ log(" <port_name>: <bit_vector>,\n");
+ log(" ...\n");
+ log(" },\n");
+ log(" }\n");
+ log("\n");
+ log("And <net_details> is:\n");
+ log("\n");
+ log(" {\n");
+ log(" \"hide_name\": <1 | 0>,\n");
+ log(" \"bits\": <bit_vector>\n");
+ log(" }\n");
+ log("\n");
+ log("The \"hide_name\" fields are set to 1 when the name of this cell or net is\n");
+ log("automatically created and is likely not of interest for a regular user.\n");
+ log("\n");
+ log("Module and cell ports and nets can be single bit wide or vectors of multiple\n");
+ log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n");
+ log("values referenced above are vectors of this integers. Signal bits that are\n");
+ log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
+ log("a number.\n");
+ log("\n");
+ log("For example the following verilog code:\n");
+ log("\n");
+ log(" module test(input x, y);\n");
+ log(" (* keep *) foo #(.P(42), .Q(1337))\n");
+ log(" foo_inst (.A({x, y}), .B({y, x}), .C({4'd10, {4{x}}}));\n");
+ log(" endmodule\n");
+ log("\n");
+ log("Translates to the following JSON output:\n");
+ log("\n");
+ log(" {\n");
+ log(" \"modules\": {\n");
+ log(" \"test\": {\n");
+ log(" \"ports\": {\n");
+ log(" \"x\": {\n");
+ log(" \"direction\": \"input\",\n");
+ log(" \"bits\": [ 2 ]\n");
+ log(" },\n");
+ log(" \"y\": {\n");
+ log(" \"direction\": \"input\",\n");
+ log(" \"bits\": [ 3 ]\n");
+ log(" }\n");
+ log(" },\n");
+ log(" \"cells\": {\n");
+ log(" \"foo_inst\": {\n");
+ log(" \"hide_name\": 0,\n");
+ log(" \"type\": \"foo\",\n");
+ log(" \"parameters\": {\n");
+ log(" \"Q\": 1337,\n");
+ log(" \"P\": 42\n");
+ log(" },\n");
+ log(" \"attributes\": {\n");
+ log(" \"keep\": 1,\n");
+ log(" \"src\": \"test.v:2\"\n");
+ log(" },\n");
+ log(" \"connections\": {\n");
+ log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ],\n");
+ log(" \"B\": [ 2, 3 ],\n");
+ log(" \"A\": [ 3, 2 ]\n");
+ log(" }\n");
+ log(" }\n");
+ log(" },\n");
+ log(" \"netnames\": {\n");
+ log(" \"y\": {\n");
+ log(" \"hide_name\": 0,\n");
+ log(" \"bits\": [ 3 ],\n");
+ log(" \"attributes\": {\n");
+ log(" \"src\": \"test.v:1\"\n");
+ log(" }\n");
+ log(" },\n");
+ log(" \"x\": {\n");
+ log(" \"hide_name\": 0,\n");
+ log(" \"bits\": [ 2 ],\n");
+ log(" \"attributes\": {\n");
+ log(" \"src\": \"test.v:1\"\n");
+ log(" }\n");
+ log(" }\n");
+ log(" }\n");
+ log(" }\n");
+ log(" }\n");
+ log(" }\n");
+ log("\n");
+ log("Future version of Yosys might add support for additional fields in the JSON\n");
+ log("format. A program processing this format must ignore all unkown fields.\n");
+ log("\n");
+ }
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-verbose") {
+ // verbose = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ log_header("Executing JSON backend.\n");
+
+ JsonWriter json_writer(*f, false);
+ json_writer.write_design(design);
+ }
+} JsonBackend;
+
+struct JsonPass : public Pass {
+ JsonPass() : Pass("json", "write design in JSON format") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" json [options] [selection]\n");
+ log("\n");
+ log("Write a JSON netlist of all selected objects.\n");
+ log("\n");
+ log(" -o <filename>\n");
+ log(" write to the specified file.\n");
+ log("\n");
+ log("See 'help write_json' for a description of the JSON format used.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::string filename;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-o" && argidx+1 < args.size()) {
+ filename = args[++argidx];
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ std::ostream *f;
+ std::stringstream buf;
+
+ if (!filename.empty()) {
+ std::ofstream *ff = new std::ofstream;
+ ff->open(filename.c_str(), std::ofstream::trunc);
+ if (ff->fail()) {
+ delete ff;
+ log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ }
+ f = ff;
+ } else {
+ f = &buf;
+ }
+
+ JsonWriter json_writer(*f, true);
+ json_writer.write_design(design);
+
+ if (!filename.empty()) {
+ delete f;
+ } else {
+ log("%s", buf.str().c_str());
+ }
+ }
+} JsonPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/backends/smt2/.gitignore b/backends/smt2/.gitignore
new file mode 100644
index 00000000..313ea0a1
--- /dev/null
+++ b/backends/smt2/.gitignore
@@ -0,0 +1 @@
+test_cells
diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc
new file mode 100644
index 00000000..4e0a393a
--- /dev/null
+++ b/backends/smt2/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += backends/smt2/smt2.o
+
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
new file mode 100644
index 00000000..3d872c63
--- /dev/null
+++ b/backends/smt2/smt2.cc
@@ -0,0 +1,711 @@
+/*
+ * 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/rtlil.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/log.h"
+#include <string>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Smt2Worker
+{
+ CellTypes ct;
+ SigMap sigmap;
+ RTLIL::Module *module;
+ bool bvmode, verbose;
+ int idcounter;
+
+ std::vector<std::string> decls, trans;
+ std::map<RTLIL::SigBit, RTLIL::Cell*> bit_driver;
+ std::set<RTLIL::Cell*> exported_cells;
+ pool<Cell*> recursive_cells, registers;
+
+ std::map<RTLIL::SigBit, std::pair<int, int>> fcache;
+ std::map<int, int> bvsizes;
+
+ Smt2Worker(RTLIL::Module *module, bool bvmode, bool verbose) :
+ ct(module->design), sigmap(module), module(module), bvmode(bvmode), verbose(verbose), idcounter(0)
+ {
+ decls.push_back(stringf("(declare-sort |%s_s| 0)\n", log_id(module)));
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections()) {
+ bool is_input = ct.cell_input(cell->type, conn.first);
+ bool is_output = ct.cell_output(cell->type, conn.first);
+ if (is_output && !is_input)
+ for (auto bit : sigmap(conn.second)) {
+ if (bit_driver.count(bit))
+ log_error("Found multiple drivers for %s.\n", log_signal(bit));
+ bit_driver[bit] = cell;
+ }
+ else if (is_output || !is_input)
+ log_error("Unsupported or unknown directionality on port %s of cell %s.%s (%s).\n",
+ log_id(conn.first), log_id(module), log_id(cell), log_id(cell->type));
+ }
+ }
+
+ void register_bool(RTLIL::SigBit bit, int id)
+ {
+ if (verbose) log("%*s-> register_bool: %s %d\n", 2+2*GetSize(recursive_cells), "",
+ log_signal(bit), id);
+
+ sigmap.apply(bit);
+ log_assert(fcache.count(bit) == 0);
+ fcache[bit] = std::pair<int, int>(id, -1);
+ }
+
+ void register_bv(RTLIL::SigSpec sig, int id)
+ {
+ if (verbose) log("%*s-> register_bv: %s %d\n", 2+2*GetSize(recursive_cells), "",
+ log_signal(sig), id);
+
+ log_assert(bvmode);
+ sigmap.apply(sig);
+
+ log_assert(bvsizes.count(id) == 0);
+ bvsizes[id] = GetSize(sig);
+
+ for (int i = 0; i < GetSize(sig); i++) {
+ log_assert(fcache.count(sig[i]) == 0);
+ fcache[sig[i]] = std::pair<int, int>(id, i);
+ }
+ }
+
+ void register_boolvec(RTLIL::SigSpec sig, int id)
+ {
+ if (verbose) log("%*s-> register_boolvec: %s %d\n", 2+2*GetSize(recursive_cells), "",
+ log_signal(sig), id);
+
+ log_assert(bvmode);
+ sigmap.apply(sig);
+ register_bool(sig[0], id);
+
+ for (int i = 1; i < GetSize(sig); i++)
+ sigmap.add(sig[i], RTLIL::State::S0);
+ }
+
+ std::string get_bool(RTLIL::SigBit bit, const char *state_name = "state")
+ {
+ sigmap.apply(bit);
+
+ if (bit.wire == nullptr)
+ return bit == RTLIL::State::S1 ? "true" : "false";
+
+ if (bit_driver.count(bit))
+ export_cell(bit_driver.at(bit));
+ sigmap.apply(bit);
+
+ if (fcache.count(bit) == 0) {
+ if (verbose) log("%*s-> external bool: %s\n", 2+2*GetSize(recursive_cells), "",
+ log_signal(bit));
+ decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
+ log_id(module), idcounter, log_id(module), log_signal(bit)));
+ register_bool(bit, idcounter++);
+ }
+
+ auto f = fcache.at(bit);
+ if (f.second >= 0)
+ return stringf("(= ((_ extract %d %d) (|%s#%d| %s)) #b1)", f.second, f.second, log_id(module), f.first, state_name);
+ return stringf("(|%s#%d| %s)", log_id(module), f.first, state_name);
+ }
+
+ std::string get_bool(RTLIL::SigSpec sig, const char *state_name = "state")
+ {
+ return get_bool(sig.to_single_sigbit(), state_name);
+ }
+
+ std::string get_bv(RTLIL::SigSpec sig, const char *state_name = "state")
+ {
+ log_assert(bvmode);
+ sigmap.apply(sig);
+
+ std::vector<std::string> subexpr;
+
+ SigSpec orig_sig;
+ while (orig_sig != sig) {
+ for (auto bit : sig)
+ if (bit_driver.count(bit))
+ export_cell(bit_driver.at(bit));
+ orig_sig = sig;
+ sigmap.apply(sig);
+ }
+
+ for (int i = 0, j = 1; i < GetSize(sig); i += j, j = 1)
+ {
+ if (sig[i].wire == nullptr) {
+ while (i+j < GetSize(sig) && sig[i+j].wire == nullptr) j++;
+ subexpr.push_back("#b");
+ for (int k = i+j-1; k >= i; k--)
+ subexpr.back() += sig[k] == RTLIL::State::S1 ? "1" : "0";
+ continue;
+ }
+
+ if (fcache.count(sig[i]) && fcache.at(sig[i]).second == -1) {
+ subexpr.push_back(stringf("(ite %s #b1 #b0)", get_bool(sig[i], state_name).c_str()));
+ continue;
+ }
+
+ if (fcache.count(sig[i])) {
+ auto t1 = fcache.at(sig[i]);
+ while (i+j < GetSize(sig)) {
+ if (fcache.count(sig[i+j]) == 0)
+ break;
+ auto t2 = fcache.at(sig[i+j]);
+ if (t1.first != t2.first)
+ break;
+ if (t1.second+j != t2.second)
+ break;
+ j++;
+ }
+ if (t1.second == 0 && j == bvsizes.at(t1.first))
+ subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), t1.first, state_name));
+ else
+ subexpr.push_back(stringf("((_ extract %d %d) (|%s#%d| %s))",
+ t1.second + j - 1, t1.second, log_id(module), t1.first, state_name));
+ continue;
+ }
+
+ std::set<RTLIL::SigBit> seen_bits = { sig[i] };
+ while (i+j < GetSize(sig) && sig[i+j].wire && !fcache.count(sig[i+j]) && !seen_bits.count(sig[i+j]))
+ seen_bits.insert(sig[i+j]), j++;
+
+ if (verbose) log("%*s-> external bv: %s\n", 2+2*GetSize(recursive_cells), "",
+ log_signal(sig.extract(i, j)));
+ for (auto bit : sig.extract(i, j))
+ log_assert(bit_driver.count(bit) == 0);
+ decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
+ log_id(module), idcounter, log_id(module), j, log_signal(sig.extract(i, j))));
+ subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), idcounter, state_name));
+ register_bv(sig.extract(i, j), idcounter++);
+ }
+
+ if (GetSize(subexpr) > 1) {
+ std::string expr = "(concat";
+ for (int i = GetSize(subexpr)-1; i >= 0; i--)
+ expr += " " + subexpr[i];
+ return expr + ")";
+ } else {
+ log_assert(GetSize(subexpr) == 1);
+ return subexpr[0];
+ }
+ }
+
+ void export_gate(RTLIL::Cell *cell, std::string expr)
+ {
+ RTLIL::SigBit bit = sigmap(cell->getPort("\\Y").to_single_sigbit());
+ std::string processed_expr;
+
+ for (char ch : expr) {
+ if (ch == 'A') processed_expr += get_bool(cell->getPort("\\A"));
+ else if (ch == 'B') processed_expr += get_bool(cell->getPort("\\B"));
+ else if (ch == 'C') processed_expr += get_bool(cell->getPort("\\C"));
+ else if (ch == 'D') processed_expr += get_bool(cell->getPort("\\D"));
+ else if (ch == 'S') processed_expr += get_bool(cell->getPort("\\S"));
+ else processed_expr += ch;
+ }
+
+ if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
+ log_id(cell));
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
+ log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(bit)));
+ register_bool(bit, idcounter++);
+ recursive_cells.erase(cell);
+ }
+
+ void export_bvop(RTLIL::Cell *cell, std::string expr, char type = 0)
+ {
+ RTLIL::SigSpec sig_a, sig_b;
+ RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ int width = GetSize(sig_y);
+
+ if (type == 's' || type == 'd' || type == 'b') {
+ width = std::max(width, GetSize(cell->getPort("\\A")));
+ width = std::max(width, GetSize(cell->getPort("\\B")));
+ }
+
+ if (cell->hasPort("\\A")) {
+ sig_a = cell->getPort("\\A");
+ sig_a.extend_u0(width, is_signed);
+ }
+
+ if (cell->hasPort("\\B")) {
+ sig_b = cell->getPort("\\B");
+ sig_b.extend_u0(width, is_signed && !(type == 's'));
+ }
+
+ std::string processed_expr;
+
+ 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 == 'L') processed_expr += is_signed ? "a" : "l";
+ else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
+ else processed_expr += ch;
+ }
+
+ if (width != GetSize(sig_y) && type != 'b')
+ processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr.c_str());
+
+ if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
+ log_id(cell));
+
+ if (type == 'b') {
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
+ log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y)));
+ register_boolvec(sig_y, idcounter++);
+ } else {
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ log_id(module), idcounter, log_id(module), GetSize(sig_y), processed_expr.c_str(), log_signal(sig_y)));
+ register_bv(sig_y, idcounter++);
+ }
+
+ recursive_cells.erase(cell);
+ }
+
+ void export_reduce(RTLIL::Cell *cell, std::string expr, bool identity_val)
+ {
+ RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+ std::string processed_expr;
+
+ for (char ch : expr)
+ if (ch == 'A' || ch == 'B') {
+ RTLIL::SigSpec sig = sigmap(cell->getPort(stringf("\\%c", ch)));
+ for (auto bit : sig)
+ processed_expr += " " + get_bool(bit);
+ if (GetSize(sig) == 1)
+ processed_expr += identity_val ? " true" : " false";
+ } else
+ processed_expr += ch;
+
+ if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
+ log_id(cell));
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
+ log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y)));
+ register_boolvec(sig_y, idcounter++);
+ recursive_cells.erase(cell);
+ }
+
+ void export_cell(RTLIL::Cell *cell)
+ {
+ if (verbose) log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "",
+ log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new");
+
+ if (recursive_cells.count(cell))
+ log_error("Found logic loop in module %s! See cell %s.\n", log_id(module), log_id(cell));
+
+ if (exported_cells.count(cell))
+ return;
+ exported_cells.insert(cell);
+ recursive_cells.insert(cell);
+
+ if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_")
+ {
+ registers.insert(cell);
+ decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
+ log_id(module), idcounter, log_id(module), log_signal(cell->getPort("\\Q"))));
+ register_bool(cell->getPort("\\Q"), idcounter++);
+ recursive_cells.erase(cell);
+ return;
+ }
+
+ if (cell->type == "$_BUF_") return export_gate(cell, "A");
+ if (cell->type == "$_NOT_") return export_gate(cell, "(not A)");
+ if (cell->type == "$_AND_") return export_gate(cell, "(and A B)");
+ if (cell->type == "$_NAND_") return export_gate(cell, "(not (and A B))");
+ if (cell->type == "$_OR_") return export_gate(cell, "(or A B)");
+ if (cell->type == "$_NOR_") return export_gate(cell, "(not (or A B))");
+ if (cell->type == "$_XOR_") return export_gate(cell, "(xor A B)");
+ if (cell->type == "$_XNOR_") return export_gate(cell, "(not (xor A B))");
+ if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)");
+ if (cell->type == "$_AOI3_") return export_gate(cell, "(not (or (and A B) C))");
+ if (cell->type == "$_OAI3_") return export_gate(cell, "(not (and (or A B) C))");
+ if (cell->type == "$_AOI4_") return export_gate(cell, "(not (or (and A B) (and C D)))");
+ if (cell->type == "$_OAI4_") return export_gate(cell, "(not (and (or A B) (or C D)))");
+
+ // FIXME: $lut
+
+ if (!bvmode)
+ log_error("Unsupported cell type %s for cell %s.%s. (Maybe this cell type would be supported in -bv mode?)\n",
+ log_id(cell->type), log_id(module), log_id(cell));
+
+ if (cell->type == "$dff")
+ {
+ registers.insert(cell);
+ decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
+ log_id(module), idcounter, log_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))));
+ register_bv(cell->getPort("\\Q"), idcounter++);
+ recursive_cells.erase(cell);
+ return;
+ }
+
+ if (cell->type == "$and") return export_bvop(cell, "(bvand A B)");
+ if (cell->type == "$or") return export_bvop(cell, "(bvor A B)");
+ if (cell->type == "$xor") return export_bvop(cell, "(bvxor A B)");
+ if (cell->type == "$xnor") return export_bvop(cell, "(bvxnor A B)");
+
+ if (cell->type == "$shl") return export_bvop(cell, "(bvshl A B)", 's');
+ if (cell->type == "$shr") return export_bvop(cell, "(bvlshr A B)", 's');
+ if (cell->type == "$sshl") return export_bvop(cell, "(bvshl A B)", 's');
+ if (cell->type == "$sshr") return export_bvop(cell, "(bvLshr A B)", 's');
+
+ // FIXME: $shift $shiftx
+
+ if (cell->type == "$lt") return export_bvop(cell, "(bvUlt A B)", 'b');
+ if (cell->type == "$le") return export_bvop(cell, "(bvUle A B)", 'b');
+ if (cell->type == "$ge") return export_bvop(cell, "(bvUge A B)", 'b');
+ if (cell->type == "$gt") return export_bvop(cell, "(bvUgt A B)", 'b');
+
+ if (cell->type == "$ne") return export_bvop(cell, "(distinct A B)", 'b');
+ if (cell->type == "$nex") return export_bvop(cell, "(distinct A B)", 'b');
+ if (cell->type == "$eq") return export_bvop(cell, "(= A B)", 'b');
+ if (cell->type == "$eqx") return export_bvop(cell, "(= A B)", 'b');
+
+ if (cell->type == "$not") return export_bvop(cell, "(bvnot A)");
+ if (cell->type == "$pos") return export_bvop(cell, "A");
+ if (cell->type == "$neg") return export_bvop(cell, "(bvneg A)");
+
+ if (cell->type == "$add") return export_bvop(cell, "(bvadd A B)");
+ if (cell->type == "$sub") return export_bvop(cell, "(bvsub A B)");
+ if (cell->type == "$mul") return export_bvop(cell, "(bvmul A B)");
+ if (cell->type == "$div") return export_bvop(cell, "(bvUdiv A B)", 'd');
+ if (cell->type == "$mod") return export_bvop(cell, "(bvUrem A B)", 'd');
+
+ if (cell->type == "$reduce_and") return export_reduce(cell, "(and A)", true);
+ if (cell->type == "$reduce_or") return export_reduce(cell, "(or A)", false);
+ if (cell->type == "$reduce_xor") return export_reduce(cell, "(xor A)", false);
+ if (cell->type == "$reduce_xnor") return export_reduce(cell, "(not (xor A))", false);
+ if (cell->type == "$reduce_bool") return export_reduce(cell, "(or A)", false);
+
+ if (cell->type == "$logic_not") return export_reduce(cell, "(not (or A))", false);
+ if (cell->type == "$logic_and") return export_reduce(cell, "(and (or A) (or B))", false);
+ if (cell->type == "$logic_or") return export_reduce(cell, "(or A B)", false);
+
+ if (cell->type == "$mux" || cell->type == "$pmux")
+ {
+ int width = GetSize(cell->getPort("\\Y"));
+ std::string processed_expr = get_bv(cell->getPort("\\A"));
+
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_s = cell->getPort("\\S");
+ get_bv(sig_b);
+ get_bv(sig_s);
+
+ for (int i = 0; i < GetSize(sig_s); i++)
+ processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]).c_str(),
+ get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str());
+
+ if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
+ log_id(cell));
+ RTLIL::SigSpec sig = sigmap(cell->getPort("\\Y"));
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ log_id(module), idcounter, log_id(module), width, processed_expr.c_str(), log_signal(sig)));
+ register_bv(sig, idcounter++);
+ recursive_cells.erase(cell);
+ return;
+ }
+
+ // FIXME: $slice $concat
+
+ log_error("Unsupported cell type %s for cell %s.%s.\n",
+ log_id(cell->type), log_id(module), log_id(cell));
+ }
+
+ void run()
+ {
+ if (verbose) log("=> export logic driving outputs\n");
+
+ for (auto wire : module->wires())
+ if (wire->port_id || wire->get_bool_attribute("\\keep")) {
+ RTLIL::SigSpec sig = sigmap(wire);
+ if (bvmode && GetSize(sig) > 1) {
+ decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) (_ BitVec %d) %s)\n",
+ log_id(module), log_id(wire), log_id(module), GetSize(sig), get_bv(sig).c_str()));
+ } else {
+ for (int i = 0; i < GetSize(sig); i++)
+ if (GetSize(sig) > 1)
+ decls.push_back(stringf("(define-fun |%s_n %s %d| ((state |%s_s|)) Bool %s)\n",
+ log_id(module), log_id(wire), i, log_id(module), get_bool(sig[i]).c_str()));
+ else
+ decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) Bool %s)\n",
+ log_id(module), log_id(wire), log_id(module), get_bool(sig[i]).c_str()));
+ }
+ }
+
+ if (verbose) log("=> export logic associated with the initial state\n");
+
+ vector<string> init_list;
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init")) {
+ RTLIL::SigSpec sig = sigmap(wire);
+ Const val = wire->attributes.at("\\init");
+ val.bits.resize(GetSize(sig));
+ if (bvmode && GetSize(sig) > 1) {
+ init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), log_id(wire)));
+ } else {
+ for (int i = 0; i < GetSize(sig); i++)
+ init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val.bits[i] == State::S1 ? "true" : "false", log_id(wire)));
+ }
+ }
+
+ if (verbose) log("=> export logic driving asserts\n");
+
+ vector<int> assert_list, assume_list;
+ for (auto cell : module->cells())
+ if (cell->type.in("$assert", "$assume")) {
+ string name_a = get_bool(cell->getPort("\\A"));
+ string name_en = get_bool(cell->getPort("\\EN"));
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n",
+ log_id(module), idcounter, log_id(module), name_a.c_str(), name_en.c_str(), log_id(cell)));
+ if (cell->type == "$assert")
+ assert_list.push_back(idcounter++);
+ else
+ assume_list.push_back(idcounter++);
+ }
+
+ for (int iter = 1; !registers.empty(); iter++)
+ {
+ pool<Cell*> this_regs;
+ this_regs.swap(registers);
+
+ if (verbose) log("=> export logic driving registers [iteration %d]\n", iter);
+
+ for (auto cell : this_regs) {
+ if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_") {
+ std::string expr_d = get_bool(cell->getPort("\\D"));
+ std::string expr_q = get_bool(cell->getPort("\\Q"), "next_state");
+ trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));
+ }
+ if (cell->type == "$dff") {
+ std::string expr_d = get_bv(cell->getPort("\\D"));
+ std::string expr_q = get_bv(cell->getPort("\\Q"), "next_state");
+ trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));
+ }
+ }
+ }
+
+ string assert_expr = assert_list.empty() ? "true" : "(and";
+ if (!assert_list.empty()) {
+ for (int i : assert_list)
+ assert_expr += stringf(" (|%s#%d| state)", log_id(module), i);
+ assert_expr += ")";
+ }
+ decls.push_back(stringf("(define-fun |%s_a| ((state |%s_s|)) Bool %s)\n",
+ log_id(module), log_id(module), assert_expr.c_str()));
+
+ string assume_expr = assume_list.empty() ? "true" : "(and";
+ if (!assume_list.empty()) {
+ for (int i : assume_list)
+ assume_expr += stringf(" (|%s#%d| state)", log_id(module), i);
+ assume_expr += ")";
+ }
+ decls.push_back(stringf("(define-fun |%s_u| ((state |%s_s|)) Bool %s)\n",
+ log_id(module), log_id(module), assume_expr.c_str()));
+
+ string init_expr = init_list.empty() ? "true" : "(and";
+ if (!init_list.empty()) {
+ for (auto &str : init_list)
+ init_expr += stringf("\n\t%s", str.c_str());
+ init_expr += "\n)";
+ }
+ decls.push_back(stringf("(define-fun |%s_i| ((state |%s_s|)) Bool %s)\n",
+ log_id(module), log_id(module), init_expr.c_str()));
+ }
+
+ void write(std::ostream &f)
+ {
+ for (auto it : decls)
+ f << it;
+
+ f << stringf("(define-fun |%s_t| ((state |%s_s|) (next_state |%s_s|)) Bool ", log_id(module), log_id(module), log_id(module));
+ if (GetSize(trans) > 1) {
+ f << "(and\n";
+ for (auto it : trans)
+ f << it;
+ f << "))";
+ } else
+ if (GetSize(trans) == 1)
+ f << "\n" + trans.front() + ")";
+ else
+ f << "true)";
+ f << stringf(" ; end of module %s\n", log_id(module));
+ }
+};
+
+struct Smt2Backend : public Backend {
+ Smt2Backend() : Backend("smt2", "write design to SMT-LIBv2 file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_smt2 [options] [filename]\n");
+ log("\n");
+ log("Write a SMT-LIBv2 [1] description of the current design. For a module with name\n");
+ log("'<mod>' this will declare the sort '<mod>_s' (state of the module) and the\n");
+ log("functions operating on that state.\n");
+ log("\n");
+ log("The '<mod>_s' sort represents a module state. Additional '<mod>_n' functions\n");
+ log("are provided that can be used to access the values of the signals in the module.\n");
+ log("Only ports, and signals with the 'keep' attribute set are made available via\n");
+ log("such functions. Without the -bv option, multi-bit wires are exported as\n");
+ log("separate functions of type Bool for the individual bits. With the -bv option\n");
+ log("multi-bit wires are exported as single functions of type BitVec.\n");
+ log("\n");
+ log("The '<mod>_t' function evaluates to 'true' when the given pair of states\n");
+ log("describes a valid state transition.\n");
+ log("\n");
+ log("The '<mod>_a' function evaluates to 'true' when the given state satisfies\n");
+ log("the asserts in the module.\n");
+ log("\n");
+ log("The '<mod>_u' function evaluates to 'true' when the given state satisfies\n");
+ log("the assumptions in the module.\n");
+ log("\n");
+ log("The '<mod>_i' function evaluates to 'true' when the given state conforms\n");
+ log("to the initial state.\n");
+ log("\n");
+ log(" -verbose\n");
+ log(" this will print the recursive walk used to export the modules.\n");
+ log("\n");
+ log(" -bv\n");
+ log(" enable support for BitVec (FixedSizeBitVectors theory). with this\n");
+ log(" option set multi-bit wires are represented using the BitVec sort and\n");
+ log(" support for coarse grain cells (incl. arithmetic) is enabled.\n");
+ log("\n");
+ log(" -tpl <template_file>\n");
+ log(" use the given template file. the line containing only the token '%%%%'\n");
+ log(" is replaced with the regular output of this command.\n");
+ log("\n");
+ log("[1] For more information on SMT-LIBv2 visit http://smt-lib.org/ or read David\n");
+ log("R. Cok's tutorial: http://www.grammatech.com/resources/smt/SMTLIBTutorial.pdf\n");
+ log("\n");
+ log("---------------------------------------------------------------------------\n");
+ log("\n");
+ log("Example:\n");
+ log("\n");
+ log("Consider the following module (test.v). We want to prove that the output can\n");
+ log("never transition from a non-zero value to a zero value.\n");
+ log("\n");
+ log(" module test(input clk, output reg [3:0] y);\n");
+ log(" always @(posedge clk)\n");
+ log(" y <= (y << 1) | ^y;\n");
+ log(" endmodule\n");
+ log("\n");
+ log("For this proof we create the following template (test.tpl).\n");
+ log("\n");
+ log(" ; we need QF_UFBV for this poof\n");
+ log(" (set-logic QF_UFBV)\n");
+ log("\n");
+ log(" ; insert the auto-generated code here\n");
+ log(" %%%%\n");
+ log("\n");
+ log(" ; declare two state variables s1 and s2\n");
+ log(" (declare-fun s1 () test_s)\n");
+ log(" (declare-fun s2 () test_s)\n");
+ log("\n");
+ log(" ; state s2 is the successor of state s1\n");
+ log(" (assert (test_t s1 s2))\n");
+ log("\n");
+ log(" ; we are looking for a model with y non-zero in s1\n");
+ log(" (assert (distinct (|test_n y| s1) #b0000))\n");
+ log("\n");
+ log(" ; we are looking for a model with y zero in s2\n");
+ log(" (assert (= (|test_n y| s2) #b0000))\n");
+ log("\n");
+ log(" ; is there such a model?\n");
+ log(" (check-sat)\n");
+ log("\n");
+ log("The following yosys script will create a 'test.smt2' file for our proof:\n");
+ log("\n");
+ log(" read_verilog test.v\n");
+ log(" hierarchy -check; proc; opt; check -assert\n");
+ log(" write_smt2 -bv -tpl test.tpl test.smt2\n");
+ log("\n");
+ log("Running 'cvc4 test.smt2' will print 'unsat' because y can never transition\n");
+ log("from non-zero to zero in the test design.\n");
+ log("\n");
+ }
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::ifstream template_f;
+ bool bvmode = false, verbose = false;
+
+ log_header("Executing SMT2 backend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-tpl" && argidx+1 < args.size()) {
+ template_f.open(args[++argidx]);
+ if (template_f.fail())
+ log_error("Can't open template file `%s'.\n", args[argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-bv") {
+ bvmode = true;
+ continue;
+ }
+ if (args[argidx] == "-verbose") {
+ verbose = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ if (template_f.is_open()) {
+ std::string line;
+ while (std::getline(template_f, line)) {
+ int indent = 0;
+ while (indent < GetSize(line) && (line[indent] == ' ' || line[indent] == '\t'))
+ indent++;
+ if (line.substr(indent, 2) == "%%")
+ break;
+ *f << line << std::endl;
+ }
+ }
+
+ *f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_version_str);
+
+ for (auto module : design->modules())
+ {
+ if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn())
+ continue;
+
+ log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));
+
+ Smt2Worker worker(module, bvmode, verbose);
+ worker.run();
+ worker.write(*f);
+ }
+
+ *f << stringf("; end of yosys output\n");
+
+ if (template_f.is_open()) {
+ std::string line;
+ while (std::getline(template_f, line))
+ *f << line << std::endl;
+ }
+ }
+} Smt2Backend;
+
+PRIVATE_NAMESPACE_END
diff --git a/backends/smt2/test_cells.sh b/backends/smt2/test_cells.sh
new file mode 100644
index 00000000..34adb7af
--- /dev/null
+++ b/backends/smt2/test_cells.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+set -ex
+
+rm -rf test_cells
+mkdir test_cells
+cd test_cells
+
+../../../yosys -p 'test_cell -muxdiv -w test all /$alu /$macc /$fa /$lcu /$lut /$shift /$shiftx'
+
+cat > miter.tpl <<- EOT
+; #model# (set-option :produce-models true)
+(set-logic QF_UFBV)
+%%
+(declare-fun s () miter_s)
+(assert (|miter_n trigger| s))
+(check-sat)
+; #model# (get-value ((|miter_n in_A| s) (|miter_n in_B| s) (|miter_n gold_Y| s) (|miter_n gate_Y| s) (|miter_n trigger| s)))
+EOT
+
+for x in $(set +x; ls test_*.il | sort -R); do
+ x=${x%.il}
+ cat > $x.ys <<- EOT
+ read_ilang $x.il
+ copy gold gate
+
+ cd gate
+ techmap; opt; abc;;
+ cd ..
+
+ miter -equiv -flatten -make_outputs gold gate miter
+ hierarchy -check -top miter
+
+ dump
+ write_smt2 -bv -tpl miter.tpl $x.smt2
+ EOT
+ ../../../yosys -q $x.ys
+ if ! cvc4 $x.smt2 > $x.result; then
+ cat $x.result
+ exit 1
+ fi
+ if ! grep unsat $x.result; then
+ echo "Proof failed! Extracting model..."
+ sed -i 's/^; #model# //' $x.smt2
+ cvc4 $x.smt2
+ exit 1
+ fi
+done
+
+set +x
+echo ""
+echo " All tests passed."
+echo ""
+exit 0
+
diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc
index b057063c..2c614178 100644
--- a/backends/spice/spice.cc
+++ b/backends/spice/spice.cc
@@ -24,6 +24,9 @@
#include "kernel/log.h"
#include <string>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter)
{
if (s.wire) {
@@ -55,7 +58,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
if (design->modules_.count(cell->type) == 0)
{
- log("Warning: no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
+ log_warning("no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
RTLIL::id2cstr(cell->type), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name));
for (auto &conn : cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
@@ -81,7 +84,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
RTLIL::SigSpec sig(RTLIL::State::Sz, wire->width);
if (cell->hasPort(wire->name)) {
sig = sigmap(cell->getPort(wire->name));
- sig.extend(wire->width, false);
+ sig.extend_u0(wire->width, false);
}
port_sigs.push_back(sig);
}
@@ -231,3 +234,4 @@ struct SpiceBackend : public Backend {
}
} SpiceBackend;
+PRIVATE_NAMESPACE_END
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index bbdbbbfa..ba57e881 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -26,7 +26,6 @@
*
*/
-#include "verilog_backend.h"
#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
@@ -35,7 +34,8 @@
#include <set>
#include <map>
-namespace {
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
bool norename, noattr, attr2comment, noexpr;
int auto_name_counter, auto_name_offset, auto_name_digits;
@@ -51,16 +51,17 @@ void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
if (*str == '$' && may_rename && !norename)
auto_name_map[id] = auto_name_counter++;
- if (str[0] != '_' && str[1] != 0)
+ if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
return;
- for (int i = 0; str[i] != 0; i++) {
- if (str[i] == '_')
+
+ for (int i = 2; str[i] != 0; i++) {
+ if (str[i] == '_' && str[i+1] == 0)
continue;
if (str[i] < '0' || str[i] > '9')
return;
}
- int num = atoi(str+1);
+ int num = atoi(str+2);
if (num >= auto_name_offset)
auto_name_offset = num + 1;
}
@@ -73,22 +74,22 @@ void reset_auto_counter(RTLIL::Module *module)
reset_auto_counter_id(module->name, false);
- for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
+ for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
reset_auto_counter_id(it->second->name, true);
- for (auto it = module->cells_.begin(); it != module->cells_.end(); it++) {
+ for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it) {
reset_auto_counter_id(it->second->name, true);
reset_auto_counter_id(it->second->type, false);
}
- for (auto it = module->processes.begin(); it != module->processes.end(); it++)
+ for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
reset_auto_counter_id(it->second->name, false);
auto_name_digits = 1;
for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
auto_name_digits++;
- for (auto it = auto_name_map.begin(); it != auto_name_map.end(); it++)
+ for (auto it = auto_name_map.begin(); it != auto_name_map.end(); ++it)
log(" renaming `%s' to `_%0*d_'.\n", it->first.c_str(), auto_name_digits, auto_name_offset + it->second);
}
@@ -150,7 +151,7 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
return true;
}
-void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false)
+void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false)
{
if (width < 0)
width = data.bits.size() - offset;
@@ -166,7 +167,7 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
if (data.bits[i] == RTLIL::S1)
val |= 1 << (i - offset);
}
- f << stringf("32'%sd%d", set_signed ? "s" : "", val);
+ f << stringf("32'%sd %d", set_signed ? "s" : "", val);
} else {
dump_bits:
f << stringf("%d'%sb", width, set_signed ? "s" : "");
@@ -198,6 +199,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
f << stringf("\\\"");
else if (str[i] == '\\')
f << stringf("\\\\");
+ else if (str[i] == '/' && escape_comment && i > 0 && str[i-1] == '*')
+ f << stringf("\\/");
else
f << str[i];
}
@@ -236,7 +239,7 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
dump_sigchunk(f, sig.as_chunk());
} else {
f << stringf("{ ");
- for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
+ for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
if (it != sig.chunks().rbegin())
f << stringf(", ");
dump_sigchunk(f, *it, true);
@@ -245,14 +248,19 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
}
}
-void dump_attributes(std::ostream &f, std::string indent, std::map<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n')
+void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false)
{
if (noattr)
return;
- for (auto it = attributes.begin(); it != attributes.end(); it++) {
+ for (auto it = attributes.begin(); it != attributes.end(); ++it) {
f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
f << stringf(" = ");
- dump_const(f, it->second);
+ if (modattr && (it->second == Const(0, 1) || it->second == Const(0)))
+ f << stringf(" 0 ");
+ else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
+ f << stringf(" 1 ");
+ else
+ dump_const(f, it->second, -1, 0, false, false, attr2comment);
f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
}
}
@@ -315,7 +323,7 @@ std::string cellname(RTLIL::Cell *cell)
if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q"))
{
RTLIL::SigSpec sig = cell->getPort("\\Q");
- if (SIZE(sig) != 1 || sig.is_fully_const())
+ if (GetSize(sig) != 1 || sig.is_fully_const())
goto no_special_reg_name;
RTLIL::Wire *wire = sig[0].wire;
@@ -663,10 +671,60 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
- if (cell->type == "$dff" || cell->type == "$adff")
+ if (cell->type == "$dffsr")
+ {
+ 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");
+
+ int width = cell->parameters["\\WIDTH"].as_int();
+ bool pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
+ bool pol_set = cell->parameters["\\SET_POLARITY"].as_bool();
+ bool pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool();
+
+ std::string reg_name = cellname(cell);
+ bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
+
+ if (!out_is_reg_wire)
+ f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());
+
+ for (int i = 0; i < width; i++) {
+ f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
+ dump_sigspec(f, sig_clk);
+ f << stringf(", %sedge ", pol_set ? "pos" : "neg");
+ dump_sigspec(f, sig_set);
+ f << stringf(", %sedge ", pol_clr ? "pos" : "neg");
+ dump_sigspec(f, sig_clr);
+ f << stringf(")\n");
+
+ f << stringf("%s" " if (%s", indent.c_str(), pol_clr ? "" : "!");
+ dump_sigspec(f, sig_clr);
+ f << stringf(") %s[%d] <= 1'b0;\n", reg_name.c_str(), i);
+
+ f << stringf("%s" " else if (%s", indent.c_str(), pol_set ? "" : "!");
+ dump_sigspec(f, sig_set);
+ f << stringf(") %s[%d] <= 1'b1;\n", reg_name.c_str(), i);
+
+ f << stringf("%s" " else %s[%d] <= ", indent.c_str(), reg_name.c_str(), i);
+ dump_sigspec(f, sig_d[i]);
+ f << stringf(";\n");
+ }
+
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, sig_q);
+ f << stringf(" = %s;\n", reg_name.c_str());
+ }
+
+ return true;
+ }
+
+ if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
{
- RTLIL::SigSpec sig_clk, sig_arst, val_arst;
- bool pol_clk, pol_arst = false;
+ RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
+ bool pol_clk, pol_arst = false, pol_en = false;
sig_clk = cell->getPort("\\CLK");
pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
@@ -677,6 +735,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
}
+ if (cell->type == "$dffe") {
+ sig_en = cell->getPort("\\EN");
+ pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
+ }
+
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
@@ -701,6 +764,12 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
f << stringf("%s" " else\n", indent.c_str());
}
+ if (cell->type == "$dffe") {
+ f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
+ dump_sigspec(f, sig_en);
+ f << stringf(")\n");
+ }
+
f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
dump_cell_expr_port(f, cell, "D", false);
f << stringf(";\n");
@@ -715,7 +784,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
}
// FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
- // FIXME: $sr, $dffsr, $dlatch, $memrd, $memwr, $mem, $fsm
+ // FIXME: $sr, $dlatch, $memrd, $memwr, $mem, $fsm
return false;
}
@@ -732,12 +801,12 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (cell->parameters.size() > 0) {
f << stringf(" #(");
- for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
+ for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
if (it != cell->parameters.begin())
f << stringf(",");
f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
- dump_const(f, it->second, -1, 0, !is_signed, is_signed);
+ dump_const(f, it->second, -1, 0, false, is_signed);
f << stringf(")");
}
f << stringf("\n%s" ")", indent.c_str());
@@ -754,7 +823,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
for (int i = 1; true; i++) {
char str[16];
snprintf(str, 16, "$%d", i);
- for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
+ for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (it->first != str)
continue;
if (!first_arg)
@@ -768,7 +837,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
break;
found_numbered_port:;
}
- for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
+ for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (numbered_ports.count(it->first))
continue;
if (!first_arg)
@@ -800,7 +869,7 @@ void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bo
if (!omit_trailing_begin && number_of_stmts >= 2)
f << stringf("%s" "begin\n", indent.c_str());
- for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
+ for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
if (it->first.size() == 0)
continue;
f << stringf("%s ", indent.c_str());
@@ -810,7 +879,7 @@ void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bo
f << stringf(";\n");
}
- for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
+ for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
dump_proc_switch(f, indent + " ", *it);
if (!omit_trailing_begin && number_of_stmts == 0)
@@ -824,7 +893,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
{
if (sw->signal.size() == 0) {
f << stringf("%s" "begin\n", indent.c_str());
- for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
+ for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
if ((*it)->compare.size() == 0)
dump_case_body(f, indent + " ", *it);
}
@@ -836,7 +905,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
dump_sigspec(f, sw->signal);
f << stringf(")\n");
- for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
+ for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
f << stringf("%s ", indent.c_str());
if ((*it)->compare.size() == 0)
f << stringf("default");
@@ -856,11 +925,11 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
void case_body_find_regs(RTLIL::CaseRule *cs)
{
- for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
+ for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
case_body_find_regs(*it2);
- for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
+ for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
for (auto &c : it->first.chunks())
if (c.wire != NULL)
reg_wires.insert(c.wire->name);
@@ -871,7 +940,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
{
if (find_regs) {
case_body_find_regs(&proc->root_case);
- for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
+ for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
for (auto &c : it2->first.chunks())
if (c.wire != NULL)
@@ -925,7 +994,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
}
}
- for (auto it = sync->actions.begin(); it != sync->actions.end(); it++) {
+ for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
if (it->first.size() == 0)
continue;
f << stringf("%s ", indent.c_str());
@@ -946,7 +1015,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
active_module = module;
f << stringf("\n");
- for (auto it = module->processes.begin(); it != module->processes.end(); it++)
+ for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
dump_process(f, indent + " ", it->second, true);
if (!noexpr)
@@ -979,12 +1048,12 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
}
}
- dump_attributes(f, indent, module->attributes);
+ dump_attributes(f, indent, module->attributes, '\n', true);
f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
bool keep_running = true;
for (int port_id = 1; keep_running; port_id++) {
keep_running = false;
- for (auto it = module->wires_.begin(); it != module->wires_.end(); it++) {
+ for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) {
RTLIL::Wire *wire = it->second;
if (wire->port_id == port_id) {
if (port_id != 1)
@@ -997,27 +1066,25 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
}
f << stringf(");\n");
- for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
+ for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
dump_wire(f, indent + " ", it->second);
- for (auto it = module->memories.begin(); it != module->memories.end(); it++)
+ for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
dump_memory(f, indent + " ", it->second);
- for (auto it = module->cells_.begin(); it != module->cells_.end(); it++)
+ for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
dump_cell(f, indent + " ", it->second);
- for (auto it = module->processes.begin(); it != module->processes.end(); it++)
+ for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
dump_process(f, indent + " ", it->second);
- for (auto it = module->connections().begin(); it != module->connections().end(); it++)
+ for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
dump_conn(f, indent + " ", it->first, it->second);
f << stringf("%s" "endmodule\n", indent.c_str());
active_module = NULL;
}
-} /* namespace */
-
struct VerilogBackend : public Backend {
VerilogBackend() : Backend("verilog", "write design to verilog file") { }
virtual void help()
@@ -1122,8 +1189,10 @@ struct VerilogBackend : public Backend {
}
extra_args(f, filename, args, argidx);
+ design->sort();
+
*f << stringf("/* Generated by %s */\n", yosys_version_str);
- for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
continue;
if (selected && !design->selected_whole_module(it->first)) {
@@ -1139,3 +1208,4 @@ struct VerilogBackend : public Backend {
}
} VerilogBackend;
+PRIVATE_NAMESPACE_END
diff --git a/backends/verilog/verilog_backend.h b/backends/verilog/verilog_backend.h
deleted file mode 100644
index 7e6ef5ab..00000000
--- a/backends/verilog/verilog_backend.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * ---
- *
- * A simple and straightforward verilog backend.
- *
- * Note that RTLIL processes can't always be mapped easily to a Verilog
- * process. Therefore this frontend should only be used to export a
- * Verilog netlist (i.e. after the "proc" pass has converted all processes
- * to logic networks and registers).
- *
- */
-
-#ifndef VERILOG_BACKEND_H
-#define VERILOG_BACKEND_H
-
-#include "kernel/yosys.h"
-
-namespace VERILOG_BACKEND {
- void verilog_backend(std::ostream &f, std::vector<std::string> args, RTLIL::Design *design);
-}
-
-#endif
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 1e43875a..0b63248d 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -26,13 +26,18 @@
*
*/
-#include "kernel/log.h"
+#include "kernel/yosys.h"
#include "libs/sha1/sha1.h"
#include "ast.h"
#include <sstream>
#include <stdarg.h>
-#include <math.h>
+
+#if defined(__APPLE__)
+# include <cmath>
+#else
+# include <math.h>
+#endif
YOSYS_NAMESPACE_BEGIN
@@ -48,12 +53,12 @@ namespace AST {
// instanciate global variables (private API)
namespace AST_INTERNAL {
- bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, 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;
- const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
+ const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
RTLIL::SigSpec ignoreThisSignalsInInitial;
- AstNode *current_top_block, *current_block, *current_block_child;
+ AstNode *current_always, *current_top_block, *current_block, *current_block_child;
AstModule *current_module;
}
@@ -85,6 +90,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_IDENTIFIER)
X(AST_PREFIX)
X(AST_ASSERT)
+ X(AST_ASSUME)
X(AST_FCALL)
X(AST_TO_BITS)
X(AST_TO_SIGNED)
@@ -127,6 +133,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_TERNARY)
X(AST_MEMRD)
X(AST_MEMWR)
+ X(AST_MEMINIT)
X(AST_TCALL)
X(AST_ASSIGN)
X(AST_CELL)
@@ -175,6 +182,10 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
// (the optional child arguments make it easier to create AST trees)
AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
{
+ static unsigned int hashidx_count = 123456789;
+ hashidx_count = mkhash_xorshift(hashidx_count);
+ hashidx_ = hashidx_count;
+
this->type = type;
filename = current_filename;
linenum = get_line_num();
@@ -267,7 +278,7 @@ void AstNode::dumpAst(FILE *f, std::string indent)
bits[i-1] == RTLIL::S1 ? '1' :
bits[i-1] == RTLIL::Sx ? 'x' :
bits[i-1] == RTLIL::Sz ? 'z' : '?');
- fprintf(f, "'(%zd)", bits.size());
+ fprintf(f, "'(%d)", GetSize(bits));
}
if (is_input)
fprintf(f, " input");
@@ -471,7 +482,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
else if (bits.size() == 32)
fprintf(f, "%d", RTLIL::Const(bits).as_int());
else
- fprintf(f, "%zd'b %s", bits.size(), RTLIL::Const(bits).as_string().c_str());
+ fprintf(f, "%d'b %s", GetSize(bits), RTLIL::Const(bits).as_string().c_str());
break;
case AST_REALVALUE:
@@ -701,6 +712,8 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
{
AstNode *node = mkconst_str(RTLIL::Const(v).decode_string());
+ while (GetSize(node->bits) < GetSize(v))
+ node->bits.push_back(RTLIL::State::S0);
log_assert(node->bits == v);
return node;
}
@@ -946,6 +959,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
current_module->ast = ast_before_simplify;
current_module->nolatches = flag_nolatches;
+ current_module->nomeminit = flag_nomeminit;
current_module->nomem2reg = flag_nomem2reg;
current_module->mem2reg = flag_mem2reg;
current_module->lib = flag_lib;
@@ -957,13 +971,14 @@ 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 dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
flag_dump_vlog = dump_vlog;
flag_nolatches = nolatches;
+ flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_lib = lib;
@@ -1011,7 +1026,7 @@ AstModule::~AstModule()
}
// create a new parametric module (when needed) and return the name of the generated module
-RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters)
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters)
{
std::string stripped_name = name.str();
@@ -1025,6 +1040,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
flag_dump_ast2 = false;
flag_dump_vlog = false;
flag_nolatches = nolatches;
+ flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_lib = lib;
@@ -1091,6 +1107,7 @@ RTLIL::Module *AstModule::clone() const
new_mod->ast = ast->clone();
new_mod->nolatches = nolatches;
+ new_mod->nomeminit = nomeminit;
new_mod->nomem2reg = nomem2reg;
new_mod->mem2reg = mem2reg;
new_mod->lib = lib;
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 0a401673..d57e91e5 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -64,6 +64,7 @@ namespace AST
AST_IDENTIFIER,
AST_PREFIX,
AST_ASSERT,
+ AST_ASSUME,
AST_FCALL,
AST_TO_BITS,
@@ -107,6 +108,7 @@ namespace AST
AST_TERNARY,
AST_MEMRD,
AST_MEMWR,
+ AST_MEMINIT,
AST_TCALL,
AST_ASSIGN,
@@ -142,6 +144,10 @@ namespace AST
// The AST is built using instances of this struct
struct AstNode
{
+ // for dict<> and pool<>
+ unsigned int hashidx_;
+ unsigned int hash() const { return hashidx_; }
+
// this nodes type
AstNodeType type;
@@ -204,11 +210,13 @@ namespace AST
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
+ AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr);
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
- void mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
- std::map<AstNode*, uint32_t> &mem2reg_flags, std::map<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
- void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
+ void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
+ dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
+ void mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
+ bool mem2reg_check(pool<AstNode*> &mem2reg_set);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
// additional functionality for evaluating constant functions
@@ -229,7 +237,7 @@ namespace AST
// for expressions the resulting signal vector is returned
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
- RTLIL::SigSpec genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
+ RTLIL::SigSpec genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
// compare AST nodes
bool operator==(const AstNode &other) const;
@@ -258,15 +266,15 @@ 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 dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
+ void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
// therfore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
- bool nolatches, nomem2reg, mem2reg, lib, noopt, icells, autowire;
+ bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
virtual ~AstModule();
- virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
+ virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::Module *clone() const;
};
@@ -288,12 +296,12 @@ namespace AST
namespace AST_INTERNAL
{
// internal state variables
- extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
- extern const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
+ extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
extern RTLIL::SigSpec ignoreThisSignalsInInitial;
- extern AST::AstNode *current_top_block, *current_block, *current_block_child;
+ extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;
extern AST::AstModule *current_module;
struct ProcessGenerator;
}
diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc
index 2eb104fa..e566d653 100644
--- a/frontends/ast/dpicall.cc
+++ b/frontends/ast/dpicall.cc
@@ -24,6 +24,8 @@
#include <dlfcn.h>
#include <ffi.h>
+YOSYS_NAMESPACE_BEGIN
+
typedef void (*ffi_fptr) ();
static ffi_fptr resolve_fn (std::string symbol_name)
@@ -73,8 +75,8 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str());
- log_assert(SIZE(args) == SIZE(argtypes));
- for (int i = 0; i < SIZE(args); i++) {
+ log_assert(GetSize(args) == GetSize(argtypes));
+ for (int i = 0; i < GetSize(args); i++) {
if (argtypes[i] == "real") {
log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
value_store[i].f64 = args[i]->asReal(args[i]->is_signed);
@@ -129,12 +131,18 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
return newNode;
}
+YOSYS_NAMESPACE_END
+
#else /* YOSYS_ENABLE_PLUGINS */
+YOSYS_NAMESPACE_BEGIN
+
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
{
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
}
+YOSYS_NAMESPACE_END
+
#endif /* YOSYS_ENABLE_PLUGINS */
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index f87a68f6..8ed8c673 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -73,7 +73,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_signed)
{
if (width <= sig.size()) {
- sig.extend(width, is_signed);
+ sig.extend_u0(width, is_signed);
return;
}
@@ -254,7 +254,7 @@ struct AST_INTERNAL::ProcessGenerator
// create initial assignments for the temporary signals
if ((flag_nolatches || always->get_bool_attribute("\\nolatches") || current_module->get_bool_attribute("\\nolatches")) && !found_clocked_sync) {
- subst_rvalue_map = subst_lvalue_from.to_sigbit_map(RTLIL::SigSpec(RTLIL::State::Sx, SIZE(subst_lvalue_from)));
+ subst_rvalue_map = subst_lvalue_from.to_sigbit_dict(RTLIL::SigSpec(RTLIL::State::Sx, GetSize(subst_lvalue_from)));
} else {
addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from);
}
@@ -289,8 +289,8 @@ struct AST_INTERNAL::ProcessGenerator
{
RTLIL::SigSpec new_lhs, new_rhs;
- log_assert(SIZE(lhs) == SIZE(rhs));
- for (int i = 0; i < SIZE(lhs); i++) {
+ log_assert(GetSize(lhs) == GetSize(rhs));
+ for (int i = 0; i < GetSize(lhs); i++) {
if (lhs[i].wire == nullptr)
continue;
new_lhs.append(lhs[i]);
@@ -306,7 +306,7 @@ struct AST_INTERNAL::ProcessGenerator
{
std::vector<RTLIL::SigChunk> chunks = sig.chunks();
- for (int i = 0; i < SIZE(chunks); i++)
+ for (int i = 0; i < GetSize(chunks); i++)
{
RTLIL::SigChunk &chunk = chunks[i];
if (chunk.wire == NULL)
@@ -430,7 +430,7 @@ struct AST_INTERNAL::ProcessGenerator
lvalue.replace(subst_lvalue_map.stdmap());
if (ast->type == AST_ASSIGN_EQ) {
- for (int i = 0; i < SIZE(unmapped_lvalue); i++)
+ for (int i = 0; i < GetSize(unmapped_lvalue); i++)
subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
}
@@ -472,7 +472,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_lvalue_map.save();
subst_rvalue_map.save();
- for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
+ for (int i = 0; i < GetSize(this_case_eq_lvalue); i++)
subst_lvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
RTLIL::CaseRule *backup_case = current_case;
@@ -507,7 +507,7 @@ struct AST_INTERNAL::ProcessGenerator
sw->cases.push_back(default_case);
}
- for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
+ for (int i = 0; i < GetSize(this_case_eq_lvalue); i++)
subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
@@ -567,9 +567,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
} else
- if (id_ast->children[0]->type == AST_CONSTANT) {
+ if (id_ast->children[0]->type != AST_CONSTANT)
+ while (id_ast->simplify(true, false, false, 1, -1, false, true)) { }
+ if (id_ast->children[0]->type == AST_CONSTANT)
this_width = id_ast->children[0]->bits.size();
- } else
+ else
log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
if (children.size() != 0)
range = children[0];
@@ -839,14 +841,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
memory->name = str;
memory->width = children[0]->range_left - children[0]->range_right + 1;
- memory->start_offset = children[0]->range_right;
- memory->size = children[1]->range_left - children[1]->range_right;
+ if (children[1]->range_right < children[1]->range_left) {
+ memory->start_offset = children[1]->range_right;
+ memory->size = children[1]->range_left - children[1]->range_right + 1;
+ } else {
+ memory->start_offset = children[1]->range_left;
+ memory->size = children[1]->range_right - children[1]->range_left + 1;
+ }
current_module->memories[memory->name] = memory;
- if (memory->size < 0)
- memory->size *= -1;
- memory->size += std::min(children[1]->range_left, children[1]->range_right) + 1;
-
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
@@ -869,7 +872,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_REALVALUE:
{
RTLIL::SigSpec sig = realAsConst(width_hint);
- log("Warning: converting real value %e to binary %s at %s:%d.\n",
+ log_warning("converting real value %e to binary %s at %s:%d.\n",
realvalue, log_signal(sig), filename.c_str(), linenum);
return sig;
}
@@ -890,7 +893,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
wire->name = str;
if (flag_autowire)
- log("Warning: Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_warning("Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
else
log_error("Identifier `%s' is implicitly declared at %s:%d and `default_nettype is set to none.\n", str.c_str(), filename.c_str(), linenum);
}
@@ -941,7 +944,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed);
fake_ast->children[1]->is_signed = true;
}
- if (SIZE(shift_val) >= 32)
+ if (GetSize(shift_val) >= 32)
fake_ast->children[1]->is_signed = true;
RTLIL::SigSpec sig = binop2rtlil(fake_ast, "$shiftx", width, fake_ast->children[0]->genRTLIL(), shift_val);
delete left_at_zero_ast;
@@ -955,10 +958,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width);
if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {
if (chunk.width == 1)
- log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
+ log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
str.c_str(), filename.c_str(), linenum);
else
- log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
+ log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
str.c_str(), filename.c_str(), linenum, chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
@@ -972,10 +975,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset += add_undef_bits_lsb;
}
if (add_undef_bits_lsb)
- log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
+ log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb);
if (add_undef_bits_msb)
- log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
+ log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
str.c_str(), filename.c_str(), linenum, add_undef_bits_msb);
}
}
@@ -1213,9 +1216,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- int addr_bits = 1;
- while ((1 << addr_bits) < current_module->memories[str]->size)
- addr_bits++;
+ int mem_width, mem_size, addr_bits;
+ id2ast->meminfo(mem_width, mem_size, addr_bits);
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
@@ -1234,28 +1236,30 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// generate $memwr cells for memory write ports
case AST_MEMWR:
+ case AST_MEMINIT:
{
std::stringstream sstr;
- sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memwr");
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? "$memwr" : "$meminit");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
- int addr_bits = 1;
- while ((1 << addr_bits) < current_module->memories[str]->size)
- addr_bits++;
+ int mem_width, mem_size, addr_bits;
+ id2ast->meminfo(mem_width, mem_size, addr_bits);
- cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width));
- cell->setPort("\\EN", children[2]->genRTLIL());
cell->parameters["\\MEMID"] = RTLIL::Const(str);
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width);
- cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
- cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
+ if (type == AST_MEMWR) {
+ cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
+ cell->setPort("\\EN", children[2]->genRTLIL());
+ cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
+ cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
+ }
cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1);
}
@@ -1263,19 +1267,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// generate $assert cells
case AST_ASSERT:
+ case AST_ASSUME:
{
log_assert(children.size() == 2);
RTLIL::SigSpec check = children[0]->genRTLIL();
- log_assert(check.size() == 1);
+ if (GetSize(check) != 1)
+ check = current_module->ReduceBool(NEW_ID, check);
RTLIL::SigSpec en = children[1]->genRTLIL();
- log_assert(en.size() == 1);
+ if (GetSize(en) != 1)
+ en = current_module->ReduceBool(NEW_ID, en);
std::stringstream sstr;
- sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$assert");
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
for (auto &attr : attributes) {
@@ -1293,15 +1300,23 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// add entries to current_module->connections for assignments (outside of always blocks)
case AST_ASSIGN:
{
- if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_AUTOWIRE) {
- RTLIL::SigSpec right = children[1]->genRTLIL();
- RTLIL::SigSpec left = children[0]->genWidthRTLIL(right.size());
- current_module->connect(RTLIL::SigSig(left, right));
- } else {
- RTLIL::SigSpec left = children[0]->genRTLIL();
- RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size());
- current_module->connect(RTLIL::SigSig(left, right));
+ RTLIL::SigSpec left = children[0]->genRTLIL();
+ RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size());
+ if (left.has_const()) {
+ RTLIL::SigSpec new_left, new_right;
+ for (int i = 0; i < GetSize(left); i++)
+ if (left[i].wire) {
+ new_left.append(left[i]);
+ new_right.append(right[i]);
+ }
+ log_warning("Ignoring assignment to constant bits at %s:%d:\n"
+ " old assignment: %s = %s\n new assignment: %s = %s.\n",
+ filename.c_str(), linenum, log_signal(left), log_signal(right),
+ log_signal(new_left), log_signal(new_right));
+ left = new_left;
+ right = new_right;
}
+ current_module->connect(RTLIL::SigSig(left, right));
}
break;
@@ -1326,16 +1341,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue;
}
if (child->type == AST_PARASET) {
- if (child->children[0]->type != AST_CONSTANT)
- log_error("Parameter `%s' with non-constant value at %s:%d!\n",
- child->str.c_str(), filename.c_str(), linenum);
- if (child->str.size() == 0) {
- char buf[100];
- snprintf(buf, 100, "$%d", ++para_counter);
- cell->parameters[buf] = child->children[0]->asParaConst();
- } else {
- cell->parameters[child->str] = child->children[0]->asParaConst();
+ IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
+ if (child->children[0]->type == AST_REALVALUE) {
+ log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n",
+ log_id(cell), log_id(paraname), child->children[0]->realvalue,
+ filename.c_str(), linenum);
+ 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_error("Parameter %s.%s with non-constant value at %s:%d!\n",
+ log_id(cell), log_id(paraname), filename.c_str(), linenum);
+ cell->parameters[paraname] = child->children[0]->asParaConst();
continue;
}
if (child->type == AST_ARGUMENT) {
@@ -1391,9 +1409,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or
// signals must be substituted before beeing used as input values (used by ProcessGenerator)
// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().
-RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
+RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
{
- const std::map<RTLIL::SigBit, RTLIL::SigBit> *backup_subst_ptr = genRTLIL_subst_ptr;
+ const dict<RTLIL::SigBit, RTLIL::SigBit> *backup_subst_ptr = genRTLIL_subst_ptr;
if (new_subst_ptr)
genRTLIL_subst_ptr = new_subst_ptr;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 969cc230..a65d2dbb 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -28,10 +28,12 @@
#include "kernel/log.h"
#include "libs/sha1/sha1.h"
+#include "frontends/verilog/verilog_frontend.h"
#include "ast.h"
#include <sstream>
#include <stdarg.h>
+#include <stdlib.h>
#include <math.h>
YOSYS_NAMESPACE_BEGIN
@@ -47,39 +49,55 @@ using namespace AST_INTERNAL;
// nodes that link to a different node using names and lexical scoping.
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) {
+ log_warning("Deep recursion in AST simplifier.\nDoes this design contain insanely long expressions?\n");
+ deep_recursion_warning = false;
+ }
+
AstNode *newNode = NULL;
bool did_something = false;
#if 0
log("-------------\n");
+ log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum);
log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",
int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));
- dumpAst(NULL, "> ");
+ // dumpAst(NULL, "> ");
#endif
if (stage == 0)
{
log_assert(type == AST_MODULE);
+ last_blocking_assignment_warn = pair<string, int>();
+ deep_recursion_warning = true;
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg"))
{
- std::map<AstNode*, std::set<std::string>> mem2reg_places;
- std::map<AstNode*, uint32_t> mem2reg_candidates, dummy_proc_flags;
+ dict<AstNode*, pool<std::string>> mem2reg_places;
+ dict<AstNode*, uint32_t> mem2reg_candidates, dummy_proc_flags;
uint32_t flags = flag_mem2reg ? AstNode::MEM2REG_FL_ALL : 0;
mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, dummy_proc_flags, flags);
- std::set<AstNode*> mem2reg_set;
+ pool<AstNode*> mem2reg_set;
for (auto &it : mem2reg_candidates)
{
AstNode *mem = it.first;
uint32_t memflags = it.second;
+ bool this_nomeminit = flag_nomeminit;
log_assert((memflags & ~0x00ffff00) == 0);
if (mem->get_bool_attribute("\\nomem2reg"))
continue;
+ if (mem->get_bool_attribute("\\nomeminit") || get_bool_attribute("\\nomeminit"))
+ this_nomeminit = true;
+
if (memflags & AstNode::MEM2REG_FL_FORCED)
goto silent_activate;
@@ -89,7 +107,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (memflags & AstNode::MEM2REG_FL_SET_ASYNC)
goto verbose_activate;
- if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE))
+ if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE) && this_nomeminit)
goto verbose_activate;
if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
@@ -100,13 +118,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
verbose_activate:
if (mem2reg_set.count(mem) == 0) {
- log("Warning: Replacing memory %s with list of registers.", mem->str.c_str());
+ std::string message = stringf("Replacing memory %s with list of registers.", mem->str.c_str());
bool first_element = true;
for (auto &place : mem2reg_places[it.first]) {
- log("%s%s", first_element ? " See " : ", ", place.c_str());
+ message += stringf("%s%s", first_element ? " See " : ", ", place.c_str());
first_element = false;
}
- log("\n");
+ log_warning("%s\n", message.c_str());
}
silent_activate:
@@ -141,6 +159,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
+ recursion_counter--;
return false;
}
@@ -149,11 +168,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// we do not look inside a task or function
// (but as soon as a task of function is instanciated we process the generated AST as usual)
- if (type == AST_FUNCTION || type == AST_TASK)
+ if (type == AST_FUNCTION || type == AST_TASK) {
+ recursion_counter--;
return false;
+ }
// deactivate all calls to non-synthesis system taks
- if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$stop" || str == "$finish")) {
+ if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$finish" ||
+ str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) {
+ log_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum);
delete_children();
str = std::string();
}
@@ -182,6 +205,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
AstNode *first_node = this_wire_scope[node->str];
if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0)
goto wires_are_compatible;
+ if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
+ AstNode *r = node->children[0];
+ if (r->range_valid && r->range_left == 0 && r->range_right == 0) {
+ delete r;
+ node->children.pop_back();
+ }
+ }
if (first_node->children.size() != node->children.size())
goto wires_are_incompatible;
for (size_t j = 0; j < node->children.size(); j++) {
@@ -242,6 +272,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
auto backup_current_block = current_block;
auto backup_current_block_child = current_block_child;
auto backup_current_top_block = current_top_block;
+ auto backup_current_always = current_always;
+
+ if (type == AST_ALWAYS || type == AST_INITIAL)
+ current_always = this;
int backup_width_hint = width_hint;
bool backup_sign_hint = sign_hint;
@@ -382,6 +416,41 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
+ if (const_fold && type == AST_CASE)
+ {
+ while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
+ if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) {
+ std::vector<AstNode*> new_children;
+ new_children.push_back(children[0]);
+ for (int i = 1; i < GetSize(children); i++) {
+ AstNode *child = children[i];
+ log_assert(child->type == AST_COND);
+ for (auto v : child->children) {
+ if (v->type == AST_DEFAULT)
+ goto keep_const_cond;
+ if (v->type == AST_BLOCK)
+ continue;
+ while (v->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
+ if (v->type == AST_CONSTANT && v->bits_only_01()) {
+ if (v->bits == children[0]->bits) {
+ while (i+1 < GetSize(children))
+ delete children[++i];
+ goto keep_const_cond;
+ }
+ continue;
+ }
+ goto keep_const_cond;
+ }
+ if (0)
+ keep_const_cond:
+ new_children.push_back(child);
+ else
+ delete child;
+ }
+ new_children.swap(children);
+ }
+ }
+
// simplify all children first
// (iterate by index as e.g. auto wires can add new children in the process)
for (size_t i = 0; i < children.size(); i++) {
@@ -446,6 +515,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
current_block = backup_current_block;
current_block_child = backup_current_block_child;
current_top_block = backup_current_top_block;
+ current_always = backup_current_always;
for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) {
if (it->second == NULL)
@@ -575,9 +645,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
AstNode *index_expr = nullptr;
- for (int i = 0; 2*i < SIZE(id2ast->multirange_dimensions); i++)
+ for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++)
{
- if (SIZE(children[0]->children) < i)
+ if (GetSize(children[0]->children) < i)
log_error("Insufficient number of array indices for %s at %s:%d.\n", log_id(str), filename.c_str(), linenum);
AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone();
@@ -591,7 +661,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i-1], true)), new_index_expr);
}
- for (int i = SIZE(id2ast->multirange_dimensions)/1; i < SIZE(children[0]->children); i++)
+ for (int i = GetSize(id2ast->multirange_dimensions)/1; i < GetSize(children[0]->children); i++)
children.push_back(children[0]->children[i]->clone());
delete children[0];
@@ -611,7 +681,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int width = children[1]->range_left - children[1]->range_right + 1;
if (children[0]->type == AST_REALVALUE) {
RTLIL::Const constvalue = children[0]->realAsConst(width);
- log("Warning: converting real value %e to binary %s at %s:%d.\n",
+ log_warning("converting real value %e to binary %s at %s:%d.\n",
children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum);
delete children[0];
children[0] = mkconst_bits(constvalue.bits, sign_hint);
@@ -653,7 +723,7 @@ 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());
+ // 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);
@@ -1123,7 +1193,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
- result_width = abs(left_at_zero_ast->integer - right_at_zero_ast->integer) + 1;
+ result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
}
did_something = true;
newNode = new AstNode(AST_CASE, shift_expr);
@@ -1141,7 +1211,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
skip_dynamic_range_lvalue_expansion:;
- if (stage > 1 && type == AST_ASSERT && current_block != NULL)
+ if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL)
{
std::stringstream sstr;
sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
@@ -1185,7 +1255,7 @@ skip_dynamic_range_lvalue_expansion:;
newNode->children.push_back(assign_check);
newNode->children.push_back(assign_en);
- AstNode *assertnode = new AstNode(AST_ASSERT);
+ AstNode *assertnode = new AstNode(type);
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children[0]->str = id_check;
@@ -1196,9 +1266,8 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
- if (stage > 1 && type == AST_ASSERT && children.size() == 1)
+ if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && children.size() == 1)
{
- children[0] = new AstNode(AST_REDUCE_BOOL, children[0]->clone());
children.push_back(mkconst_int(1, false, 1));
did_something = true;
}
@@ -1222,9 +1291,13 @@ 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)
- log("Warning: Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
- filename.c_str(), linenum);
+ 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;
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
@@ -1241,11 +1314,14 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_data->str] = wire_data;
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
- AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
- wire_en->str = id_en;
- current_ast_mod->children.push_back(wire_en);
- current_scope[wire_en->str] = wire_en;
- while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
+ AstNode *wire_en = nullptr;
+ if (current_always->type != AST_INITIAL) {
+ wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
+ wire_en->str = id_en;
+ current_ast_mod->children.push_back(wire_en);
+ current_scope[wire_en->str] = wire_en;
+ while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
+ }
std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en;
for (int i = 0; i < addr_bits; i++)
@@ -1261,13 +1337,17 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false));
assign_data->children[0]->str = id_data;
- AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
- assign_en->children[0]->str = id_en;
+ AstNode *assign_en = nullptr;
+ if (current_always->type != AST_INITIAL) {
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
+ assign_en->children[0]->str = id_en;
+ }
AstNode *default_signals = new AstNode(AST_BLOCK);
default_signals->children.push_back(assign_addr);
default_signals->children.push_back(assign_data);
- default_signals->children.push_back(assign_en);
+ if (current_always->type != AST_INITIAL)
+ default_signals->children.push_back(assign_en);
current_top_block->children.insert(current_top_block->children.begin(), default_signals);
assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
@@ -1282,15 +1362,16 @@ skip_dynamic_range_lvalue_expansion:;
std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx);
- for (int i = 0; i < mem_width; i++)
- set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
-
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone()));
assign_data->children[0]->str = id_data;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
- assign_en->children[0]->str = id_en;
+ if (current_always->type != AST_INITIAL) {
+ for (int i = 0; i < mem_width; i++)
+ set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
+ assign_en->children[0]->str = id_en;
+ }
}
else
{
@@ -1305,16 +1386,17 @@ skip_dynamic_range_lvalue_expansion:;
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
- for (int i = 0; i < mem_width; i++)
- set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
-
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
assign_data->children[0]->str = id_data;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
- new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
- assign_en->children[0]->str = id_en;
+ if (current_always->type != AST_INITIAL) {
+ for (int i = 0; i < mem_width; i++)
+ set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
+ new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
+ assign_en->children[0]->str = id_en;
+ }
delete left_at_zero_ast;
delete right_at_zero_ast;
@@ -1326,23 +1408,29 @@ skip_dynamic_range_lvalue_expansion:;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
assign_data->children[0]->str = id_data;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
- assign_en->children[0]->str = id_en;
+ if (current_always->type != AST_INITIAL) {
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
+ assign_en->children[0]->str = id_en;
+ }
}
newNode = new AstNode(AST_BLOCK);
newNode->children.push_back(assign_addr);
newNode->children.push_back(assign_data);
- newNode->children.push_back(assign_en);
+ if (current_always->type != AST_INITIAL)
+ newNode->children.push_back(assign_en);
- AstNode *wrnode = new AstNode(AST_MEMWR);
- wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR);
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ if (current_always->type != AST_INITIAL)
+ wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
wrnode->str = children[0]->str;
+ wrnode->id2ast = children[0]->id2ast;
wrnode->children[0]->str = id_addr;
wrnode->children[1]->str = id_data;
- wrnode->children[2]->str = id_en;
+ if (current_always->type != AST_INITIAL)
+ wrnode->children[2]->str = id_en;
current_ast_mod->children.push_back(wrnode);
goto apply_newNode;
@@ -1366,7 +1454,7 @@ skip_dynamic_range_lvalue_expansion:;
RTLIL::Const arg_value = buf->bitsAsConst();
if (arg_value.as_bool())
- arg_value = const_sub(arg_value, 1, false, false, SIZE(arg_value));
+ arg_value = const_sub(arg_value, 1, false, false, GetSize(arg_value));
delete buf;
uint32_t result = 0;
@@ -1455,9 +1543,9 @@ skip_dynamic_range_lvalue_expansion:;
rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str);
fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str);
- for (int i = 2; i < SIZE(dpi_decl->children); i++)
+ for (int i = 2; i < GetSize(dpi_decl->children); i++)
{
- if (i-2 >= SIZE(children))
+ if (i-2 >= GetSize(children))
log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum);
argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));
@@ -1480,6 +1568,44 @@ skip_dynamic_range_lvalue_expansion:;
log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
if (type == AST_TCALL) {
+ if (str == "\\$readmemh" || str == "\\$readmemb")
+ {
+ if (GetSize(children) < 2 || GetSize(children) > 4)
+ log_error("System function %s got %d arguments, expected 2-4 at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+
+ AstNode *node_filename = children[0]->clone();
+ while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_filename->type != AST_CONSTANT)
+ log_error("Failed to evaluate system function `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+ AstNode *node_memory = children[1]->clone();
+ while (node_memory->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY)
+ log_error("Failed to evaluate system function `%s' with non-memory 2nd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+ int start_addr = -1, finish_addr = -1;
+
+ if (GetSize(children) > 2) {
+ AstNode *node_addr = children[2]->clone();
+ while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_addr->type != AST_CONSTANT)
+ log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ start_addr = node_addr->asInt(false);
+ }
+
+ if (GetSize(children) > 3) {
+ AstNode *node_addr = children[3]->clone();
+ while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_addr->type != AST_CONSTANT)
+ log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ finish_addr = node_addr->asInt(false);
+ }
+
+ newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr);
+ goto apply_newNode;
+ }
+
if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK)
log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
@@ -1558,7 +1684,7 @@ skip_dynamic_range_lvalue_expansion:;
celltype = RTLIL::escape_id(celltype);
AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE));
- cell->str = prefix.substr(0, SIZE(prefix)-1);
+ cell->str = prefix.substr(0, GetSize(prefix)-1);
cell->children[0]->str = celltype;
for (auto attr : decl->attributes)
@@ -1681,7 +1807,7 @@ skip_dynamic_range_lvalue_expansion:;
bool param_upto = current_scope[str]->range_valid && current_scope[str]->range_swapped;
int param_offset = current_scope[str]->range_valid ? current_scope[str]->range_right : 0;
int param_width = current_scope[str]->range_valid ? current_scope[str]->range_left - current_scope[str]->range_right + 1 :
- SIZE(current_scope[str]->children[0]->bits);
+ GetSize(current_scope[str]->children[0]->bits);
int tmp_range_left = children[0]->range_left, tmp_range_right = children[0]->range_right;
if (param_upto) {
tmp_range_left = (param_width + 2*param_offset) - children[0]->range_right - 1;
@@ -1843,37 +1969,6 @@ skip_dynamic_range_lvalue_expansion:;
newNode->realvalue = -children[0]->asReal(sign_hint);
}
break;
- case AST_CASE:
- if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) {
- std::vector<AstNode*> new_children;
- new_children.push_back(children[0]);
- for (int i = 1; i < SIZE(children); i++) {
- AstNode *child = children[i];
- log_assert(child->type == AST_COND);
- for (auto v : child->children) {
- if (v->type == AST_DEFAULT)
- goto keep_const_cond;
- if (v->type == AST_BLOCK)
- continue;
- if (v->type == AST_CONSTANT && v->bits_only_01()) {
- if (v->bits == children[0]->bits) {
- while (i+1 < SIZE(children))
- delete children[++i];
- goto keep_const_cond;
- }
- continue;
- }
- goto keep_const_cond;
- }
- if (0)
- keep_const_cond:
- new_children.push_back(child);
- else
- delete child;
- }
- new_children.swap(children);
- }
- break;
case AST_TERNARY:
if (children[0]->isConst())
{
@@ -1977,6 +2072,7 @@ apply_newNode:
if (!did_something)
basic_prep = true;
+ recursion_counter--;
return did_something;
}
@@ -1988,6 +2084,83 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro
node->str = to;
}
+// replace a readmem[bh] TCALL ast node with a block of memory assignments
+AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr)
+{
+ AstNode *block = new AstNode(AST_BLOCK);
+
+ std::ifstream f;
+ f.open(mem_filename.c_str());
+
+ if (f.fail())
+ log_error("Can not open file `%s` for %s at %s:%d.\n", mem_filename.c_str(), str.c_str(), filename.c_str(), linenum);
+
+ log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid);
+ int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right;
+ int range_min = std::min(range_left, range_right), range_max = std::max(range_left, range_right);
+
+ if (start_addr < 0)
+ start_addr = range_min;
+
+ if (finish_addr < 0)
+ finish_addr = range_max;
+
+ bool in_comment = false;
+ int increment = start_addr <= finish_addr ? +1 : -1;
+ int cursor = start_addr;
+
+ 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)
+ {
+ token = next_token(line, " \t\r\n");
+ if (token.empty() || token.substr(0, 2) == "//")
+ break;
+
+ if (token[0] == '@') {
+ token = token.substr(1);
+ const char *nptr = token.c_str();
+ char *endptr;
+ cursor = strtol(nptr, &endptr, 16);
+ if (!*nptr || *endptr)
+ log_error("Can not parse address `%s` for %s at %s:%d.\n", nptr, str.c_str(), filename.c_str(), linenum);
+ continue;
+ }
+
+ AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token);
+
+ 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;
+
+ if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
+ break;
+ cursor += increment;
+ }
+
+ if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
+ break;
+ }
+
+ return block;
+}
+
// annotate the names of all wires and other named objects in a generate block
void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map)
{
@@ -2063,8 +2236,8 @@ void AstNode::replace_ids(const std::string &prefix, const std::map<std::string,
}
// helper function for mem2reg_as_needed_pass1
-static void mark_memories_assign_lhs_complex(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
- std::map<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
+static void mark_memories_assign_lhs_complex(dict<AstNode*, pool<std::string>> &mem2reg_places,
+ dict<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
{
for (auto &child : that->children)
mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child);
@@ -2078,8 +2251,8 @@ static void mark_memories_assign_lhs_complex(std::map<AstNode*, std::set<std::st
}
// find memories that should be replaced by registers
-void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
- std::map<AstNode*, uint32_t> &mem2reg_candidates, std::map<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
+void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
+ 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;
@@ -2141,7 +2314,7 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
if (type == AST_MODULE && get_bool_attribute("\\mem2reg"))
children_flags |= AstNode::MEM2REG_FL_ALL;
- std::map<AstNode*, uint32_t> *proc_flags_p = NULL;
+ dict<AstNode*, uint32_t> *proc_flags_p = NULL;
if (type == AST_ALWAYS) {
int count_edge_events = 0;
@@ -2150,12 +2323,12 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
count_edge_events++;
if (count_edge_events != 1)
children_flags |= AstNode::MEM2REG_FL_ASYNC;
- proc_flags_p = new std::map<AstNode*, uint32_t>;
+ proc_flags_p = new dict<AstNode*, uint32_t>;
}
if (type == AST_INITIAL) {
children_flags |= AstNode::MEM2REG_FL_INIT;
- proc_flags_p = new std::map<AstNode*, uint32_t>;
+ proc_flags_p = new dict<AstNode*, uint32_t>;
}
uint32_t backup_flags = flags;
@@ -2173,20 +2346,33 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
flags &= ~children_flags | backup_flags;
if (proc_flags_p) {
+#ifndef NDEBUG
for (auto it : *proc_flags_p)
log_assert((it.second & ~0xff000000) == 0);
+#endif
delete proc_flags_p;
}
}
+bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
+{
+ if (type != AST_IDENTIFIER || !id2ast || !mem2reg_set.count(id2ast))
+ return false;
+
+ if (children.empty() || children[0]->type != AST_RANGE || GetSize(children[0]->children) != 1)
+ log_error("Invalid array access at %s:%d.\n", filename.c_str(), linenum);
+
+ return true;
+}
+
// actually replace memories with registers
-void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
+void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
{
if (type == AST_BLOCK)
block = this;
- if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL && children[0]->id2ast &&
- mem2reg_set.count(children[0]->id2ast) > 0 && children[0]->children[0]->children[0]->type != AST_CONSTANT)
+ if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL &&
+ children[0]->mem2reg_check(mem2reg_set) && children[0]->children[0]->children[0]->type != AST_CONSTANT)
{
std::stringstream sstr;
sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
@@ -2242,7 +2428,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
type = AST_ASSIGN_EQ;
}
- if (type == AST_IDENTIFIER && id2ast && mem2reg_set.count(id2ast) > 0)
+ if (mem2reg_check(mem2reg_set))
{
AstNode *bit_part_sel = NULL;
if (children.size() == 2)
@@ -2446,7 +2632,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
}
log_assert(block != NULL);
- log_assert(variables.count(str));
+ log_assert(variables.count(str) != 0);
while (!block->children.empty())
{
diff --git a/frontends/ilang/.gitignore b/frontends/ilang/.gitignore
index 72b06b0b..43106a81 100644
--- a/frontends/ilang/.gitignore
+++ b/frontends/ilang/.gitignore
@@ -1,4 +1,4 @@
-lexer.cc
-parser.output
-parser.tab.cc
-parser.tab.h
+ilang_lexer.cc
+ilang_parser.output
+ilang_parser.tab.cc
+ilang_parser.tab.h
diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc
index e832cfed..c15e2cc4 100644
--- a/frontends/ilang/Makefile.inc
+++ b/frontends/ilang/Makefile.inc
@@ -1,18 +1,18 @@
-GENFILES += frontends/ilang/parser.tab.cc
-GENFILES += frontends/ilang/parser.tab.h
-GENFILES += frontends/ilang/parser.output
-GENFILES += frontends/ilang/lexer.cc
+GENFILES += frontends/ilang/ilang_parser.tab.cc
+GENFILES += frontends/ilang/ilang_parser.tab.h
+GENFILES += frontends/ilang/ilang_parser.output
+GENFILES += frontends/ilang/ilang_lexer.cc
-frontends/ilang/parser.tab.cc: frontends/ilang/parser.y
- $(P) bison -d -r all -b frontends/ilang/parser frontends/ilang/parser.y
- $(Q) mv frontends/ilang/parser.tab.c frontends/ilang/parser.tab.cc
+frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y
+ $(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser frontends/ilang/ilang_parser.y
+ $(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc
-frontends/ilang/parser.tab.h: frontends/ilang/parser.tab.cc
+frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc
-frontends/ilang/lexer.cc: frontends/ilang/lexer.l
- $(P) flex -o frontends/ilang/lexer.cc frontends/ilang/lexer.l
+frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l
+ $(P) flex -o frontends/ilang/ilang_lexer.cc frontends/ilang/ilang_lexer.l
-OBJS += frontends/ilang/parser.tab.o frontends/ilang/lexer.o
+OBJS += frontends/ilang/ilang_parser.tab.o frontends/ilang/ilang_lexer.o
OBJS += frontends/ilang/ilang_frontend.o
diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc
index f6f926db..7a4687a3 100644
--- a/frontends/ilang/ilang_frontend.cc
+++ b/frontends/ilang/ilang_frontend.cc
@@ -26,13 +26,13 @@
#include "kernel/register.h"
#include "kernel/log.h"
-YOSYS_NAMESPACE_BEGIN
-
void rtlil_frontend_ilang_yyerror(char const *s)
{
- log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
+ YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
}
+YOSYS_NAMESPACE_BEGIN
+
struct IlangFrontend : public Frontend {
IlangFrontend() : Frontend("ilang", "read modules from ilang file") { }
virtual void help()
diff --git a/frontends/ilang/lexer.l b/frontends/ilang/ilang_lexer.l
index 4109cd4b..ace992fb 100644
--- a/frontends/ilang/lexer.l
+++ b/frontends/ilang/ilang_lexer.l
@@ -30,10 +30,12 @@
#endif
#include "ilang_frontend.h"
-#include "parser.tab.h"
+#include "ilang_parser.tab.h"
+
+USING_YOSYS_NAMESPACE
#define YY_INPUT(buf,result,max_size) \
- result = ILANG_FRONTEND::lexin->readsome(buf, max_size);
+ result = readsome(*ILANG_FRONTEND::lexin, buf, max_size)
%}
diff --git a/frontends/ilang/parser.y b/frontends/ilang/ilang_parser.y
index a5cc0689..4661d577 100644
--- a/frontends/ilang/parser.y
+++ b/frontends/ilang/ilang_parser.y
@@ -36,7 +36,7 @@ namespace ILANG_FRONTEND {
RTLIL::Process *current_process;
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
- std::map<RTLIL::IdString, RTLIL::Const> attrbuf;
+ dict<RTLIL::IdString, RTLIL::Const> attrbuf;
}
using namespace ILANG_FRONTEND;
YOSYS_NAMESPACE_END
@@ -183,6 +183,9 @@ memory_options:
memory_options TOK_SIZE TOK_INT {
current_memory->size = $3;
} |
+ memory_options TOK_OFFSET TOK_INT {
+ current_memory->start_offset = $3;
+ } |
/* empty */;
cell_stmt:
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index a9ab022a..464c5c94 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -22,7 +22,6 @@
#include "kernel/log.h"
YOSYS_NAMESPACE_BEGIN
-using namespace PASS_DFFLIBMAP;
struct token_t {
char type;
diff --git a/frontends/verific/build_amd64.txt b/frontends/verific/build_amd64.txt
index 94615d38..9bb6e320 100644
--- a/frontends/verific/build_amd64.txt
+++ b/frontends/verific/build_amd64.txt
@@ -10,6 +10,7 @@ CONFIG := clang
ENABLE_TCL := 0
ENABLE_QT4 := 0
ENABLE_ABC := 0
+ENABLE_PLUGINS := 0
ENABLE_VERIFIC := 1
CXXFLAGS += -m32
LDFLAGS += -m32
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index d0f14838..79abcf24 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -20,11 +20,14 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
-#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <dirent.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+# include <dirent.h>
+#endif
USING_YOSYS_NAMESPACE
@@ -324,7 +327,7 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
if (inst->GetCin()->IsGnd()) {
module->addAdd(RTLIL::escape_id(inst->Name()), IN1, IN2, out, SIGNED);
} else {
- RTLIL::SigSpec tmp = module->addWire(NEW_ID, SIZE(out));
+ RTLIL::SigSpec tmp = module->addWire(NEW_ID, GetSize(out));
module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED);
module->addAdd(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetCin()), out, false);
}
@@ -687,8 +690,8 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
cell->parameters["\\CLK_ENABLE"] = false;
cell->parameters["\\CLK_POLARITY"] = true;
cell->parameters["\\TRANSPARENT"] = false;
- cell->parameters["\\ABITS"] = SIZE(addr);
- cell->parameters["\\WIDTH"] = SIZE(data);
+ cell->parameters["\\ABITS"] = GetSize(addr);
+ cell->parameters["\\WIDTH"] = GetSize(data);
cell->setPort("\\CLK", RTLIL::State::S0);
cell->setPort("\\ADDR", addr);
cell->setPort("\\DATA", data);
@@ -709,9 +712,9 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
cell->parameters["\\CLK_ENABLE"] = false;
cell->parameters["\\CLK_POLARITY"] = true;
cell->parameters["\\PRIORITY"] = 0;
- cell->parameters["\\ABITS"] = SIZE(addr);
- cell->parameters["\\WIDTH"] = SIZE(data);
- cell->setPort("\\EN", RTLIL::SigSpec(net_map.at(inst->GetControl())).repeat(SIZE(data)));
+ 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);
@@ -727,7 +730,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
if (import_netlist_instance_cells(module, net_map, inst))
continue;
if (inst->IsOperator())
- log("Warning: Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name());
+ log_warning("Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name());
} else {
if (import_netlist_instance_gates(module, net_map, inst))
continue;
@@ -753,9 +756,9 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
RTLIL::SigSpec conn;
if (cell->hasPort(RTLIL::escape_id(port_name)))
conn = cell->getPort(RTLIL::escape_id(port_name));
- while (SIZE(conn) <= port_offset) {
+ while (GetSize(conn) <= port_offset) {
if (pr->GetPort()->GetDir() != DIR_IN)
- conn.append(module->addWire(NEW_ID, port_offset - SIZE(conn)));
+ conn.append(module->addWire(NEW_ID, port_offset - GetSize(conn)));
conn.append(RTLIL::State::Sz);
}
conn.replace(port_offset, net_map.at(pr->GetNet()));
diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore
index 72b06b0b..1d4ae9e5 100644
--- a/frontends/verilog/.gitignore
+++ b/frontends/verilog/.gitignore
@@ -1,4 +1,4 @@
-lexer.cc
-parser.output
-parser.tab.cc
-parser.tab.h
+verilog_lexer.cc
+verilog_parser.output
+verilog_parser.tab.cc
+verilog_parser.tab.h
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index 49eb320e..92cbd0b8 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -1,20 +1,20 @@
-GENFILES += frontends/verilog/parser.tab.cc
-GENFILES += frontends/verilog/parser.tab.h
-GENFILES += frontends/verilog/parser.output
-GENFILES += frontends/verilog/lexer.cc
+GENFILES += frontends/verilog/verilog_parser.tab.cc
+GENFILES += frontends/verilog/verilog_parser.tab.h
+GENFILES += frontends/verilog/verilog_parser.output
+GENFILES += frontends/verilog/verilog_lexer.cc
-frontends/verilog/parser.tab.cc: frontends/verilog/parser.y
- $(P) bison -d -r all -b frontends/verilog/parser frontends/verilog/parser.y
- $(Q) mv frontends/verilog/parser.tab.c frontends/verilog/parser.tab.cc
+frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
+ $(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser frontends/verilog/verilog_parser.y
+ $(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc
-frontends/verilog/parser.tab.h: frontends/verilog/parser.tab.cc
+frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc
-frontends/verilog/lexer.cc: frontends/verilog/lexer.l
- $(P) flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
+frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
+ $(P) flex -o frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_lexer.l
-OBJS += frontends/verilog/parser.tab.o
-OBJS += frontends/verilog/lexer.o
+OBJS += frontends/verilog/verilog_parser.tab.o
+OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o
OBJS += frontends/verilog/verilog_frontend.o
OBJS += frontends/verilog/const2ast.o
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index a81e3010..735bc5f9 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -132,8 +132,16 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
}
// convert the verilog code for a constant to an AST node
-AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
+AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z)
{
+ if (warn_z) {
+ AstNode *ret = const2ast(code, case_type);
+ if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
+ log_warning("Yosys does not support tri-state logic at the moment. (%s:%d)\n",
+ current_filename.c_str(), frontend_verilog_yyget_lineno());
+ return ret;
+ }
+
const char *str = code.c_str();
// Strings
@@ -174,7 +182,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
if (str == endptr)
len_in_bits = -1;
- // The "<bits>'s?[bodh]<digits>" syntax
+ // The "<bits>'s?[bodhBODH]<digits>" syntax
if (*endptr == '\'')
{
std::vector<RTLIL::State> data;
@@ -186,15 +194,19 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
switch (*(endptr+1))
{
case 'b':
+ case 'B':
my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
break;
case 'o':
+ case 'O':
my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
break;
case 'd':
+ case 'D':
my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
break;
case 'h':
+ case 'H':
my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
break;
default:
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
index f8343321..e2118630 100644
--- a/frontends/verilog/preproc.cc
+++ b/frontends/verilog/preproc.cc
@@ -201,8 +201,8 @@ static void input_file(std::istream &f, std::string filename)
insert_input("");
auto it = input_buffer.begin();
- input_buffer.insert(it, "`file_push " + filename + "\n");
- while ((rc = f.readsome(buffer, sizeof(buffer)-1)) > 0) {
+ input_buffer.insert(it, "`file_push \"" + filename + "\"\n");
+ while ((rc = readsome(f, buffer, sizeof(buffer)-1)) > 0) {
buffer[rc] = 0;
input_buffer.insert(it, buffer);
}
@@ -221,7 +221,8 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
input_buffer_charp = 0;
input_file(f, filename);
- defines_map["__YOSYS__"] = "1";
+ defines_map["YOSYS"] = "1";
+ defines_map["SYNTHESIS"] = "1";
while (!input_buffer.empty())
{
@@ -422,7 +423,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
if (tok == "(" || tok == "{" || tok == "[")
level++;
}
- for (size_t i = 0; i < args.size(); i++)
+ for (int i = 0; i < GetSize(args); i++)
defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i];
} else {
insert_input(tok);
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index c6d4a0b7..635c9ce4 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -54,6 +54,10 @@ struct VerilogFrontend : public Frontend {
log(" enable support for SystemVerilog features. (only a small subset\n");
log(" of SystemVerilog is supported)\n");
log("\n");
+ log(" -formal\n");
+ log(" enable support for assert() and assume() statements\n");
+ log(" (assert support is also enabled with -sv)\n");
+ log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@@ -83,11 +87,20 @@ struct VerilogFrontend : public Frontend {
log(" this can also be achieved by setting the 'nomem2reg'\n");
log(" attribute on the respective module or register.\n");
log("\n");
+ log(" This is potentially dangerous. Usually the front-end has good\n");
+ log(" reasons for converting an array to a list of registers.\n");
+ log(" Prohibiting this step will likely result in incorrect synthesis\n");
+ log(" results.\n");
+ log("\n");
log(" -mem2reg\n");
log(" always convert memories to registers. this can also be\n");
log(" achieved by setting the 'mem2reg' attribute on the respective\n");
log(" module or register.\n");
log("\n");
+ log(" -nomeminit\n");
+ log(" do not infer $meminit cells and instead convert initialized\n");
+ log(" memories to registers directly in the front-end.\n");
+ log("\n");
log(" -ppdump\n");
log(" dump verilog code after pre-processor\n");
log("\n");
@@ -139,6 +152,7 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_ast2 = false;
bool flag_dump_vlog = false;
bool flag_nolatches = false;
+ bool flag_nomeminit = false;
bool flag_nomem2reg = false;
bool flag_mem2reg = false;
bool flag_ppdump = false;
@@ -154,6 +168,7 @@ struct VerilogFrontend : public Frontend {
frontend_verilog_yydebug = false;
sv_mode = false;
+ formal_mode = false;
log_header("Executing Verilog-2005 frontend.\n");
@@ -166,6 +181,10 @@ struct VerilogFrontend : public Frontend {
sv_mode = true;
continue;
}
+ if (arg == "-formal") {
+ formal_mode = true;
+ continue;
+ }
if (arg == "-dump_ast1") {
flag_dump_ast1 = true;
continue;
@@ -186,6 +205,10 @@ struct VerilogFrontend : public Frontend {
flag_nolatches = true;
continue;
}
+ if (arg == "-nomeminit") {
+ flag_nomeminit = true;
+ continue;
+ }
if (arg == "-nomem2reg") {
flag_nomem2reg = true;
continue;
@@ -257,7 +280,8 @@ struct VerilogFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
- log("Parsing Verilog input from `%s' to AST representation.\n", filename.c_str());
+ log("Parsing %s%s input from `%s' to AST representation.\n",
+ formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
AST::current_filename = filename;
AST::set_line_num = &frontend_verilog_yyset_lineno;
@@ -288,7 +312,7 @@ struct VerilogFrontend : public Frontend {
child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
}
- AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
+ AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
@@ -300,22 +324,6 @@ struct VerilogFrontend : public Frontend {
}
} VerilogFrontend;
-// the yyerror function used by bison to report parser errors
-void frontend_verilog_yyerror(char const *fmt, ...)
-{
- va_list ap;
- char buffer[1024];
- char *p = buffer;
- p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
- AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
- va_start(ap, fmt);
- p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
- va_end(ap);
- p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
- log_error("%s", buffer);
- exit(1);
-}
-
struct VerilogDefaults : public Pass {
VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { }
virtual void help()
@@ -376,3 +384,19 @@ struct VerilogDefaults : public Pass {
YOSYS_NAMESPACE_END
+// the yyerror function used by bison to report parser errors
+void frontend_verilog_yyerror(char const *fmt, ...)
+{
+ va_list ap;
+ char buffer[1024];
+ char *p = buffer;
+ p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
+ YOSYS_NAMESPACE_PREFIX AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
+ va_start(ap, fmt);
+ p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
+ va_end(ap);
+ p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
+ YOSYS_NAMESPACE_PREFIX log_error("%s", buffer);
+ exit(1);
+}
+
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index af6495f8..5561f54c 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -43,7 +43,7 @@ namespace VERILOG_FRONTEND
extern struct AST::AstNode *current_ast;
// this function converts a Verilog constant to an AST_CONSTANT node
- AST::AstNode *const2ast(std::string code, char case_type = 0);
+ AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
// state of `default_nettype
extern bool default_nettype_wire;
@@ -51,6 +51,9 @@ namespace VERILOG_FRONTEND
// running in SystemVerilog mode
extern bool sv_mode;
+ // running in -formal mode
+ extern bool formal_mode;
+
// lexer input stream
extern std::istream *lexin;
}
diff --git a/frontends/verilog/lexer.l b/frontends/verilog/verilog_lexer.l
index c9302aba..8fbaa953 100644
--- a/frontends/verilog/lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -42,7 +42,7 @@
#include "kernel/log.h"
#include "verilog_frontend.h"
#include "frontends/ast/ast.h"
-#include "parser.tab.h"
+#include "verilog_parser.tab.h"
USING_YOSYS_NAMESPACE
using namespace AST;
@@ -64,7 +64,7 @@ YOSYS_NAMESPACE_END
return TOK_ID;
#define YY_INPUT(buf,result,max_size) \
- result = lexin->readsome(buf, max_size);
+ result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
%}
@@ -85,6 +85,10 @@ YOSYS_NAMESPACE_END
fn_stack.push_back(current_filename);
ln_stack.push_back(frontend_verilog_yyget_lineno());
current_filename = yytext+11;
+ if (!current_filename.empty() && current_filename.front() == '"')
+ current_filename = current_filename.substr(1);
+ if (!current_filename.empty() && current_filename.back() == '"')
+ current_filename = current_filename.substr(0, current_filename.size()-1);
frontend_verilog_yyset_lineno(0);
}
@@ -112,6 +116,9 @@ YOSYS_NAMESPACE_END
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
+"`celldefine"[^\n]* /* ignore `celldefine */
+"`endcelldefine"[^\n]* /* ignore `endcelldefine */
+
"`default_nettype"[ \t]+[^ \t\r\n/]+ {
char *p = yytext;
while (*p != 0 && *p != ' ' && *p != '\t') p++;
@@ -162,8 +169,9 @@ YOSYS_NAMESPACE_END
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
-"assert" { SV_KEYWORD(TOK_ASSERT); }
-"property" { SV_KEYWORD(TOK_PROPERTY); }
+"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
+"assume" { if (formal_mode) return TOK_ASSUME; return TOK_ID; }
+"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
"logic" { SV_KEYWORD(TOK_REG); }
"bit" { SV_KEYWORD(TOK_REG); }
@@ -177,12 +185,12 @@ YOSYS_NAMESPACE_END
"genvar" { return TOK_GENVAR; }
"real" { return TOK_REAL; }
-[0-9]+ {
+[0-9][0-9_]* {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONST;
}
-[0-9]*[ \t]*\'s?[bodh][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
+[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONST;
}
@@ -240,7 +248,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
supply0 { return TOK_SUPPLY0; }
supply1 { return TOK_SUPPLY1; }
-"$"(display|time|stop|finish) {
+"$"(display|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;
}
@@ -254,8 +262,12 @@ supply1 { return TOK_SUPPLY1; }
}
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
- log("Warning: Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n");
- log("It is strongly suggested to use `ifdef constructs instead!\n");
+ static bool printed_warning = false;
+ if (!printed_warning) {
+ log_warning("Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n"
+ "Yosys does support them but it is recommended to use `ifdef constructs instead!\n");
+ printed_warning = true;
+ }
BEGIN(SYNOPSYS_TRANSLATE_OFF);
}
<SYNOPSYS_TRANSLATE_OFF>. /* ignore synopsys translate_off body */
@@ -266,13 +278,21 @@ supply1 { return TOK_SUPPLY1; }
BEGIN(SYNOPSYS_FLAGS);
}
<SYNOPSYS_FLAGS>full_case {
- log("Warning: Found one of those horrible `(synopsys|synthesis) full_case' comments.\n");
- log("It is strongly suggested to use verilog x-values and default branches instead!\n");
+ static bool printed_warning = false;
+ if (!printed_warning) {
+ log_warning("Found one of those horrible `(synopsys|synthesis) full_case' comments.\n"
+ "Yosys does support them but it is recommended to use verilog `full_case' attributes instead!\n");
+ printed_warning = true;
+ }
return TOK_SYNOPSYS_FULL_CASE;
}
<SYNOPSYS_FLAGS>parallel_case {
- log("Warning: Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n");
- log("It is strongly suggested to use verilog `parallel_case' attributes instead!\n");
+ static bool printed_warning = false;
+ if (!printed_warning) {
+ log_warning("Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n"
+ "Yosys does support them but it is recommended to use verilog `parallel_case' attributes instead!\n");
+ printed_warning = true;
+ }
return TOK_SYNOPSYS_PARALLEL_CASE;
}
<SYNOPSYS_FLAGS>. /* ignore everything else */
@@ -342,7 +362,10 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
[ \t\r\n] /* ignore whitespaces */
\\[\r\n] /* ignore continuation sequence */
"//"[^\r\n]* /* ignore one-line comments */
-"#"[$a-zA-Z_0-9\.]+ /* ignore simulation timings */
+
+"#"\ *[0-9][0-9_]* /* ignore simulation timings */
+"#"\ *[0-9][0-9_]*\.[0-9][0-9_]* /* ignore simulation timings */
+"#"\ *[$a-zA-Z_\.][$a-zA-Z_0-9\.]* /* ignore simulation timings */
. { return *yytext; }
diff --git a/frontends/verilog/parser.y b/frontends/verilog/verilog_parser.y
index a9f69a49..d935cab3 100644
--- a/frontends/verilog/parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -57,7 +57,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
- bool sv_mode;
+ bool sv_mode, formal_mode;
std::istream *lexin;
}
YOSYS_NAMESPACE_END
@@ -111,7 +111,7 @@ 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_PROPERTY
+%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME TOK_PROPERTY
%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
@@ -139,10 +139,11 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%%
input: {
+ ast_stack.clear();
ast_stack.push_back(current_ast);
} design {
ast_stack.pop_back();
- log_assert(SIZE(ast_stack) == 0);
+ log_assert(GetSize(ast_stack) == 0);
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
@@ -240,7 +241,7 @@ module:
};
module_para_opt:
- '#' '(' module_para_list ')' | /* empty */;
+ '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */;
module_para_list:
single_module_para |
@@ -249,11 +250,10 @@ module_para_list:
single_module_para:
TOK_PARAMETER {
+ if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
- } param_signed param_integer param_range single_param_decl {
- delete astbuf1;
- };
+ } param_signed param_integer param_range single_param_decl | single_param_decl;
module_args_opt:
'(' ')' | /* empty */ | '(' module_args optional_comma ')';
@@ -310,10 +310,17 @@ module_arg:
do_not_require_port_stubs = true;
};
+non_opt_delay:
+ '#' '(' expr ')' { delete $3; } |
+ '#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; };
+
+delay:
+ non_opt_delay | /* empty */;
+
wire_type:
{
astbuf3 = new AstNode(AST_WIRE);
- } wire_type_token_list {
+ } wire_type_token_list delay {
$$ = astbuf3;
};
@@ -449,7 +456,7 @@ task_func_decl:
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
- attr TOK_TASK TOK_ID ';' {
+ attr TOK_TASK TOK_ID {
current_function_or_task = new AstNode(AST_TASK);
current_function_or_task->str = *$3;
append_attr(current_function_or_task, $1);
@@ -457,11 +464,11 @@ task_func_decl:
ast_stack.push_back(current_function_or_task);
current_function_or_task_port_id = 1;
delete $3;
- } task_func_body TOK_ENDTASK {
+ } task_func_args_opt ';' task_func_body TOK_ENDTASK {
current_function_or_task = NULL;
ast_stack.pop_back();
} |
- attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID ';' {
+ attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID {
current_function_or_task = new AstNode(AST_FUNCTION);
current_function_or_task->str = *$5;
append_attr(current_function_or_task, $1);
@@ -478,7 +485,7 @@ task_func_decl:
current_function_or_task->children.push_back(outreg);
current_function_or_task_port_id = 1;
delete $5;
- } task_func_body TOK_ENDFUNCTION {
+ } task_func_args_opt ';' task_func_body TOK_ENDFUNCTION {
current_function_or_task = NULL;
ast_stack.pop_back();
};
@@ -512,6 +519,45 @@ opt_signed:
$$ = false;
};
+task_func_args_opt:
+ '(' ')' | /* empty */ | '(' {
+ albuf = nullptr;
+ astbuf1 = nullptr;
+ astbuf2 = nullptr;
+ } task_func_args optional_comma {
+ delete astbuf1;
+ if (astbuf2 != NULL)
+ delete astbuf2;
+ free_attr(albuf);
+ } ')';
+
+task_func_args:
+ task_func_port | task_func_args ',' task_func_port;
+
+task_func_port:
+ attr wire_type range {
+ if (albuf) {
+ delete astbuf1;
+ if (astbuf2 != NULL)
+ delete astbuf2;
+ free_attr(albuf);
+ }
+ albuf = $1;
+ astbuf1 = $2;
+ astbuf2 = $3;
+ if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
+ if (astbuf2) {
+ frontend_verilog_yyerror("Syntax error.");
+ } else {
+ astbuf2 = new AstNode(AST_RANGE);
+ astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
+ astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true));
+ }
+ }
+ if (astbuf2 && astbuf2->children.size() != 2)
+ frontend_verilog_yyerror("Syntax error.");
+ } wire_name | wire_name;
+
task_func_body:
task_func_body behavioral_stmt |
/* empty */;
@@ -568,6 +614,8 @@ param_decl_list:
single_param_decl:
TOK_ID '=' expr {
+ if (astbuf1 == nullptr)
+ frontend_verilog_yyerror("syntax error");
AstNode *node = astbuf1->clone();
node->str = *$1;
delete node->children[0];
@@ -609,27 +657,39 @@ wire_decl:
}
if (astbuf2 && astbuf2->children.size() != 2)
frontend_verilog_yyerror("Syntax error.");
- } wire_name_list ';' {
+ } wire_name_list {
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
free_attr(albuf);
- } |
- attr TOK_SUPPLY0 TOK_ID ';' {
+ } ';' |
+ attr TOK_SUPPLY0 TOK_ID {
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
ast_stack.back()->children.back()->str = *$3;
append_attr(ast_stack.back()->children.back(), $1);
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)));
ast_stack.back()->children.back()->children[0]->str = *$3;
delete $3;
- } |
- attr TOK_SUPPLY1 TOK_ID ';' {
+ } opt_supply_wires ';' |
+ attr TOK_SUPPLY1 TOK_ID {
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
ast_stack.back()->children.back()->str = *$3;
append_attr(ast_stack.back()->children.back(), $1);
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1)));
ast_stack.back()->children.back()->children[0]->str = *$3;
delete $3;
+ } opt_supply_wires ';';
+
+opt_supply_wires:
+ /* empty */ |
+ opt_supply_wires ',' TOK_ID {
+ AstNode *wire_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-2)->clone();
+ AstNode *assign_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-1)->clone();
+ wire_node->str = *$3;
+ assign_node->children[0]->str = *$3;
+ ast_stack.back()->children.push_back(wire_node);
+ ast_stack.back()->children.push_back(assign_node);
+ delete $3;
};
wire_name_list:
@@ -689,7 +749,7 @@ wire_name:
};
assign_stmt:
- TOK_ASSIGN assign_expr_list ';';
+ TOK_ASSIGN delay assign_expr_list ';';
assign_expr_list:
assign_expr | assign_expr_list ',' assign_expr;
@@ -709,7 +769,7 @@ cell_stmt:
} cell_parameter_list_opt cell_list ';' {
delete astbuf1;
} |
- attr tok_prim_wrapper {
+ attr tok_prim_wrapper delay {
astbuf1 = new AstNode(AST_PRIMITIVE);
astbuf1->str = *$2;
append_attr(astbuf1, $1);
@@ -874,27 +934,34 @@ opt_label:
assert:
TOK_ASSERT '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3));
+ } |
+ TOK_ASSUME '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
};
assert_property:
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4));
+ } |
+ TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
};
simple_behavioral_stmt:
- lvalue '=' expr {
- AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
+ lvalue '=' delay expr {
+ AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4);
ast_stack.back()->children.push_back(node);
} |
- lvalue OP_LE expr {
- AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $3);
+ lvalue OP_LE delay expr {
+ AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4);
ast_stack.back()->children.push_back(node);
};
// this production creates the obligatory if-else shift/reduce conflict
behavioral_stmt:
defattr | assert | wire_decl |
- simple_behavioral_stmt ';' |
+ non_opt_delay behavioral_stmt |
+ simple_behavioral_stmt ';' | ';' |
hierarchical_id attr {
AstNode *node = new AstNode(AST_TCALL);
node->str = *$1;
@@ -1008,10 +1075,6 @@ opt_synopsys_attr:
} |
/* empty */;
-behavioral_stmt_opt:
- behavioral_stmt |
- ';' ;
-
behavioral_stmt_list:
behavioral_stmt_list behavioral_stmt |
/* empty */;
@@ -1040,7 +1103,7 @@ case_item:
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
case_type_stack.push_back(0);
- } behavioral_stmt_opt {
+ } behavioral_stmt {
case_type_stack.pop_back();
ast_stack.pop_back();
ast_stack.pop_back();
@@ -1211,7 +1274,7 @@ basic_expr:
if ($4->substr(0, 1) != "'")
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = $2;
- AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $4->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1222,7 +1285,7 @@ basic_expr:
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = new AstNode(AST_IDENTIFIER);
bits->str = *$1;
- AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $2->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1230,14 +1293,14 @@ basic_expr:
delete $2;
} |
TOK_CONST TOK_CONST {
- $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if ($$ == NULL || (*$2)[0] != '\'')
log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
delete $1;
delete $2;
} |
TOK_CONST {
- $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
+ $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if ($$ == NULL)
log_error("Value conversion failed: `%s'\n", $1->c_str());
delete $1;
@@ -1278,10 +1341,15 @@ basic_expr:
'(' expr ')' {
$$ = $2;
} |
+ '(' expr ':' expr ':' expr ')' {
+ delete $2;
+ $$ = $4;
+ delete $6;
+ } |
'{' concat_list '}' {
$$ = $2;
} |
- '{' expr '{' expr '}' '}' {
+ '{' expr '{' concat_list '}' '}' {
$$ = new AstNode(AST_REPLICATE, $2, $4);
} |
'~' attr basic_expr %prec UNARY_OPS {
diff --git a/frontends/vhdl2verilog/vhdl2verilog.cc b/frontends/vhdl2verilog/vhdl2verilog.cc
index b408d621..82ff7b50 100644
--- a/frontends/vhdl2verilog/vhdl2verilog.cc
+++ b/frontends/vhdl2verilog/vhdl2verilog.cc
@@ -20,14 +20,17 @@
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
-#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <dirent.h>
#include <errno.h>
#include <limits.h>
+#ifndef _WIN32
+# include <unistd.h>
+# include <dirent.h>
+#endif
+
YOSYS_NAMESPACE_BEGIN
struct Vhdl2verilogPass : public Pass {
@@ -120,11 +123,8 @@ struct Vhdl2verilogPass : public Pass {
if (top_entity.empty())
log_cmd_error("Missing -top option.\n");
- char tempdir_name[] = "/tmp/yosys-vhdl2verilog-XXXXXX";
- char *p = mkdtemp(tempdir_name);
- log("Using temp directory %s.\n", tempdir_name);
- if (p == NULL)
- log_error("For some reason mkdtemp() failed!\n");
+ std::string tempdir_name = make_temp_dir("/tmp/yosys-vhdl2verilog-XXXXXX");
+ log("Using temp directory %s.\n", tempdir_name.c_str());
if (!out_file.empty() && out_file[0] != '/') {
char pwd[PATH_MAX];
@@ -135,7 +135,7 @@ struct Vhdl2verilogPass : public Pass {
out_file = pwd + ("/" + out_file);
}
- FILE *f = fopen(stringf("%s/files.list", tempdir_name).c_str(), "wt");
+ FILE *f = fopen(stringf("%s/files.list", tempdir_name.c_str()).c_str(), "wt");
while (argidx < args.size()) {
std::string file = args[argidx++];
if (file.empty())
@@ -156,38 +156,25 @@ struct Vhdl2verilogPass : public Pass {
std::string command = "exec 2>&1; ";
if (!vhdl2verilog_dir.empty())
command += stringf("cd '%s'; . ./setup_env.sh; ", vhdl2verilog_dir.c_str());
- command += stringf("cd '%s'; vhdl2verilog -out '%s' -filelist files.list -top '%s'%s", tempdir_name,
+ command += stringf("cd '%s'; vhdl2verilog -out '%s' -filelist files.list -top '%s'%s", tempdir_name.c_str(),
out_file.empty() ? "vhdl2verilog_output.v" : out_file.c_str(), top_entity.c_str(), extra_opts.c_str());
log("Running '%s'..\n", command.c_str());
- errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
- f = popen(command.c_str(), "r");
- if (f == NULL)
- log_error("Opening pipe to `%s' for reading failed: %s\n", command.c_str(), strerror(errno));
-
- char logbuf[1024];
- while (fgets(logbuf, 1024, f) != NULL)
- log("%s", logbuf);
-
- int ret = pclose(f);
- if (ret < 0)
- log_error("Closing pipe to `%s' failed: %s\n", command.c_str(), strerror(errno));
- if (WEXITSTATUS(ret) != 0)
- log_error("Execution of command \"%s\" failed: the shell returned %d\n", command.c_str(), WEXITSTATUS(ret));
+ int ret = run_command(command, [](const std::string &line) { log("%s", line.c_str()); });
+ if (ret != 0)
+ log_error("Execution of command \"%s\" failed: return code %d.\n", command.c_str(), ret);
if (out_file.empty()) {
std::ifstream ff;
- ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name).c_str());
+ ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()).c_str());
if (ff.fail())
log_error("Can't open vhdl2verilog output file `vhdl2verilog_output.v'.\n");
- Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name), "verilog");
+ Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()), "verilog");
}
- log_header("Removing temp directory `%s':\n", tempdir_name);
- if (system(stringf("rm -rf '%s'", tempdir_name).c_str()) != 0)
- log_error("Execution of \"rm -rf '%s'\" failed!\n", tempdir_name);
-
+ log_header("Removing temp directory `%s':\n", tempdir_name.c_str());
+ remove_directory(tempdir_name);
log_pop();
}
} Vhdl2verilogPass;
diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h
index 91f54593..00bbc3bf 100644
--- a/kernel/bitpattern.h
+++ b/kernel/bitpattern.h
@@ -23,24 +23,46 @@
#include "kernel/log.h"
#include "kernel/rtlil.h"
+YOSYS_NAMESPACE_BEGIN
+
struct BitPatternPool
{
int width;
- typedef std::vector<RTLIL::State> bits_t;
- std::set<bits_t> pool;
+ struct bits_t {
+ std::vector<RTLIL::State> bitdata;
+ unsigned int cached_hash;
+ bits_t(int width = 0) : bitdata(width), cached_hash(0) { }
+ RTLIL::State &operator[](int index) {
+ return bitdata[index];
+ }
+ const RTLIL::State &operator[](int index) const {
+ return bitdata[index];
+ }
+ bool operator==(const bits_t &other) const {
+ if (hash() != other.hash())
+ return false;
+ return bitdata == other.bitdata;
+ }
+ unsigned int hash() const {
+ if (!cached_hash)
+ ((bits_t*)this)->cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata);
+ return cached_hash;
+ }
+ };
+ pool<bits_t> database;
BitPatternPool(RTLIL::SigSpec sig)
{
width = sig.size();
if (width > 0) {
- std::vector<RTLIL::State> pattern(width);
+ bits_t pattern(width);
for (int i = 0; i < width; i++) {
if (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1)
pattern[i] = sig[i].data;
else
pattern[i] = RTLIL::State::Sa;
}
- pool.insert(pattern);
+ database.insert(pattern);
}
}
@@ -48,17 +70,18 @@ struct BitPatternPool
{
this->width = width;
if (width > 0) {
- std::vector<RTLIL::State> pattern(width);
+ bits_t pattern(width);
for (int i = 0; i < width; i++)
pattern[i] = RTLIL::State::Sa;
- pool.insert(pattern);
+ database.insert(pattern);
}
}
bits_t sig2bits(RTLIL::SigSpec sig)
{
- bits_t bits = sig.as_const().bits;
- for (auto &b : bits)
+ bits_t bits;
+ bits.bitdata = sig.as_const().bits;
+ for (auto &b : bits.bitdata)
if (b > RTLIL::State::S1)
b = RTLIL::State::Sa;
return bits;
@@ -66,8 +89,8 @@ struct BitPatternPool
bool match(bits_t a, bits_t b)
{
- log_assert(int(a.size()) == width);
- log_assert(int(b.size()) == width);
+ log_assert(int(a.bitdata.size()) == width);
+ log_assert(int(b.bitdata.size()) == width);
for (int i = 0; i < width; i++)
if (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i])
return false;
@@ -77,7 +100,7 @@ struct BitPatternPool
bool has_any(RTLIL::SigSpec sig)
{
bits_t bits = sig2bits(sig);
- for (auto &it : pool)
+ for (auto &it : database)
if (match(it, bits))
return true;
return false;
@@ -86,13 +109,13 @@ struct BitPatternPool
bool has_all(RTLIL::SigSpec sig)
{
bits_t bits = sig2bits(sig);
- for (auto &it : pool)
+ for (auto &it : database)
if (match(it, bits)) {
for (int i = 0; i < width; i++)
if (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1)
- goto next_pool_entry;
+ goto next_database_entry;
return true;
- next_pool_entry:;
+ next_database_entry:;
}
return false;
}
@@ -101,36 +124,38 @@ struct BitPatternPool
{
bool status = false;
bits_t bits = sig2bits(sig);
- std::vector<bits_t> pattern_list;
- for (auto &it : pool)
- if (match(it, bits))
- pattern_list.push_back(it);
- for (auto pattern : pattern_list) {
- pool.erase(pattern);
- for (int i = 0; i < width; i++) {
- if (pattern[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
- continue;
- bits_t new_pattern = pattern;
- new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
- pool.insert(new_pattern);
- }
- status = true;
- }
+ for (auto it = database.begin(); it != database.end();)
+ if (match(*it, bits)) {
+ for (int i = 0; i < width; i++) {
+ if ((*it)[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
+ continue;
+ bits_t new_pattern;
+ new_pattern.bitdata = it->bitdata;
+ new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
+ database.insert(new_pattern);
+ }
+ it = database.erase(it);
+ status = true;
+ continue;
+ } else
+ ++it;
return status;
}
bool take_all()
{
- if (pool.empty())
+ if (database.empty())
return false;
- pool.clear();
+ database.clear();
return true;
}
bool empty()
{
- return pool.empty();
+ return database.empty();
}
};
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/kernel/calc.cc b/kernel/calc.cc
index 41179d04..aa3e8b91 100644
--- a/kernel/calc.cc
+++ b/kernel/calc.cc
@@ -303,7 +303,7 @@ RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
- extend_u0(arg1_ext, std::max(result_len, SIZE(arg1)), signed1);
+ extend_u0(arg1_ext, std::max(result_len, GetSize(arg1)), signed1);
return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
}
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 85c21ef3..533c370f 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -27,13 +27,13 @@ YOSYS_NAMESPACE_BEGIN
struct CellType
{
RTLIL::IdString type;
- std::set<RTLIL::IdString> inputs, outputs;
+ pool<RTLIL::IdString> inputs, outputs;
bool is_evaluable;
};
struct CellTypes
{
- std::map<RTLIL::IdString, CellType> cell_types;
+ dict<RTLIL::IdString, CellType> cell_types;
CellTypes()
{
@@ -55,7 +55,7 @@ struct CellTypes
setup_stdcells_mem();
}
- void setup_type(RTLIL::IdString type, const std::set<RTLIL::IdString> &inputs, const std::set<RTLIL::IdString> &outputs, bool is_evaluable = false)
+ void setup_type(RTLIL::IdString type, const pool<RTLIL::IdString> &inputs, const pool<RTLIL::IdString> &outputs, bool is_evaluable = false)
{
CellType ct = {type, inputs, outputs, is_evaluable};
cell_types[ct.type] = ct;
@@ -63,7 +63,7 @@ struct CellTypes
void setup_module(RTLIL::Module *module)
{
- std::set<RTLIL::IdString> inputs, outputs;
+ pool<RTLIL::IdString> inputs, outputs;
for (RTLIL::IdString wire_name : module->ports) {
RTLIL::Wire *wire = module->wire(wire_name);
if (wire->port_input)
@@ -96,82 +96,105 @@ struct CellTypes
"$logic_and", "$logic_or", "$concat", "$macc"
};
+ IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y";
+ IdString P = "\\P", G = "\\G", C = "\\C", X = "\\X";
+ IdString BI = "\\BI", CI = "\\CI", CO = "\\CO", EN = "\\EN";
+
for (auto type : unary_ops)
- setup_type(type, {"\\A"}, {"\\Y"}, true);
+ setup_type(type, {A}, {Y}, true);
for (auto type : binary_ops)
- setup_type(type, {"\\A", "\\B"}, {"\\Y"}, true);
+ setup_type(type, {A, B}, {Y}, true);
for (auto type : std::vector<RTLIL::IdString>({"$mux", "$pmux"}))
- setup_type(type, {"\\A", "\\B", "\\S"}, {"\\Y"}, true);
+ setup_type(type, {A, B, S}, {Y}, true);
- setup_type("$lcu", {"\\P", "\\G", "\\CI"}, {"\\CO"}, true);
- setup_type("$alu", {"\\A", "\\B", "\\CI", "\\BI"}, {"\\X", "\\Y", "\\CO"}, true);
- setup_type("$fa", {"\\A", "\\B", "\\C"}, {"\\X", "\\Y"}, true);
+ setup_type("$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("$assert", {"\\A", "\\EN"}, std::set<RTLIL::IdString>(), true);
+ setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$equiv", {A, B}, {Y}, true);
}
void setup_internals_mem()
{
- setup_type("$sr", {"\\SET", "\\CLR"}, {"\\Q"});
- setup_type("$dff", {"\\CLK", "\\D"}, {"\\Q"});
- setup_type("$dffsr", {"\\CLK", "\\SET", "\\CLR", "\\D"}, {"\\Q"});
- setup_type("$adff", {"\\CLK", "\\ARST", "\\D"}, {"\\Q"});
- setup_type("$dlatch", {"\\EN", "\\D"}, {"\\Q"});
- setup_type("$dlatchsr", {"\\EN", "\\SET", "\\CLR", "\\D"}, {"\\Q"});
-
- setup_type("$memrd", {"\\CLK", "\\ADDR"}, {"\\DATA"});
- setup_type("$memwr", {"\\CLK", "\\EN", "\\ADDR", "\\DATA"}, std::set<RTLIL::IdString>());
- setup_type("$mem", {"\\RD_CLK", "\\RD_ADDR", "\\WR_CLK", "\\WR_EN", "\\WR_ADDR", "\\WR_DATA"}, {"\\RD_DATA"});
-
- setup_type("$fsm", {"\\CLK", "\\ARST", "\\CTRL_IN"}, {"\\CTRL_OUT"});
+ IdString SET = "\\SET", CLR = "\\CLR", CLK = "\\CLK", ARST = "\\ARST", EN = "\\EN";
+ IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA";
+ IdString RD_CLK = "\\RD_CLK", RD_ADDR = "\\RD_ADDR", WR_CLK = "\\WR_CLK", WR_EN = "\\WR_EN";
+ IdString WR_ADDR = "\\WR_ADDR", WR_DATA = "\\WR_DATA", RD_DATA = "\\RD_DATA";
+ IdString CTRL_IN = "\\CTRL_IN", CTRL_OUT = "\\CTRL_OUT";
+
+ setup_type("$sr", {SET, CLR}, {Q});
+ setup_type("$dff", {CLK, D}, {Q});
+ setup_type("$dffe", {CLK, EN, D}, {Q});
+ setup_type("$dffsr", {CLK, SET, CLR, D}, {Q});
+ setup_type("$adff", {CLK, ARST, D}, {Q});
+ setup_type("$dlatch", {EN, D}, {Q});
+ setup_type("$dlatchsr", {EN, SET, CLR, D}, {Q});
+
+ setup_type("$memrd", {CLK, ADDR}, {DATA});
+ setup_type("$memwr", {CLK, EN, ADDR, DATA}, pool<RTLIL::IdString>());
+ setup_type("$meminit", {ADDR, DATA}, pool<RTLIL::IdString>());
+ setup_type("$mem", {RD_CLK, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA});
+
+ setup_type("$fsm", {CLK, ARST, CTRL_IN}, {CTRL_OUT});
}
void setup_stdcells()
{
- setup_type("$_NOT_", {"\\A"}, {"\\Y"}, true);
- setup_type("$_AND_", {"\\A", "\\B"}, {"\\Y"}, true);
- setup_type("$_NAND_", {"\\A", "\\B"}, {"\\Y"}, true);
- setup_type("$_OR_", {"\\A", "\\B"}, {"\\Y"}, true);
- setup_type("$_NOR_", {"\\A", "\\B"}, {"\\Y"}, true);
- setup_type("$_XOR_", {"\\A", "\\B"}, {"\\Y"}, true);
- setup_type("$_XNOR_", {"\\A", "\\B"}, {"\\Y"}, true);
- setup_type("$_MUX_", {"\\A", "\\B", "\\S"}, {"\\Y"}, true);
- setup_type("$_AOI3_", {"\\A", "\\B", "\\C"}, {"\\Y"}, true);
- setup_type("$_OAI3_", {"\\A", "\\B", "\\C"}, {"\\Y"}, true);
- setup_type("$_AOI4_", {"\\A", "\\B", "\\C", "\\D"}, {"\\Y"}, true);
- setup_type("$_OAI4_", {"\\A", "\\B", "\\C", "\\D"}, {"\\Y"}, true);
+ IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D", S = "\\S", Y = "\\Y";
+ setup_type("$_BUF_", {A}, {Y}, true);
+ setup_type("$_NOT_", {A}, {Y}, true);
+ setup_type("$_AND_", {A, B}, {Y}, true);
+ setup_type("$_NAND_", {A, B}, {Y}, true);
+ setup_type("$_OR_", {A, B}, {Y}, true);
+ setup_type("$_NOR_", {A, B}, {Y}, true);
+ setup_type("$_XOR_", {A, B}, {Y}, true);
+ setup_type("$_XNOR_", {A, B}, {Y}, true);
+ setup_type("$_MUX_", {A, B, S}, {Y}, true);
+ setup_type("$_AOI3_", {A, B, C}, {Y}, true);
+ setup_type("$_OAI3_", {A, B, C}, {Y}, true);
+ setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
+ setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
}
void setup_stdcells_mem()
{
+ IdString S = "\\S", R = "\\R", C = "\\C";
+ IdString D = "\\D", Q = "\\Q", E = "\\E";
+
std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};
for (auto c1 : list_np)
for (auto c2 : list_np)
- setup_type(stringf("$_SR_%c%c_", c1, c2), {"\\S", "\\R"}, {"\\Q"});
+ setup_type(stringf("$_SR_%c%c_", c1, c2), {S, R}, {Q});
+
+ for (auto c1 : list_np)
+ setup_type(stringf("$_DFF_%c_", c1), {C, D}, {Q});
for (auto c1 : list_np)
- setup_type(stringf("$_DFF_%c_", c1), {"\\C", "\\D"}, {"\\Q"});
+ for (auto c2 : list_np)
+ setup_type(stringf("$_DFFE_%c%c_", c1, c2), {C, D, E}, {Q});
for (auto c1 : list_np)
for (auto c2 : list_np)
for (auto c3 : list_01)
- setup_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {"\\C", "\\R", "\\D"}, {"\\Q"});
+ setup_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {C, R, D}, {Q});
for (auto c1 : list_np)
for (auto c2 : list_np)
for (auto c3 : list_np)
- setup_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {"\\C", "\\S", "\\R", "\\D"}, {"\\Q"});
+ setup_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {C, S, R, D}, {Q});
for (auto c1 : list_np)
- setup_type(stringf("$_DLATCH_%c_", c1), {"\\E", "\\D"}, {"\\Q"});
+ setup_type(stringf("$_DLATCH_%c_", c1), {E, D}, {Q});
for (auto c1 : list_np)
for (auto c2 : list_np)
for (auto c3 : list_np)
- setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {"\\E", "\\S", "\\R", "\\D"}, {"\\Q"});
+ setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {E, S, R, D}, {Q});
}
void clear()
@@ -261,6 +284,8 @@ struct CellTypes
HANDLE_CELL_TYPE(neg)
#undef HANDLE_CELL_TYPE
+ if (type == "$_BUF_")
+ return arg1;
if (type == "$_NOT_")
return eval_not(arg1);
if (type == "$_AND_")
@@ -300,7 +325,7 @@ struct CellTypes
int width = cell->parameters.at("\\WIDTH").as_int();
std::vector<RTLIL::State> t = cell->parameters.at("\\LUT").bits;
- while (SIZE(t) < (1 << width))
+ while (GetSize(t) < (1 << width))
t.push_back(RTLIL::S0);
t.resize(1 << width);
@@ -308,16 +333,16 @@ struct CellTypes
RTLIL::State sel = arg1.bits.at(i);
std::vector<RTLIL::State> new_t;
if (sel == RTLIL::S0)
- new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + SIZE(t)/2);
+ new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
else if (sel == RTLIL::S1)
- new_t = std::vector<RTLIL::State>(t.begin() + SIZE(t)/2, t.end());
+ new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
else
- for (int j = 0; j < SIZE(t)/2; j++)
- new_t.push_back(t[j] == t[j + SIZE(t)/2] ? t[j] : RTLIL::Sx);
+ for (int j = 0; j < GetSize(t)/2; j++)
+ new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
t.swap(new_t);
}
- log_assert(SIZE(t) == 1);
+ log_assert(GetSize(t) == 1);
return t;
}
@@ -360,6 +385,9 @@ struct CellTypes
}
};
+// initialized by yosys_setup()
+extern CellTypes yosys_celltypes;
+
YOSYS_NAMESPACE_END
#endif
diff --git a/kernel/consteval.h b/kernel/consteval.h
index 2d29d3f7..c2e9710f 100644
--- a/kernel/consteval.h
+++ b/kernel/consteval.h
@@ -25,6 +25,8 @@
#include "kernel/celltypes.h"
#include "kernel/macc.h"
+YOSYS_NAMESPACE_BEGIN
+
struct ConstEval
{
RTLIL::Module *module;
@@ -72,7 +74,7 @@ struct ConstEval
assign_map.apply(sig);
#ifndef NDEBUG
RTLIL::SigSpec current_val = values_map(sig);
- for (int i = 0; i < SIZE(current_val); i++)
+ for (int i = 0; i < GetSize(current_val); i++)
log_assert(current_val[i].wire != NULL || current_val[i] == value.bits[i]);
#endif
values_map.add(sig, RTLIL::SigSpec(value));
@@ -107,10 +109,10 @@ struct ConstEval
if (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def())
{
- RTLIL::Const coval(RTLIL::Sx, SIZE(sig_co));
+ RTLIL::Const coval(RTLIL::Sx, GetSize(sig_co));
bool carry = sig_ci.as_bool();
- for (int i = 0; i < SIZE(coval); i++) {
+ for (int i = 0; i < GetSize(coval); i++) {
carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry);
coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0;
}
@@ -118,7 +120,7 @@ struct ConstEval
set(sig_co, coval);
}
else
- set(sig_co, RTLIL::Const(RTLIL::Sx, SIZE(sig_co)));
+ set(sig_co, RTLIL::Const(RTLIL::Sx, GetSize(sig_co)));
return true;
}
@@ -196,7 +198,7 @@ struct ConstEval
{
RTLIL::SigSpec sig_c = cell->getPort("\\C");
RTLIL::SigSpec sig_x = cell->getPort("\\X");
- int width = SIZE(sig_c);
+ int width = GetSize(sig_c);
if (!eval(sig_a, undef, cell))
return false;
@@ -214,7 +216,7 @@ struct ConstEval
RTLIL::Const t3 = const_and(sig_c.as_const(), t1, false, false, width);
RTLIL::Const val_x = const_or(t2, t3, false, false, width);
- for (int i = 0; i < SIZE(val_y); i++)
+ for (int i = 0; i < GetSize(val_y); i++)
if (val_y.bits[i] == RTLIL::Sx)
val_x.bits[i] = RTLIL::Sx;
@@ -245,13 +247,13 @@ struct ConstEval
RTLIL::SigSpec sig_co = cell->getPort("\\CO");
bool any_input_undef = !(sig_a.is_fully_def() && sig_b.is_fully_def() && sig_ci.is_fully_def() && sig_bi.is_fully_def());
- sig_a.extend_u0(SIZE(sig_y), signed_a);
- sig_b.extend_u0(SIZE(sig_y), signed_b);
+ sig_a.extend_u0(GetSize(sig_y), signed_a);
+ sig_b.extend_u0(GetSize(sig_y), signed_b);
bool carry = sig_ci[0] == RTLIL::S1;
bool b_inv = sig_bi[0] == RTLIL::S1;
- for (int i = 0; i < SIZE(sig_y); i++)
+ for (int i = 0; i < GetSize(sig_y); i++)
{
RTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] };
@@ -292,7 +294,7 @@ struct ConstEval
return false;
}
- RTLIL::Const result(0, SIZE(cell->getPort("\\Y")));
+ RTLIL::Const result(0, GetSize(cell->getPort("\\Y")));
if (!macc.eval(result))
log_abort();
@@ -376,4 +378,6 @@ struct ConstEval
}
};
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/kernel/cost.h b/kernel/cost.h
new file mode 100644
index 00000000..c6c631e0
--- /dev/null
+++ b/kernel/cost.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef COST_H
+#define COST_H
+
+#include <kernel/yosys.h>
+
+YOSYS_NAMESPACE_BEGIN
+
+int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr);
+
+int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
+ RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr)
+{
+ static dict<RTLIL::IdString, int> gate_cost = {
+ { "$_BUF_", 1 },
+ { "$_NOT_", 2 },
+ { "$_AND_", 4 },
+ { "$_NAND_", 4 },
+ { "$_OR_", 4 },
+ { "$_NOR_", 4 },
+ { "$_XOR_", 8 },
+ { "$_XNOR_", 8 },
+ { "$_AOI3_", 6 },
+ { "$_OAI3_", 6 },
+ { "$_AOI4_", 8 },
+ { "$_OAI4_", 8 },
+ { "$_MUX_", 4 }
+ };
+
+ if (gate_cost.count(type))
+ return gate_cost.at(type);
+
+ if (parameters.empty() && design && design->module(type))
+ {
+ RTLIL::Module *mod = design->module(type);
+
+ if (mod->attributes.count("\\cost"))
+ return mod->attributes.at("\\cost").as_int();
+
+ dict<RTLIL::IdString, int> local_mod_cost_cache;
+ if (mod_cost_cache == nullptr)
+ mod_cost_cache = &local_mod_cost_cache;
+
+ if (mod_cost_cache->count(mod->name))
+ return mod_cost_cache->at(mod->name);
+
+ int module_cost = 1;
+ for (auto c : mod->cells())
+ module_cost += get_cell_cost(c, mod_cost_cache);
+
+ (*mod_cost_cache)[mod->name] = module_cost;
+ return module_cost;
+ }
+
+ log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters));
+ return 1;
+}
+
+int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache)
+{
+ return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache);
+}
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/kernel/driver.cc b/kernel/driver.cc
index f26d9ef8..dda27c6a 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -27,13 +27,98 @@
#include <stdio.h>
#include <string.h>
-#include <unistd.h>
-#include <libgen.h>
#include <limits.h>
#include <errno.h>
+#ifdef __linux__
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+
+#if !defined(_WIN32) || defined(__MINGW32__)
+# include <unistd.h>
+#else
+char *optarg;
+int optind = 1, optcur = 1;
+int getopt(int argc, char **argv, const char *optstring)
+{
+ if (optind >= argc || argv[optind][0] != '-')
+ return -1;
+
+ bool takes_arg = false;
+ int opt = argv[optind][optcur];
+ for (int i = 0; optstring[i]; i++)
+ if (opt == optstring[i] && optstring[i + 1] == ':')
+ takes_arg = true;
+
+ if (!takes_arg) {
+ if (argv[optind][++optcur] == 0)
+ optind++, optcur = 1;
+ return opt;
+ }
+
+ if (argv[optind][++optcur]) {
+ optarg = argv[optind++] + optcur;
+ optcur = 1;
+ return opt;
+ }
+
+ optarg = argv[++optind];
+ optind++, optcur = 1;
+ return opt;
+}
+#endif
+
+
USING_YOSYS_NAMESPACE
+#ifdef EMSCRIPTEN
+# include <sys/stat.h>
+# include <sys/types.h>
+
+extern "C" int main(int, char**);
+extern "C" void run(const char*);
+extern "C" const char *errmsg();
+extern "C" const char *prompt();
+
+int main(int, char**)
+{
+ mkdir("/work", 0777);
+ chdir("/work");
+ log_files.push_back(stdout);
+ log_error_stderr = true;
+ yosys_banner();
+ yosys_setup();
+}
+
+void run(const char *command)
+{
+ int selSize = GetSize(yosys_get_design()->selection_stack);
+ try {
+ log_last_error = "Internal error (see JavaScript console for details)";
+ run_pass(command);
+ log_last_error = "";
+ } catch (...) {
+ while (GetSize(yosys_get_design()->selection_stack) > selSize)
+ yosys_get_design()->selection_stack.pop_back();
+ throw;
+ }
+}
+
+const char *errmsg()
+{
+ return log_last_error.c_str();
+}
+
+const char *prompt()
+{
+ const char *p = create_prompt(yosys_get_design(), 0);
+ while (*p == '\n') p++;
+ return p;
+}
+
+#else /* EMSCRIPTEN */
+
int main(int argc, char **argv)
{
std::string frontend_command = "auto";
@@ -47,6 +132,9 @@ int main(int argc, char **argv)
bool print_banner = true;
bool print_stats = true;
bool call_abort = false;
+ bool timing_details = false;
+ bool mode_v = false;
+ bool mode_q = false;
#ifdef YOSYS_ENABLE_READLINE
int history_offset = 0;
@@ -58,11 +146,103 @@ int main(int argc, char **argv)
}
#endif
+ if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "--help")))
+ {
+ printf("\n");
+ printf("Usage: %s [options] [<infile> [..]]\n", argv[0]);
+ printf("\n");
+ printf(" -Q\n");
+ printf(" suppress printing of banner (copyright, disclaimer, version)\n");
+ printf("\n");
+ printf(" -T\n");
+ printf(" suppress printing of footer (log hash, version, timing statistics)\n");
+ printf("\n");
+ printf(" -q\n");
+ printf(" quiet operation. only write warnings and error messages to console\n");
+ printf(" use this option twice to also quiet warning messages\n");
+ printf("\n");
+ printf(" -v <level>\n");
+ printf(" print log headers up to level <level> to the console. (this\n");
+ printf(" implies -q for everything except the 'End of script.' message.)\n");
+ printf("\n");
+ printf(" -t\n");
+ printf(" annotate all log messages with a time stamp\n");
+ printf("\n");
+ printf(" -d\n");
+ printf(" print more detailed timing stats at exit\n");
+ printf("\n");
+ printf(" -l logfile\n");
+ printf(" write log messages to the specified file\n");
+ printf("\n");
+ printf(" -L logfile\n");
+ printf(" like -l but open log file in line buffered mode\n");
+ printf("\n");
+ printf(" -o outfile\n");
+ printf(" write the design to the specified file on exit\n");
+ printf("\n");
+ printf(" -b backend\n");
+ printf(" use this backend for the output file specified on the command line\n");
+ printf("\n");
+ printf(" -f backend\n");
+ printf(" use the specified front for the input files on the command line\n");
+ printf("\n");
+ printf(" -H\n");
+ printf(" print the command list\n");
+ printf("\n");
+ printf(" -h command\n");
+ printf(" print the help message for the specified command\n");
+ printf("\n");
+ printf(" -s scriptfile\n");
+ printf(" execute the commands in the script file\n");
+ printf("\n");
+ printf(" -c tcl_scriptfile\n");
+ printf(" execute the commands in the tcl script file (see 'help tcl' for details)\n");
+ printf("\n");
+ printf(" -p command\n");
+ printf(" execute the commands\n");
+ printf("\n");
+ printf(" -m module_file\n");
+ printf(" load the specified module (aka plugin)\n");
+ printf("\n");
+ printf(" -X\n");
+ printf(" enable tracing of core data structure changes. for debugging\n");
+ printf("\n");
+ printf(" -M\n");
+ printf(" will slightly randomize allocated pointer addresses. for debugging\n");
+ printf("\n");
+ printf(" -A\n");
+ printf(" will call abort() at the end of the script. for debugging\n");
+ printf("\n");
+ printf(" -V\n");
+ printf(" print version information and exit\n");
+ printf("\n");
+ printf("The option -S is an shortcut for calling the \"synth\" command, a default\n");
+ printf("script for transforming the verilog input to a gate-level netlist. For example:\n");
+ printf("\n");
+ printf(" yosys -o output.blif -S input.v\n");
+ printf("\n");
+ printf("For more complex synthesis jobs it is recommended to use the read_* and write_*\n");
+ printf("commands in a script file instead of specifying input and output files on the\n");
+ printf("command line.\n");
+ printf("\n");
+ printf("When no commands, script files or input files are specified on the command\n");
+ printf("line, yosys automatically enters the interactive command mode. Use the 'help'\n");
+ printf("command to get information on the individual commands.\n");
+ printf("\n");
+ exit(0);
+ }
+
int opt;
- while ((opt = getopt(argc, argv, "AQTVSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1)
+ while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:")) != -1)
{
switch (opt)
{
+ case 'M':
+ memhasher_on();
+ break;
+ case 'X':
+ yosys_xtrace++;
+ break;
case 'A':
call_abort = true;
break;
@@ -101,22 +281,32 @@ int main(int argc, char **argv)
got_output_filename = true;
break;
case 'l':
+ case 'L':
log_files.push_back(fopen(optarg, "wt"));
if (log_files.back() == NULL) {
fprintf(stderr, "Can't open log file `%s' for writing!\n", optarg);
exit(1);
}
+ if (opt == 'L')
+ setvbuf(log_files.back(), NULL, _IOLBF, 0);
break;
case 'q':
+ mode_q = true;
+ if (log_errfile == stderr)
+ log_quiet_warnings = true;
log_errfile = stderr;
break;
case 'v':
+ mode_v = true;
log_errfile = stderr;
log_verbose_level = atoi(optarg);
break;
case 't':
log_time = true;
break;
+ case 'd':
+ timing_details = true;
+ break;
case 's':
scriptfile = optarg;
scriptfile_tcl = false;
@@ -126,107 +316,19 @@ int main(int argc, char **argv)
scriptfile_tcl = true;
break;
default:
- fprintf(stderr, "\n");
- fprintf(stderr, "Usage: %s [-V -S -Q -T -q] [-v <level>[-t] [-l <logfile>] [-o <outfile>] [-f <frontend>] [-h cmd] \\\n", argv[0]);
- fprintf(stderr, " %*s[{-s|-c} <scriptfile>] [-p <pass> [-p ..]] [-b <backend>] [-m <module_file>] [<infile> [..]]\n", int(strlen(argv[0])+1), "");
- fprintf(stderr, "\n");
- fprintf(stderr, " -Q\n");
- fprintf(stderr, " suppress printing of banner (copyright, disclaimer, version)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -T\n");
- fprintf(stderr, " suppress printing of footer (log hash, version, timing statistics)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -q\n");
- fprintf(stderr, " quiet operation. only write error messages to console\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -v <level>\n");
- fprintf(stderr, " print log headers up to level <level> to the console. (implies -q)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -t\n");
- fprintf(stderr, " annotate all log messages with a time stamp\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -l logfile\n");
- fprintf(stderr, " write log messages to the specified file\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -o outfile\n");
- fprintf(stderr, " write the design to the specified file on exit\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -b backend\n");
- fprintf(stderr, " use this backend for the output file specified on the command line\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -f backend\n");
- fprintf(stderr, " use the specified front for the input files on the command line\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -H\n");
- fprintf(stderr, " print the command list\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -h command\n");
- fprintf(stderr, " print the help message for the specified command\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -s scriptfile\n");
- fprintf(stderr, " execute the commands in the script file\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -c tcl_scriptfile\n");
- fprintf(stderr, " execute the commands in the tcl script file (see 'help tcl' for details)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -p command\n");
- fprintf(stderr, " execute the commands\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -m module_file\n");
- fprintf(stderr, " load the specified module (aka plugin)\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -A\n");
- fprintf(stderr, " will call abort() at the end of the script. useful for debugging\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " -V\n");
- fprintf(stderr, " print version information and exit\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "The option -S is an shortcut for calling the \"synth\" command, a default\n");
- fprintf(stderr, "script for transforming the verilog input to a gate-level netlist. For example:\n");
- fprintf(stderr, "\n");
- fprintf(stderr, " yosys -o output.blif -S input.v\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "For more complex synthesis jobs it is recommended to use the read_* and write_*\n");
- fprintf(stderr, "commands in a script file instead of specifying input and output files on the\n");
- fprintf(stderr, "command line.\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "When no commands, script files or input files are specified on the command\n");
- fprintf(stderr, "line, yosys automatically enters the interactive command mode. Use the 'help'\n");
- fprintf(stderr, "command to get information on the individual commands.\n");
- fprintf(stderr, "\n");
+ fprintf(stderr, "Run '%s -h' for help.\n", argv[0]);
exit(1);
}
}
- if (log_errfile == NULL)
- log_files.push_back(stderr);
-
- if (print_banner) {
- log("\n");
- log(" /-----------------------------------------------------------------------------\\\n");
- log(" | |\n");
- log(" | yosys -- Yosys Open SYnthesis Suite |\n");
- log(" | |\n");
- log(" | Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |\n");
- log(" | |\n");
- log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
- log(" | purpose with or without fee is hereby granted, provided that the above |\n");
- log(" | copyright notice and this permission notice appear in all copies. |\n");
- log(" | |\n");
- log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
- log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
- log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
- log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
- log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
- log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
- log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
- log(" | |\n");
- log(" \\-----------------------------------------------------------------------------/\n");
- log("\n");
- log(" %s\n", yosys_version_str);
- log("\n");
+ if (log_errfile == NULL) {
+ log_files.push_back(stdout);
+ log_error_stderr = true;
}
+ if (print_banner)
+ yosys_banner();
+
if (print_stats)
log_hasher = new SHA1;
@@ -242,7 +344,7 @@ int main(int argc, char **argv)
}
while (optind < argc)
- run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL, NULL);
+ run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
if (!scriptfile.empty()) {
if (scriptfile_tcl) {
@@ -253,14 +355,14 @@ int main(int argc, char **argv)
log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n");
#endif
} else
- run_frontend(scriptfile, "script", yosys_design, output_filename == "-" ? &backend_command : NULL, NULL);
+ run_frontend(scriptfile, "script", output_filename == "-" ? &backend_command : NULL);
}
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
- run_pass(*it, yosys_design);
+ run_pass(*it);
if (!backend_command.empty())
- run_backend(output_filename, backend_command, yosys_design);
+ run_backend(output_filename, backend_command);
if (print_stats)
{
@@ -268,12 +370,37 @@ int main(int argc, char **argv)
delete log_hasher;
log_hasher = nullptr;
+ log_time = false;
+ yosys_xtrace = 0;
+ log_spacer();
+
+ if (mode_v && !mode_q)
+ log_files.push_back(stderr);
+
+#ifdef _WIN32
+ log("End of script. Logfile hash: %s\n", hash.c_str());
+#else
+ std::string meminfo;
+ std::string stats_divider = ", ";
+# ifdef __linux__
+ std::ifstream statm;
+ statm.open(stringf("/proc/%lld/statm", (long long)getpid()));
+ if (statm.is_open()) {
+ int sz_total, sz_resident;
+ statm >> sz_total >> sz_resident;
+ meminfo = stringf(", MEM: %.2f MB total, %.2f MB resident",
+ sz_total * (getpagesize() / 1024.0 / 1024.0),
+ sz_resident * (getpagesize() / 1024.0 / 1024.0));
+ stats_divider = "\n";
+ }
+# endif
+
struct rusage ru_buffer;
getrusage(RUSAGE_SELF, &ru_buffer);
- log_spacer();
- log("End of script. Logfile hash: %s, CPU: user %.2fs system %.2fs\n", hash.c_str(),
- ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec,
- ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec);
+ log("End of script. Logfile hash: %s%sCPU: user %.2fs system %.2fs%s\n", hash.c_str(),
+ stats_divider.c_str(), ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec,
+ ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec, meminfo.c_str());
+#endif
log("%s\n", yosys_version_str);
int64_t total_ns = 0;
@@ -285,37 +412,49 @@ int main(int argc, char **argv)
timedat.insert(make_tuple(it.second->runtime_ns + 1, it.second->call_counter, it.first));
}
- int out_count = 0;
- log("Time spent:");
- for (auto it = timedat.rbegin(); it != timedat.rend() && out_count < 4; it++, out_count++) {
- if (out_count >= 2 && (std::get<0>(*it) < 1000000000 || int(100*std::get<0>(*it) / total_ns) < 20)) {
- log(", ...");
- break;
+ if (timing_details)
+ {
+ log("Time spent:\n");
+ for (auto it = timedat.rbegin(); it != timedat.rend(); it++) {
+ log("%5d%% %5d calls %8.3f sec %s\n", int(100*std::get<0>(*it) / total_ns),
+ std::get<1>(*it), std::get<0>(*it) / 1000000000.0, std::get<2>(*it).c_str());
+ }
+ }
+ else
+ {
+ int out_count = 0;
+ log("Time spent:");
+ for (auto it = timedat.rbegin(); it != timedat.rend() && out_count < 4; it++, out_count++) {
+ if (out_count >= 2 && (std::get<0>(*it) < 1000000000 || int(100*std::get<0>(*it) / total_ns) < 20)) {
+ log(", ...");
+ break;
+ }
+ log("%s %d%% %dx %s (%d sec)", out_count ? "," : "", int(100*std::get<0>(*it) / total_ns),
+ std::get<1>(*it), std::get<2>(*it).c_str(), int(std::get<0>(*it) / 1000000000));
}
- log("%s %d%% %dx %s (%d sec)", out_count ? "," : "", int(100*std::get<0>(*it) / total_ns),
- std::get<1>(*it), std::get<2>(*it).c_str(), int(std::get<0>(*it) / 1000000000));
+ log("%s\n", out_count ? "" : " no commands executed");
}
- log("%s\n", out_count ? "" : " no commands executed");
}
-#ifdef COVER_ACTIVE
+#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE"))
{
- char filename_buffer[4096];
+ string filename;
FILE *f;
if (getenv("YOSYS_COVER_DIR")) {
- snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid());
- f = fdopen(mkstemps(filename_buffer, 4), "w");
+ filename = stringf("%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid());
+ filename = make_temp_file(filename);
} else {
- snprintf(filename_buffer, 4096, "%s", getenv("YOSYS_COVER_FILE"));
- f = fopen(filename_buffer, "a+");
+ filename = getenv("YOSYS_COVER_FILE");
}
+ f = fopen(filename.c_str(), "a+");
+
if (f == NULL)
- log_error("Can't create coverage file `%s'.\n", filename_buffer);
+ log_error("Can't create coverage file `%s'.\n", filename.c_str());
- log("<writing coverage file \"%s\">\n", filename_buffer);
+ log("<writing coverage file \"%s\">\n", filename.c_str());
for (auto &it : get_coverage_data())
fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
@@ -324,6 +463,7 @@ int main(int argc, char **argv)
}
#endif
+ memhasher_off();
if (call_abort)
abort();
@@ -347,3 +487,5 @@ int main(int argc, char **argv)
return 0;
}
+#endif /* EMSCRIPTEN */
+
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
new file mode 100644
index 00000000..94b573e4
--- /dev/null
+++ b/kernel/hashlib.h
@@ -0,0 +1,887 @@
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+
+// -------------------------------------------------------
+// Written by Clifford Wolf <clifford@clifford.at> in 2014
+// -------------------------------------------------------
+
+#ifndef HASHLIB_H
+
+#include <stdexcept>
+#include <algorithm>
+#include <string>
+#include <vector>
+
+namespace hashlib {
+
+const int hashtable_size_trigger = 2;
+const int hashtable_size_factor = 3;
+
+// The XOR version of DJB2
+inline unsigned int mkhash(unsigned int a, unsigned int b) {
+ return ((a << 5) + a) ^ b;
+}
+
+// traditionally 5381 is used as starting value for the djb2 hash
+const unsigned int mkhash_init = 5381;
+
+// The ADD version of DJB2
+// (usunsigned int mkhashe this version for cache locality in b)
+inline unsigned int mkhash_add(unsigned int a, unsigned int b) {
+ return ((a << 5) + a) + b;
+}
+
+inline unsigned int mkhash_xorshift(unsigned int a) {
+ if (sizeof(a) == 4) {
+ a ^= a << 13;
+ a ^= a >> 17;
+ a ^= a << 5;
+ } else if (sizeof(a) == 8) {
+ a ^= a << 13;
+ a ^= a >> 7;
+ a ^= a << 17;
+ } else
+ throw std::runtime_error("mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
+ return a;
+}
+
+template<typename T> struct hash_ops {
+ static inline bool cmp(const T &a, const T &b) {
+ return a == b;
+ }
+ static inline unsigned int hash(const T &a) {
+ return a.hash();
+ }
+};
+
+template<> struct hash_ops<int> {
+ template<typename T>
+ static inline bool cmp(T a, T b) {
+ return a == b;
+ }
+ template<typename T>
+ static inline unsigned int hash(T a) {
+ return a;
+ }
+};
+
+template<> struct hash_ops<std::string> {
+ static inline bool cmp(const std::string &a, const std::string &b) {
+ return a == b;
+ }
+ static inline unsigned int hash(const std::string &a) {
+ unsigned int v = 0;
+ for (auto c : a)
+ v = mkhash(v, c);
+ return v;
+ }
+};
+
+template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
+ static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
+ return a == b;
+ }
+ static inline unsigned int hash(std::pair<P, Q> a) {
+ hash_ops<P> p_ops;
+ hash_ops<Q> q_ops;
+ return mkhash(p_ops.hash(a.first), q_ops.hash(a.second));
+ }
+};
+
+template<typename T> struct hash_ops<std::vector<T>> {
+ static inline bool cmp(std::vector<T> a, std::vector<T> b) {
+ return a == b;
+ }
+ static inline unsigned int hash(std::vector<T> a) {
+ hash_ops<T> t_ops;
+ unsigned int h = mkhash_init;
+ for (auto k : a)
+ h = mkhash(h, t_ops.hash(k));
+ return h;
+ }
+};
+
+struct hash_cstr_ops {
+ static inline bool cmp(const char *a, const char *b) {
+ for (int i = 0; a[i] || b[i]; i++)
+ if (a[i] != b[i])
+ return false;
+ return true;
+ }
+ static inline unsigned int hash(const char *a) {
+ unsigned int hash = mkhash_init;
+ while (*a)
+ hash = mkhash(hash, *(a++));
+ return hash;
+ }
+};
+
+struct hash_ptr_ops {
+ static inline bool cmp(const void *a, const void *b) {
+ return a == b;
+ }
+ static inline unsigned int hash(const void *a) {
+ return (unsigned long)a;
+ }
+};
+
+struct hash_obj_ops {
+ static inline bool cmp(const void *a, const void *b) {
+ return a == b;
+ }
+ template<typename T>
+ static inline unsigned int hash(const T *a) {
+ return a->hash();
+ }
+};
+
+inline int hashtable_size(int min_size)
+{
+ static std::vector<int> zero_and_some_primes = {
+ 0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
+ 853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
+ 12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
+ 120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
+ 897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
+ 5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
+ 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
+ 121590311, 151987889, 189984863, 237481091, 296851369, 371064217
+ };
+
+ for (auto p : zero_and_some_primes)
+ if (p >= min_size) return p;
+
+ if (sizeof(int) == 4)
+ throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables.");
+
+ for (auto p : zero_and_some_primes)
+ if (100129 * p > min_size) return 100129 * p;
+
+ throw std::length_error("hash table exceeded maximum size.");
+}
+
+template<typename K, typename T, typename OPS = hash_ops<K>> class dict;
+template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
+template<typename K, typename OPS = hash_ops<K>> class pool;
+
+template<typename K, typename T, typename OPS>
+class dict
+{
+ struct entry_t
+ {
+ std::pair<K, T> udata;
+ int next;
+
+ entry_t() { }
+ entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { }
+ entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { }
+ };
+
+ std::vector<int> hashtable;
+ std::vector<entry_t> entries;
+ OPS ops;
+
+#ifdef NDEBUG
+ static inline void do_assert(bool) { }
+#else
+ static inline void do_assert(bool cond) {
+ if (!cond) throw std::runtime_error("dict<> assert failed.");
+ }
+#endif
+
+ int do_hash(const K &key) const
+ {
+ unsigned int hash = 0;
+ if (!hashtable.empty())
+ hash = ops.hash(key) % (unsigned int)(hashtable.size());
+ return hash;
+ }
+
+ void do_rehash()
+ {
+ hashtable.clear();
+ hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
+
+ for (int i = 0; i < int(entries.size()); i++) {
+ do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
+ int hash = do_hash(entries[i].udata.first);
+ entries[i].next = hashtable[hash];
+ hashtable[hash] = i;
+ }
+ }
+
+ int do_erase(int index, int hash)
+ {
+ do_assert(index < int(entries.size()));
+ if (hashtable.empty() || index < 0)
+ return 0;
+
+ int k = hashtable[hash];
+ do_assert(0 <= k && k < int(entries.size()));
+
+ if (k == index) {
+ hashtable[hash] = entries[index].next;
+ } else {
+ while (entries[k].next != index) {
+ k = entries[k].next;
+ do_assert(0 <= k && k < int(entries.size()));
+ }
+ entries[k].next = entries[index].next;
+ }
+
+ int back_idx = entries.size()-1;
+
+ if (index != back_idx)
+ {
+ int back_hash = do_hash(entries[back_idx].udata.first);
+
+ k = hashtable[back_hash];
+ do_assert(0 <= k && k < int(entries.size()));
+
+ if (k == back_idx) {
+ hashtable[back_hash] = index;
+ } else {
+ while (entries[k].next != back_idx) {
+ k = entries[k].next;
+ do_assert(0 <= k && k < int(entries.size()));
+ }
+ entries[k].next = index;
+ }
+
+ entries[index] = std::move(entries[back_idx]);
+ }
+
+ entries.pop_back();
+
+ if (entries.empty())
+ hashtable.clear();
+
+ return 1;
+ }
+
+ int do_lookup(const K &key, int &hash) const
+ {
+ if (hashtable.empty())
+ return -1;
+
+ if (entries.size() * hashtable_size_trigger > hashtable.size()) {
+ ((dict*)this)->do_rehash();
+ hash = do_hash(key);
+ }
+
+ int index = hashtable[hash];
+
+ while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
+ index = entries[index].next;
+ do_assert(-1 <= index && index < int(entries.size()));
+ }
+
+ return index;
+ }
+
+ int do_insert(const K &key, int &hash)
+ {
+ if (hashtable.empty()) {
+ entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
+ do_rehash();
+ hash = do_hash(key);
+ } else {
+ entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+ int do_insert(const std::pair<K, T> &value, int &hash)
+ {
+ if (hashtable.empty()) {
+ entries.push_back(entry_t(value, -1));
+ do_rehash();
+ hash = do_hash(value.first);
+ } else {
+ entries.push_back(entry_t(value, hashtable[hash]));
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+public:
+ class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
+ {
+ friend class dict;
+ protected:
+ const dict *ptr;
+ int index;
+ const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { }
+ public:
+ const_iterator() { }
+ const_iterator operator++() { index--; return *this; }
+ bool operator<(const const_iterator &other) const { return index > other.index; }
+ bool operator==(const const_iterator &other) const { return index == other.index; }
+ bool operator!=(const const_iterator &other) const { return index != other.index; }
+ const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
+ const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
+ };
+
+ class iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
+ {
+ friend class dict;
+ protected:
+ dict *ptr;
+ int index;
+ iterator(dict *ptr, int index) : ptr(ptr), index(index) { }
+ public:
+ iterator() { }
+ iterator operator++() { index--; return *this; }
+ bool operator<(const iterator &other) const { return index > other.index; }
+ bool operator==(const iterator &other) const { return index == other.index; }
+ bool operator!=(const iterator &other) const { return index != other.index; }
+ std::pair<K, T> &operator*() { return ptr->entries[index].udata; }
+ std::pair<K, T> *operator->() { return &ptr->entries[index].udata; }
+ const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
+ const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
+ operator const_iterator() const { return const_iterator(ptr, index); }
+ };
+
+ dict()
+ {
+ }
+
+ dict(const dict &other)
+ {
+ entries = other.entries;
+ do_rehash();
+ }
+
+ dict(dict &&other)
+ {
+ swap(other);
+ }
+
+ dict &operator=(const dict &other) {
+ entries = other.entries;
+ do_rehash();
+ return *this;
+ }
+
+ dict &operator=(dict &&other) {
+ clear();
+ swap(other);
+ return *this;
+ }
+
+ dict(const std::initializer_list<std::pair<K, T>> &list)
+ {
+ for (auto &it : list)
+ insert(it);
+ }
+
+ template<class InputIterator>
+ dict(InputIterator first, InputIterator last)
+ {
+ insert(first, last);
+ }
+
+ template<class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ {
+ for (; first != last; ++first)
+ insert(*first);
+ }
+
+ std::pair<iterator, bool> insert(const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(key, hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> insert(const std::pair<K, T> &value)
+ {
+ int hash = do_hash(value.first);
+ int i = do_lookup(value.first, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(value, hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ int erase(const K &key)
+ {
+ int hash = do_hash(key);
+ int index = do_lookup(key, hash);
+ return do_erase(index, hash);
+ }
+
+ iterator erase(iterator it)
+ {
+ int hash = do_hash(it->first);
+ do_erase(it.index, hash);
+ return ++it;
+ }
+
+ int count(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i < 0 ? 0 : 1;
+ }
+
+ int count(const K &key, const_iterator it) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i < 0 || i > it.index ? 0 : 1;
+ }
+
+ iterator find(const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return end();
+ return iterator(this, i);
+ }
+
+ const_iterator find(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return end();
+ return const_iterator(this, i);
+ }
+
+ T& at(const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ throw std::out_of_range("dict::at()");
+ return entries[i].udata.second;
+ }
+
+ const T& at(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ throw std::out_of_range("dict::at()");
+ return entries[i].udata.second;
+ }
+
+ T& operator[](const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ i = do_insert(std::pair<K, T>(key, T()), hash);
+ return entries[i].udata.second;
+ }
+
+ template<typename Compare = std::less<K>>
+ void sort(Compare comp = Compare())
+ {
+ std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });
+ do_rehash();
+ }
+
+ void swap(dict &other)
+ {
+ hashtable.swap(other.hashtable);
+ entries.swap(other.entries);
+ }
+
+ bool operator==(const dict &other) const {
+ if (size() != other.size())
+ return false;
+ for (auto &it : entries) {
+ auto oit = other.find(it.udata.first);
+ if (oit == other.end() || !(oit->second == it.udata.second))
+ return false;
+ }
+ return true;
+ }
+
+ bool operator!=(const dict &other) const {
+ return !operator==(other);
+ }
+
+ size_t size() const { return entries.size(); }
+ bool empty() const { return entries.empty(); }
+ void clear() { hashtable.clear(); entries.clear(); }
+
+ iterator begin() { return iterator(this, int(entries.size())-1); }
+ iterator end() { return iterator(nullptr, -1); }
+
+ const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
+ const_iterator end() const { return const_iterator(nullptr, -1); }
+};
+
+template<typename K, typename OPS>
+class pool
+{
+ template<typename, int, typename> friend class idict;
+
+protected:
+ struct entry_t
+ {
+ K udata;
+ int next;
+
+ entry_t() { }
+ entry_t(const K &udata, int next) : udata(udata), next(next) { }
+ };
+
+ std::vector<int> hashtable;
+ std::vector<entry_t> entries;
+ OPS ops;
+
+#ifdef NDEBUG
+ static inline void do_assert(bool) { }
+#else
+ static inline void do_assert(bool cond) {
+ if (!cond) throw std::runtime_error("pool<> assert failed.");
+ }
+#endif
+
+ int do_hash(const K &key) const
+ {
+ unsigned int hash = 0;
+ if (!hashtable.empty())
+ hash = ops.hash(key) % (unsigned int)(hashtable.size());
+ return hash;
+ }
+
+ void do_rehash()
+ {
+ hashtable.clear();
+ hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
+
+ for (int i = 0; i < int(entries.size()); i++) {
+ do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
+ int hash = do_hash(entries[i].udata);
+ entries[i].next = hashtable[hash];
+ hashtable[hash] = i;
+ }
+ }
+
+ int do_erase(int index, int hash)
+ {
+ do_assert(index < int(entries.size()));
+ if (hashtable.empty() || index < 0)
+ return 0;
+
+ int k = hashtable[hash];
+ if (k == index) {
+ hashtable[hash] = entries[index].next;
+ } else {
+ while (entries[k].next != index) {
+ k = entries[k].next;
+ do_assert(0 <= k && k < int(entries.size()));
+ }
+ entries[k].next = entries[index].next;
+ }
+
+ int back_idx = entries.size()-1;
+
+ if (index != back_idx)
+ {
+ int back_hash = do_hash(entries[back_idx].udata);
+
+ k = hashtable[back_hash];
+ if (k == back_idx) {
+ hashtable[back_hash] = index;
+ } else {
+ while (entries[k].next != back_idx) {
+ k = entries[k].next;
+ do_assert(0 <= k && k < int(entries.size()));
+ }
+ entries[k].next = index;
+ }
+
+ entries[index] = std::move(entries[back_idx]);
+ }
+
+ entries.pop_back();
+
+ if (entries.empty())
+ hashtable.clear();
+
+ return 1;
+ }
+
+ int do_lookup(const K &key, int &hash) const
+ {
+ if (hashtable.empty())
+ return -1;
+
+ if (entries.size() * hashtable_size_trigger > hashtable.size()) {
+ ((pool*)this)->do_rehash();
+ hash = do_hash(key);
+ }
+
+ int index = hashtable[hash];
+
+ while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
+ index = entries[index].next;
+ do_assert(-1 <= index && index < int(entries.size()));
+ }
+
+ return index;
+ }
+
+ int do_insert(const K &value, int &hash)
+ {
+ if (hashtable.empty()) {
+ entries.push_back(entry_t(value, -1));
+ do_rehash();
+ hash = do_hash(value);
+ } else {
+ entries.push_back(entry_t(value, hashtable[hash]));
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+public:
+ class const_iterator : public std::iterator<std::forward_iterator_tag, K>
+ {
+ friend class pool;
+ protected:
+ const pool *ptr;
+ int index;
+ const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { }
+ public:
+ const_iterator() { }
+ const_iterator operator++() { index--; return *this; }
+ bool operator==(const const_iterator &other) const { return index == other.index; }
+ bool operator!=(const const_iterator &other) const { return index != other.index; }
+ const K &operator*() const { return ptr->entries[index].udata; }
+ const K *operator->() const { return &ptr->entries[index].udata; }
+ };
+
+ class iterator : public std::iterator<std::forward_iterator_tag, K>
+ {
+ friend class pool;
+ protected:
+ pool *ptr;
+ int index;
+ iterator(pool *ptr, int index) : ptr(ptr), index(index) { }
+ public:
+ iterator() { }
+ iterator operator++() { index--; return *this; }
+ bool operator==(const iterator &other) const { return index == other.index; }
+ bool operator!=(const iterator &other) const { return index != other.index; }
+ K &operator*() { return ptr->entries[index].udata; }
+ K *operator->() { return &ptr->entries[index].udata; }
+ const K &operator*() const { return ptr->entries[index].udata; }
+ const K *operator->() const { return &ptr->entries[index].udata; }
+ operator const_iterator() const { return const_iterator(ptr, index); }
+ };
+
+ pool()
+ {
+ }
+
+ pool(const pool &other)
+ {
+ entries = other.entries;
+ do_rehash();
+ }
+
+ pool(pool &&other)
+ {
+ swap(other);
+ }
+
+ pool &operator=(const pool &other) {
+ entries = other.entries;
+ do_rehash();
+ return *this;
+ }
+
+ pool &operator=(pool &&other) {
+ clear();
+ swap(other);
+ return *this;
+ }
+
+ pool(const std::initializer_list<K> &list)
+ {
+ for (auto &it : list)
+ insert(it);
+ }
+
+ template<class InputIterator>
+ pool(InputIterator first, InputIterator last)
+ {
+ insert(first, last);
+ }
+
+ template<class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ {
+ for (; first != last; ++first)
+ insert(*first);
+ }
+
+ std::pair<iterator, bool> insert(const K &value)
+ {
+ int hash = do_hash(value);
+ int i = do_lookup(value, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(value, hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ int erase(const K &key)
+ {
+ int hash = do_hash(key);
+ int index = do_lookup(key, hash);
+ return do_erase(index, hash);
+ }
+
+ iterator erase(iterator it)
+ {
+ int hash = do_hash(*it);
+ do_erase(it.index, hash);
+ return ++it;
+ }
+
+ int count(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i < 0 ? 0 : 1;
+ }
+
+ int count(const K &key, const_iterator it) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i < 0 || i > it.index ? 0 : 1;
+ }
+
+ iterator find(const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return end();
+ return iterator(this, i);
+ }
+
+ const_iterator find(const K &key) const
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i < 0)
+ return end();
+ return const_iterator(this, i);
+ }
+
+ bool operator[](const K &key)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ return i >= 0;
+ }
+
+ template<typename Compare = std::less<K>>
+ void sort(Compare comp = Compare())
+ {
+ std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
+ do_rehash();
+ }
+
+ void swap(pool &other)
+ {
+ hashtable.swap(other.hashtable);
+ entries.swap(other.entries);
+ }
+
+ bool operator==(const pool &other) const {
+ if (size() != other.size())
+ return false;
+ for (auto &it : entries)
+ if (!other.count(it.udata))
+ return false;
+ return true;
+ }
+
+ bool operator!=(const pool &other) const {
+ return !operator==(other);
+ }
+
+ size_t size() const { return entries.size(); }
+ bool empty() const { return entries.empty(); }
+ void clear() { hashtable.clear(); entries.clear(); }
+
+ iterator begin() { return iterator(this, int(entries.size())-1); }
+ iterator end() { return iterator(nullptr, -1); }
+
+ const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
+ const_iterator end() const { return const_iterator(nullptr, -1); }
+};
+
+template<typename K, int offset, typename OPS>
+class idict
+{
+ pool<K, OPS> database;
+
+public:
+ typedef typename pool<K, OPS>::const_iterator const_iterator;
+
+ int operator()(const K &key)
+ {
+ int hash = database.do_hash(key);
+ int i = database.do_lookup(key, hash);
+ if (i < 0)
+ i = database.do_insert(key, hash);
+ return i + offset;
+ }
+
+ int at(const K &key) const
+ {
+ int hash = database.do_hash(key);
+ int i = database.do_lookup(key, hash);
+ if (i < 0)
+ throw std::out_of_range("idict::at()");
+ return i + offset;
+ }
+
+ int count(const K &key) const
+ {
+ int hash = database.do_hash(key);
+ int i = database.do_lookup(key, hash);
+ return i < 0 ? 0 : 1;
+ }
+
+ void expect(const K &key, int i)
+ {
+ int j = (*this)(key);
+ if (i != j)
+ throw std::out_of_range("idict::expect()");
+ }
+
+ const K &operator[](int index) const
+ {
+ return database.entries.at(index - offset).udata;
+ }
+
+ const_iterator begin() const { return database.begin(); }
+ const_iterator end() const { return database.end(); }
+};
+
+} /* namespace hashlib */
+
+#endif
diff --git a/kernel/log.cc b/kernel/log.cc
index 1b0eb664..bf92dace 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -21,7 +21,14 @@
#include "libs/sha1/sha1.h"
#include "backends/ilang/ilang_backend.h"
-#include <sys/time.h>
+#if !defined(_WIN32) || defined(__MINGW32__)
+# include <sys/time.h>
+#endif
+
+#ifdef __linux__
+# include <dlfcn.h>
+#endif
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -37,17 +44,41 @@ FILE *log_errfile = NULL;
SHA1 *log_hasher = NULL;
bool log_time = false;
+bool log_error_stderr = false;
bool log_cmd_error_throw = false;
+bool log_quiet_warnings = false;
int log_verbose_level;
+string log_last_error;
-std::vector<int> header_count;
-std::list<std::string> string_buf;
-int string_buf_size = 0;
+vector<int> header_count;
+pool<RTLIL::IdString> log_id_cache;
+vector<string> string_buf;
+int string_buf_index = -1;
static struct timeval initial_tv = { 0, 0 };
static bool next_print_log = false;
static int log_newline_count = 0;
+#if defined(_WIN32) && !defined(__MINGW32__)
+// this will get time information and return it in timeval, simulating gettimeofday()
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ LARGE_INTEGER counter;
+ LARGE_INTEGER freq;
+
+ QueryPerformanceFrequency(&freq);
+ QueryPerformanceCounter(&counter);
+
+ counter.QuadPart *= 1000000;
+ counter.QuadPart /= freq.QuadPart;
+
+ tv->tv_sec = long(counter.QuadPart / 1000000);
+ tv->tv_usec = counter.QuadPart % 1000000;
+
+ return 0;
+}
+#endif
+
void logv(const char *format, va_list ap)
{
while (format[0] == '\n' && format[1] != 0) {
@@ -62,9 +93,9 @@ void logv(const char *format, va_list ap)
size_t nnl_pos = str.find_last_not_of('\n');
if (nnl_pos == std::string::npos)
- log_newline_count += SIZE(str);
+ log_newline_count += GetSize(str);
else
- log_newline_count = SIZE(str) - nnl_pos - 1;
+ log_newline_count = GetSize(str) - nnl_pos - 1;
if (log_hasher)
log_hasher->update(str);
@@ -128,15 +159,43 @@ void logv_header(const char *format, va_list ap)
log_files.pop_back();
}
+void logv_warning(const char *format, va_list ap)
+{
+ if (log_errfile != NULL && !log_quiet_warnings)
+ log_files.push_back(log_errfile);
+
+ log("Warning: ");
+ logv(format, ap);
+ log_flush();
+
+ if (log_errfile != NULL && !log_quiet_warnings)
+ log_files.pop_back();
+}
+
void logv_error(const char *format, va_list ap)
{
+#ifdef EMSCRIPTEN
+ auto backup_log_files = log_files;
+#endif
+
if (log_errfile != NULL)
log_files.push_back(log_errfile);
- log("ERROR: ");
- logv(format, ap);
+ if (log_error_stderr)
+ for (auto &f : log_files)
+ if (f == stdout)
+ f = stderr;
+
+ log_last_error = vstringf(format, ap);
+ log("ERROR: %s", log_last_error.c_str());
log_flush();
+
+#ifdef EMSCRIPTEN
+ log_files = backup_log_files;
+ throw 0;
+#else
exit(1);
+#endif
}
void log(const char *format, ...)
@@ -155,6 +214,14 @@ void log_header(const char *format, ...)
va_end(ap);
}
+void log_warning(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ logv_warning(format, ap);
+ va_end(ap);
+}
+
void log_error(const char *format, ...)
{
va_list ap;
@@ -168,10 +235,10 @@ void log_cmd_error(const char *format, ...)
va_start(ap, format);
if (log_cmd_error_throw) {
- log("ERROR: ");
- logv(format, ap);
+ log_last_error = vstringf(format, ap);
+ log("ERROR: %s", log_last_error.c_str());
log_flush();
- throw log_cmd_error_expection();
+ throw log_cmd_error_exception();
}
logv_error(format, ap);
@@ -191,17 +258,112 @@ void log_push()
void log_pop()
{
header_count.pop_back();
+ log_id_cache.clear();
string_buf.clear();
- string_buf_size = 0;
+ string_buf_index = -1;
log_flush();
}
+#ifdef __linux__
+void log_backtrace(const char *prefix, int levels)
+{
+ if (levels <= 0) return;
+
+ Dl_info dli;
+ void *p;
+
+ if ((p = __builtin_extract_return_addr(__builtin_return_address(0))) && dladdr(p, &dli)) {
+ log("%sframe #1: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
+ } else {
+ log("%sframe #1: ---\n", prefix);
+ return;
+ }
+
+ if (levels <= 1) return;
+
+ if ((p = __builtin_extract_return_addr(__builtin_return_address(1))) && dladdr(p, &dli)) {
+ log("%sframe #2: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
+ } else {
+ log("%sframe #2: ---\n", prefix);
+ return;
+ }
+
+ if (levels <= 2) return;
+
+ if ((p = __builtin_extract_return_addr(__builtin_return_address(2))) && dladdr(p, &dli)) {
+ log("%sframe #3: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
+ } else {
+ log("%sframe #3: ---\n", prefix);
+ return;
+ }
+
+ if (levels <= 3) return;
+
+ if ((p = __builtin_extract_return_addr(__builtin_return_address(3))) && dladdr(p, &dli)) {
+ log("%sframe #4: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
+ } else {
+ log("%sframe #4: ---\n", prefix);
+ return;
+ }
+
+ if (levels <= 4) return;
+
+ if ((p = __builtin_extract_return_addr(__builtin_return_address(4))) && dladdr(p, &dli)) {
+ log("%sframe #5: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
+ } else {
+ log("%sframe #5: ---\n", prefix);
+ return;
+ }
+
+ if (levels <= 5) return;
+
+ if ((p = __builtin_extract_return_addr(__builtin_return_address(5))) && dladdr(p, &dli)) {
+ log("%sframe #6: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
+ } else {
+ log("%sframe #6: ---\n", prefix);
+ return;
+ }
+
+ if (levels <= 6) return;
+
+ if ((p = __builtin_extract_return_addr(__builtin_return_address(6))) && dladdr(p, &dli)) {
+ log("%sframe #7: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
+ } else {
+ log("%sframe #7: ---\n", prefix);
+ return;
+ }
+
+ if (levels <= 7) return;
+
+ if ((p = __builtin_extract_return_addr(__builtin_return_address(7))) && dladdr(p, &dli)) {
+ log("%sframe #8: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
+ } else {
+ log("%sframe #8: ---\n", prefix);
+ return;
+ }
+
+ if (levels <= 8) return;
+
+ if ((p = __builtin_extract_return_addr(__builtin_return_address(8))) && dladdr(p, &dli)) {
+ log("%sframe #9: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
+ } else {
+ log("%sframe #9: ---\n", prefix);
+ return;
+ }
+
+ if (levels <= 9) return;
+}
+#else
+void log_backtrace(const char*, int) { }
+#endif
+
void log_reset_stack()
{
while (header_count.size() > 1)
header_count.pop_back();
+ log_id_cache.clear();
string_buf.clear();
- string_buf_size = 0;
+ string_buf_index = -1;
log_flush();
}
@@ -223,22 +385,28 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
std::stringstream buf;
ILANG_BACKEND::dump_sigspec(buf, sig, autoint);
- if (string_buf_size < 100)
- string_buf_size++;
- else
- string_buf.pop_front();
- string_buf.push_back(buf.str());
-
- return string_buf.back().c_str();
+ if (string_buf.size() < 100) {
+ string_buf.push_back(buf.str());
+ return string_buf.back().c_str();
+ } else {
+ if (++string_buf_index == 100)
+ string_buf_index = 0;
+ string_buf[string_buf_index] = buf.str();
+ return string_buf[string_buf_index].c_str();
+ }
}
const char *log_id(RTLIL::IdString str)
{
+ log_id_cache.insert(str);
const char *p = str.c_str();
- log_assert(RTLIL::IdString::global_refcount_storage_[str.index_] > 1);
- if (p[0] == '\\' && p[1] != '$' && p[1] != 0)
- return p+1;
- return p;
+ if (p[0] != '\\')
+ return p;
+ if (p[1] == '$' || p[1] == '\\' || p[1] == 0)
+ return p;
+ if (p[1] >= '0' && p[1] <= '9')
+ return p;
+ return p+1;
}
void log_cell(RTLIL::Cell *cell, std::string indent)
@@ -251,9 +419,9 @@ void log_cell(RTLIL::Cell *cell, std::string indent)
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
-#ifdef COVER_ACTIVE
+#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
-std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
+dict<std::string, std::pair<std::string, int>> extra_coverage_data;
void cover_extra(std::string parent, std::string id, bool increment) {
if (extra_coverage_data.count(id) == 0) {
@@ -266,9 +434,9 @@ void cover_extra(std::string parent, std::string id, bool increment) {
extra_coverage_data[id].second++;
}
-std::map<std::string, std::pair<std::string, int>> get_coverage_data()
+dict<std::string, std::pair<std::string, int>> get_coverage_data()
{
- std::map<std::string, std::pair<std::string, int>> coverage_data;
+ dict<std::string, std::pair<std::string, int>> coverage_data;
for (auto &it : pass_register) {
std::string key = stringf("passes.%s", it.first.c_str());
@@ -278,14 +446,14 @@ std::map<std::string, std::pair<std::string, int>> get_coverage_data()
for (auto &it : extra_coverage_data) {
if (coverage_data.count(it.first))
- log("WARNING: found duplicate coverage id \"%s\".\n", it.first.c_str());
+ log_warning("found duplicate coverage id \"%s\".\n", it.first.c_str());
coverage_data[it.first].first = it.second.first;
coverage_data[it.first].second += it.second.second;
}
for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) {
if (coverage_data.count(p->id))
- log("WARNING: found duplicate coverage id \"%s\".\n", p->id);
+ log_warning("found duplicate coverage id \"%s\".\n", p->id);
coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
coverage_data[p->id].second += p->counter;
}
diff --git a/kernel/log.h b/kernel/log.h
index e2b4db87..16ad7b6c 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -23,8 +23,14 @@
#define LOG_H
#include <time.h>
-#include <sys/time.h>
-#include <sys/resource.h>
+
+#ifndef _WIN32
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif
+
+// from libs/sha1/sha1.h
+class SHA1;
YOSYS_NAMESPACE_BEGIN
@@ -32,30 +38,36 @@ YOSYS_NAMESPACE_BEGIN
#define S__LINE__sub1(x) S__LINE__sub2(x)
#define S__LINE__ S__LINE__sub1(__LINE__)
-struct log_cmd_error_expection { };
+struct log_cmd_error_exception { };
extern std::vector<FILE*> log_files;
extern std::vector<std::ostream*> log_streams;
extern FILE *log_errfile;
-extern class SHA1 *log_hasher;
+extern SHA1 *log_hasher;
extern bool log_time;
+extern bool log_error_stderr;
extern bool log_cmd_error_throw;
+extern bool log_quiet_warnings;
extern int log_verbose_level;
+extern string log_last_error;
void logv(const char *format, va_list ap);
void logv_header(const char *format, va_list ap);
-void logv_error(const char *format, va_list ap) __attribute__ ((noreturn));
+void logv_warning(const char *format, va_list ap);
+YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn);
-void log(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
-void log_header(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
-void log_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
-void log_cmd_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
+void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
+void log_header(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
+void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
+YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
+YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
void log_spacer();
void log_push();
void log_pop();
+void log_backtrace(const char *prefix, int levels);
void log_reset_stack();
void log_flush();
@@ -68,36 +80,43 @@ template<typename T> static inline const char *log_id(T *obj) {
void log_cell(RTLIL::Cell *cell, std::string indent = "");
-#define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
-#define log_assert(_assert_expr_) do { if (_assert_expr_) break; log_error("Assert `%s' failed in %s:%d.\n", #_assert_expr_, __FILE__, __LINE__); } while (0)
-#define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#ifndef NDEBUG
+static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) {
+ if (!cond) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line);
+}
+# define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__)
+#else
+# define log_assert(_assert_expr_)
+#endif
+
+#define log_abort() YOSYS_NAMESPACE_PREFIX log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
+#define log_ping() YOSYS_NAMESPACE_PREFIX log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
-#if defined(__linux__) && !defined(NDEBUG)
-#define COVER_ACTIVE
+#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
#define cover(_id) do { \
- static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1))) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
+ static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
__d.counter++; \
} while (0)
struct CoverData {
const char *file, *func, *id;
int line, counter;
-} __attribute__ ((packed));
+} YS_ATTRIBUTE(packed);
// this two symbols are created by the linker for the "yosys_cover_list" ELF section
extern "C" struct CoverData __start_yosys_cover_list[];
extern "C" struct CoverData __stop_yosys_cover_list[];
-extern std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
+extern dict<std::string, std::pair<std::string, int>> extra_coverage_data;
void cover_extra(std::string parent, std::string id, bool increment = true);
-std::map<std::string, std::pair<std::string, int>> get_coverage_data();
+dict<std::string, std::pair<std::string, int>> get_coverage_data();
#define cover_list(_id, ...) do { cover(_id); \
std::string r = cover_list_worker(_id, __VA_ARGS__); \
@@ -151,6 +170,8 @@ struct PerformanceTimer
t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL;
t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;
return t;
+#elif _WIN32
+ return 0;
#else
#error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).
#endif
@@ -169,7 +190,7 @@ struct PerformanceTimer
}
float sec() const {
- return total_ns * 1e-9;
+ return total_ns * 1e-9f;
}
#else
static int64_t query() { return 0; }
@@ -188,8 +209,10 @@ static inline void log_dump_val_worker(int v) { log("%d", v); }
static inline void log_dump_val_worker(unsigned int v) { log("%u", v); }
static inline void log_dump_val_worker(long int v) { log("%ld", v); }
static inline void log_dump_val_worker(unsigned long int v) { log("%lu", v); }
+#ifndef _WIN32
static inline void log_dump_val_worker(long long int v) { log("%lld", v); }
static inline void log_dump_val_worker(unsigned long long int v) { log("%lld", v); }
+#endif
static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); }
static inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); }
static inline void log_dump_val_worker(bool v) { log("%s", v ? "true" : "false"); }
@@ -198,7 +221,7 @@ static inline void log_dump_val_worker(char *v) { log("%s", v); }
static inline void log_dump_val_worker(const char *v) { log("%s", v); }
static inline void log_dump_val_worker(std::string v) { log("%s", v.c_str()); }
static inline void log_dump_val_worker(PerformanceTimer p) { log("%f seconds", p.sec()); }
-static inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); }
+static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { log_assert(*p == 0); }
void log_dump_val_worker(RTLIL::SigSpec v);
template<typename T>
diff --git a/kernel/macc.h b/kernel/macc.h
index 27114111..cac5b00d 100644
--- a/kernel/macc.h
+++ b/kernel/macc.h
@@ -42,17 +42,20 @@ struct Macc
for (auto &port : ports)
{
- if (SIZE(port.in_a) == 0 && SIZE(port.in_b) == 0)
+ if (GetSize(port.in_a) == 0 && GetSize(port.in_b) == 0)
continue;
- if (SIZE(port.in_a) == 1 && SIZE(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
+ if (GetSize(port.in_a) < GetSize(port.in_b))
+ std::swap(port.in_a, port.in_b);
+
+ if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
bit_ports.append(port.in_a);
continue;
}
if (port.in_a.is_fully_const() && port.in_b.is_fully_const()) {
RTLIL::Const v = port.in_a.as_const();
- if (SIZE(port.in_b))
+ if (GetSize(port.in_b))
v = const_mul(v, port.in_b.as_const(), port.is_signed, port.is_signed, width);
if (port.do_subtract)
off = const_sub(off, v, port.is_signed, port.is_signed, width);
@@ -62,15 +65,15 @@ struct Macc
}
if (port.is_signed) {
- while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == port.in_a[SIZE(port.in_a)-2])
- port.in_a.remove(SIZE(port.in_a)-1);
- while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == port.in_b[SIZE(port.in_b)-2])
- port.in_b.remove(SIZE(port.in_b)-1);
+ while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == port.in_a[GetSize(port.in_a)-2])
+ port.in_a.remove(GetSize(port.in_a)-1);
+ while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == port.in_b[GetSize(port.in_b)-2])
+ port.in_b.remove(GetSize(port.in_b)-1);
} else {
- while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == RTLIL::S0)
- port.in_a.remove(SIZE(port.in_a)-1);
- while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == RTLIL::S0)
- port.in_b.remove(SIZE(port.in_b)-1);
+ while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == RTLIL::S0)
+ port.in_a.remove(GetSize(port.in_a)-1);
+ while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == RTLIL::S0)
+ port.in_b.remove(GetSize(port.in_b)-1);
}
new_ports.push_back(port);
@@ -102,10 +105,12 @@ struct Macc
bit_ports = cell->getPort("\\B");
std::vector<RTLIL::State> config_bits = cell->getParam("\\CONFIG").bits;
- int config_width = cell->getParam("\\CONFIG_WIDTH").as_int();
int config_cursor = 0;
- log_assert(SIZE(config_bits) >= config_width);
+#ifndef NDEBUG
+ int config_width = cell->getParam("\\CONFIG_WIDTH").as_int();
+ log_assert(GetSize(config_bits) >= config_width);
+#endif
int num_bits = 0;
if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 1;
@@ -114,7 +119,7 @@ struct Macc
if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 8;
int port_a_cursor = 0;
- while (port_a_cursor < SIZE(port_a))
+ while (port_a_cursor < GetSize(port_a))
{
log_assert(config_cursor + 2 + 2*num_bits <= config_width);
@@ -143,7 +148,7 @@ struct Macc
}
log_assert(config_cursor == config_width);
- log_assert(port_a_cursor == SIZE(port_a));
+ log_assert(port_a_cursor == GetSize(port_a));
}
void to_cell(RTLIL::Cell *cell) const
@@ -153,8 +158,8 @@ struct Macc
int max_size = 0, num_bits = 0;
for (auto &port : ports) {
- max_size = std::max(max_size, SIZE(port.in_a));
- max_size = std::max(max_size, SIZE(port.in_b));
+ max_size = std::max(max_size, GetSize(port.in_a));
+ max_size = std::max(max_size, GetSize(port.in_b));
}
while (max_size)
@@ -168,17 +173,17 @@ struct Macc
for (auto &port : ports)
{
- if (SIZE(port.in_a) == 0)
+ if (GetSize(port.in_a) == 0)
continue;
config_bits.push_back(port.is_signed ? RTLIL::S1 : RTLIL::S0);
config_bits.push_back(port.do_subtract ? RTLIL::S1 : RTLIL::S0);
- int size_a = SIZE(port.in_a);
+ int size_a = GetSize(port.in_a);
for (int i = 0; i < num_bits; i++)
config_bits.push_back(size_a & (1 << i) ? RTLIL::S1 : RTLIL::S0);
- int size_b = SIZE(port.in_b);
+ int size_b = GetSize(port.in_b);
for (int i = 0; i < num_bits; i++)
config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::S0);
@@ -189,9 +194,9 @@ struct Macc
cell->setPort("\\A", port_a);
cell->setPort("\\B", bit_ports);
cell->setParam("\\CONFIG", config_bits);
- cell->setParam("\\CONFIG_WIDTH", SIZE(config_bits));
- cell->setParam("\\A_WIDTH", SIZE(port_a));
- cell->setParam("\\B_WIDTH", SIZE(bit_ports));
+ cell->setParam("\\CONFIG_WIDTH", GetSize(config_bits));
+ cell->setParam("\\A_WIDTH", GetSize(port_a));
+ cell->setParam("\\B_WIDTH", GetSize(bit_ports));
}
bool eval(RTLIL::Const &result) const
@@ -205,25 +210,31 @@ struct Macc
return false;
RTLIL::Const summand;
- if (SIZE(port.in_b) == 0)
- summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result));
+ if (GetSize(port.in_b) == 0)
+ summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result));
else
- summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result));
+ summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result));
if (port.do_subtract)
- result = const_sub(result, summand, port.is_signed, port.is_signed, SIZE(result));
+ result = const_sub(result, summand, port.is_signed, port.is_signed, GetSize(result));
else
- result = const_add(result, summand, port.is_signed, port.is_signed, SIZE(result));
+ result = const_add(result, summand, port.is_signed, port.is_signed, GetSize(result));
}
for (auto bit : bit_ports) {
if (bit.wire)
return false;
- result = const_add(result, bit.data, false, false, SIZE(result));
+ result = const_add(result, bit.data, false, false, GetSize(result));
}
return true;
}
+
+ Macc(RTLIL::Cell *cell = nullptr)
+ {
+ if (cell != nullptr)
+ from_cell(cell);
+ }
};
YOSYS_NAMESPACE_END
diff --git a/kernel/modtools.h b/kernel/modtools.h
index 58cdd5b0..69c13bd3 100644
--- a/kernel/modtools.h
+++ b/kernel/modtools.h
@@ -33,6 +33,7 @@ struct ModIndex : public RTLIL::Monitor
RTLIL::IdString port;
int offset;
+ PortInfo() : cell(), port(), offset() { }
PortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { }
bool operator<(const PortInfo &other) const {
@@ -42,24 +43,44 @@ struct ModIndex : public RTLIL::Monitor
return offset < other.offset;
return port < other.port;
}
+
+ bool operator==(const PortInfo &other) const {
+ return cell == other.cell && port == other.port && offset == other.offset;
+ }
+
+ unsigned int hash() const {
+ return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
+ }
};
struct SigBitInfo
{
bool is_input, is_output;
- std::set<PortInfo> ports;
+ pool<PortInfo> ports;
SigBitInfo() : is_input(false), is_output(false) { }
+
+ bool operator==(const SigBitInfo &other) const {
+ return is_input == other.is_input && is_output == other.is_output && ports == other.ports;
+ }
+
+ void merge(const SigBitInfo &other)
+ {
+ is_input = is_input || other.is_input;
+ is_output = is_output || other.is_output;
+ ports.insert(other.ports.begin(), other.ports.end());
+ }
};
SigMap sigmap;
RTLIL::Module *module;
std::map<RTLIL::SigBit, SigBitInfo> database;
+ int auto_reload_counter;
bool auto_reload_module;
void port_add(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
{
- for (int i = 0; i < SIZE(sig); i++) {
+ for (int i = 0; i < GetSize(sig); i++) {
RTLIL::SigBit bit = sigmap(sig[i]);
if (bit.wire)
database[bit].ports.insert(PortInfo(cell, port, i));
@@ -68,7 +89,7 @@ struct ModIndex : public RTLIL::Monitor
void port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
{
- for (int i = 0; i < SIZE(sig); i++) {
+ for (int i = 0; i < GetSize(sig); i++) {
RTLIL::SigBit bit = sigmap(sig[i]);
if (bit.wire)
database[bit].ports.erase(PortInfo(cell, port, i));
@@ -80,15 +101,17 @@ struct ModIndex : public RTLIL::Monitor
return database[sigmap(bit)];
}
- void reload_module()
+ void reload_module(bool reset_sigmap = true)
{
- sigmap.clear();
- sigmap.set(module);
+ if (reset_sigmap) {
+ sigmap.clear();
+ sigmap.set(module);
+ }
database.clear();
for (auto wire : module->wires())
if (wire->port_input || wire->port_output)
- for (int i = 0; i < SIZE(wire); i++) {
+ for (int i = 0; i < GetSize(wire); i++) {
RTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i));
if (bit.wire && wire->port_input)
database[bit].is_input = true;
@@ -99,31 +122,105 @@ struct ModIndex : public RTLIL::Monitor
for (auto &conn : cell->connections())
port_add(cell, conn.first, conn.second);
- auto_reload_module = false;
+ if (auto_reload_module) {
+ if (++auto_reload_counter > 2)
+ log_warning("Auto-reload in ModIndex -- possible performance bug!\n");
+ auto_reload_module = false;
+ }
}
- virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE
+ void check()
{
+#ifndef NDEBUG
if (auto_reload_module)
- reload_module();
+ return;
+
+ for (auto it : database)
+ log_assert(it.first == sigmap(it.first));
+
+ auto database_bak = std::move(database);
+ reload_module(false);
+
+ if (!(database == database_bak))
+ {
+ for (auto &it : database_bak)
+ if (!database.count(it.first))
+ log("ModuleIndex::check(): Only in database_bak, not database: %s\n", log_signal(it.first));
+
+ for (auto &it : database)
+ if (!database_bak.count(it.first))
+ log("ModuleIndex::check(): Only in database, not database_bak: %s\n", log_signal(it.first));
+ else if (!(it.second == database_bak.at(it.first)))
+ log("ModuleIndex::check(): Different content for database[%s].\n", log_signal(it.first));
+
+ log_assert(database == database_bak);
+ }
+#endif
+ }
+
+ virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
+ {
+ log_assert(module == cell->module);
+
+ if (auto_reload_module)
+ return;
port_del(cell, port, old_sig);
port_add(cell, port, sig);
}
- virtual void notify_connect(RTLIL::Module *mod, const RTLIL::SigSig&)
+ virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE
{
log_assert(module == mod);
- auto_reload_module = true;
+
+ if (auto_reload_module)
+ return;
+
+ for (int i = 0; i < GetSize(sigsig.first); i++)
+ {
+ RTLIL::SigBit lhs = sigmap(sigsig.first[i]);
+ RTLIL::SigBit rhs = sigmap(sigsig.second[i]);
+ bool has_lhs = database.count(lhs);
+ bool has_rhs = database.count(rhs);
+
+ if (!has_lhs && !has_rhs) {
+ sigmap.add(lhs, rhs);
+ } else
+ if (!has_rhs) {
+ SigBitInfo new_info = database.at(lhs);
+ database.erase(lhs);
+ sigmap.add(lhs, rhs);
+ lhs = sigmap(lhs);
+ if (lhs.wire)
+ database[lhs] = new_info;
+ } else
+ if (!has_lhs) {
+ SigBitInfo new_info = database.at(rhs);
+ database.erase(rhs);
+ sigmap.add(lhs, rhs);
+ rhs = sigmap(rhs);
+ if (rhs.wire)
+ database[rhs] = new_info;
+ } else {
+ SigBitInfo new_info = database.at(lhs);
+ new_info.merge(database.at(rhs));
+ database.erase(lhs);
+ database.erase(rhs);
+ sigmap.add(lhs, rhs);
+ rhs = sigmap(rhs);
+ if (rhs.wire)
+ database[rhs] = new_info;
+ }
+ }
}
- virtual void notify_connect(RTLIL::Module *mod, const std::vector<RTLIL::SigSig>&)
+ virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector<RTLIL::SigSig>&) YS_OVERRIDE
{
log_assert(module == mod);
auto_reload_module = true;
}
- virtual void notify_blackout(RTLIL::Module *mod)
+ virtual void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE
{
log_assert(module == mod);
auto_reload_module = true;
@@ -131,6 +228,7 @@ struct ModIndex : public RTLIL::Monitor
ModIndex(RTLIL::Module *_m) : module(_m)
{
+ auto_reload_counter = 0;
auto_reload_module = true;
module->monitors.insert(this);
}
@@ -168,9 +266,9 @@ struct ModIndex : public RTLIL::Monitor
return info->is_output;
}
- std::set<PortInfo> &query_ports(RTLIL::SigBit bit)
+ pool<PortInfo> &query_ports(RTLIL::SigBit bit)
{
- static std::set<PortInfo> empty_result_set;
+ static pool<PortInfo> empty_result_set;
SigBitInfo *info = query(bit);
if (info == nullptr)
return empty_result_set;
@@ -193,6 +291,14 @@ struct ModWalker
return port < other.port;
return offset < other.offset;
}
+
+ bool operator==(const PortBit &other) const {
+ return cell == other.cell && port == other.port && offset == other.offset;
+ }
+
+ unsigned int hash() const {
+ return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
+ }
};
RTLIL::Design *design;
@@ -201,11 +307,11 @@ struct ModWalker
CellTypes ct;
SigMap sigmap;
- std::map<RTLIL::SigBit, std::set<PortBit>> signal_drivers;
- std::map<RTLIL::SigBit, std::set<PortBit>> signal_consumers;
- std::set<RTLIL::SigBit> signal_inputs, signal_outputs;
+ dict<RTLIL::SigBit, pool<PortBit>> signal_drivers;
+ dict<RTLIL::SigBit, pool<PortBit>> signal_consumers;
+ pool<RTLIL::SigBit> signal_inputs, signal_outputs;
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_outputs, cell_inputs;
+ dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_outputs, cell_inputs;
void add_wire(RTLIL::Wire *wire)
{
@@ -286,11 +392,11 @@ struct ModWalker
// get_* methods -- single RTLIL::SigBit
template<typename T>
- inline bool get_drivers(std::set<PortBit> &result, RTLIL::SigBit bit) const
+ inline bool get_drivers(pool<PortBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_drivers.count(bit)) {
- const std::set<PortBit> &r = signal_drivers.at(bit);
+ const pool<PortBit> &r = signal_drivers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
@@ -298,11 +404,11 @@ struct ModWalker
}
template<typename T>
- inline bool get_consumers(std::set<PortBit> &result, RTLIL::SigBit bit) const
+ inline bool get_consumers(pool<PortBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_consumers.count(bit)) {
- const std::set<PortBit> &r = signal_consumers.at(bit);
+ const pool<PortBit> &r = signal_consumers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
@@ -310,7 +416,7 @@ struct ModWalker
}
template<typename T>
- inline bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
+ inline bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_inputs.count(bit))
@@ -319,7 +425,7 @@ struct ModWalker
}
template<typename T>
- inline bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
+ inline bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_outputs.count(bit))
@@ -330,12 +436,12 @@ struct ModWalker
// get_* methods -- container of RTLIL::SigBit's (always by reference)
template<typename T>
- inline bool get_drivers(std::set<PortBit> &result, const T &bits) const
+ inline bool get_drivers(pool<PortBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
if (signal_drivers.count(bit)) {
- const std::set<PortBit> &r = signal_drivers.at(bit);
+ const pool<PortBit> &r = signal_drivers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
@@ -343,12 +449,12 @@ struct ModWalker
}
template<typename T>
- inline bool get_consumers(std::set<PortBit> &result, const T &bits) const
+ inline bool get_consumers(pool<PortBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
if (signal_consumers.count(bit)) {
- const std::set<PortBit> &r = signal_consumers.at(bit);
+ const pool<PortBit> &r = signal_consumers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
@@ -356,7 +462,7 @@ struct ModWalker
}
template<typename T>
- inline bool get_inputs(std::set<RTLIL::SigBit> &result, const T &bits) const
+ inline bool get_inputs(pool<RTLIL::SigBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
@@ -366,7 +472,7 @@ struct ModWalker
}
template<typename T>
- inline bool get_outputs(std::set<RTLIL::SigBit> &result, const T &bits) const
+ inline bool get_outputs(pool<RTLIL::SigBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
@@ -377,25 +483,25 @@ struct ModWalker
// get_* methods -- call by RTLIL::SigSpec (always by value)
- bool get_drivers(std::set<PortBit> &result, RTLIL::SigSpec signal) const
+ bool get_drivers(pool<PortBit> &result, RTLIL::SigSpec signal) const
{
std::vector<RTLIL::SigBit> bits = sigmap(signal);
return get_drivers(result, bits);
}
- bool get_consumers(std::set<PortBit> &result, RTLIL::SigSpec signal) const
+ bool get_consumers(pool<PortBit> &result, RTLIL::SigSpec signal) const
{
std::vector<RTLIL::SigBit> bits = sigmap(signal);
return get_consumers(result, bits);
}
- bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
+ bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
{
std::vector<RTLIL::SigBit> bits = sigmap(signal);
return get_inputs(result, bits);
}
- bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
+ bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
{
std::vector<RTLIL::SigBit> bits = sigmap(signal);
return get_outputs(result, bits);
@@ -405,47 +511,47 @@ struct ModWalker
template<typename T>
inline bool has_drivers(const T &sig) const {
- std::set<PortBit> result;
+ pool<PortBit> result;
return get_drivers(result, sig);
}
template<typename T>
inline bool has_consumers(const T &sig) const {
- std::set<PortBit> result;
+ pool<PortBit> result;
return get_consumers(result, sig);
}
template<typename T>
inline bool has_inputs(const T &sig) const {
- std::set<RTLIL::SigBit> result;
+ pool<RTLIL::SigBit> result;
return get_inputs(result, sig);
}
template<typename T>
inline bool has_outputs(const T &sig) const {
- std::set<RTLIL::SigBit> result;
+ pool<RTLIL::SigBit> result;
return get_outputs(result, sig);
}
// has_* methods -- call by value
inline bool has_drivers(RTLIL::SigSpec sig) const {
- std::set<PortBit> result;
+ pool<PortBit> result;
return get_drivers(result, sig);
}
inline bool has_consumers(RTLIL::SigSpec sig) const {
- std::set<PortBit> result;
+ pool<PortBit> result;
return get_consumers(result, sig);
}
inline bool has_inputs(RTLIL::SigSpec sig) const {
- std::set<RTLIL::SigBit> result;
+ pool<RTLIL::SigBit> result;
return get_inputs(result, sig);
}
inline bool has_outputs(RTLIL::SigSpec sig) const {
- std::set<RTLIL::SigBit> result;
+ pool<RTLIL::SigBit> result;
return get_outputs(result, sig);
}
};
diff --git a/kernel/register.cc b/kernel/register.cc
index 2f7b89ff..af1cb77b 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -18,6 +18,8 @@
*/
#include "kernel/yosys.h"
+#include "kernel/satgen.h"
+
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -146,35 +148,39 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig
void Pass::call(RTLIL::Design *design, std::string command)
{
std::vector<std::string> args;
- char *s = strdup(command.c_str()), *sstart = s, *saveptr;
- s += strspn(s, " \t\r\n");
- if (*s == 0 || *s == '#') {
- free(sstart);
+
+ std::string cmd_buf = command;
+ std::string tok = next_token(cmd_buf, " \t\r\n");
+
+ if (tok.empty())
return;
- }
- if (*s == '!') {
- for (s++; *s == ' ' || *s == '\t'; s++) { }
- char *p = s + strlen(s) - 1;
- while (p >= s && (*p == '\r' || *p == '\n'))
- *(p--) = 0;
- log_header("Shell command: %s\n", s);
- int retCode = system(s);
+
+ if (tok[0] == '!') {
+ cmd_buf = command.substr(command.find('!') + 1);
+ while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' ||
+ cmd_buf.back() == '\r' || cmd_buf.back() == '\n'))
+ cmd_buf.resize(cmd_buf.size()-1);
+ log_header("Shell command: %s\n", cmd_buf.c_str());
+ int retCode = run_command(cmd_buf);
if (retCode != 0)
log_cmd_error("Shell command returned error code %d.\n", retCode);
- free(sstart);
return;
}
- for (char *p = strtok_r(s, " \t\r\n", &saveptr); p; p = strtok_r(NULL, " \t\r\n", &saveptr)) {
- std::string str = p;
- int strsz = str.size();
- if (str == "#")
- break;
- if (strsz > 0 && str[strsz-1] == ';') {
+
+ while (!tok.empty()) {
+ if (tok == "#") {
+ int stop;
+ for (stop = 0; stop < GetSize(cmd_buf); stop++)
+ if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n')
+ break;
+ cmd_buf = cmd_buf.substr(stop);
+ } else
+ if (tok.back() == ';') {
int num_semikolon = 0;
- while (strsz > 0 && str[strsz-1] == ';')
- strsz--, num_semikolon++;
- if (strsz > 0)
- args.push_back(str.substr(0, strsz));
+ while (!tok.empty() && tok.back() == ';')
+ tok.resize(tok.size()-1), num_semikolon++;
+ if (!tok.empty())
+ args.push_back(tok);
call(design, args);
args.clear();
if (num_semikolon == 2)
@@ -182,9 +188,22 @@ void Pass::call(RTLIL::Design *design, std::string command)
if (num_semikolon == 3)
call(design, "clean -purge");
} else
- args.push_back(str);
+ args.push_back(tok);
+ bool found_nl = false;
+ for (auto c : cmd_buf) {
+ if (c == ' ' || c == '\t')
+ continue;
+ if (c == '\r' || c == '\n')
+ found_nl = true;
+ break;
+ }
+ if (found_nl) {
+ call(design, args);
+ args.clear();
+ }
+ tok = next_token(cmd_buf, " \t\r\n");
}
- free(sstart);
+
call(design, args);
}
@@ -333,8 +352,8 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
if (buffer.size() > 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r'))
break;
}
- int indent = buffer.find_first_not_of(" \t\r\n");
- if (buffer.substr(indent, eot_marker.size()) == eot_marker)
+ size_t indent = buffer.find_first_not_of(" \t\r\n");
+ if (indent != std::string::npos && buffer.substr(indent, eot_marker.size()) == eot_marker)
break;
last_here_document += buffer;
}
@@ -528,11 +547,10 @@ struct HelpPass : public Pass {
}
void escape_tex(std::string &tex)
{
- size_t pos = 0;
- while ((pos = tex.find('_', pos)) != std::string::npos) {
+ for (size_t pos = 0; (pos = tex.find('_', pos)) != std::string::npos; pos += 2)
tex.replace(pos, 1, "\\_");
- pos += 2;
- }
+ for (size_t pos = 0; (pos = tex.find('$', pos)) != std::string::npos; pos += 2)
+ tex.replace(pos, 1, "\\$");
}
void write_tex(FILE *f, std::string cmd, std::string title, std::string text)
{
@@ -675,6 +693,18 @@ struct EchoPass : public Pass {
log("echo %s\n", echo_mode ? "on" : "off");
}
} EchoPass;
+
+SatSolver *yosys_satsolver_list;
+SatSolver *yosys_satsolver;
+
+struct MinisatSatSolver : public SatSolver {
+ MinisatSatSolver() : SatSolver("minisat") {
+ yosys_satsolver = this;
+ }
+ virtual ezSAT *create() YS_OVERRIDE {
+ return new ezMiniSAT();
+ }
+} MinisatSatSolver;
YOSYS_NAMESPACE_END
diff --git a/kernel/register.h b/kernel/register.h
index a49675ed..0a10483f 100644
--- a/kernel/register.h
+++ b/kernel/register.h
@@ -71,9 +71,9 @@ struct Frontend : Pass
std::string frontend_name;
Frontend(std::string name, std::string short_help = "** document me **");
- virtual void run_register();
+ virtual void run_register() YS_OVERRIDE;
virtual ~Frontend();
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
static std::vector<std::string> next_args;
@@ -87,9 +87,9 @@ struct Backend : Pass
{
std::string backend_name;
Backend(std::string name, std::string short_help = "** document me **");
- virtual void run_register();
+ virtual void run_register() YS_OVERRIDE;
virtual ~Backend();
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
void extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
@@ -100,6 +100,8 @@ struct Backend : Pass
// implemented in passes/cmds/select.cc
extern void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design);
+extern RTLIL::Selection eval_select_args(const vector<string> &args, RTLIL::Design *design);
+extern void eval_select_op(vector<RTLIL::Selection> &work, const string &op, RTLIL::Design *design);
extern std::map<std::string, Pass*> pass_register;
extern std::map<std::string, Frontend*> frontend_register;
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 00be796f..adf89a24 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/macc.h"
+#include "kernel/celltypes.h"
#include "frontends/verilog/verilog_frontend.h"
#include "backends/ilang/ilang_backend.h"
@@ -27,9 +28,10 @@
YOSYS_NAMESPACE_BEGIN
+RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard;
std::vector<int> RTLIL::IdString::global_refcount_storage_;
std::vector<char*> RTLIL::IdString::global_id_storage_;
-std::map<char*, int, RTLIL::IdString::char_ptr_cmp> RTLIL::IdString::global_id_index_;
+dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
std::vector<int> RTLIL::IdString::global_free_idx_list_;
RTLIL::Const::Const()
@@ -127,6 +129,21 @@ std::string RTLIL::Const::as_string() const
return ret;
}
+RTLIL::Const RTLIL::Const::from_string(std::string str)
+{
+ Const c;
+ for (auto it = str.rbegin(); it != str.rend(); it++)
+ switch (*it) {
+ case '0': c.bits.push_back(State::S0); break;
+ case '1': c.bits.push_back(State::S1); break;
+ case 'x': c.bits.push_back(State::Sx); break;
+ case 'z': c.bits.push_back(State::Sz); break;
+ case 'm': c.bits.push_back(State::Sm); break;
+ default: c.bits.push_back(State::Sa);
+ }
+ return c;
+}
+
std::string RTLIL::Const::decode_string() const
{
std::string string;
@@ -235,13 +252,17 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
RTLIL::Design::Design()
{
+ static unsigned int hashidx_count = 123456789;
+ hashidx_count = mkhash_xorshift(hashidx_count);
+ hashidx_ = hashidx_count;
+
refcount_modules_ = 0;
selection_stack.push_back(RTLIL::Selection());
}
RTLIL::Design::~Design()
{
- for (auto it = modules_.begin(); it != modules_.end(); it++)
+ for (auto it = modules_.begin(); it != modules_.end(); ++it)
delete it->second;
}
@@ -264,6 +285,11 @@ void RTLIL::Design::add(RTLIL::Module *module)
for (auto mon : monitors)
mon->notify_module_add(module);
+
+ if (yosys_xtrace) {
+ log("#X# New Module: %s\n", log_id(module));
+ log_backtrace("-X- ", yosys_xtrace-1);
+ }
}
RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name)
@@ -279,6 +305,11 @@ RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name)
for (auto mon : monitors)
mon->notify_module_add(module);
+ if (yosys_xtrace) {
+ log("#X# New Module: %s\n", log_id(module));
+ log_backtrace("-X- ", yosys_xtrace-1);
+ }
+
return module;
}
@@ -348,11 +379,24 @@ void RTLIL::Design::remove(RTLIL::Module *module)
for (auto mon : monitors)
mon->notify_module_del(module);
+ if (yosys_xtrace) {
+ log("#X# Remove Module: %s\n", log_id(module));
+ log_backtrace("-X- ", yosys_xtrace-1);
+ }
+
log_assert(modules_.at(module->name) == module);
modules_.erase(module->name);
delete module;
}
+void RTLIL::Design::sort()
+{
+ scratchpad.sort();
+ modules_.sort(sort_by_id_str());
+ for (auto &it : modules_)
+ it.second->sort();
+}
+
void RTLIL::Design::check()
{
#ifndef NDEBUG
@@ -417,7 +461,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
- if (selected_module(it.first))
+ if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
result.push_back(it.second);
return result;
}
@@ -427,7 +471,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
- if (selected_whole_module(it.first))
+ if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
result.push_back(it.second);
return result;
}
@@ -437,15 +481,21 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
- if (selected_whole_module(it.first))
+ if (it.second->get_bool_attribute("\\blackbox"))
+ continue;
+ else if (selected_whole_module(it.first))
result.push_back(it.second);
else if (selected_module(it.first))
- log("Warning: Ignoring partially selected module %s.\n", log_id(it.first));
+ log_warning("Ignoring partially selected module %s.\n", log_id(it.first));
return result;
}
RTLIL::Module::Module()
{
+ static unsigned int hashidx_count = 123456789;
+ hashidx_count = mkhash_xorshift(hashidx_count);
+ hashidx_ = hashidx_count;
+
design = nullptr;
refcount_wires_ = 0;
refcount_cells_ = 0;
@@ -453,17 +503,17 @@ RTLIL::Module::Module()
RTLIL::Module::~Module()
{
- for (auto it = wires_.begin(); it != wires_.end(); it++)
+ for (auto it = wires_.begin(); it != wires_.end(); ++it)
delete it->second;
- for (auto it = memories.begin(); it != memories.end(); it++)
+ for (auto it = memories.begin(); it != memories.end(); ++it)
delete it->second;
- for (auto it = cells_.begin(); it != cells_.end(); it++)
+ for (auto it = cells_.begin(); it != cells_.end(); ++it)
delete it->second;
- for (auto it = processes.begin(); it != processes.end(); it++)
+ for (auto it = processes.begin(); it != processes.end(); ++it)
delete it->second;
}
-RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString, RTLIL::Const>)
+RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>)
{
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
}
@@ -479,7 +529,7 @@ namespace {
{
RTLIL::Module *module;
RTLIL::Cell *cell;
- std::set<RTLIL::IdString> expected_params, expected_ports;
+ pool<RTLIL::IdString> expected_params, expected_ports;
InternalCellChecker(RTLIL::Module *module, RTLIL::Cell *cell) : module(module), cell(cell) { }
@@ -752,6 +802,17 @@ namespace {
return;
}
+ if (cell->type == "$dffe") {
+ param_bool("\\CLK_POLARITY");
+ param_bool("\\EN_POLARITY");
+ port("\\CLK", 1);
+ port("\\EN", 1);
+ port("\\D", param("\\WIDTH"));
+ port("\\Q", param("\\WIDTH"));
+ check_expected();
+ return;
+ }
+
if (cell->type == "$dffsr") {
param_bool("\\CLK_POLARITY");
param_bool("\\SET_POLARITY");
@@ -843,10 +904,20 @@ namespace {
return;
}
+ if (cell->type == "$meminit") {
+ param("\\MEMID");
+ param("\\PRIORITY");
+ port("\\ADDR", param("\\ABITS"));
+ port("\\DATA", param("\\WIDTH"));
+ check_expected();
+ return;
+ }
+
if (cell->type == "$mem") {
param("\\MEMID");
param("\\SIZE");
param("\\OFFSET");
+ param("\\INIT");
param_bits("\\RD_CLK_ENABLE", param("\\RD_PORTS"));
param_bits("\\RD_CLK_POLARITY", param("\\RD_PORTS"));
param_bits("\\RD_TRANSPARENT", param("\\RD_PORTS"));
@@ -870,6 +941,22 @@ namespace {
return;
}
+ if (cell->type == "$assume") {
+ port("\\A", 1);
+ port("\\EN", 1);
+ check_expected();
+ return;
+ }
+
+ if (cell->type == "$equiv") {
+ port("\\A", 1);
+ port("\\B", 1);
+ port("\\Y", 1);
+ check_expected();
+ return;
+ }
+
+ if (cell->type == "$_BUF_") { check_gate("AY"); return; }
if (cell->type == "$_NOT_") { check_gate("AY"); return; }
if (cell->type == "$_AND_") { check_gate("ABY"); return; }
if (cell->type == "$_NAND_") { check_gate("ABY"); return; }
@@ -891,6 +978,11 @@ namespace {
if (cell->type == "$_DFF_N_") { check_gate("DQC"); return; }
if (cell->type == "$_DFF_P_") { check_gate("DQC"); return; }
+ if (cell->type == "$_DFFE_NN_") { check_gate("DQCE"); return; }
+ if (cell->type == "$_DFFE_NP_") { check_gate("DQCE"); return; }
+ if (cell->type == "$_DFFE_PN_") { check_gate("DQCE"); return; }
+ if (cell->type == "$_DFFE_PP_") { check_gate("DQCE"); return; }
+
if (cell->type == "$_DFF_NN0_") { check_gate("DQCR"); return; }
if (cell->type == "$_DFF_NN1_") { check_gate("DQCR"); return; }
if (cell->type == "$_DFF_NP0_") { check_gate("DQCR"); return; }
@@ -927,6 +1019,21 @@ namespace {
}
#endif
+void RTLIL::Module::sort()
+{
+ wires_.sort(sort_by_id_str());
+ cells_.sort(sort_by_id_str());
+ avail_parameters.sort(sort_by_id_str());
+ memories.sort(sort_by_id_str());
+ processes.sort(sort_by_id_str());
+ for (auto &it : cells_)
+ it.second->sort();
+ for (auto &it : wires_)
+ it.second->attributes.sort(sort_by_id_str());
+ for (auto &it : memories)
+ it.second->attributes.sort(sort_by_id_str());
+}
+
void RTLIL::Module::check()
{
#ifndef NDEBUG
@@ -940,10 +1047,10 @@ void RTLIL::Module::check()
for (auto &it2 : it.second->attributes)
log_assert(!it2.first.empty());
if (it.second->port_id) {
- log_assert(SIZE(ports) >= it.second->port_id);
+ log_assert(GetSize(ports) >= it.second->port_id);
log_assert(ports.at(it.second->port_id-1) == it.first);
log_assert(it.second->port_input || it.second->port_output);
- if (SIZE(ports_declared) < it.second->port_id)
+ if (GetSize(ports_declared) < it.second->port_id)
ports_declared.resize(it.second->port_id);
log_assert(ports_declared[it.second->port_id-1] == false);
ports_declared[it.second->port_id-1] = true;
@@ -952,7 +1059,7 @@ void RTLIL::Module::check()
}
for (auto port_declared : ports_declared)
log_assert(port_declared == true);
- log_assert(SIZE(ports) == SIZE(ports_declared));
+ log_assert(GetSize(ports) == GetSize(ports_declared));
for (auto &it : memories) {
log_assert(it.first == it.second->name);
@@ -988,6 +1095,7 @@ void RTLIL::Module::check()
for (auto &it : connections_) {
log_assert(it.first.size() == it.second.size());
+ log_assert(!it.first.has_const());
it.first.check();
it.second.check();
}
@@ -1006,8 +1114,11 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const
log_assert(new_mod->refcount_wires_ == 0);
log_assert(new_mod->refcount_cells_ == 0);
- new_mod->connections_ = connections_;
- new_mod->attributes = attributes;
+ for (auto &conn : connections_)
+ new_mod->connect(conn);
+
+ for (auto &attr : attributes)
+ new_mod->attributes[attr.first] = attr.second;
for (auto &it : wires_)
new_mod->addWire(it.first, it.second);
@@ -1061,14 +1172,14 @@ bool RTLIL::Module::has_processes() const
bool RTLIL::Module::has_memories_warn() const
{
if (!memories.empty())
- log("Warning: Ignoring module %s because it contains memories (run 'memory' command first).\n", log_id(this));
+ log_warning("Ignoring module %s because it contains memories (run 'memory' command first).\n", log_id(this));
return !memories.empty();
}
bool RTLIL::Module::has_processes_warn() const
{
if (!processes.empty())
- log("Warning: Ignoring module %s because it contains processes (run 'proc' command first).\n", log_id(this));
+ log_warning("Ignoring module %s because it contains processes (run 'proc' command first).\n", log_id(this));
return !processes.empty();
}
@@ -1114,7 +1225,7 @@ namespace {
struct DeleteWireWorker
{
RTLIL::Module *module;
- const std::set<RTLIL::Wire*> *wires_p;
+ const pool<RTLIL::Wire*> *wires_p;
void operator()(RTLIL::SigSpec &sig) {
std::vector<RTLIL::SigChunk> chunks = sig;
@@ -1128,16 +1239,7 @@ namespace {
};
}
-#if 0
-void RTLIL::Module::remove(RTLIL::Wire *wire)
-{
- std::setPort<RTLIL::Wire*> wires_;
- wires_.insert(wire);
- remove(wires_);
-}
-#endif
-
-void RTLIL::Module::remove(const std::set<RTLIL::Wire*> &wires)
+void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
{
log_assert(refcount_wires_ == 0);
@@ -1266,6 +1368,11 @@ void RTLIL::Module::connect(const RTLIL::SigSig &conn)
for (auto mon : design->monitors)
mon->notify_connect(this, conn);
+ if (yosys_xtrace) {
+ log("#X# Connect (SigSig) in %s: %s = %s (%d bits)\n", log_id(this), log_signal(conn.first), log_signal(conn.second), GetSize(conn.first));
+ log_backtrace("-X- ", yosys_xtrace-1);
+ }
+
connections_.push_back(conn);
}
@@ -1283,6 +1390,13 @@ void RTLIL::Module::new_connections(const std::vector<RTLIL::SigSig> &new_conn)
for (auto mon : design->monitors)
mon->notify_connect(this, new_conn);
+ if (yosys_xtrace) {
+ log("#X# New connections vector in %s:\n", log_id(this));
+ for (auto &conn: new_conn)
+ log("#X# %s = %s (%d bits)\n", log_signal(conn.first), log_signal(conn.second), GetSize(conn.first));
+ log_backtrace("-X- ", yosys_xtrace-1);
+ }
+
connections_ = new_conn;
}
@@ -1566,6 +1680,15 @@ RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a
return cell;
}
+RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y)
+{
+ RTLIL::Cell *cell = addCell(name, "$equiv");
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\B", sig_b);
+ cell->setPort("\\Y", sig_y);
+ return cell;
+}
+
RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity, bool clr_polarity)
{
RTLIL::Cell *cell = addCell(name, "$sr");
@@ -1578,7 +1701,7 @@ RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set,
return cell;
}
-RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity)
+RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity)
{
RTLIL::Cell *cell = addCell(name, "$dff");
cell->parameters["\\CLK_POLARITY"] = clk_polarity;
@@ -1589,6 +1712,19 @@ RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk,
return cell;
}
+RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, "$dffe");
+ cell->parameters["\\CLK_POLARITY"] = clk_polarity;
+ cell->parameters["\\EN_POLARITY"] = en_polarity;
+ cell->parameters["\\WIDTH"] = sig_q.size();
+ cell->setPort("\\CLK", sig_clk);
+ cell->setPort("\\EN", sig_en);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity)
{
@@ -1656,6 +1792,16 @@ RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_
return cell;
}
+RTLIL::Cell* RTLIL::Module::addDffeGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity)
+{
+ RTLIL::Cell *cell = addCell(name, stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
+ cell->setPort("\\C", sig_clk);
+ cell->setPort("\\E", sig_en);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ return cell;
+}
+
RTLIL::Cell* RTLIL::Module::addDffsrGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity)
{
@@ -1703,6 +1849,10 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec
RTLIL::Wire::Wire()
{
+ static unsigned int hashidx_count = 123456789;
+ hashidx_count = mkhash_xorshift(hashidx_count);
+ hashidx_ = hashidx_count;
+
module = nullptr;
width = 1;
start_offset = 0;
@@ -1714,12 +1864,22 @@ RTLIL::Wire::Wire()
RTLIL::Memory::Memory()
{
+ static unsigned int hashidx_count = 123456789;
+ hashidx_count = mkhash_xorshift(hashidx_count);
+ hashidx_ = hashidx_count;
+
width = 1;
size = 0;
}
RTLIL::Cell::Cell() : module(nullptr)
{
+ static unsigned int hashidx_count = 123456789;
+ hashidx_count = mkhash_xorshift(hashidx_count);
+ hashidx_ = hashidx_count;
+
+ // log("#memtrace# %p\n", this);
+ memhasher();
}
bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const
@@ -1741,6 +1901,11 @@ void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
for (auto mon : module->design->monitors)
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
+ if (yosys_xtrace) {
+ log("#X# Unconnect %s.%s.%s\n", log_id(this->module), log_id(this), log_id(portname));
+ log_backtrace("-X- ", yosys_xtrace-1);
+ }
+
connections_.erase(conn_it);
}
}
@@ -1753,7 +1918,9 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
connections_[portname] = RTLIL::SigSpec();
conn_it = connections_.find(portname);
log_assert(conn_it != connections_.end());
- }
+ } else
+ if (conn_it->second == signal)
+ return;
for (auto mon : module->monitors)
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
@@ -1762,6 +1929,11 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
for (auto mon : module->design->monitors)
mon->notify_connect(this, conn_it->first, conn_it->second, signal);
+ if (yosys_xtrace) {
+ log("#X# Connect %s.%s.%s = %s (%d)\n", log_id(this->module), log_id(this), log_id(portname), log_signal(signal), GetSize(signal));
+ log_backtrace("-X- ", yosys_xtrace-1);
+ }
+
conn_it->second = signal;
}
@@ -1770,14 +1942,47 @@ const RTLIL::SigSpec &RTLIL::Cell::getPort(RTLIL::IdString portname) const
return connections_.at(portname);
}
-const std::map<RTLIL::IdString, RTLIL::SigSpec> &RTLIL::Cell::connections() const
+const dict<RTLIL::IdString, RTLIL::SigSpec> &RTLIL::Cell::connections() const
{
return connections_;
}
+bool RTLIL::Cell::known() const
+{
+ if (yosys_celltypes.cell_known(type))
+ return true;
+ if (module && module->design && module->design->module(type))
+ return true;
+ return false;
+}
+
+bool RTLIL::Cell::input(RTLIL::IdString portname) const
+{
+ if (yosys_celltypes.cell_known(type))
+ return yosys_celltypes.cell_input(type, portname);
+ if (module && module->design) {
+ RTLIL::Module *m = module->design->module(type);
+ RTLIL::Wire *w = m ? m->wire(portname) : nullptr;
+ return w && w->port_input;
+ }
+ return false;
+}
+
+bool RTLIL::Cell::output(RTLIL::IdString portname) const
+{
+ if (yosys_celltypes.cell_known(type))
+ return yosys_celltypes.cell_output(type, portname);
+ if (module && module->design) {
+ RTLIL::Module *m = module->design->module(type);
+ RTLIL::Wire *w = m ? m->wire(portname) : nullptr;
+ return w && w->port_output;
+ }
+ return false;
+}
+
bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const
{
- return parameters.count(paramname);
+ return parameters.count(paramname) != 0;
}
void RTLIL::Cell::unsetParam(RTLIL::IdString paramname)
@@ -1795,6 +2000,13 @@ const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const
return parameters.at(paramname);
}
+void RTLIL::Cell::sort()
+{
+ connections_.sort(sort_by_id_str());
+ parameters.sort(sort_by_id_str());
+ attributes.sort(sort_by_id_str());
+}
+
void RTLIL::Cell::check()
{
#ifndef NDEBUG
@@ -1810,25 +2022,25 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
return;
if (type == "$mux" || type == "$pmux") {
- parameters["\\WIDTH"] = SIZE(connections_["\\Y"]);
+ parameters["\\WIDTH"] = GetSize(connections_["\\Y"]);
if (type == "$pmux")
- parameters["\\S_WIDTH"] = SIZE(connections_["\\S"]);
+ parameters["\\S_WIDTH"] = GetSize(connections_["\\S"]);
check();
return;
}
if (type == "$lut") {
- parameters["\\WIDTH"] = SIZE(connections_["\\A"]);
+ parameters["\\WIDTH"] = GetSize(connections_["\\A"]);
return;
}
if (type == "$fa") {
- parameters["\\WIDTH"] = SIZE(connections_["\\Y"]);
+ parameters["\\WIDTH"] = GetSize(connections_["\\Y"]);
return;
}
if (type == "$lcu") {
- parameters["\\WIDTH"] = SIZE(connections_["\\CO"]);
+ parameters["\\WIDTH"] = GetSize(connections_["\\CO"]);
return;
}
@@ -1841,7 +2053,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
else if (parameters.count("\\A_SIGNED") == 0)
parameters["\\A_SIGNED"] = false;
}
- parameters["\\A_WIDTH"] = SIZE(connections_["\\A"]);
+ parameters["\\A_WIDTH"] = GetSize(connections_["\\A"]);
}
if (connections_.count("\\B")) {
@@ -1851,11 +2063,11 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
else if (parameters.count("\\B_SIGNED") == 0)
parameters["\\B_SIGNED"] = false;
}
- parameters["\\B_WIDTH"] = SIZE(connections_["\\B"]);
+ parameters["\\B_WIDTH"] = GetSize(connections_["\\B"]);
}
if (connections_.count("\\Y"))
- parameters["\\Y_WIDTH"] = SIZE(connections_["\\Y"]);
+ parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]);
check();
}
@@ -1871,7 +2083,7 @@ RTLIL::SigChunk::SigChunk(const RTLIL::Const &value)
{
wire = NULL;
data = value.bits;
- width = SIZE(data);
+ width = GetSize(data);
offset = 0;
}
@@ -1895,7 +2107,7 @@ RTLIL::SigChunk::SigChunk(const std::string &str)
{
wire = NULL;
data = RTLIL::Const(str).bits;
- width = SIZE(data);
+ width = GetSize(data);
offset = 0;
}
@@ -1903,7 +2115,7 @@ RTLIL::SigChunk::SigChunk(int val, int width)
{
wire = NULL;
data = RTLIL::Const(val, width).bits;
- this->width = SIZE(data);
+ this->width = GetSize(data);
offset = 0;
}
@@ -1911,7 +2123,7 @@ RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width)
{
wire = NULL;
data = RTLIL::Const(bit, width).bits;
- this->width = SIZE(data);
+ this->width = GetSize(data);
offset = 0;
}
@@ -2137,6 +2349,17 @@ RTLIL::SigSpec::SigSpec(std::vector<RTLIL::SigBit> bits)
check();
}
+RTLIL::SigSpec::SigSpec(pool<RTLIL::SigBit> bits)
+{
+ cover("kernel.rtlil.sigspec.init.pool_bits");
+
+ width_ = 0;
+ hash_ = 0;
+ for (auto &bit : bits)
+ append_bit(bit);
+ check();
+}
+
RTLIL::SigSpec::SigSpec(std::set<RTLIL::SigBit> bits)
{
cover("kernel.rtlil.sigspec.init.stdset_bits");
@@ -2148,6 +2371,16 @@ RTLIL::SigSpec::SigSpec(std::set<RTLIL::SigBit> bits)
check();
}
+RTLIL::SigSpec::SigSpec(bool bit)
+{
+ cover("kernel.rtlil.sigspec.init.bool");
+
+ width_ = 0;
+ hash_ = 0;
+ append_bit(bit);
+ check();
+}
+
void RTLIL::SigSpec::pack() const
{
RTLIL::SigSpec *that = (RTLIL::SigSpec*)this;
@@ -2203,9 +2436,7 @@ void RTLIL::SigSpec::unpack() const
that->hash_ = 0;
}
-#define DJB2(_hash, _value) do { (_hash) = (((_hash) << 5) + (_hash)) + (_value); } while (0)
-
-void RTLIL::SigSpec::hash() const
+void RTLIL::SigSpec::updhash() const
{
RTLIL::SigSpec *that = (RTLIL::SigSpec*)this;
@@ -2215,15 +2446,15 @@ void RTLIL::SigSpec::hash() const
cover("kernel.rtlil.sigspec.hash");
that->pack();
- that->hash_ = 5381;
+ that->hash_ = mkhash_init;
for (auto &c : that->chunks_)
if (c.wire == NULL) {
for (auto &v : c.data)
- DJB2(that->hash_, v);
+ that->hash_ = mkhash(that->hash_, v);
} else {
- DJB2(that->hash_, c.wire->name.index_);
- DJB2(that->hash_, c.offset);
- DJB2(that->hash_, c.width);
+ that->hash_ = mkhash(that->hash_, c.wire->name.index_);
+ that->hash_ = mkhash(that->hash_, c.offset);
+ that->hash_ = mkhash(that->hash_, c.width);
}
if (that->hash_ == 0)
@@ -2255,15 +2486,39 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec
pattern.unpack();
with.unpack();
- std::map<RTLIL::SigBit, RTLIL::SigBit> rules;
+ dict<RTLIL::SigBit, RTLIL::SigBit> rules;
- for (int i = 0; i < SIZE(pattern.bits_); i++)
+ for (int i = 0; i < GetSize(pattern.bits_); i++)
if (pattern.bits_[i].wire != NULL)
rules[pattern.bits_[i]] = with.bits_[i];
replace(rules, other);
}
+void RTLIL::SigSpec::replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules)
+{
+ replace(rules, this);
+}
+
+void RTLIL::SigSpec::replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const
+{
+ cover("kernel.rtlil.sigspec.replace_dict");
+
+ log_assert(other != NULL);
+ log_assert(width_ == other->width_);
+
+ unpack();
+ other->unpack();
+
+ for (int i = 0; i < GetSize(bits_); i++) {
+ auto it = rules.find(bits_[i]);
+ if (it != rules.end())
+ other->bits_[i] = it->second;
+ }
+
+ other->check();
+}
+
void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules)
{
replace(rules, this);
@@ -2271,7 +2526,7 @@ void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules
void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const
{
- cover("kernel.rtlil.sigspec.replace");
+ cover("kernel.rtlil.sigspec.replace_map");
log_assert(other != NULL);
log_assert(width_ == other->width_);
@@ -2279,7 +2534,7 @@ void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules
unpack();
other->unpack();
- for (int i = 0; i < SIZE(bits_); i++) {
+ for (int i = 0; i < GetSize(bits_); i++) {
auto it = rules.find(bits_[i]);
if (it != rules.end())
other->bits_[i] = it->second;
@@ -2301,22 +2556,22 @@ void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other
void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other)
{
- std::set<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_set();
+ pool<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_pool();
remove2(pattern_bits, other);
}
-void RTLIL::SigSpec::remove(const std::set<RTLIL::SigBit> &pattern)
+void RTLIL::SigSpec::remove(const pool<RTLIL::SigBit> &pattern)
{
remove2(pattern, NULL);
}
-void RTLIL::SigSpec::remove(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const
+void RTLIL::SigSpec::remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const
{
RTLIL::SigSpec tmp = *this;
tmp.remove2(pattern, other);
}
-void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other)
+void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other)
{
if (other)
cover("kernel.rtlil.sigspec.remove_other");
@@ -2332,12 +2587,12 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS
std::vector<RTLIL::SigBit> new_bits, new_other_bits;
- new_bits.resize(SIZE(bits_));
+ new_bits.resize(GetSize(bits_));
if (other != NULL)
- new_other_bits.resize(SIZE(bits_));
+ new_other_bits.resize(GetSize(bits_));
int k = 0;
- for (int i = 0; i < SIZE(bits_); i++) {
+ for (int i = 0; i < GetSize(bits_); i++) {
if (bits_[i].wire != NULL && pattern.count(bits_[i]))
continue;
if (other != NULL)
@@ -2350,11 +2605,11 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS
new_other_bits.resize(k);
bits_.swap(new_bits);
- width_ = SIZE(bits_);
+ width_ = GetSize(bits_);
if (other != NULL) {
other->bits_.swap(new_other_bits);
- other->width_ = SIZE(other->bits_);
+ other->width_ = GetSize(other->bits_);
}
check();
@@ -2362,11 +2617,11 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS
RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const
{
- std::set<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_set();
+ pool<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_pool();
return extract(pattern_bits, other);
}
-RTLIL::SigSpec RTLIL::SigSpec::extract(const std::set<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other) const
+RTLIL::SigSpec RTLIL::SigSpec::extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other) const
{
if (other)
cover("kernel.rtlil.sigspec.extract_other");
@@ -2417,7 +2672,7 @@ void RTLIL::SigSpec::remove_const()
cover("kernel.rtlil.sigspec.remove_const.packed");
std::vector<RTLIL::SigChunk> new_chunks;
- new_chunks.reserve(SIZE(chunks_));
+ new_chunks.reserve(GetSize(chunks_));
width_ = 0;
for (auto &chunk : chunks_)
@@ -2539,25 +2794,6 @@ void RTLIL::SigSpec::append_bit(const RTLIL::SigBit &bit)
check();
}
-void RTLIL::SigSpec::extend(int width, bool is_signed)
-{
- cover("kernel.rtlil.sigspec.extend");
-
- pack();
-
- if (width_ > width)
- remove(width, width_ - width);
-
- if (width_ < width) {
- RTLIL::SigSpec padding = width_ > 0 ? extract(width_ - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0);
- if (!is_signed && padding != RTLIL::SigSpec(RTLIL::State::Sx) && padding != RTLIL::SigSpec(RTLIL::State::Sz) &&
- padding != RTLIL::SigSpec(RTLIL::State::Sa) && padding != RTLIL::SigSpec(RTLIL::State::Sm))
- padding = RTLIL::SigSpec(RTLIL::State::S0);
- while (width_ < width)
- append(padding);
- }
-}
-
void RTLIL::SigSpec::extend_u0(int width, bool is_signed)
{
cover("kernel.rtlil.sigspec.extend_u0");
@@ -2568,9 +2804,9 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed)
remove(width, width_ - width);
if (width_ < width) {
- RTLIL::SigSpec padding = width_ > 0 ? extract(width_ - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0);
+ RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0;
if (!is_signed)
- padding = RTLIL::SigSpec(RTLIL::State::S0);
+ padding = RTLIL::State::S0;
while (width_ < width)
append(padding);
}
@@ -2623,7 +2859,7 @@ void RTLIL::SigSpec::check() const
{
cover("kernel.rtlil.sigspec.check.unpacked");
- log_assert(width_ == SIZE(bits_));
+ log_assert(width_ == GetSize(bits_));
log_assert(chunks_.empty());
}
}
@@ -2645,8 +2881,8 @@ bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const
if (chunks_.size() != other.chunks_.size())
return chunks_.size() < other.chunks_.size();
- hash();
- other.hash();
+ updhash();
+ other.updhash();
if (hash_ != other.hash_)
return hash_ < other.hash_;
@@ -2677,8 +2913,8 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
if (chunks_.size() != chunks_.size())
return false;
- hash();
- other.hash();
+ updhash();
+ other.updhash();
if (hash_ != other.hash_)
return false;
@@ -2698,7 +2934,7 @@ bool RTLIL::SigSpec::is_wire() const
cover("kernel.rtlil.sigspec.is_wire");
pack();
- return SIZE(chunks_) == 1 && chunks_[0].wire && chunks_[0].wire->width == width_;
+ return GetSize(chunks_) == 1 && chunks_[0].wire && chunks_[0].wire->width == width_;
}
bool RTLIL::SigSpec::is_chunk() const
@@ -2706,7 +2942,7 @@ bool RTLIL::SigSpec::is_chunk() const
cover("kernel.rtlil.sigspec.is_chunk");
pack();
- return SIZE(chunks_) == 1;
+ return GetSize(chunks_) == 1;
}
bool RTLIL::SigSpec::is_fully_const() const
@@ -2750,6 +2986,17 @@ bool RTLIL::SigSpec::is_fully_undef() const
return true;
}
+bool RTLIL::SigSpec::has_const() const
+{
+ cover("kernel.rtlil.sigspec.has_const");
+
+ pack();
+ for (auto it = chunks_.begin(); it != chunks_.end(); it++)
+ if (it->width > 0 && it->wire == NULL)
+ return true;
+ return false;
+}
+
bool RTLIL::SigSpec::has_marked_bits() const
{
cover("kernel.rtlil.sigspec.has_marked_bits");
@@ -2769,7 +3016,7 @@ bool RTLIL::SigSpec::as_bool() const
cover("kernel.rtlil.sigspec.as_bool");
pack();
- log_assert(is_fully_const() && SIZE(chunks_) <= 1);
+ log_assert(is_fully_const() && GetSize(chunks_) <= 1);
if (width_)
return RTLIL::Const(chunks_[0].data).as_bool();
return false;
@@ -2780,7 +3027,7 @@ int RTLIL::SigSpec::as_int(bool is_signed) const
cover("kernel.rtlil.sigspec.as_int");
pack();
- log_assert(is_fully_const() && SIZE(chunks_) <= 1);
+ log_assert(is_fully_const() && GetSize(chunks_) <= 1);
if (width_)
return RTLIL::Const(chunks_[0].data).as_int(is_signed);
return 0;
@@ -2808,7 +3055,7 @@ RTLIL::Const RTLIL::SigSpec::as_const() const
cover("kernel.rtlil.sigspec.as_const");
pack();
- log_assert(is_fully_const() && SIZE(chunks_) <= 1);
+ log_assert(is_fully_const() && GetSize(chunks_) <= 1);
if (width_)
return chunks_[0].data;
return RTLIL::Const();
@@ -2867,6 +3114,18 @@ std::set<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_set() const
return sigbits;
}
+pool<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_pool() const
+{
+ cover("kernel.rtlil.sigspec.to_sigbit_pool");
+
+ pack();
+ pool<RTLIL::SigBit> sigbits;
+ for (auto &c : chunks_)
+ for (int i = 0; i < c.width; i++)
+ sigbits.insert(RTLIL::SigBit(c, i));
+ return sigbits;
+}
+
std::vector<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_vector() const
{
cover("kernel.rtlil.sigspec.to_sigbit_vector");
@@ -2891,6 +3150,22 @@ std::map<RTLIL::SigBit, RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_map(const RTLIL
return new_map;
}
+dict<RTLIL::SigBit, RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_dict(const RTLIL::SigSpec &other) const
+{
+ cover("kernel.rtlil.sigspec.to_sigbit_dict");
+
+ unpack();
+ other.unpack();
+
+ log_assert(width_ == other.width_);
+
+ dict<RTLIL::SigBit, RTLIL::SigBit> new_map;
+ for (int i = 0; i < width_; i++)
+ new_map[bits_[i]] = other.bits_[i];
+
+ return new_map;
+}
+
RTLIL::SigBit RTLIL::SigSpec::to_single_sigbit() const
{
cover("kernel.rtlil.sigspec.to_single_sigbit");
@@ -2934,7 +3209,7 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
if (netname.size() == 0)
continue;
- if ('0' <= netname[0] && netname[0] <= '9') {
+ if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') {
cover("kernel.rtlil.sigspec.parse.const");
AST::get_line_num = sigspec_parse_get_dummy_line_num;
AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname);
@@ -2979,7 +3254,10 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
sigspec_parse_split(index_tokens, indices.substr(1, indices.size()-2), ':');
if (index_tokens.size() == 1) {
cover("kernel.rtlil.sigspec.parse.bit_sel");
- sig.append(RTLIL::SigSpec(wire, atoi(index_tokens.at(0).c_str())));
+ int a = atoi(index_tokens.at(0).c_str());
+ if (a < 0 || a >= wire->width)
+ return false;
+ sig.append(RTLIL::SigSpec(wire, a));
} else {
cover("kernel.rtlil.sigspec.parse.part_sel");
int a = atoi(index_tokens.at(0).c_str());
@@ -2988,6 +3266,10 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri
int tmp = a;
a = b, b = tmp;
}
+ if (a < 0 || a >= wire->width)
+ return false;
+ if (b < 0 || b >= wire->width)
+ return false;
sig.append(RTLIL::SigSpec(wire, a, b-a+1));
}
} else
@@ -3033,7 +3315,7 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R
if (lhs.chunks_.size() == 1) {
char *p = (char*)str.c_str(), *endptr;
- long long int val = strtoll(p, &endptr, 10);
+ long int val = strtol(p, &endptr, 10);
if (endptr && endptr != p && *endptr == 0) {
sig = RTLIL::SigSpec(val, lhs.width_);
cover("kernel.rtlil.sigspec.parse.rhs_dec");
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index a0ae8f08..1d0008f9 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -76,18 +76,15 @@ namespace RTLIL
{
// the global id string cache
- struct char_ptr_cmp {
- bool operator()(const char *a, const char *b) const {
- for (int i = 0; a[i] || b[i]; i++)
- if (a[i] != b[i])
- return a[i] < b[i];
- return false;
- }
- };
+ static struct destruct_guard_t {
+ bool ok; // POD, will be initialized to zero
+ destruct_guard_t() { ok = true; }
+ ~destruct_guard_t() { ok = false; }
+ } destruct_guard;
static std::vector<int> global_refcount_storage_;
static std::vector<char*> global_id_storage_;
- static std::map<char*, int, char_ptr_cmp> global_id_index_;
+ static dict<char*, int, hash_cstr_ops> global_id_index_;
static std::vector<int> global_free_idx_list_;
static inline int get_reference(int idx)
@@ -98,6 +95,8 @@ namespace RTLIL
static inline int get_reference(const char *p)
{
+ log_assert(destruct_guard.ok);
+
if (p[0]) {
log_assert(p[1] != 0);
log_assert(p[0] == '$' || p[0] == '\\');
@@ -121,16 +120,38 @@ namespace RTLIL
global_id_storage_.at(idx) = strdup(p);
global_id_index_[global_id_storage_.at(idx)] = idx;
global_refcount_storage_.at(idx)++;
+
+ // Avoid Create->Delete->Create pattern
+ static IdString last_created_id;
+ put_reference(last_created_id.index_);
+ last_created_id.index_ = idx;
+ get_reference(last_created_id.index_);
+
+ if (yosys_xtrace) {
+ log("#X# New IdString '%s' with index %d.\n", p, idx);
+ log_backtrace("-X- ", yosys_xtrace-1);
+ }
+
return idx;
}
static inline void put_reference(int idx)
{
+ // put_reference() may be called from destructors after the destructor of
+ // global_refcount_storage_ has been run. in this case we simply do nothing.
+ if (!destruct_guard.ok)
+ return;
+
log_assert(global_refcount_storage_.at(idx) > 0);
if (--global_refcount_storage_.at(idx) != 0)
return;
+ if (yosys_xtrace) {
+ log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx);
+ log_backtrace("-X- ", yosys_xtrace-1);
+ }
+
global_id_index_.erase(global_id_storage_.at(idx));
free(global_id_storage_.at(idx));
global_id_storage_.at(idx) = nullptr;
@@ -211,12 +232,16 @@ namespace RTLIL
*this = IdString();
}
+ unsigned int hash() const {
+ return index_;
+ }
+
// The following is a helper key_compare class. Instead of for example std::set<Cell*>
// use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the
// set has an influence on the algorithm.
template<typename T> struct compare_ptr_by_name {
- bool operator()(const T *a, const T *b) {
+ bool operator()(const T *a, const T *b) const {
return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name);
}
};
@@ -225,14 +250,14 @@ namespace RTLIL
// of cell types). the following functions helps with that.
template<typename T, typename... Args>
- bool in(T first, Args... rest) {
+ bool in(T first, Args... rest) const {
return in(first) || in(rest...);
}
- bool in(IdString rhs) { return *this == rhs; }
- bool in(const char *rhs) { return *this == rhs; }
- bool in(const std::string &rhs) { return *this == rhs; }
- bool in(const std::set<IdString> &rhs) { return rhs.count(*this) != 0; }
+ bool in(IdString rhs) const { return *this == rhs; }
+ bool in(const char *rhs) const { return *this == rhs; }
+ bool in(const std::string &rhs) const { return *this == rhs; }
+ bool in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }
};
static inline std::string escape_id(std::string str) {
@@ -242,9 +267,15 @@ namespace RTLIL
}
static inline std::string unescape_id(std::string str) {
- if (str.size() > 1 && str[0] == '\\' && str[1] != '$')
- return str.substr(1);
- return str;
+ if (str.size() < 2)
+ return str;
+ if (str[0] != '\\')
+ return str;
+ if (str[1] == '$' || str[1] == '\\')
+ return str;
+ if (str[1] >= '0' && str[1] <= '9')
+ return str;
+ return str.substr(1);
}
static inline std::string unescape_id(RTLIL::IdString str) {
@@ -323,8 +354,8 @@ namespace RTLIL
template<typename T>
struct ObjIterator
{
- typename std::map<RTLIL::IdString, T>::iterator it;
- std::map<RTLIL::IdString, T> *list_p;
+ typename dict<RTLIL::IdString, T>::iterator it;
+ dict<RTLIL::IdString, T> *list_p;
int *refcount_p;
ObjIterator() : list_p(nullptr), refcount_p(nullptr) {
@@ -388,7 +419,7 @@ namespace RTLIL
template<typename T>
struct ObjRange
{
- std::map<RTLIL::IdString, T> *list_p;
+ dict<RTLIL::IdString, T> *list_p;
int *refcount_p;
ObjRange(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { }
@@ -399,8 +430,8 @@ namespace RTLIL
return list_p->size();
}
- operator std::set<T>() const {
- std::set<T> result;
+ operator pool<T>() const {
+ pool<T> result;
for (auto &it : *list_p)
result.insert(it.second);
return result;
@@ -414,7 +445,7 @@ namespace RTLIL
return result;
}
- std::set<T> to_set() const { return *this; }
+ pool<T> to_pool() const { return *this; }
std::vector<T> to_vector() const { return *this; }
};
};
@@ -438,17 +469,249 @@ struct RTLIL::Const
bool as_bool() const;
int as_int(bool is_signed = false) const;
std::string as_string() const;
+ static Const from_string(std::string str);
std::string decode_string() const;
inline int size() const { return bits.size(); }
+
+ inline unsigned int hash() const {
+ unsigned int h = mkhash_init;
+ for (auto b : bits)
+ mkhash(h, b);
+ return h;
+ }
+};
+
+struct RTLIL::SigChunk
+{
+ RTLIL::Wire *wire;
+ std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0
+ int width, offset;
+
+ SigChunk();
+ SigChunk(const RTLIL::Const &value);
+ SigChunk(RTLIL::Wire *wire);
+ SigChunk(RTLIL::Wire *wire, int offset, int width = 1);
+ SigChunk(const std::string &str);
+ SigChunk(int val, int width = 32);
+ SigChunk(RTLIL::State bit, int width = 1);
+ SigChunk(RTLIL::SigBit bit);
+
+ RTLIL::SigChunk extract(int offset, int length) const;
+
+ bool operator <(const RTLIL::SigChunk &other) const;
+ bool operator ==(const RTLIL::SigChunk &other) const;
+ bool operator !=(const RTLIL::SigChunk &other) const;
+};
+
+struct RTLIL::SigBit
+{
+ RTLIL::Wire *wire;
+ union {
+ RTLIL::State data; // used if wire == NULL
+ int offset; // used if wire != NULL
+ };
+
+ SigBit();
+ SigBit(RTLIL::State bit);
+ SigBit(bool bit);
+ SigBit(RTLIL::Wire *wire);
+ SigBit(RTLIL::Wire *wire, int offset);
+ SigBit(const RTLIL::SigChunk &chunk);
+ SigBit(const RTLIL::SigChunk &chunk, int index);
+ SigBit(const RTLIL::SigSpec &sig);
+
+ bool operator <(const RTLIL::SigBit &other) const;
+ bool operator ==(const RTLIL::SigBit &other) const;
+ bool operator !=(const RTLIL::SigBit &other) const;
+ unsigned int hash() const;
+};
+
+struct RTLIL::SigSpecIterator : public std::iterator<std::input_iterator_tag, RTLIL::SigSpec>
+{
+ RTLIL::SigSpec *sig_p;
+ int index;
+
+ inline RTLIL::SigBit &operator*() const;
+ inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; }
+ inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }
+ inline void operator++() { index++; }
+};
+
+struct RTLIL::SigSpecConstIterator : public std::iterator<std::input_iterator_tag, RTLIL::SigSpec>
+{
+ const RTLIL::SigSpec *sig_p;
+ int index;
+
+ inline const RTLIL::SigBit &operator*() const;
+ inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
+ inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }
+ inline void operator++() { index++; }
+};
+
+struct RTLIL::SigSpec
+{
+private:
+ int width_;
+ unsigned long hash_;
+ std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
+ std::vector<RTLIL::SigBit> bits_; // LSB at index 0
+
+ void pack() const;
+ void unpack() const;
+ void updhash() const;
+
+ inline bool packed() const {
+ return bits_.empty();
+ }
+
+ inline void inline_unpack() const {
+ if (!chunks_.empty())
+ unpack();
+ }
+
+public:
+ SigSpec();
+ SigSpec(const RTLIL::SigSpec &other);
+ SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
+ const RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other);
+
+ SigSpec(const RTLIL::Const &value);
+ SigSpec(const RTLIL::SigChunk &chunk);
+ SigSpec(RTLIL::Wire *wire);
+ SigSpec(RTLIL::Wire *wire, int offset, int width = 1);
+ SigSpec(const std::string &str);
+ SigSpec(int val, int width = 32);
+ SigSpec(RTLIL::State bit, int width = 1);
+ SigSpec(RTLIL::SigBit bit, int width = 1);
+ SigSpec(std::vector<RTLIL::SigChunk> chunks);
+ SigSpec(std::vector<RTLIL::SigBit> bits);
+ SigSpec(pool<RTLIL::SigBit> bits);
+ SigSpec(std::set<RTLIL::SigBit> bits);
+ SigSpec(bool bit);
+
+ SigSpec(RTLIL::SigSpec &&other) {
+ width_ = other.width_;
+ hash_ = other.hash_;
+ chunks_ = std::move(other.chunks_);
+ bits_ = std::move(other.bits_);
+ }
+
+ const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) {
+ width_ = other.width_;
+ hash_ = other.hash_;
+ chunks_ = std::move(other.chunks_);
+ bits_ = std::move(other.bits_);
+ return *this;
+ }
+
+ size_t get_hash() const {
+ if (!hash_) hash();
+ return hash_;
+ }
+
+ inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
+ inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
+
+ inline int size() const { return width_; }
+ inline bool empty() const { return width_ == 0; }
+
+ inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
+ inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }
+
+ inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }
+ inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }
+
+ inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }
+ inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
+
+ void sort();
+ void sort_and_unify();
+
+ void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
+ void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
+
+ void replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules);
+ void replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
+
+ void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules);
+ void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
+
+ void replace(int offset, const RTLIL::SigSpec &with);
+
+ void remove(const RTLIL::SigSpec &pattern);
+ void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;
+ void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);
+
+ void remove(const pool<RTLIL::SigBit> &pattern);
+ void remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;
+ void remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
+
+ void remove(int offset, int length = 1);
+ void remove_const();
+
+ RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
+ RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
+ RTLIL::SigSpec extract(int offset, int length = 1) const;
+
+ void append(const RTLIL::SigSpec &signal);
+ void append_bit(const RTLIL::SigBit &bit);
+
+ void extend_u0(int width, bool is_signed = false);
+
+ RTLIL::SigSpec repeat(int num) const;
+
+ bool operator <(const RTLIL::SigSpec &other) const;
+ bool operator ==(const RTLIL::SigSpec &other) const;
+ inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }
+
+ bool is_wire() const;
+ bool is_chunk() const;
+
+ bool is_fully_const() const;
+ bool is_fully_def() const;
+ bool is_fully_undef() const;
+ bool has_const() const;
+ bool has_marked_bits() const;
+
+ bool as_bool() const;
+ int as_int(bool is_signed = false) const;
+ std::string as_string() const;
+ RTLIL::Const as_const() const;
+ RTLIL::Wire *as_wire() const;
+ RTLIL::SigChunk as_chunk() const;
+
+ bool match(std::string pattern) const;
+
+ std::set<RTLIL::SigBit> to_sigbit_set() const;
+ pool<RTLIL::SigBit> to_sigbit_pool() const;
+ std::vector<RTLIL::SigBit> to_sigbit_vector() const;
+ std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;
+ dict<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_dict(const RTLIL::SigSpec &other) const;
+ RTLIL::SigBit to_single_sigbit() const;
+
+ static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
+ static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
+ static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
+
+ operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
+ operator std::vector<RTLIL::SigBit>() const { return bits(); }
+
+ unsigned int hash() const { if (!hash_) updhash(); return hash_; };
+
+#ifndef NDEBUG
+ void check() const;
+#else
+ void check() const { }
+#endif
};
struct RTLIL::Selection
{
bool full_selection;
- std::set<RTLIL::IdString> selected_modules;
- std::map<RTLIL::IdString, std::set<RTLIL::IdString>> selected_members;
+ pool<RTLIL::IdString> selected_modules;
+ dict<RTLIL::IdString, pool<RTLIL::IdString>> selected_members;
Selection(bool full = true) : full_selection(full) { }
@@ -476,6 +739,15 @@ struct RTLIL::Selection
struct RTLIL::Monitor
{
+ unsigned int hashidx_;
+ unsigned int hash() const { return hashidx_; }
+
+ Monitor() {
+ static unsigned int hashidx_count = 123456789;
+ hashidx_count = mkhash_xorshift(hashidx_count);
+ hashidx_ = hashidx_count;
+ }
+
virtual ~Monitor() { }
virtual void notify_module_add(RTLIL::Module*) { }
virtual void notify_module_del(RTLIL::Module*) { }
@@ -487,14 +759,17 @@ struct RTLIL::Monitor
struct RTLIL::Design
{
- std::set<RTLIL::Monitor*> monitors;
- std::map<std::string, std::string> scratchpad;
+ unsigned int hashidx_;
+ unsigned int hash() const { return hashidx_; }
+
+ pool<RTLIL::Monitor*> monitors;
+ dict<std::string, std::string> scratchpad;
int refcount_modules_;
- std::map<RTLIL::IdString, RTLIL::Module*> modules_;
+ dict<RTLIL::IdString, RTLIL::Module*> modules_;
std::vector<RTLIL::Selection> selection_stack;
- std::map<RTLIL::IdString, RTLIL::Selection> selection_vars;
+ dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
std::string selected_active_module;
Design();
@@ -521,6 +796,7 @@ struct RTLIL::Design
bool scratchpad_get_bool(std::string varname, bool default_value = false) const;
std::string scratchpad_get_string(std::string varname, std::string default_value = std::string()) const;
+ void sort();
void check();
void optimize();
@@ -531,6 +807,14 @@ struct RTLIL::Design
bool selected_module(RTLIL::Module *mod) const;
bool selected_whole_module(RTLIL::Module *mod) const;
+ RTLIL::Selection &selection() {
+ return selection_stack.back();
+ }
+
+ const RTLIL::Selection &selection() const {
+ return selection_stack.back();
+ }
+
bool full_selection() const {
return selection_stack.back().full_selection;
}
@@ -556,7 +840,7 @@ struct RTLIL::Design
};
#define RTLIL_ATTRIBUTE_MEMBERS \
- std::map<RTLIL::IdString, RTLIL::Const> attributes; \
+ dict<RTLIL::IdString, RTLIL::Const> attributes; \
void set_bool_attribute(RTLIL::IdString id) { \
attributes[id] = RTLIL::Const(1); \
} \
@@ -568,31 +852,36 @@ struct RTLIL::Design
struct RTLIL::Module
{
+ unsigned int hashidx_;
+ unsigned int hash() const { return hashidx_; }
+
protected:
void add(RTLIL::Wire *wire);
void add(RTLIL::Cell *cell);
public:
RTLIL::Design *design;
- std::set<RTLIL::Monitor*> monitors;
+ pool<RTLIL::Monitor*> monitors;
int refcount_wires_;
int refcount_cells_;
- std::map<RTLIL::IdString, RTLIL::Wire*> wires_;
- std::map<RTLIL::IdString, RTLIL::Cell*> cells_;
+ dict<RTLIL::IdString, RTLIL::Wire*> wires_;
+ dict<RTLIL::IdString, RTLIL::Cell*> cells_;
std::vector<RTLIL::SigSig> connections_;
RTLIL::IdString name;
- std::set<RTLIL::IdString> avail_parameters;
- std::map<RTLIL::IdString, RTLIL::Memory*> memories;
- std::map<RTLIL::IdString, RTLIL::Process*> processes;
+ pool<RTLIL::IdString> avail_parameters;
+ dict<RTLIL::IdString, RTLIL::Memory*> memories;
+ dict<RTLIL::IdString, RTLIL::Process*> processes;
RTLIL_ATTRIBUTE_MEMBERS
Module();
virtual ~Module();
- virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
+ virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
virtual size_t count_id(RTLIL::IdString id);
+
+ virtual void sort();
virtual void check();
virtual void optimize();
@@ -628,7 +917,7 @@ public:
RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }
// Removing wires is expensive. If you have to remove wires, remove them all at once.
- void remove(const std::set<RTLIL::Wire*> &wires);
+ void remove(const pool<RTLIL::Wire*> &wires);
void remove(RTLIL::Cell *cell);
void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
@@ -698,9 +987,11 @@ public:
RTLIL::Cell* addConcat (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_i, RTLIL::SigSpec sig_o, RTLIL::Const lut);
RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
+ RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true);
RTLIL::Cell* addDff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true);
+ RTLIL::Cell* addDffe (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_polarity = true);
RTLIL::Cell* addDffsr (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true);
RTLIL::Cell* addAdff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
@@ -723,6 +1014,7 @@ public:
RTLIL::Cell* addOai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y);
RTLIL::Cell* addDffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true);
+ RTLIL::Cell* addDffeGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_polarity = true);
RTLIL::Cell* addDffsrGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true);
RTLIL::Cell* addAdffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
@@ -795,6 +1087,9 @@ public:
struct RTLIL::Wire
{
+ unsigned int hashidx_;
+ unsigned int hash() const { return hashidx_; }
+
protected:
// use module->addWire() and module->remove() to create or destroy wires
friend struct RTLIL::Module;
@@ -815,6 +1110,9 @@ public:
struct RTLIL::Memory
{
+ unsigned int hashidx_;
+ unsigned int hash() const { return hashidx_; }
+
Memory();
RTLIL::IdString name;
@@ -824,6 +1122,9 @@ struct RTLIL::Memory
struct RTLIL::Cell
{
+ unsigned int hashidx_;
+ unsigned int hash() const { return hashidx_; }
+
protected:
// use module->addCell() and module->remove() to create or destroy cells
friend struct RTLIL::Module;
@@ -837,8 +1138,8 @@ public:
RTLIL::Module *module;
RTLIL::IdString name;
RTLIL::IdString type;
- std::map<RTLIL::IdString, RTLIL::SigSpec> connections_;
- std::map<RTLIL::IdString, RTLIL::Const> parameters;
+ dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
+ dict<RTLIL::IdString, RTLIL::Const> parameters;
RTLIL_ATTRIBUTE_MEMBERS
// access cell ports
@@ -846,7 +1147,12 @@ public:
void unsetPort(RTLIL::IdString portname);
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal);
const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const;
- const std::map<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
+ const dict<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
+
+ // information about cell ports
+ bool known() const;
+ bool input(RTLIL::IdString portname) const;
+ bool output(RTLIL::IdString portname) const;
// access cell parameters
bool hasParam(RTLIL::IdString paramname) const;
@@ -854,242 +1160,18 @@ public:
void setParam(RTLIL::IdString paramname, RTLIL::Const value);
const RTLIL::Const &getParam(RTLIL::IdString paramname) const;
+ void sort();
void check();
void fixup_parameters(bool set_a_signed = false, bool set_b_signed = false);
- template<typename T> void rewrite_sigspecs(T functor);
-};
-
-struct RTLIL::SigChunk
-{
- RTLIL::Wire *wire;
- std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0
- int width, offset;
-
- SigChunk();
- SigChunk(const RTLIL::Const &value);
- SigChunk(RTLIL::Wire *wire);
- SigChunk(RTLIL::Wire *wire, int offset, int width = 1);
- SigChunk(const std::string &str);
- SigChunk(int val, int width = 32);
- SigChunk(RTLIL::State bit, int width = 1);
- SigChunk(RTLIL::SigBit bit);
-
- RTLIL::SigChunk extract(int offset, int length) const;
-
- bool operator <(const RTLIL::SigChunk &other) const;
- bool operator ==(const RTLIL::SigChunk &other) const;
- bool operator !=(const RTLIL::SigChunk &other) const;
-};
-
-struct RTLIL::SigBit
-{
- RTLIL::Wire *wire;
- union {
- RTLIL::State data; // used if wire == NULL
- int offset; // used if wire != NULL
- };
-
- SigBit() : wire(NULL), data(RTLIL::State::S0) { }
- SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }
- SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }
- SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire); }
- SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
- SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
- SigBit(const RTLIL::SigSpec &sig);
-
- bool operator <(const RTLIL::SigBit &other) const {
- if (wire == other.wire)
- return wire ? (offset < other.offset) : (data < other.data);
- if (wire != nullptr && other.wire != nullptr)
- return wire->name < other.wire->name;
- return wire < other.wire;
- }
-
- bool operator ==(const RTLIL::SigBit &other) const {
- return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data));
- }
-
- bool operator !=(const RTLIL::SigBit &other) const {
- return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
+ bool has_keep_attr() const {
+ return get_bool_attribute("\\keep") || (module && module->design && module->design->module(type) &&
+ module->design->module(type)->get_bool_attribute("\\keep"));
}
-};
-
-struct RTLIL::SigSpecIterator
-{
- RTLIL::SigSpec *sig_p;
- int index;
-
- inline RTLIL::SigBit &operator*() const;
- inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; }
- inline void operator++() { index++; }
-};
-
-struct RTLIL::SigSpecConstIterator
-{
- const RTLIL::SigSpec *sig_p;
- int index;
- inline const RTLIL::SigBit &operator*() const;
- inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
- inline void operator++() { index++; }
-};
-
-struct RTLIL::SigSpec
-{
-private:
- int width_;
- unsigned long hash_;
- std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
- std::vector<RTLIL::SigBit> bits_; // LSB at index 0
-
- void pack() const;
- void unpack() const;
- void hash() const;
-
- inline bool packed() const {
- return bits_.empty();
- }
-
- inline void inline_unpack() const {
- if (!chunks_.empty())
- unpack();
- }
-
-public:
- SigSpec();
- SigSpec(const RTLIL::SigSpec &other);
- SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
- const RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other);
-
- SigSpec(const RTLIL::Const &value);
- SigSpec(const RTLIL::SigChunk &chunk);
- SigSpec(RTLIL::Wire *wire);
- SigSpec(RTLIL::Wire *wire, int offset, int width = 1);
- SigSpec(const std::string &str);
- SigSpec(int val, int width = 32);
- SigSpec(RTLIL::State bit, int width = 1);
- SigSpec(RTLIL::SigBit bit, int width = 1);
- SigSpec(std::vector<RTLIL::SigChunk> chunks);
- SigSpec(std::vector<RTLIL::SigBit> bits);
- SigSpec(std::set<RTLIL::SigBit> bits);
-
- SigSpec(RTLIL::SigSpec &&other) {
- width_ = other.width_;
- hash_ = other.hash_;
- chunks_ = std::move(other.chunks_);
- bits_ = std::move(other.bits_);
- }
-
- const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) {
- width_ = other.width_;
- hash_ = other.hash_;
- chunks_ = std::move(other.chunks_);
- bits_ = std::move(other.bits_);
- return *this;
- }
-
- inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
- inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
-
- inline int size() const { return width_; }
-
- inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
- inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }
-
- inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }
- inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }
-
- inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }
- inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
-
- void sort();
- void sort_and_unify();
-
- void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
- void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
-
- void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules);
- void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
-
- void replace(int offset, const RTLIL::SigSpec &with);
-
- void remove(const RTLIL::SigSpec &pattern);
- void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;
- void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);
-
- void remove(const std::set<RTLIL::SigBit> &pattern);
- void remove(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;
- void remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
-
- void remove(int offset, int length = 1);
- void remove_const();
-
- RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
- RTLIL::SigSpec extract(const std::set<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
- RTLIL::SigSpec extract(int offset, int length = 1) const;
-
- void append(const RTLIL::SigSpec &signal);
- void append_bit(const RTLIL::SigBit &bit);
-
- void extend(int width, bool is_signed = false);
- void extend_u0(int width, bool is_signed = false);
-
- RTLIL::SigSpec repeat(int num) const;
-
- bool operator <(const RTLIL::SigSpec &other) const;
- bool operator ==(const RTLIL::SigSpec &other) const;
- inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }
-
- bool is_wire() const;
- bool is_chunk() const;
-
- bool is_fully_const() const;
- bool is_fully_def() const;
- bool is_fully_undef() const;
- bool has_marked_bits() const;
-
- bool as_bool() const;
- int as_int(bool is_signed = false) const;
- std::string as_string() const;
- RTLIL::Const as_const() const;
- RTLIL::Wire *as_wire() const;
- RTLIL::SigChunk as_chunk() const;
-
- bool match(std::string pattern) const;
-
- std::set<RTLIL::SigBit> to_sigbit_set() const;
- std::vector<RTLIL::SigBit> to_sigbit_vector() const;
- std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;
- RTLIL::SigBit to_single_sigbit() const;
-
- static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
- static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
- static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
-
- operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
- operator std::vector<RTLIL::SigBit>() const { return bits(); }
-
-#ifndef NDEBUG
- void check() const;
-#else
- inline void check() const { }
-#endif
+ template<typename T> void rewrite_sigspecs(T functor);
};
-inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
- return (*sig_p)[index];
-}
-
-inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
- return (*sig_p)[index];
-}
-
-inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
- log_assert(sig.size() == 1 && sig.chunks().size() == 1);
- *this = SigBit(sig.chunks().front());
-}
-
struct RTLIL::CaseRule
{
std::vector<RTLIL::SigSpec> compare;
@@ -1138,6 +1220,50 @@ struct RTLIL::Process
RTLIL::Process *clone() const;
};
+
+inline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { }
+inline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }
+inline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? RTLIL::S1 : RTLIL::S0) { }
+inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }
+inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); }
+inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
+inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
+
+inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
+ if (wire == other.wire)
+ return wire ? (offset < other.offset) : (data < other.data);
+ if (wire != nullptr && other.wire != nullptr)
+ return wire->name < other.wire->name;
+ return wire < other.wire;
+}
+
+inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
+ return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data));
+}
+
+inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const {
+ return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
+}
+
+inline unsigned int RTLIL::SigBit::hash() const {
+ if (wire)
+ return mkhash_add(wire->name.hash(), offset);
+ return data;
+}
+
+inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
+ return (*sig_p)[index];
+}
+
+inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
+ return (*sig_p)[index];
+}
+
+inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
+ log_assert(sig.size() == 1 && sig.chunks().size() == 1);
+ *this = SigBit(sig.chunks().front());
+}
+
template<typename T>
void RTLIL::Module::rewrite_sigspecs(T functor)
{
diff --git a/kernel/satgen.h b/kernel/satgen.h
index 692c6e7f..719b0a83 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -26,7 +26,40 @@
#include "kernel/macc.h"
#include "libs/ezsat/ezminisat.h"
-typedef ezMiniSAT ezDefaultSAT;
+
+YOSYS_NAMESPACE_BEGIN
+
+// defined in kernel/register.cc
+extern struct SatSolver *yosys_satsolver_list;
+extern struct SatSolver *yosys_satsolver;
+
+struct SatSolver
+{
+ string name;
+ SatSolver *next;
+ virtual ezSAT *create() = 0;
+
+ SatSolver(string name) : name(name) {
+ next = yosys_satsolver_list;
+ yosys_satsolver_list = this;
+ }
+
+ virtual ~SatSolver() {
+ auto p = &yosys_satsolver_list;
+ while (*p) {
+ if (*p == this)
+ *p = next;
+ else
+ p = &(*p)->next;
+ }
+ if (yosys_satsolver == this)
+ yosys_satsolver = yosys_satsolver_list;
+ }
+};
+
+struct ezSatPtr : public std::unique_ptr<ezSAT> {
+ ezSatPtr() : unique_ptr<ezSAT>(yosys_satsolver->create()) { }
+};
struct SatGen
{
@@ -35,6 +68,8 @@ struct SatGen
std::string prefix;
SigPool initial_state;
std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en;
+ std::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en;
+ std::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals;
bool ignore_div_by_zero;
bool model_undef;
@@ -49,23 +84,24 @@ struct SatGen
this->prefix = prefix;
}
- std::vector<int> importSigSpecWorker(RTLIL::SigSpec &sig, std::string &pf, bool undef_mode, bool dup_undef)
+ std::vector<int> importSigSpecWorker(RTLIL::SigSpec sig, std::string &pf, bool undef_mode, bool dup_undef)
{
log_assert(!undef_mode || model_undef);
sigmap->apply(sig);
std::vector<int> vec;
- vec.reserve(SIZE(sig));
+ vec.reserve(GetSize(sig));
for (auto &bit : sig)
if (bit.wire == NULL) {
if (model_undef && dup_undef && bit == RTLIL::State::Sx)
vec.push_back(ez->frozen_literal());
else
- vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->TRUE : ez->FALSE);
+ vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->CONST_TRUE : ez->CONST_FALSE);
} else {
- std::string name = pf + stringf(bit.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(bit.wire->name), bit.offset);
+ std::string name = pf + (bit.wire->width == 1 ? stringf("%s", log_id(bit.wire)) : stringf("%s [%d]", log_id(bit.wire->name), bit.offset));
vec.push_back(ez->frozen_literal(name));
+ imported_signals[pf][bit] = vec.back();
}
return vec;
}
@@ -91,6 +127,34 @@ struct SatGen
return importSigSpecWorker(sig, pf, true, false);
}
+ int importSigBit(RTLIL::SigBit bit, int timestep = -1)
+ {
+ log_assert(timestep != 0);
+ std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
+ return importSigSpecWorker(bit, pf, false, false).front();
+ }
+
+ int importDefSigBit(RTLIL::SigBit bit, int timestep = -1)
+ {
+ log_assert(timestep != 0);
+ std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
+ return importSigSpecWorker(bit, pf, false, true).front();
+ }
+
+ int importUndefSigBit(RTLIL::SigBit bit, int timestep = -1)
+ {
+ log_assert(timestep != 0);
+ std::string pf = "undef:" + prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
+ return importSigSpecWorker(bit, pf, true, false).front();
+ }
+
+ bool importedSigBit(RTLIL::SigBit bit, int timestep = -1)
+ {
+ log_assert(timestep != 0);
+ std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
+ return imported_signals[pf].count(bit) != 0;
+ }
+
void getAsserts(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
@@ -98,6 +162,13 @@ struct SatGen
sig_en = asserts_en[pf];
}
+ void getAssumes(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)
+ {
+ std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
+ sig_a = assumes_a[pf];
+ sig_en = assumes_en[pf];
+ }
+
int importAsserts(int timestep = -1)
{
std::vector<int> check_bits, enable_bits;
@@ -112,6 +183,20 @@ struct SatGen
return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));
}
+ int importAssumes(int timestep = -1)
+ {
+ std::vector<int> check_bits, enable_bits;
+ std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
+ if (model_undef) {
+ check_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_a[pf], timestep)), importDefSigSpec(assumes_a[pf], timestep));
+ enable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_en[pf], timestep)), importDefSigSpec(assumes_en[pf], timestep));
+ } else {
+ check_bits = importDefSigSpec(assumes_a[pf], timestep);
+ enable_bits = importDefSigSpec(assumes_en[pf], timestep);
+ }
+ return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));
+ }
+
int signals_eq(RTLIL::SigSpec lhs, RTLIL::SigSpec rhs, int timestep_lhs = -1, int timestep_rhs = -1)
{
if (timestep_rhs < 0)
@@ -141,9 +226,9 @@ struct SatGen
if (!forced_signed && cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters.count("\\B_SIGNED") > 0)
is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool();
while (vec_a.size() < vec_b.size() || vec_a.size() < y_width)
- vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->FALSE);
+ vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);
while (vec_b.size() < vec_a.size() || vec_b.size() < y_width)
- vec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->FALSE);
+ vec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->CONST_FALSE);
}
void extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false)
@@ -157,7 +242,7 @@ struct SatGen
{
bool is_signed = forced_signed || (cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool());
while (vec_a.size() < vec_y.size())
- vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->FALSE);
+ vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);
while (vec_y.size() < vec_a.size())
vec_y.push_back(ez->literal());
}
@@ -207,7 +292,7 @@ struct SatGen
if (is_arith_compare) {
for (size_t i = 1; i < undef_y.size(); i++)
- ez->SET(ez->FALSE, undef_y.at(i));
+ ez->SET(ez->CONST_FALSE, undef_y.at(i));
ez->SET(undef_y_bit, undef_y.at(0));
} else {
std::vector<int> undef_y_bits(undef_y.size(), undef_y_bit);
@@ -288,7 +373,7 @@ struct SatGen
int a = importDefSigSpec(cell->getPort("\\A"), timestep).at(0);
int b = importDefSigSpec(cell->getPort("\\B"), timestep).at(0);
int c = importDefSigSpec(cell->getPort("\\C"), timestep).at(0);
- int d = three_mode ? (aoi_mode ? ez->TRUE : ez->FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0);
+ int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0);
int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0);
int yy = model_undef ? ez->literal() : y;
@@ -302,7 +387,7 @@ struct SatGen
int undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep).at(0);
int undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep).at(0);
int undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep).at(0);
- int undef_d = three_mode ? ez->FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0);
+ int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0);
int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0);
if (aoi_mode)
@@ -414,14 +499,14 @@ struct SatGen
std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
- int maybe_one_hot = ez->FALSE;
- int maybe_many_hot = ez->FALSE;
+ int maybe_one_hot = ez->CONST_FALSE;
+ int maybe_many_hot = ez->CONST_FALSE;
- int sure_one_hot = ez->FALSE;
- int sure_many_hot = ez->FALSE;
+ int sure_one_hot = ez->CONST_FALSE;
+ int sure_many_hot = ez->CONST_FALSE;
- std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->FALSE);
- std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->FALSE);
+ std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
+ std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
for (size_t i = 0; i < s.size(); i++)
{
@@ -463,7 +548,7 @@ struct SatGen
if (cell->type == "$pos") {
ez->assume(ez->vec_eq(a, yy));
} else {
- std::vector<int> zero(a.size(), ez->FALSE);
+ std::vector<int> zero(a.size(), ez->CONST_FALSE);
ez->assume(ez->vec_eq(ez->vec_sub(zero, a), yy));
}
@@ -505,7 +590,7 @@ struct SatGen
if (cell->type == "$logic_not")
ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0));
for (size_t i = 1; i < y.size(); i++)
- ez->SET(ez->FALSE, yy.at(i));
+ ez->SET(ez->CONST_FALSE, yy.at(i));
if (model_undef)
{
@@ -527,7 +612,7 @@ struct SatGen
log_abort();
for (size_t i = 1; i < undef_y.size(); i++)
- ez->SET(ez->FALSE, undef_y.at(i));
+ ez->SET(ez->CONST_FALSE, undef_y.at(i));
undefGating(y, yy, undef_y);
}
@@ -550,7 +635,7 @@ struct SatGen
else
ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0));
for (size_t i = 1; i < y.size(); i++)
- ez->SET(ez->FALSE, yy.at(i));
+ ez->SET(ez->CONST_FALSE, yy.at(i));
if (model_undef)
{
@@ -573,7 +658,7 @@ struct SatGen
log_abort();
for (size_t i = 1; i < undef_y.size(); i++)
- ez->SET(ez->FALSE, undef_y.at(i));
+ ez->SET(ez->CONST_FALSE, undef_y.at(i));
undefGating(y, yy, undef_y);
}
@@ -611,7 +696,7 @@ struct SatGen
if (cell->type == "$gt")
ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0));
for (size_t i = 1; i < y.size(); i++)
- ez->SET(ez->FALSE, yy.at(i));
+ ez->SET(ez->CONST_FALSE, yy.at(i));
if (model_undef && (cell->type == "$eqx" || cell->type == "$nex"))
{
@@ -626,7 +711,7 @@ struct SatGen
yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b));
for (size_t i = 0; i < y.size(); i++)
- ez->SET(ez->FALSE, undef_y.at(i));
+ ez->SET(ez->CONST_FALSE, undef_y.at(i));
ez->assume(ez->vec_eq(y, yy));
}
@@ -648,7 +733,7 @@ struct SatGen
int undef_y_bit = ez->AND(undef_any, ez->NOT(masked_ne));
for (size_t i = 1; i < undef_y.size(); i++)
- ez->SET(ez->FALSE, undef_y.at(i));
+ ez->SET(ez->CONST_FALSE, undef_y.at(i));
ez->SET(undef_y_bit, undef_y.at(0));
undefGating(y, yy, undef_y);
@@ -670,7 +755,7 @@ struct SatGen
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
- int extend_bit = ez->FALSE;
+ int extend_bit = ez->CONST_FALSE;
if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
extend_bit = a.back();
@@ -684,16 +769,16 @@ struct SatGen
std::vector<int> shifted_a;
if (cell->type == "$shl" || cell->type == "$sshl")
- shifted_a = ez->vec_shift_left(a, b, false, ez->FALSE, ez->FALSE);
+ shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shr")
- shifted_a = ez->vec_shift_right(a, b, false, ez->FALSE, ez->FALSE);
+ shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$sshr")
- shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->FALSE, ez->FALSE);
+ shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shift" || cell->type == "$shiftx")
- shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
+ shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
ez->assume(ez->vec_eq(shifted_a, yy));
@@ -704,7 +789,7 @@ struct SatGen
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> undef_a_shifted;
- extend_bit = cell->type == "$shiftx" ? ez->TRUE : ez->FALSE;
+ extend_bit = cell->type == "$shiftx" ? ez->CONST_TRUE : ez->CONST_FALSE;
if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
extend_bit = undef_a.back();
@@ -714,19 +799,19 @@ struct SatGen
undef_a.push_back(extend_bit);
if (cell->type == "$shl" || cell->type == "$sshl")
- undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->FALSE, ez->FALSE);
+ undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shr")
- undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->FALSE, ez->FALSE);
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$sshr")
- undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->FALSE, ez->FALSE);
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shift")
- undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shiftx")
- undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->TRUE, ez->TRUE);
+ undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE);
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
std::vector<int> undef_all_y_bits(undef_y.size(), undef_any_b);
@@ -745,10 +830,10 @@ struct SatGen
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
- std::vector<int> tmp(a.size(), ez->FALSE);
+ std::vector<int> tmp(a.size(), ez->CONST_FALSE);
for (int i = 0; i < int(a.size()); i++)
{
- std::vector<int> shifted_a(a.size(), ez->FALSE);
+ std::vector<int> shifted_a(a.size(), ez->CONST_FALSE);
for (int j = i; j < int(a.size()); j++)
shifted_a.at(j) = a.at(j-i);
tmp = ez->vec_ite(b.at(i), ez->vec_add(tmp, shifted_a), tmp);
@@ -772,25 +857,25 @@ struct SatGen
Macc macc;
macc.from_cell(cell);
- std::vector<int> tmp(SIZE(y), ez->FALSE);
+ std::vector<int> tmp(GetSize(y), ez->CONST_FALSE);
for (auto &port : macc.ports)
{
std::vector<int> in_a = importDefSigSpec(port.in_a, timestep);
std::vector<int> in_b = importDefSigSpec(port.in_b, timestep);
- while (SIZE(in_a) < SIZE(y))
- in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->FALSE);
- in_a.resize(SIZE(y));
+ while (GetSize(in_a) < GetSize(y))
+ in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->CONST_FALSE);
+ in_a.resize(GetSize(y));
- if (SIZE(in_b))
+ if (GetSize(in_b))
{
- while (SIZE(in_b) < SIZE(y))
- in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->FALSE);
- in_b.resize(SIZE(y));
+ while (GetSize(in_b) < GetSize(y))
+ in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->CONST_FALSE);
+ in_b.resize(GetSize(y));
- for (int i = 0; i < SIZE(in_b); i++) {
- std::vector<int> shifted_a(in_a.size(), ez->FALSE);
+ for (int i = 0; i < GetSize(in_b); i++) {
+ std::vector<int> shifted_a(in_a.size(), ez->CONST_FALSE);
for (int j = i; j < int(in_a.size()); j++)
shifted_a.at(j) = in_a.at(j-i);
if (port.do_subtract)
@@ -808,8 +893,8 @@ struct SatGen
}
}
- for (int i = 0; i < SIZE(b); i++) {
- std::vector<int> val(SIZE(y), ez->FALSE);
+ for (int i = 0; i < GetSize(b); i++) {
+ std::vector<int> val(GetSize(y), ez->CONST_FALSE);
val.at(0) = b.at(i);
tmp = ez->vec_add(tmp, val);
}
@@ -823,7 +908,7 @@ struct SatGen
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
- ez->assume(ez->vec_eq(undef_y, std::vector<int>(SIZE(y), ez->OR(undef_any_a, undef_any_b))));
+ ez->assume(ez->vec_eq(undef_y, std::vector<int>(GetSize(y), ez->OR(undef_any_a, undef_any_b))));
undefGating(y, tmp, undef_y);
}
@@ -852,14 +937,14 @@ struct SatGen
}
std::vector<int> chain_buf = a_u;
- std::vector<int> y_u(a_u.size(), ez->FALSE);
+ std::vector<int> y_u(a_u.size(), ez->CONST_FALSE);
for (int i = int(a.size())-1; i >= 0; i--)
{
- chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->FALSE);
+ chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->CONST_FALSE);
- std::vector<int> b_shl(i, ez->FALSE);
+ std::vector<int> b_shl(i, ez->CONST_FALSE);
b_shl.insert(b_shl.end(), b_u.begin(), b_u.end());
- b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->FALSE);
+ b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->CONST_FALSE);
y_u.at(i) = ez->vec_ge_unsigned(chain_buf, b_shl);
chain_buf = ez->vec_ite(y_u.at(i), ez->vec_sub(chain_buf, b_shl), chain_buf);
@@ -886,13 +971,13 @@ struct SatGen
std::vector<int> div_zero_result;
if (cell->type == "$div") {
if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) {
- std::vector<int> all_ones(y.size(), ez->TRUE);
- std::vector<int> only_first_one(y.size(), ez->FALSE);
- only_first_one.at(0) = ez->TRUE;
+ std::vector<int> all_ones(y.size(), ez->CONST_TRUE);
+ std::vector<int> only_first_one(y.size(), ez->CONST_FALSE);
+ only_first_one.at(0) = ez->CONST_TRUE;
div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones);
} else {
- div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->TRUE);
- div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE);
+ div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->CONST_TRUE);
+ div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
}
} else {
int copy_a_bits = std::min(cell->getPort("\\A").size(), cell->getPort("\\B").size());
@@ -900,7 +985,7 @@ struct SatGen
if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool())
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back());
else
- div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE);
+ div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
}
ez->assume(ez->vec_eq(yy, ez->vec_ite(ez->expression(ezSAT::OpOr, b), y_tmp, div_zero_result)));
}
@@ -920,44 +1005,44 @@ struct SatGen
std::vector<int> lut;
for (auto bit : cell->getParam("\\LUT").bits)
- lut.push_back(bit == RTLIL::S1 ? ez->TRUE : ez->FALSE);
- while (SIZE(lut) < (1 << SIZE(a)))
- lut.push_back(ez->FALSE);
- lut.resize(1 << SIZE(a));
+ lut.push_back(bit == RTLIL::S1 ? ez->CONST_TRUE : ez->CONST_FALSE);
+ while (GetSize(lut) < (1 << GetSize(a)))
+ lut.push_back(ez->CONST_FALSE);
+ lut.resize(1 << GetSize(a));
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
- std::vector<int> t(lut), u(SIZE(t), ez->FALSE);
+ std::vector<int> t(lut), u(GetSize(t), ez->CONST_FALSE);
- for (int i = SIZE(a)-1; i >= 0; i--)
+ for (int i = GetSize(a)-1; i >= 0; i--)
{
- std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2);
- std::vector<int> t1(t.begin() + SIZE(t)/2, t.end());
+ std::vector<int> t0(t.begin(), t.begin() + GetSize(t)/2);
+ std::vector<int> t1(t.begin() + GetSize(t)/2, t.end());
- std::vector<int> u0(u.begin(), u.begin() + SIZE(u)/2);
- std::vector<int> u1(u.begin() + SIZE(u)/2, u.end());
+ std::vector<int> u0(u.begin(), u.begin() + GetSize(u)/2);
+ std::vector<int> u1(u.begin() + GetSize(u)/2, u.end());
t = ez->vec_ite(a[i], t1, t0);
u = ez->vec_ite(undef_a[i], ez->vec_or(ez->vec_xor(t0, t1), ez->vec_or(u0, u1)), ez->vec_ite(a[i], u1, u0));
}
- log_assert(SIZE(t) == 1);
- log_assert(SIZE(u) == 1);
+ log_assert(GetSize(t) == 1);
+ log_assert(GetSize(u) == 1);
undefGating(y, t, u);
ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort("\\Y"), timestep), u));
}
else
{
std::vector<int> t = lut;
- for (int i = SIZE(a)-1; i >= 0; i--)
+ for (int i = GetSize(a)-1; i >= 0; i--)
{
- std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2);
- std::vector<int> t1(t.begin() + SIZE(t)/2, t.end());
+ std::vector<int> t0(t.begin(), t.begin() + GetSize(t)/2);
+ std::vector<int> t1(t.begin() + GetSize(t)/2, t.end());
t = ez->vec_ite(a[i], t1, t0);
}
- log_assert(SIZE(t) == 1);
+ log_assert(GetSize(t) == 1);
ez->assume(ez->vec_eq(y, t));
}
return true;
@@ -1008,7 +1093,7 @@ struct SatGen
std::vector<int> yy = model_undef ? ez->vec_var(co.size()) : co;
- for (int i = 0; i < SIZE(co); i++)
+ for (int i = 0; i < GetSize(co); i++)
ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0])));
if (model_undef)
@@ -1049,12 +1134,12 @@ struct SatGen
std::vector<int> def_x = model_undef ? ez->vec_var(x.size()) : x;
std::vector<int> def_co = model_undef ? ez->vec_var(co.size()) : co;
- log_assert(SIZE(y) == SIZE(x));
- log_assert(SIZE(y) == SIZE(co));
- log_assert(SIZE(ci) == 1);
- log_assert(SIZE(bi) == 1);
+ log_assert(GetSize(y) == GetSize(x));
+ log_assert(GetSize(y) == GetSize(co));
+ log_assert(GetSize(ci) == 1);
+ log_assert(GetSize(bi) == 1);
- for (int i = 0; i < SIZE(y); i++)
+ for (int i = 0; i < GetSize(y); i++)
{
int s1 = a.at(i), s2 = ez->XOR(b.at(i), bi.at(0)), s3 = i ? co.at(i-1) : ci.at(0);
ez->SET(def_x.at(i), ez->XOR(s1, s2));
@@ -1084,7 +1169,7 @@ struct SatGen
all_inputs_undef.insert(all_inputs_undef.end(), undef_bi.begin(), undef_bi.end());
int undef_any = ez->expression(ezSAT::OpOr, all_inputs_undef);
- for (int i = 0; i < SIZE(undef_y); i++) {
+ for (int i = 0; i < GetSize(undef_y); i++) {
ez->SET(undef_y.at(i), undef_any);
ez->SET(undef_x.at(i), ez->OR(undef_a.at(i), undef_b.at(i), undef_bi.at(0)));
ez->SET(undef_co.at(i), undef_any);
@@ -1144,6 +1229,25 @@ struct SatGen
return true;
}
+ if (cell->type == "$_BUF_" || cell->type == "$equiv")
+ {
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ extendSignalWidthUnary(a, y, cell);
+
+ std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
+ ez->assume(ez->vec_eq(a, yy));
+
+ if (model_undef) {
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ extendSignalWidthUnary(undef_a, undef_y, cell, false);
+ ez->assume(ez->vec_eq(undef_a, undef_y));
+ undefGating(y, yy, undef_y);
+ }
+ return true;
+ }
+
if (cell->type == "$assert")
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
@@ -1152,10 +1256,20 @@ struct SatGen
return true;
}
+ if (cell->type == "$assume")
+ {
+ std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
+ assumes_a[pf].append((*sigmap)(cell->getPort("\\A")));
+ assumes_en[pf].append((*sigmap)(cell->getPort("\\EN")));
+ return true;
+ }
+
// Unsupported internal cell types: $pow $lut
// .. and all sequential cells except $dff and $_DFF_[NP]_
return false;
}
};
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/kernel/sigtools.h b/kernel/sigtools.h
index 32ef444a..f92a87db 100644
--- a/kernel/sigtools.h
+++ b/kernel/sigtools.h
@@ -29,9 +29,10 @@ struct SigPool
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
+ unsigned int hash() const { return first->name.hash() + second; }
};
- std::set<bitDef_t> bits;
+ pool<bitDef_t> bits;
void clear()
{
@@ -66,8 +67,8 @@ struct SigPool
void expand(RTLIL::SigSpec from, RTLIL::SigSpec to)
{
- log_assert(SIZE(from) == SIZE(to));
- for (int i = 0; i < SIZE(from); i++) {
+ log_assert(GetSize(from) == GetSize(to));
+ for (int i = 0; i < GetSize(from); i++) {
bitDef_t bit_from(from[i]), bit_to(to[i]);
if (bit_from.first != NULL && bit_to.first != NULL && bits.count(bit_from) > 0)
bits.insert(bit_to);
@@ -122,13 +123,13 @@ struct SigPool
RTLIL::SigSpec export_all()
{
- std::set<RTLIL::SigBit> sig;
+ pool<RTLIL::SigBit> sig;
for (auto &bit : bits)
sig.insert(RTLIL::SigBit(bit.first, bit.second));
return sig;
}
- size_t size()
+ size_t size() const
{
return bits.size();
}
@@ -140,9 +141,10 @@ struct SigSet
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
+ unsigned int hash() const { return first->name.hash() + second; }
};
- std::map<bitDef_t, std::set<T, Compare>> bits;
+ dict<bitDef_t, std::set<T, Compare>> bits;
void clear()
{
@@ -193,6 +195,15 @@ struct SigSet
}
}
+ void find(RTLIL::SigSpec sig, pool<T> &result)
+ {
+ for (auto &bit : sig)
+ if (bit.wire != NULL) {
+ auto &data = bits[bit];
+ result.insert(data.begin(), data.end());
+ }
+ }
+
std::set<T> find(RTLIL::SigSpec sig)
{
std::set<T> result;
@@ -214,6 +225,7 @@ struct SigMap
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
+ unsigned int hash() const { return first->name.hash() + second; }
};
struct shared_bit_data_t {
@@ -221,7 +233,7 @@ struct SigMap
std::set<bitDef_t> bits;
};
- std::map<bitDef_t, shared_bit_data_t*> bits;
+ dict<bitDef_t, shared_bit_data_t*> bits;
SigMap(RTLIL::Module *module = NULL)
{
@@ -346,9 +358,9 @@ struct SigMap
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
{
- log_assert(SIZE(from) == SIZE(to));
+ log_assert(GetSize(from) == GetSize(to));
- for (int i = 0; i < SIZE(from); i++)
+ for (int i = 0; i < GetSize(from); i++)
{
RTLIL::SigBit &bf = from[i];
RTLIL::SigBit &bt = to[i];
diff --git a/kernel/utils.h b/kernel/utils.h
index a03caf80..2ec6182e 100644
--- a/kernel/utils.h
+++ b/kernel/utils.h
@@ -25,21 +25,23 @@
#ifndef UTILS_H
#define UTILS_H
+YOSYS_NAMESPACE_BEGIN
+
// ------------------------------------------------
// A map-like container, but you can save and restore the state
// ------------------------------------------------
-template<typename Key, typename T, typename Compare = std::less<Key>>
+template<typename Key, typename T, typename OPS = hash_ops<Key>>
struct stackmap
{
private:
- std::vector<std::map<Key, T*, Compare>> backup_state;
- std::map<Key, T, Compare> current_state;
+ std::vector<dict<Key, T*, OPS>> backup_state;
+ dict<Key, T, OPS> current_state;
static T empty_tuple;
public:
stackmap() { }
- stackmap(const std::map<Key, T, Compare> &other) : current_state(other) { }
+ stackmap(const dict<Key, T, OPS> &other) : current_state(other) { }
template<typename Other>
void operator=(const Other &other)
@@ -81,7 +83,7 @@ public:
void reset(const Key &k)
{
- for (int i = SIZE(backup_state)-1; i >= 0; i--)
+ for (int i = GetSize(backup_state)-1; i >= 0; i--)
if (backup_state[i].count(k) != 0) {
if (backup_state[i].at(k) == nullptr)
current_state.erase(k);
@@ -92,7 +94,7 @@ public:
current_state.erase(k);
}
- const std::map<Key, T, Compare> &stdmap()
+ const dict<Key, T, OPS> &stdmap()
{
return current_state;
}
@@ -126,12 +128,12 @@ public:
// A simple class for topological sorting
// ------------------------------------------------
-template<typename T>
+template<typename T, typename C = std::less<T>>
struct TopoSort
{
bool analyze_loops, found_loops;
- std::map<T, std::set<T>> database;
- std::set<std::set<T>> loops;
+ std::map<T, std::set<T, C>, C> database;
+ std::set<std::set<T, C>> loops;
std::vector<T> sorted;
TopoSort()
@@ -143,7 +145,7 @@ struct TopoSort
void node(T n)
{
if (database.count(n) == 0)
- database[n] = std::set<T>();
+ database[n] = std::set<T, C>();
}
void edge(T left, T right)
@@ -152,13 +154,13 @@ struct TopoSort
database[right].insert(left);
}
- void sort_worker(const T &n, std::set<T> &marked_cells, std::set<T> &active_cells, std::vector<T> &active_stack)
+ void sort_worker(const T &n, std::set<T, C> &marked_cells, std::set<T, C> &active_cells, std::vector<T> &active_stack)
{
if (active_cells.count(n)) {
found_loops = true;
if (analyze_loops) {
- std::set<T> loop;
- for (int i = SIZE(active_stack)-1; i >= 0; i--) {
+ std::set<T, C> loop;
+ for (int i = GetSize(active_stack)-1; i >= 0; i--) {
loop.insert(active_stack[i]);
if (active_stack[i] == n)
break;
@@ -195,16 +197,18 @@ struct TopoSort
sorted.clear();
found_loops = false;
- std::set<T> marked_cells;
- std::set<T> active_cells;
+ std::set<T, C> marked_cells;
+ std::set<T, C> active_cells;
std::vector<T> active_stack;
for (auto &it : database)
sort_worker(it.first, marked_cells, active_cells, active_stack);
- log_assert(SIZE(sorted) == SIZE(database));
+ log_assert(GetSize(sorted) == GetSize(database));
return !found_loops;
}
};
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 0ecb4cda..884b2c59 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -18,26 +18,112 @@
*/
#include "kernel/yosys.h"
+#include "kernel/celltypes.h"
#ifdef YOSYS_ENABLE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif
-#include <dlfcn.h>
-#include <unistd.h>
+#ifdef YOSYS_ENABLE_PLUGINS
+# include <dlfcn.h>
+#endif
+
+#ifdef _WIN32
+# include <windows.h>
+# include <io.h>
+#elif defined(__APPLE__)
+# include <mach-o/dyld.h>
+# include <unistd.h>
+# include <dirent.h>
+# include <sys/stat.h>
+#else
+# include <unistd.h>
+# include <dirent.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+
#include <limits.h>
#include <errno.h>
YOSYS_NAMESPACE_BEGIN
int autoidx = 1;
+int yosys_xtrace = 0;
RTLIL::Design *yosys_design = NULL;
+CellTypes yosys_celltypes;
#ifdef YOSYS_ENABLE_TCL
Tcl_Interp *yosys_tcl_interp = NULL;
#endif
+bool memhasher_active = false;
+uint32_t memhasher_rng = 123456;
+std::vector<void*> memhasher_store;
+
+void memhasher_on()
+{
+#ifdef __linux__
+ memhasher_rng += time(NULL) << 16 ^ getpid();
+#endif
+ memhasher_store.resize(0x10000);
+ memhasher_active = true;
+}
+
+void memhasher_off()
+{
+ for (auto p : memhasher_store)
+ if (p) free(p);
+ memhasher_store.clear();
+ memhasher_active = false;
+}
+
+void memhasher_do()
+{
+ memhasher_rng ^= memhasher_rng << 13;
+ memhasher_rng ^= memhasher_rng >> 17;
+ memhasher_rng ^= memhasher_rng << 5;
+
+ int size, index = (memhasher_rng >> 4) & 0xffff;
+ switch (memhasher_rng & 7) {
+ case 0: size = 16; break;
+ case 1: size = 256; break;
+ case 2: size = 1024; break;
+ case 3: size = 4096; break;
+ default: size = 0;
+ }
+ if (index < 16) size *= 16;
+ memhasher_store[index] = realloc(memhasher_store[index], size);
+}
+
+void yosys_banner()
+{
+ log("\n");
+ log(" /----------------------------------------------------------------------------\\\n");
+ log(" | |\n");
+ log(" | yosys -- Yosys Open SYnthesis Suite |\n");
+ log(" | |\n");
+ log(" | Copyright (C) 2012 - 2015 Clifford Wolf <clifford@clifford.at> |\n");
+ log(" | |\n");
+ log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
+ log(" | purpose with or without fee is hereby granted, provided that the above |\n");
+ log(" | copyright notice and this permission notice appear in all copies. |\n");
+ log(" | |\n");
+ log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
+ log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
+ log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
+ log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
+ log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
+ log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
+ log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
+ log(" | |\n");
+ log(" \\----------------------------------------------------------------------------/\n");
+ log("\n");
+ log(" %s\n", yosys_version_str);
+ log("\n");
+}
+
std::string stringf(const char *fmt, ...)
{
std::string string;
@@ -55,8 +141,22 @@ std::string vstringf(const char *fmt, va_list ap)
std::string string;
char *str = NULL;
+#ifdef _WIN32
+ int sz = 64, rc;
+ while (1) {
+ va_list apc;
+ va_copy(apc, ap);
+ str = (char*)realloc(str, sz);
+ rc = vsnprintf(str, sz, fmt, apc);
+ va_end(apc);
+ if (rc >= 0 && rc < sz)
+ break;
+ sz *= 2;
+ }
+#else
if (vasprintf(&str, fmt, ap) < 0)
str = NULL;
+#endif
if (str != NULL) {
string = str;
@@ -66,15 +166,264 @@ std::string vstringf(const char *fmt, va_list ap)
return string;
}
-int SIZE(RTLIL::Wire *wire)
+int readsome(std::istream &f, char *s, int n)
+{
+ int rc = f.readsome(s, n);
+
+ // f.readsome() sometimes returns 0 on a non-empty stream..
+ if (rc == 0) {
+ int c = f.get();
+ if (c != EOF) {
+ *s = c;
+ rc = 1;
+ }
+ }
+
+ return rc;
+}
+
+std::string next_token(std::string &text, const char *sep)
+{
+ size_t pos_begin = text.find_first_not_of(sep);
+
+ if (pos_begin == std::string::npos)
+ pos_begin = text.size();
+
+ size_t pos_end = text.find_first_of(sep, pos_begin);
+
+ if (pos_end == std::string::npos)
+ pos_end = text.size();
+
+ std::string token = text.substr(pos_begin, pos_end-pos_begin);
+ text = text.substr(pos_end);
+ return token;
+}
+
+// this is very similar to fnmatch(). the exact rules used by this
+// function are:
+//
+// ? matches any character except
+// * matches any sequence of characters
+// [...] matches any of the characters in the list
+// [!..] matches any of the characters not in the list
+//
+// a backslash may be used to escape the next characters in the
+// pattern. each special character can also simply match itself.
+//
+bool patmatch(const char *pattern, const char *string)
+{
+ if (*pattern == 0)
+ return *string == 0;
+
+ if (*pattern == '\\') {
+ if (pattern[1] == string[0] && patmatch(pattern+2, string+1))
+ return true;
+ }
+
+ if (*pattern == '?') {
+ if (*string == 0)
+ return false;
+ return patmatch(pattern+1, string+1);
+ }
+
+ if (*pattern == '*') {
+ while (*string) {
+ if (patmatch(pattern+1, string++))
+ return true;
+ }
+ return pattern[1] == 0;
+ }
+
+ if (*pattern == '[') {
+ bool found_match = false;
+ bool inverted_list = pattern[1] == '!';
+ const char *p = pattern + (inverted_list ? 1 : 0);
+
+ while (*++p) {
+ if (*p == ']') {
+ if (found_match != inverted_list && patmatch(p+1, string+1))
+ return true;
+ break;
+ }
+
+ if (*p == '\\') {
+ if (*++p == *string)
+ found_match = true;
+ } else
+ if (*p == *string)
+ found_match = true;
+ }
+ }
+
+ if (*pattern == *string)
+ return patmatch(pattern+1, string+1);
+
+ return false;
+}
+
+int run_command(const std::string &command, std::function<void(const std::string&)> process_line)
+{
+ if (!process_line)
+ return system(command.c_str());
+
+ FILE *f = popen(command.c_str(), "r");
+ if (f == nullptr)
+ return -1;
+
+ std::string line;
+ char logbuf[128];
+ while (fgets(logbuf, 128, f) != NULL) {
+ line += logbuf;
+ if (!line.empty() && line.back() == '\n')
+ process_line(line), line.clear();
+ }
+ if (!line.empty())
+ process_line(line);
+
+ int ret = pclose(f);
+ if (ret < 0)
+ return -1;
+#ifdef _WIN32
+ return ret;
+#else
+ return WEXITSTATUS(ret);
+#endif
+}
+
+std::string make_temp_file(std::string template_str)
+{
+#ifdef _WIN32
+ if (template_str.rfind("/tmp/", 0) == 0) {
+# ifdef __MINGW32__
+ char longpath[MAX_PATH + 1];
+ char shortpath[MAX_PATH + 1];
+# else
+ WCHAR longpath[MAX_PATH + 1];
+ TCHAR shortpath[MAX_PATH + 1];
+# endif
+ if (!GetTempPath(MAX_PATH+1, longpath))
+ log_error("GetTempPath() failed.\n");
+ if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1))
+ log_error("GetShortPathName() failed.\n");
+ std::string path;
+ for (int i = 0; shortpath[i]; i++)
+ path += char(shortpath[i]);
+ template_str = stringf("%s\\%s", path.c_str(), template_str.c_str() + 5);
+ }
+
+ size_t pos = template_str.rfind("XXXXXX");
+ log_assert(pos != std::string::npos);
+
+ while (1) {
+ for (int i = 0; i < 6; i++) {
+ static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ static uint32_t x = 314159265 ^ uint32_t(time(NULL));
+ x ^= x << 13, x ^= x >> 17, x ^= x << 5;
+ template_str[pos+i] = y[x % y.size()];
+ }
+ if (_access(template_str.c_str(), 0) != 0)
+ break;
+ }
+#else
+ size_t pos = template_str.rfind("XXXXXX");
+ log_assert(pos != std::string::npos);
+
+ int suffixlen = GetSize(template_str) - pos - 6;
+
+ char *p = strdup(template_str.c_str());
+ close(mkstemps(p, suffixlen));
+ template_str = p;
+ free(p);
+#endif
+
+ return template_str;
+}
+
+std::string make_temp_dir(std::string template_str)
+{
+#ifdef _WIN32
+ template_str = make_temp_file(template_str);
+ mkdir(template_str.c_str());
+ return template_str;
+#else
+# ifndef NDEBUG
+ size_t pos = template_str.rfind("XXXXXX");
+ log_assert(pos != std::string::npos);
+
+ int suffixlen = GetSize(template_str) - pos - 6;
+ log_assert(suffixlen == 0);
+# endif
+
+ char *p = strdup(template_str.c_str());
+ p = mkdtemp(p);
+ log_assert(p != NULL);
+ template_str = p;
+ free(p);
+
+ return template_str;
+#endif
+}
+
+#ifdef _WIN32
+bool check_file_exists(std::string filename, bool)
+{
+ return _access(filename.c_str(), 0) == 0;
+}
+#else
+bool check_file_exists(std::string filename, bool is_exec)
+{
+ return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0;
+}
+#endif
+
+bool is_absolute_path(std::string filename)
+{
+#ifdef _WIN32
+ return filename[0] == '/' || filename[0] == '\\' || (filename[0] != 0 && filename[1] == ':');
+#else
+ return filename[0] == '/';
+#endif
+}
+
+void remove_directory(std::string dirname)
+{
+#ifdef _WIN32
+ run_command(stringf("rmdir /s /q \"%s\"", dirname.c_str()));
+#else
+ struct stat stbuf;
+ struct dirent **namelist;
+ int n = scandir(dirname.c_str(), &namelist, nullptr, alphasort);
+ log_assert(n >= 0);
+ for (int i = 0; i < n; i++) {
+ if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
+ std::string buffer = stringf("%s/%s", dirname.c_str(), namelist[i]->d_name);
+ if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) {
+ remove(buffer.c_str());
+ } else
+ remove_directory(buffer);
+ }
+ free(namelist[i]);
+ }
+ free(namelist);
+ rmdir(dirname.c_str());
+#endif
+}
+
+int GetSize(RTLIL::Wire *wire)
{
return wire->width;
}
void yosys_setup()
{
+ // if there are already IdString objects then we have a global initialization order bug
+ IdString empty_id;
+ log_assert(empty_id.index_ == 0);
+ IdString::get_reference(empty_id.index_);
+
Pass::init_register();
yosys_design = new RTLIL::Design;
+ yosys_celltypes.setup();
log_push();
}
@@ -92,6 +441,7 @@ void yosys_shutdown()
log_files.clear();
Pass::done_register();
+ yosys_celltypes.clear();
#ifdef YOSYS_ENABLE_TCL
if (yosys_tcl_interp != NULL) {
@@ -101,20 +451,33 @@ void yosys_shutdown()
}
#endif
+#ifdef YOSYS_ENABLE_PLUGINS
for (auto &it : loaded_plugins)
dlclose(it.second);
loaded_plugins.clear();
loaded_plugin_aliases.clear();
+#endif
+
+ IdString empty_id;
+ IdString::put_reference(empty_id.index_);
}
RTLIL::IdString new_id(std::string file, int line, std::string func)
{
- std::string str = "$auto$";
+#ifdef _WIN32
+ size_t pos = file.find_last_of("/\\");
+#else
size_t pos = file.find_last_of('/');
- str += pos != std::string::npos ? file.substr(pos+1) : file;
- str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++);
- return str;
+#endif
+ if (pos != std::string::npos)
+ file = file.substr(pos+1);
+
+ pos = func.find_last_of(':');
+ if (pos != std::string::npos)
+ func = func.substr(pos+1);
+
+ return stringf("$auto$%s:%d:%s$%d", file.c_str(), line, func.c_str(), autoidx++);
}
RTLIL::Design *yosys_get_design()
@@ -210,9 +573,9 @@ struct TclPass : public Pass {
#endif
#if defined(__linux__)
-std::string proc_self_dirname ()
+std::string proc_self_dirname()
{
- char path [PATH_MAX];
+ char path[PATH_MAX];
ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path));
if (buflen < 0) {
log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno));
@@ -222,10 +585,9 @@ std::string proc_self_dirname ()
return std::string(path, buflen);
}
#elif defined(__APPLE__)
-#include <mach-o/dyld.h>
-std::string proc_self_dirname ()
+std::string proc_self_dirname()
{
- char * path = NULL;
+ char *path = NULL;
uint32_t buflen = 0;
while (_NSGetExecutablePath(path, &buflen) != 0)
path = (char *) realloc((void *) path, buflen);
@@ -233,8 +595,32 @@ std::string proc_self_dirname ()
buflen--;
return std::string(path, buflen);
}
+#elif defined(_WIN32)
+std::string proc_self_dirname()
+{
+ int i = 0;
+# ifdef __MINGW32__
+ char longpath[MAX_PATH + 1];
+ char shortpath[MAX_PATH + 1];
+# else
+ WCHAR longpath[MAX_PATH + 1];
+ TCHAR shortpath[MAX_PATH + 1];
+# endif
+ if (!GetModuleFileName(0, longpath, MAX_PATH+1))
+ log_error("GetModuleFileName() failed.\n");
+ if (!GetShortPathName(longpath, shortpath, MAX_PATH+1))
+ log_error("GetShortPathName() failed.\n");
+ while (shortpath[i] != 0)
+ i++;
+ while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\')
+ shortpath[--i] = 0;
+ std::string path;
+ for (i = 0; shortpath[i]; i++)
+ path += char(shortpath[i]);
+ return path;
+}
#elif defined(EMSCRIPTEN)
-std::string proc_self_dirname ()
+std::string proc_self_dirname()
{
return "/";
}
@@ -242,17 +628,33 @@ std::string proc_self_dirname ()
#error Dont know how to determine process executable base path!
#endif
-std::string proc_share_dirname ()
+#ifdef EMSCRIPTEN
+std::string proc_share_dirname()
+{
+ return "/share";
+}
+#else
+std::string proc_share_dirname()
{
std::string proc_self_path = proc_self_dirname();
+# ifdef _WIN32
+ std::string proc_share_path = proc_self_path + "share\\";
+ if (check_file_exists(proc_share_path, true))
+ return proc_share_path;
+ proc_share_path = proc_self_path + "..\\share\\";
+ if (check_file_exists(proc_share_path, true))
+ return proc_share_path;
+# else
std::string proc_share_path = proc_self_path + "share/";
- if (access(proc_share_path.c_str(), X_OK) == 0)
+ if (check_file_exists(proc_share_path, true))
return proc_share_path;
proc_share_path = proc_self_path + "../share/yosys/";
- if (access(proc_share_path.c_str(), X_OK) == 0)
+ if (check_file_exists(proc_share_path, true))
return proc_share_path;
+# endif
log_error("proc_share_dirname: unable to determine share/ directory!\n");
}
+#endif
bool fgetline(FILE *f, std::string &buffer)
{
@@ -275,15 +677,15 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
int pos = 0;
std::string label;
- while (pos < SIZE(command) && (command[pos] == ' ' || command[pos] == '\t'))
+ while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t'))
pos++;
- while (pos < SIZE(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
+ while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
label += command[pos++];
- if (label.back() == ':' && SIZE(label) > 1)
+ if (label.back() == ':' && GetSize(label) > 1)
{
- label = label.substr(0, SIZE(label)-1);
+ label = label.substr(0, GetSize(label)-1);
command = command.substr(pos);
if (label == run_from)
@@ -293,8 +695,11 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
}
}
-void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label)
+void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design)
{
+ if (design == nullptr)
+ design = yosys_design;
+
if (command == "auto") {
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
command = "verilog";
@@ -361,9 +766,9 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi
Pass::call(design, command);
}
}
- catch (log_cmd_error_expection) {
+ catch (...) {
Frontend::current_script_file = backup_script_file;
- throw log_cmd_error_expection();
+ throw;
}
Frontend::current_script_file = backup_script_file;
@@ -386,15 +791,26 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi
Frontend::frontend_call(design, NULL, filename, command);
}
+void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
+{
+ run_frontend(filename, command, nullptr, nullptr, design);
+}
+
void run_pass(std::string command, RTLIL::Design *design)
{
- log("\n-- Running pass `%s' --\n", command.c_str());
+ if (design == nullptr)
+ design = yosys_design;
+
+ log("\n-- Running command `%s' --\n", command.c_str());
Pass::call(design, command);
}
void run_backend(std::string filename, std::string command, RTLIL::Design *design)
{
+ if (design == nullptr)
+ design = yosys_design;
+
if (command == "auto") {
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
command = "verilog";
@@ -518,11 +934,16 @@ void shell(RTLIL::Design *design)
char *command = NULL;
#ifdef YOSYS_ENABLE_READLINE
while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
+ {
#else
char command_buffer[4096];
- while ((command = fgets(command_buffer, 4096, stdin)) != NULL)
-#endif
+ while (1)
{
+ fputs(create_prompt(design, recursion_counter), stdout);
+ fflush(stdout);
+ if ((command = fgets(command_buffer, 4096, stdin)) == NULL)
+ break;
+#endif
if (command[strspn(command, " \t\r\n")] == 0)
continue;
#ifdef YOSYS_ENABLE_READLINE
@@ -540,7 +961,7 @@ void shell(RTLIL::Design *design)
try {
log_assert(design->selection_stack.size() == 1);
Pass::call(design, command);
- } catch (log_cmd_error_expection) {
+ } catch (log_cmd_error_exception) {
while (design->selection_stack.size() > 1)
design->selection_stack.pop_back();
log_reset_stack();
@@ -634,9 +1055,9 @@ struct ScriptPass : public Pass {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
else if (args.size() == 2)
- run_frontend(args[1], "script", design, NULL, NULL);
+ run_frontend(args[1], "script", design);
else if (args.size() == 3)
- run_frontend(args[1], "script", design, NULL, &args[2]);
+ run_frontend(args[1], "script", NULL, &args[2], design);
else
extra_args(args, 2, design, false);
}
diff --git a/kernel/yosys.h b/kernel/yosys.h
index b571e177..231dd4de 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -45,7 +45,11 @@
#include <string>
#include <algorithm>
#include <functional>
+#include <unordered_map>
+#include <unordered_set>
#include <initializer_list>
+#include <stdexcept>
+#include <memory>
#include <sstream>
#include <fstream>
@@ -56,44 +60,164 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <stdint.h>
#include <stdio.h>
+#ifndef _YOSYS_
+# error It looks like you are trying to build Yosys without the config defines set. \
+ When building Yosys with a custom make system, make sure you set all the \
+ defines the Yosys Makefile would set for your build configuration.
+#endif
+
+#ifdef YOSYS_ENABLE_TCL
+# include <tcl.h>
+#endif
+
+#ifdef _WIN32
+# undef NOMINMAX
+# define NOMINMAX 1
+# undef YY_NO_UNISTD_H
+# define YY_NO_UNISTD_H 1
+
+# include <windows.h>
+# include <io.h>
+# include <direct.h>
+
+# define strtok_r strtok_s
+# define strdup _strdup
+# define snprintf _snprintf
+# define getcwd _getcwd
+# define mkdir _mkdir
+# define popen _popen
+# define pclose _pclose
+# define PATH_MAX MAX_PATH
+
+# ifndef __MINGW32__
+# define isatty _isatty
+# define fileno _fileno
+# endif
+#endif
+
#define PRIVATE_NAMESPACE_BEGIN namespace {
#define PRIVATE_NAMESPACE_END }
+#define YOSYS_NAMESPACE_BEGIN namespace Yosys {
+#define YOSYS_NAMESPACE_END }
+#define YOSYS_NAMESPACE_PREFIX Yosys::
+#define USING_YOSYS_NAMESPACE using namespace Yosys;
-#if 0
-# define YOSYS_NAMESPACE_BEGIN namespace Yosys {
-# define YOSYS_NAMESPACE_END }
-# define YOSYS_NAMESPACE_PREFIX Yosys::
-# define USING_YOSYS_NAMESPACE using namespace Yosys;
+#if __cplusplus >= 201103L
+# define YS_OVERRIDE override
+# define YS_FINAL final
#else
-# define YOSYS_NAMESPACE_BEGIN
-# define YOSYS_NAMESPACE_END
-# define YOSYS_NAMESPACE_PREFIX
-# define USING_YOSYS_NAMESPACE
+# define YS_OVERRIDE
+# define YS_FINAL
#endif
-#if __cplusplus >= 201103L
-# define OVERRIDE override
-# define FINAL final
+#if defined(__GNUC__) || defined(__clang__)
+# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
+# define YS_NORETURN
+#elif defined(_MSC_VER)
+# define YS_ATTRIBUTE(...)
+# define YS_NORETURN __declspec(noreturn)
#else
-# define OVERRIDE
-# define FINAL
+# define YS_ATTRIBUTE(...)
+# define YS_NORETURN
#endif
YOSYS_NAMESPACE_BEGIN
+// Note: All headers included in hashlib.h must be included
+// outside of YOSYS_NAMESPACE before this or bad things will happen.
+#ifdef HASHLIB_H
+# undef HASHLIB_H
+# include "kernel/hashlib.h"
+#else
+# include "kernel/hashlib.h"
+# undef HASHLIB_H
+#endif
+
+using std::vector;
+using std::string;
+using std::pair;
+
+using hashlib::mkhash;
+using hashlib::mkhash_init;
+using hashlib::mkhash_add;
+using hashlib::mkhash_xorshift;
+using hashlib::hash_ops;
+using hashlib::hash_cstr_ops;
+using hashlib::hash_ptr_ops;
+using hashlib::hash_obj_ops;
+using hashlib::dict;
+using hashlib::idict;
+using hashlib::pool;
+
namespace RTLIL {
struct IdString;
+ struct Const;
+ struct SigBit;
struct SigSpec;
struct Wire;
struct Cell;
+ struct Module;
+ struct Design;
+ struct Monitor;
+}
+
+namespace AST {
+ struct AstNode;
+}
+
+using RTLIL::IdString;
+using RTLIL::Const;
+using RTLIL::SigBit;
+using RTLIL::SigSpec;
+using RTLIL::Wire;
+using RTLIL::Cell;
+using RTLIL::Module;
+using RTLIL::Design;
+
+namespace hashlib {
+ template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
+ template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
+ template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
+ template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
+ template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
+ template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
+
+ template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
+ template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
+ template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
+ template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
+ template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
+ template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
}
-std::string stringf(const char *fmt, ...);
+void memhasher_on();
+void memhasher_off();
+void memhasher_do();
+
+extern bool memhasher_active;
+inline void memhasher() { if (memhasher_active) memhasher_do(); }
+
+void yosys_banner();
+std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
std::string vstringf(const char *fmt, va_list ap);
-template<typename T> int SIZE(const T &obj) { return obj.size(); }
-int SIZE(RTLIL::Wire *wire);
+int readsome(std::istream &f, char *s, int n);
+std::string next_token(std::string &text, const char *sep = " \t\r\n");
+bool patmatch(const char *pattern, const char *string);
+int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
+std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX");
+std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");
+bool check_file_exists(std::string filename, bool is_exec = false);
+bool is_absolute_path(std::string filename);
+void remove_directory(std::string dirname);
+
+template<typename T> int GetSize(const T &obj) { return obj.size(); }
+int GetSize(RTLIL::Wire *wire);
+
+extern int autoidx;
+extern int yosys_xtrace;
YOSYS_NAMESPACE_END
@@ -103,15 +227,19 @@ YOSYS_NAMESPACE_END
YOSYS_NAMESPACE_BEGIN
+using RTLIL::State;
+
+namespace hashlib {
+ template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
+}
+
void yosys_setup();
void yosys_shutdown();
#ifdef YOSYS_ENABLE_TCL
-#include <tcl.h>
Tcl_Interp *yosys_get_tcl_interp();
#endif
-extern int autoidx;
extern RTLIL::Design *yosys_design;
RTLIL::IdString new_id(std::string file, int line, std::string func);
@@ -127,9 +255,10 @@ std::string proc_self_dirname();
std::string proc_share_dirname();
const char *create_prompt(RTLIL::Design *design, int recursion_counter);
-void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label);
-void run_pass(std::string command, RTLIL::Design *design);
-void run_backend(std::string filename, std::string command, RTLIL::Design *design);
+void run_pass(std::string command, RTLIL::Design *design = nullptr);
+void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label = nullptr, RTLIL::Design *design = nullptr);
+void run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
+void run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
void shell(RTLIL::Design *design);
// from kernel/version_*.o (cc source generated from Makefile)
diff --git a/libs/ezsat/ezminisat.cc b/libs/ezsat/ezminisat.cc
index dc4e5d28..dee82a8d 100644
--- a/libs/ezsat/ezminisat.cc
+++ b/libs/ezsat/ezminisat.cc
@@ -27,7 +27,10 @@
#include <stdint.h>
#include <csignal>
#include <cinttypes>
-#include <unistd.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+#endif
#include "../minisat/Solver.h"
#include "../minisat/SimpSolver.h"
@@ -37,8 +40,8 @@ ezMiniSAT::ezMiniSAT() : minisatSolver(NULL)
minisatSolver = NULL;
foundContradiction = false;
- freeze(TRUE);
- freeze(FALSE);
+ freeze(CONST_TRUE);
+ freeze(CONST_FALSE);
}
ezMiniSAT::~ezMiniSAT()
@@ -77,6 +80,7 @@ bool ezMiniSAT::eliminated(int idx)
}
#endif
+#ifndef _WIN32
ezMiniSAT *ezMiniSAT::alarmHandlerThis = NULL;
clock_t ezMiniSAT::alarmHandlerTimeout = 0;
@@ -88,6 +92,7 @@ void ezMiniSAT::alarmHandler(int)
} else
alarm(1);
}
+#endif
bool ezMiniSAT::solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions)
{
@@ -174,6 +179,7 @@ contradiction:
#endif
}
+#ifndef _WIN32
struct sigaction sig_action;
struct sigaction old_sig_action;
int old_alarm_timeout = 0;
@@ -188,9 +194,11 @@ contradiction:
sigaction(SIGALRM, &sig_action, &old_sig_action);
alarm(1);
}
+#endif
bool foundSolution = minisatSolver->solve(assumps);
+#ifndef _WIN32
if (solverTimeout > 0) {
if (alarmHandlerTimeout == 0)
solverTimoutStatus = true;
@@ -198,6 +206,7 @@ contradiction:
sigaction(SIGALRM, &old_sig_action, NULL);
alarm(old_alarm_timeout);
}
+#endif
if (!foundSolution) {
#if !EZMINISAT_INCREMENTAL
diff --git a/libs/ezsat/ezminisat.h b/libs/ezsat/ezminisat.h
index ac9c071c..5b5252d8 100644
--- a/libs/ezsat/ezminisat.h
+++ b/libs/ezsat/ezminisat.h
@@ -51,9 +51,11 @@ private:
std::set<int> cnfFrozenVars;
#endif
+#ifndef _WIN32
static ezMiniSAT *alarmHandlerThis;
static clock_t alarmHandlerTimeout;
static void alarmHandler(int);
+#endif
public:
ezMiniSAT();
diff --git a/libs/ezsat/ezsat.cc b/libs/ezsat/ezsat.cc
index 13ed112e..8d232f33 100644
--- a/libs/ezsat/ezsat.cc
+++ b/libs/ezsat/ezsat.cc
@@ -22,14 +22,28 @@
#include <cmath>
#include <algorithm>
#include <cassert>
+#include <string>
#include <stdlib.h>
-const int ezSAT::TRUE = 1;
-const int ezSAT::FALSE = 2;
+const int ezSAT::CONST_TRUE = 1;
+const int ezSAT::CONST_FALSE = 2;
+
+static std::string my_int_to_string(int i)
+{
+#ifdef __MINGW32__
+ char buffer[64];
+ snprintf(buffer, 64, "%d", i);
+ return buffer;
+#else
+ return std::to_string(i);
+#endif
+}
ezSAT::ezSAT()
{
+ statehash = 5381;
+
flag_keep_cnf = false;
flag_non_incremental = false;
@@ -42,20 +56,25 @@ ezSAT::ezSAT()
solverTimeout = 0;
solverTimoutStatus = false;
- literal("TRUE");
- literal("FALSE");
+ literal("CONST_TRUE");
+ literal("CONST_FALSE");
- assert(literal("TRUE") == TRUE);
- assert(literal("FALSE") == FALSE);
+ assert(literal("CONST_TRUE") == CONST_TRUE);
+ assert(literal("CONST_FALSE") == CONST_FALSE);
}
ezSAT::~ezSAT()
{
}
+void ezSAT::addhash(unsigned int h)
+{
+ statehash = ((statehash << 5) + statehash) ^ h;
+}
+
int ezSAT::value(bool val)
{
- return val ? TRUE : FALSE;
+ return val ? CONST_TRUE : CONST_FALSE;
}
int ezSAT::literal()
@@ -101,15 +120,21 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
myArgs.reserve(args.size());
bool xorRemovedOddTrues = false;
+ addhash(__LINE__);
+ addhash(op);
+
for (auto arg : args)
{
+ addhash(__LINE__);
+ addhash(arg);
+
if (arg == 0)
continue;
- if (op == OpAnd && arg == TRUE)
+ if (op == OpAnd && arg == CONST_TRUE)
continue;
- if ((op == OpOr || op == OpXor) && arg == FALSE)
+ if ((op == OpOr || op == OpXor) && arg == CONST_FALSE)
continue;
- if (op == OpXor && arg == TRUE) {
+ if (op == OpXor && arg == CONST_TRUE) {
xorRemovedOddTrues = !xorRemovedOddTrues;
continue;
}
@@ -131,29 +156,29 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
{
case OpNot:
assert(myArgs.size() == 1);
- if (myArgs[0] == TRUE)
- return FALSE;
- if (myArgs[0] == FALSE)
- return TRUE;
+ if (myArgs[0] == CONST_TRUE)
+ return CONST_FALSE;
+ if (myArgs[0] == CONST_FALSE)
+ return CONST_TRUE;
break;
case OpAnd:
if (myArgs.size() == 0)
- return TRUE;
+ return CONST_TRUE;
if (myArgs.size() == 1)
return myArgs[0];
break;
case OpOr:
if (myArgs.size() == 0)
- return FALSE;
+ return CONST_FALSE;
if (myArgs.size() == 1)
return myArgs[0];
break;
case OpXor:
if (myArgs.size() == 0)
- return xorRemovedOddTrues ? TRUE : FALSE;
+ return xorRemovedOddTrues ? CONST_TRUE : CONST_FALSE;
if (myArgs.size() == 1)
return xorRemovedOddTrues ? NOT(myArgs[0]) : myArgs[0];
break;
@@ -161,15 +186,15 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
case OpIFF:
assert(myArgs.size() >= 1);
if (myArgs.size() == 1)
- return TRUE;
+ return CONST_TRUE;
// FIXME: Add proper const folding
break;
case OpITE:
assert(myArgs.size() == 3);
- if (myArgs[0] == TRUE)
+ if (myArgs[0] == CONST_TRUE)
return myArgs[1];
- if (myArgs[0] == FALSE)
+ if (myArgs[0] == CONST_FALSE)
return myArgs[2];
break;
@@ -183,12 +208,18 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
if (expressionsCache.count(myExpr) > 0) {
id = expressionsCache.at(myExpr);
} else {
- id = -(expressions.size() + 1);
+ id = -(int(expressions.size()) + 1);
expressionsCache[myExpr] = id;
expressions.push_back(myExpr);
}
- return xorRemovedOddTrues ? NOT(id) : id;
+ if (xorRemovedOddTrues)
+ id = NOT(id);
+
+ addhash(__LINE__);
+ addhash(id);
+
+ return id;
}
void ezSAT::lookup_literal(int id, std::string &name) const
@@ -281,7 +312,7 @@ std::string ezSAT::to_string(int id) const
int ezSAT::eval(int id, const std::vector<int> &values) const
{
if (id > 0) {
- if (id <= int(values.size()) && (values[id-1] == TRUE || values[id-1] == FALSE || values[id-1] == 0))
+ if (id <= int(values.size()) && (values[id-1] == CONST_TRUE || values[id-1] == CONST_FALSE || values[id-1] == 0))
return values[id-1];
return 0;
}
@@ -295,39 +326,39 @@ int ezSAT::eval(int id, const std::vector<int> &values) const
case OpNot:
assert(args.size() == 1);
a = eval(args[0], values);
- if (a == TRUE)
- return FALSE;
- if (a == FALSE)
- return TRUE;
+ if (a == CONST_TRUE)
+ return CONST_FALSE;
+ if (a == CONST_FALSE)
+ return CONST_TRUE;
return 0;
case OpAnd:
- a = TRUE;
+ a = CONST_TRUE;
for (auto arg : args) {
b = eval(arg, values);
- if (b != TRUE && b != FALSE)
+ if (b != CONST_TRUE && b != CONST_FALSE)
a = 0;
- if (b == FALSE)
- return FALSE;
+ if (b == CONST_FALSE)
+ return CONST_FALSE;
}
return a;
case OpOr:
- a = FALSE;
+ a = CONST_FALSE;
for (auto arg : args) {
b = eval(arg, values);
- if (b != TRUE && b != FALSE)
+ if (b != CONST_TRUE && b != CONST_FALSE)
a = 0;
- if (b == TRUE)
- return TRUE;
+ if (b == CONST_TRUE)
+ return CONST_TRUE;
}
return a;
case OpXor:
- a = FALSE;
+ a = CONST_FALSE;
for (auto arg : args) {
b = eval(arg, values);
- if (b != TRUE && b != FALSE)
+ if (b != CONST_TRUE && b != CONST_FALSE)
return 0;
- if (b == TRUE)
- a = a == TRUE ? FALSE : TRUE;
+ if (b == CONST_TRUE)
+ a = a == CONST_TRUE ? CONST_FALSE : CONST_TRUE;
}
return a;
case OpIFF:
@@ -335,18 +366,18 @@ int ezSAT::eval(int id, const std::vector<int> &values) const
a = eval(args[0], values);
for (auto arg : args) {
b = eval(arg, values);
- if (b != TRUE && b != FALSE)
+ if (b != CONST_TRUE && b != CONST_FALSE)
return 0;
if (b != a)
- return FALSE;
+ return CONST_FALSE;
}
- return TRUE;
+ return CONST_TRUE;
case OpITE:
assert(args.size() == 3);
a = eval(args[0], values);
- if (a == TRUE)
+ if (a == CONST_TRUE)
return eval(args[1], values);
- if (a == FALSE)
+ if (a == CONST_FALSE)
return eval(args[2], values);
return 0;
default:
@@ -375,6 +406,9 @@ bool ezSAT::eliminated(int)
void ezSAT::assume(int id)
{
+ addhash(__LINE__);
+ addhash(id);
+
if (id < 0)
{
assert(0 < -id && -id <= int(expressions.size()));
@@ -417,6 +451,10 @@ void ezSAT::assume(int id)
void ezSAT::add_clause(const std::vector<int> &args)
{
+ addhash(__LINE__);
+ for (auto arg : args)
+ addhash(arg);
+
cnfClauses.push_back(args);
cnfClausesCount++;
}
@@ -490,13 +528,13 @@ int ezSAT::bound(int id) const
std::string ezSAT::cnfLiteralInfo(int idx) const
{
- for (size_t i = 0; i < cnfLiteralVariables.size(); i++) {
+ for (int i = 0; i < int(cnfLiteralVariables.size()); i++) {
if (cnfLiteralVariables[i] == idx)
return to_string(i+1);
if (cnfLiteralVariables[i] == -idx)
return "NOT " + to_string(i+1);
}
- for (size_t i = 0; i < cnfExpressionVariables.size(); i++) {
+ for (int i = 0; i < int(cnfExpressionVariables.size()); i++) {
if (cnfExpressionVariables[i] == idx)
return to_string(-i-1);
if (cnfExpressionVariables[i] == -idx)
@@ -507,6 +545,10 @@ std::string ezSAT::cnfLiteralInfo(int idx) const
int ezSAT::bind(int id, bool auto_freeze)
{
+ addhash(__LINE__);
+ addhash(id);
+ addhash(auto_freeze);
+
if (id >= 0) {
assert(0 < id && id <= int(literals.size()));
cnfLiteralVariables.resize(literals.size());
@@ -516,9 +558,9 @@ int ezSAT::bind(int id, bool auto_freeze)
}
if (cnfLiteralVariables[id-1] == 0) {
cnfLiteralVariables[id-1] = ++cnfVariableCount;
- if (id == TRUE)
+ if (id == CONST_TRUE)
add_clause(+cnfLiteralVariables[id-1]);
- if (id == FALSE)
+ if (id == CONST_FALSE)
add_clause(-cnfLiteralVariables[id-1]);
}
return cnfLiteralVariables[id-1];
@@ -549,10 +591,13 @@ int ezSAT::bind(int id, bool auto_freeze)
while (args.size() > 1) {
std::vector<int> newArgs;
for (int i = 0; i < int(args.size()); i += 2)
- if (i+1 == int(args.size()))
+ if (i+1 == int(args.size())) {
newArgs.push_back(args[i]);
- else
- newArgs.push_back(OR(AND(args[i], NOT(args[i+1])), AND(NOT(args[i]), args[i+1])));
+ } else {
+ int sub1 = AND(args[i], NOT(args[i+1]));
+ int sub2 = AND(NOT(args[i]), args[i+1]);
+ newArgs.push_back(OR(sub1, sub2));
+ }
args.swap(newArgs);
}
idx = bind(args.at(0), false);
@@ -563,12 +608,16 @@ int ezSAT::bind(int id, bool auto_freeze)
std::vector<int> invArgs;
for (auto arg : args)
invArgs.push_back(NOT(arg));
- idx = bind(OR(expression(OpAnd, args), expression(OpAnd, invArgs)), false);
+ int sub1 = expression(OpAnd, args);
+ int sub2 = expression(OpAnd, invArgs);
+ idx = bind(OR(sub1, sub2), false);
goto assign_idx;
}
if (op == OpITE) {
- idx = bind(OR(AND(args[0], args[1]), AND(NOT(args[0]), args[2])), false);
+ int sub1 = AND(args[0], args[1]);
+ int sub2 = AND(NOT(args[0]), args[2]);
+ idx = bind(OR(sub1, sub2), false);
goto assign_idx;
}
@@ -638,7 +687,7 @@ std::vector<int> ezSAT::vec_const(const std::vector<bool> &bits)
{
std::vector<int> vec;
for (auto bit : bits)
- vec.push_back(bit ? TRUE : FALSE);
+ vec.push_back(bit ? CONST_TRUE : CONST_FALSE);
return vec;
}
@@ -646,7 +695,7 @@ std::vector<int> ezSAT::vec_const_signed(int64_t value, int numBits)
{
std::vector<int> vec;
for (int i = 0; i < numBits; i++)
- vec.push_back(((value >> i) & 1) != 0 ? TRUE : FALSE);
+ vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE);
return vec;
}
@@ -654,7 +703,7 @@ std::vector<int> ezSAT::vec_const_unsigned(uint64_t value, int numBits)
{
std::vector<int> vec;
for (int i = 0; i < numBits; i++)
- vec.push_back(((value >> i) & 1) != 0 ? TRUE : FALSE);
+ vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE);
return vec;
}
@@ -669,8 +718,9 @@ std::vector<int> ezSAT::vec_var(int numBits)
std::vector<int> ezSAT::vec_var(std::string name, int numBits)
{
std::vector<int> vec;
- for (int i = 0; i < numBits; i++)
- vec.push_back(VAR(name + "[" + std::to_string(i) + "]"));
+ for (int i = 0; i < numBits; i++) {
+ vec.push_back(VAR(name + my_int_to_string(i)));
+ }
return vec;
}
@@ -679,7 +729,7 @@ std::vector<int> ezSAT::vec_cast(const std::vector<int> &vec1, int toBits, bool
std::vector<int> vec;
for (int i = 0; i < toBits; i++)
if (i >= int(vec1.size()))
- vec.push_back(signExtend ? vec1.back() : FALSE);
+ vec.push_back(signExtend ? vec1.back() : CONST_FALSE);
else
vec.push_back(vec1[i]);
return vec;
@@ -807,7 +857,7 @@ std::vector<int> ezSAT::vec_add(const std::vector<int> &vec1, const std::vector<
{
assert(vec1.size() == vec2.size());
std::vector<int> vec(vec1.size());
- int carry = FALSE;
+ int carry = CONST_FALSE;
for (int i = 0; i < int(vec1.size()); i++)
fulladder(this, vec1[i], vec2[i], carry, carry, vec[i]);
@@ -831,7 +881,7 @@ std::vector<int> ezSAT::vec_sub(const std::vector<int> &vec1, const std::vector<
{
assert(vec1.size() == vec2.size());
std::vector<int> vec(vec1.size());
- int carry = TRUE;
+ int carry = CONST_TRUE;
for (int i = 0; i < int(vec1.size()); i++)
fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, vec[i]);
@@ -853,15 +903,15 @@ std::vector<int> ezSAT::vec_sub(const std::vector<int> &vec1, const std::vector<
std::vector<int> ezSAT::vec_neg(const std::vector<int> &vec)
{
- std::vector<int> zero(vec.size(), FALSE);
+ std::vector<int> zero(vec.size(), CONST_FALSE);
return vec_sub(zero, vec);
}
void ezSAT::vec_cmp(const std::vector<int> &vec1, const std::vector<int> &vec2, int &carry, int &overflow, int &sign, int &zero)
{
assert(vec1.size() == vec2.size());
- carry = TRUE;
- zero = FALSE;
+ carry = CONST_TRUE;
+ zero = CONST_FALSE;
for (int i = 0; i < int(vec1.size()); i++) {
overflow = carry;
fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, sign);
@@ -954,11 +1004,11 @@ std::vector<int> ezSAT::vec_shl(const std::vector<int> &vec1, int shift, bool si
for (int i = 0; i < int(vec1.size()); i++) {
int j = i-shift;
if (int(vec1.size()) <= j)
- vec.push_back(signExtend ? vec1.back() : FALSE);
+ vec.push_back(signExtend ? vec1.back() : CONST_FALSE);
else if (0 <= j)
vec.push_back(vec1[j]);
else
- vec.push_back(FALSE);
+ vec.push_back(CONST_FALSE);
}
return vec;
}
@@ -1005,10 +1055,10 @@ std::vector<int> ezSAT::vec_shift_right(const std::vector<int> &vec1, const std:
int vec2_bits = std::min(my_clog2(vec1.size()) + (vec2_signed ? 1 : 0), int(vec2.size()));
std::vector<int> overflow_bits(vec2.begin() + vec2_bits, vec2.end());
- int overflow_left = FALSE, overflow_right = FALSE;
+ int overflow_left = CONST_FALSE, overflow_right = CONST_FALSE;
if (vec2_signed) {
- int overflow = FALSE;
+ int overflow = CONST_FALSE;
for (auto bit : overflow_bits)
overflow = OR(overflow, XOR(bit, vec2[vec2_bits-1]));
overflow_left = AND(overflow, NOT(vec2.back()));
@@ -1046,7 +1096,7 @@ std::vector<int> ezSAT::vec_shift_right(const std::vector<int> &vec1, const std:
std::vector<int> ezSAT::vec_shift_left(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right)
{
// vec2_signed is not implemented in vec_shift_left() yet
- assert(vec2_signed == false);
+ if (vec2_signed) assert(vec2_signed == false);
int vec2_bits = std::min(my_clog2(vec1.size()), int(vec2.size()));
@@ -1105,7 +1155,7 @@ int64_t ezSAT::vec_model_get_signed(const std::vector<int> &modelExpressions, co
for (int i = 0; i < 64; i++) {
int j = i < int(vec1.size()) ? i : vec1.size()-1;
if (modelMap.at(vec1[j]))
- value |= 1 << i;
+ value |= int64_t(1) << i;
}
return value;
}
@@ -1119,7 +1169,7 @@ uint64_t ezSAT::vec_model_get_unsigned(const std::vector<int> &modelExpressions,
modelMap[modelExpressions[i]] = modelValues[i];
for (int i = 0; i < int(vec1.size()); i++)
if (modelMap.at(vec1[i]))
- value |= 1 << i;
+ value |= uint64_t(1) << i;
return value;
}
@@ -1195,7 +1245,7 @@ void ezSAT::printDIMACS(FILE *f, bool verbose) const
fprintf(f, "c mapping of variables to expressions:\n");
for (int i = 0; i < int(cnfExpressionVariables.size()); i++)
if (cnfExpressionVariables[i] != 0)
- fprintf(f, "c %*d: %s\n", digits, cnfExpressionVariables[i], to_string(-i-1).c_str());
+ fprintf(f, "c %*d: %d\n", digits, cnfExpressionVariables[i], -i-1);
if (mode_keep_cnf()) {
fprintf(f, "c\n");
@@ -1243,7 +1293,7 @@ static std::string expression2str(const std::pair<ezSAT::OpId, std::vector<int>>
}
text += ":";
for (auto it : data.second)
- text += " " + std::to_string(it);
+ text += " " + my_int_to_string(it);
return text;
}
@@ -1330,7 +1380,7 @@ int ezSAT::manyhot(const std::vector<int> &vec, int min_hot, int max_hot)
for (int i = -1; i < N; i++)
for (int j = -1; j < M; j++)
- x[std::pair<int,int>(i,j)] = j < 0 ? TRUE : i < 0 ? FALSE : literal();
+ x[std::pair<int,int>(i,j)] = j < 0 ? CONST_TRUE : i < 0 ? CONST_FALSE : literal();
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++) {
@@ -1358,7 +1408,7 @@ int ezSAT::manyhot(const std::vector<int> &vec, int min_hot, int max_hot)
int ezSAT::ordered(const std::vector<int> &vec1, const std::vector<int> &vec2, bool allow_equal)
{
std::vector<int> formula;
- int last_x = FALSE;
+ int last_x = CONST_FALSE;
assert(vec1.size() == vec2.size());
for (size_t i = 0; i < vec1.size(); i++)
@@ -1366,7 +1416,7 @@ int ezSAT::ordered(const std::vector<int> &vec1, const std::vector<int> &vec2, b
int a = vec1[i], b = vec2[i];
formula.push_back(OR(NOT(a), b, last_x));
- int next_x = i+1 < vec1.size() ? literal() : allow_equal ? FALSE : TRUE;
+ int next_x = i+1 < vec1.size() ? literal() : allow_equal ? CONST_FALSE : CONST_TRUE;
formula.push_back(OR(a, b, last_x, NOT(next_x)));
formula.push_back(OR(NOT(a), NOT(b), last_x, NOT(next_x)));
last_x = next_x;
diff --git a/libs/ezsat/ezsat.h b/libs/ezsat/ezsat.h
index c5ef6b0a..0faaa6b8 100644
--- a/libs/ezsat/ezsat.h
+++ b/libs/ezsat/ezsat.h
@@ -25,6 +25,7 @@
#include <vector>
#include <string>
#include <stdio.h>
+#include <stdint.h>
class ezSAT
{
@@ -34,7 +35,7 @@ class ezSAT
// the number zero is not used as valid token number and is used to encode
// unused parameters for the functions.
//
- // positive numbers are literals, with 1 = TRUE and 2 = FALSE;
+ // positive numbers are literals, with 1 = CONST_TRUE and 2 = CONST_FALSE;
//
// negative numbers are non-literal expressions. each expression is represented
// by an operator id and a list of expressions (literals or non-literals).
@@ -44,8 +45,8 @@ public:
OpNot, OpAnd, OpOr, OpXor, OpIFF, OpITE
};
- static const int TRUE;
- static const int FALSE;
+ static const int CONST_TRUE;
+ static const int CONST_FALSE;
private:
bool flag_keep_cnf;
@@ -82,6 +83,9 @@ public:
ezSAT();
virtual ~ezSAT();
+ unsigned int statehash;
+ void addhash(unsigned int);
+
void keep_cnf() { flag_keep_cnf = true; }
void non_incremental() { flag_non_incremental = true; }
@@ -159,6 +163,7 @@ public:
virtual void freeze(int id);
virtual bool eliminated(int idx);
void assume(int id);
+ void assume(int id, int context_id) { assume(OR(id, NOT(context_id))); }
int bind(int id, bool auto_freeze = true);
int bound(int id) const;
diff --git a/libs/sha1/sha1.cpp b/libs/sha1/sha1.cpp
index dc86b2ce..51bbd85c 100644
--- a/libs/sha1/sha1.cpp
+++ b/libs/sha1/sha1.cpp
@@ -1,74 +1,76 @@
/*
sha1.cpp - source code of
-
+
============
SHA-1 in C++
============
-
+
100% Public Domain.
-
+
Original C Code
-- Steve Reid <steve@edmweb.com>
Small changes to fit into bglibs
-- Bruce Guenter <bruce@untroubled.org>
Translation to simpler C++ Code
-- Volker Grabsch <vog@notjusthosting.com>
+ Fixing bugs and improving style
+ -- Eugene Hopkinson <slowriot at voxelstorm dot com>
*/
-
+
#include "sha1.h"
#include <sstream>
#include <iomanip>
#include <fstream>
-
+
/* Help macros */
#define SHA1_ROL(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits))))
#define SHA1_BLK(i) (block[i&15] = SHA1_ROL(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15],1))
-
+
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define SHA1_R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + block[i] + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + SHA1_BLK(i) + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R2(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0x6ed9eba1 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + SHA1_BLK(i) + 0x8f1bbcdc + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R4(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0xca62c1d6 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
-
+
SHA1::SHA1()
{
reset();
}
-
-
+
+
void SHA1::update(const std::string &s)
{
std::istringstream is(s);
update(is);
}
-
-
+
+
void SHA1::update(std::istream &is)
{
std::string rest_of_buffer;
read(is, rest_of_buffer, BLOCK_BYTES - buffer.size());
buffer += rest_of_buffer;
-
+
while (is)
{
- uint32 block[BLOCK_INTS];
+ uint32_t block[BLOCK_INTS];
buffer_to_block(buffer, block);
transform(block);
read(is, buffer, BLOCK_BYTES);
}
}
-
-
+
+
/*
* Add padding and return the message digest.
*/
-
+
std::string SHA1::final()
{
/* Total number of hashed bits */
- uint64 total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
-
+ uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
+
/* Padding */
buffer += 0x80;
unsigned int orig_size = buffer.size();
@@ -76,10 +78,10 @@ std::string SHA1::final()
{
buffer += (char)0x00;
}
-
- uint32 block[BLOCK_INTS];
+
+ uint32_t block[BLOCK_INTS];
buffer_to_block(buffer, block);
-
+
if (orig_size > BLOCK_BYTES - 8)
{
transform(block);
@@ -88,12 +90,12 @@ std::string SHA1::final()
block[i] = 0;
}
}
-
- /* Append total_bits, split this uint64 into two uint32 */
+
+ /* Append total_bits, split this uint64_t into two uint32_t */
block[BLOCK_INTS - 1] = total_bits;
block[BLOCK_INTS - 2] = (total_bits >> 32);
transform(block);
-
+
/* Hex std::string */
std::ostringstream result;
for (unsigned int i = 0; i < DIGEST_INTS; i++)
@@ -101,14 +103,14 @@ std::string SHA1::final()
result << std::hex << std::setfill('0') << std::setw(8);
result << (digest[i] & 0xffffffff);
}
-
+
/* Reset for next run */
reset();
-
+
return result.str();
}
-
-
+
+
std::string SHA1::from_file(const std::string &filename)
{
std::ifstream stream(filename.c_str(), std::ios::binary);
@@ -116,8 +118,8 @@ std::string SHA1::from_file(const std::string &filename)
checksum.update(stream);
return checksum.final();
}
-
-
+
+
void SHA1::reset()
{
/* SHA1 initialization constants */
@@ -126,27 +128,27 @@ void SHA1::reset()
digest[2] = 0x98badcfe;
digest[3] = 0x10325476;
digest[4] = 0xc3d2e1f0;
-
+
/* Reset counters */
transforms = 0;
buffer = "";
}
-
-
+
+
/*
* Hash a single 512-bit block. This is the core of the algorithm.
*/
-
-void SHA1::transform(uint32 block[BLOCK_BYTES])
+
+void SHA1::transform(uint32_t block[BLOCK_BYTES])
{
/* Copy digest[] to working vars */
- uint32 a = digest[0];
- uint32 b = digest[1];
- uint32 c = digest[2];
- uint32 d = digest[3];
- uint32 e = digest[4];
-
-
+ uint32_t a = digest[0];
+ uint32_t b = digest[1];
+ uint32_t c = digest[2];
+ uint32_t d = digest[3];
+ uint32_t e = digest[4];
+
+
/* 4 rounds of 20 operations each. Loop unrolled. */
SHA1_R0(a,b,c,d,e, 0);
SHA1_R0(e,a,b,c,d, 1);
@@ -228,22 +230,22 @@ void SHA1::transform(uint32 block[BLOCK_BYTES])
SHA1_R4(d,e,a,b,c,77);
SHA1_R4(c,d,e,a,b,78);
SHA1_R4(b,c,d,e,a,79);
-
+
/* Add the working vars back into digest[] */
digest[0] += a;
digest[1] += b;
digest[2] += c;
digest[3] += d;
digest[4] += e;
-
+
/* Count the number of transformations */
transforms++;
}
-
-
-void SHA1::buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES])
+
+
+void SHA1::buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS])
{
- /* Convert the std::string (byte buffer) to a uint32 array (MSB) */
+ /* Convert the std::string (byte buffer) to a uint32_t array (MSB) */
for (unsigned int i = 0; i < BLOCK_INTS; i++)
{
block[i] = (buffer[4*i+3] & 0xff)
@@ -252,16 +254,19 @@ void SHA1::buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES])
| (buffer[4*i+0] & 0xff)<<24;
}
}
-
-
-void SHA1::read(std::istream &is, std::string &s, int max)
+
+
+void SHA1::read(std::istream &is, std::string &s, size_t max)
{
- char sbuf[max];
+ char* sbuf = new char[max];
+
is.read(sbuf, max);
s.assign(sbuf, is.gcount());
+
+ delete[] sbuf;
}
-
-
+
+
std::string sha1(const std::string &string)
{
SHA1 checksum;
diff --git a/libs/sha1/sha1.h b/libs/sha1/sha1.h
index 15edee12..9f526376 100644
--- a/libs/sha1/sha1.h
+++ b/libs/sha1/sha1.h
@@ -1,27 +1,30 @@
/*
sha1.h - header of
-
+
============
SHA-1 in C++
============
-
+
100% Public Domain.
-
+
Original C Code
-- Steve Reid <steve@edmweb.com>
Small changes to fit into bglibs
-- Bruce Guenter <bruce@untroubled.org>
Translation to simpler C++ Code
-- Volker Grabsch <vog@notjusthosting.com>
+ Fixing bugs and improving style
+ -- Eugene Hopkinson <slowriot at voxelstorm dot com>
*/
-
+
#ifndef SHA1_HPP
#define SHA1_HPP
-
-
+
+
#include <iostream>
#include <string>
-
+#include <stdint.h>
+
class SHA1
{
public:
@@ -30,28 +33,25 @@ public:
void update(std::istream &is);
std::string final();
static std::string from_file(const std::string &filename);
-
+
private:
- typedef unsigned long int uint32; /* just needs to be at least 32bit */
- typedef unsigned long long uint64; /* just needs to be at least 64bit */
-
static const unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */
static const unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4;
-
- uint32 digest[DIGEST_INTS];
+
+ uint32_t digest[DIGEST_INTS];
std::string buffer;
- uint64 transforms;
-
+ uint64_t transforms;
+
void reset();
- void transform(uint32 block[BLOCK_BYTES]);
-
- static void buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES]);
- static void read(std::istream &is, std::string &s, int max);
+ void transform(uint32_t block[BLOCK_BYTES]);
+
+ static void read(std::istream &is, std::string &s, size_t max);
+ static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS]);
};
-
+
std::string sha1(const std::string &string);
-
-
-
+
+
+
#endif /* SHA1_HPP */
diff --git a/libs/subcircuit/subcircuit.cc b/libs/subcircuit/subcircuit.cc
index 84f23d63..cf14df0a 100644
--- a/libs/subcircuit/subcircuit.cc
+++ b/libs/subcircuit/subcircuit.cc
@@ -34,6 +34,7 @@
using namespace SubCircuit;
+#ifndef _YOSYS_
static std::string my_stringf(const char *fmt, ...)
{
std::string string;
@@ -52,6 +53,9 @@ static std::string my_stringf(const char *fmt, ...)
return string;
}
+#else
+# define my_stringf YOSYS_NAMESPACE_PREFIX stringf
+#endif
SubCircuit::Graph::Graph(const Graph &other, const std::vector<std::string> &otherNodes)
{
diff --git a/manual/APPNOTE_010_Verilog_to_BLIF.tex b/manual/APPNOTE_010_Verilog_to_BLIF.tex
index 9ee87bc4..0f521fb0 100644
--- a/manual/APPNOTE_010_Verilog_to_BLIF.tex
+++ b/manual/APPNOTE_010_Verilog_to_BLIF.tex
@@ -61,7 +61,7 @@ to easily create complex designs from small HDL code. It is the preferred
method of design entry for many designers\footnote{The other half prefers VHDL,
a very different but -- of course -- equally powerful language.}.
-The Berkeley Logic Interchange Format (BLIF) is a simple file format for
+The Berkeley Logic Interchange Format (BLIF) \cite{blif} is a simple file format for
exchanging sequential logic between programs. It is easy to generate and
easy to parse and is therefore the preferred method of design entry for
many authors of logic synthesis tools.
@@ -456,6 +456,10 @@ Conor Santifort. Amber ARM-compatible core. \\
Berkeley Logic Synthesis and Verification Group. ABC: A System for Sequential Synthesis and Verification. \\
\url{http://www.eecs.berkeley.edu/~alanmi/abc/}
+\bibitem{blif}
+Berkeley Logic Interchange Format (BLIF) \\
+\url{http://vlsi.colorado.edu/~vis/blif.ps}
+
\end{thebibliography}
diff --git a/manual/APPNOTE_011_Design_Investigation/cmos_00.dot b/manual/APPNOTE_011_Design_Investigation/cmos_00.dot
index 85ca7849..49c63008 100644
--- a/manual/APPNOTE_011_Design_Investigation/cmos_00.dot
+++ b/manual/APPNOTE_011_Design_Investigation/cmos_00.dot
@@ -31,4 +31,4 @@ n5:e -> c11:p7:w [color="black", label=""];
n6:e -> x0:s0:w [color="black", label=""];
n6:e -> x1:s0:w [color="black", label=""];
n6:e -> x2:s0:w [color="black", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/cmos_01.dot b/manual/APPNOTE_011_Design_Investigation/cmos_01.dot
index de9af170..ea6f4403 100644
--- a/manual/APPNOTE_011_Design_Investigation/cmos_01.dot
+++ b/manual/APPNOTE_011_Design_Investigation/cmos_01.dot
@@ -20,4 +20,4 @@ n5:e -> c12:p8:w [color="black", label=""];
c15:p10:e -> n6:w [color="black", label=""];
c14:p10:e -> n7:w [color="black", label=""];
n7:e -> c15:p9:w [color="black", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/example_00.dot b/manual/APPNOTE_011_Design_Investigation/example_00.dot
index b38862c4..1e23ed0e 100644
--- a/manual/APPNOTE_011_Design_Investigation/example_00.dot
+++ b/manual/APPNOTE_011_Design_Investigation/example_00.dot
@@ -20,4 +20,4 @@ n7:e -> p1:w [color="black", label=""];
p1:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
n8:e -> p1:w [color="black", style="setlinewidth(3)", label=""];
v0:e -> c14:p9:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/example_01.dot b/manual/APPNOTE_011_Design_Investigation/example_01.dot
index e2e3f02d..e89292b5 100644
--- a/manual/APPNOTE_011_Design_Investigation/example_01.dot
+++ b/manual/APPNOTE_011_Design_Investigation/example_01.dot
@@ -30,4 +30,4 @@ n8:e -> c21:p19:w [color="black", label=""];
n8:e -> x1:w:w [color="black", label=""];
n9:e -> c18:p15:w [color="black", label=""];
v0:e -> c21:p11:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/example_02.dot b/manual/APPNOTE_011_Design_Investigation/example_02.dot
index 4b57f89c..f950ed2e 100644
--- a/manual/APPNOTE_011_Design_Investigation/example_02.dot
+++ b/manual/APPNOTE_011_Design_Investigation/example_02.dot
@@ -17,4 +17,4 @@ n5:e -> c17:p16:w [color="black", label=""];
n6:e -> c15:p12:w [color="black", label=""];
c15:p14:e -> n7:w [color="black", style="setlinewidth(3)", label=""];
n7:e -> c17:p8:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/example_03.dot b/manual/APPNOTE_011_Design_Investigation/example_03.dot
index 6c00c29a..e19d24af 100644
--- a/manual/APPNOTE_011_Design_Investigation/example_03.dot
+++ b/manual/APPNOTE_011_Design_Investigation/example_03.dot
@@ -8,4 +8,4 @@ c4 [ shape=record, label="{{<p1> A|<p2> B}|$2\n$add|{<p3> Y}}" ];
v0:e -> c4:p1:w [color="black", label=""];
v1:e -> c4:p2:w [color="black", label=""];
c4:p3:e -> v2:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/memdemo_00.dot b/manual/APPNOTE_011_Design_Investigation/memdemo_00.dot
index 9e81edbc..0336a9aa 100644
--- a/manual/APPNOTE_011_Design_Investigation/memdemo_00.dot
+++ b/manual/APPNOTE_011_Design_Investigation/memdemo_00.dot
@@ -135,4 +135,4 @@ v6:e -> c47:p34:w [color="black", label=""];
v7:e -> c48:p33:w [color="black", style="setlinewidth(3)", label=""];
v8:e -> c49:p33:w [color="black", style="setlinewidth(3)", label=""];
v9:e -> c50:p33:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/memdemo_01.dot b/manual/APPNOTE_011_Design_Investigation/memdemo_01.dot
index bbd7fcc6..2ad92c78 100644
--- a/manual/APPNOTE_011_Design_Investigation/memdemo_01.dot
+++ b/manual/APPNOTE_011_Design_Investigation/memdemo_01.dot
@@ -26,4 +26,4 @@ v0:e -> c13:p11:w [color="black", label=""];
v1:e -> c14:p11:w [color="black", label=""];
v2:e -> c15:p11:w [color="black", label=""];
v3:e -> c19:p16:w [color="black", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/splice.dot b/manual/APPNOTE_011_Design_Investigation/splice.dot
index 1bcd55b4..4657feed 100644
--- a/manual/APPNOTE_011_Design_Investigation/splice.dot
+++ b/manual/APPNOTE_011_Design_Investigation/splice.dot
@@ -36,4 +36,4 @@ x1:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
x3:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
x3:s1:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
x6:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/submod_00.dot b/manual/APPNOTE_011_Design_Investigation/submod_00.dot
index 4567dfb4..2e55268e 100644
--- a/manual/APPNOTE_011_Design_Investigation/submod_00.dot
+++ b/manual/APPNOTE_011_Design_Investigation/submod_00.dot
@@ -42,4 +42,4 @@ c21:p8:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
n8:e -> c20:p8:w [color="black", style="setlinewidth(3)", label=""];
c21:p9:e -> n9:w [color="black", style="setlinewidth(3)", label=""];
n9:e -> c20:p9:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/submod_01.dot b/manual/APPNOTE_011_Design_Investigation/submod_01.dot
index b1daae23..f8f8c008 100644
--- a/manual/APPNOTE_011_Design_Investigation/submod_01.dot
+++ b/manual/APPNOTE_011_Design_Investigation/submod_01.dot
@@ -84,4 +84,4 @@ v4:e -> c35:p24:w [color="black", style="setlinewidth(3)", label=""];
v5:e -> c36:p24:w [color="black", style="setlinewidth(3)", label=""];
v6:e -> c37:p24:w [color="black", style="setlinewidth(3)", label=""];
v7:e -> c38:p24:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/submod_02.dot b/manual/APPNOTE_011_Design_Investigation/submod_02.dot
index 68266db9..1a672c48 100644
--- a/manual/APPNOTE_011_Design_Investigation/submod_02.dot
+++ b/manual/APPNOTE_011_Design_Investigation/submod_02.dot
@@ -30,4 +30,4 @@ n8:e -> c17:p12:w [color="black", style="setlinewidth(3)", label=""];
n9:e -> x0:s0:w [color="black", label=""];
n9:e -> x1:s0:w [color="black", label=""];
n9:e -> x2:s0:w [color="black", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/submod_03.dot b/manual/APPNOTE_011_Design_Investigation/submod_03.dot
index 92ef5759..0dbbe3ba 100644
--- a/manual/APPNOTE_011_Design_Investigation/submod_03.dot
+++ b/manual/APPNOTE_011_Design_Investigation/submod_03.dot
@@ -23,4 +23,4 @@ x1:s1:e -> n5:w [color="black", style="setlinewidth(3)", label=""];
n6:e -> x2:s1:w [color="black", style="setlinewidth(3)", label=""];
n7:e -> x2:s0:w [color="black", style="setlinewidth(3)", label=""];
v0:e -> c13:p8:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/sumprod_00.dot b/manual/APPNOTE_011_Design_Investigation/sumprod_00.dot
index 6f9b7d3d..06522dcc 100644
--- a/manual/APPNOTE_011_Design_Investigation/sumprod_00.dot
+++ b/manual/APPNOTE_011_Design_Investigation/sumprod_00.dot
@@ -15,4 +15,4 @@ c4:p3:e -> v2:w [color="black", style="setlinewidth(3)", label=""];
v3:e -> c5:p1:w [color="black", style="setlinewidth(3)", label=""];
v4:e -> c5:p2:w [color="black", style="setlinewidth(3)", label=""];
c5:p3:e -> v5:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/sumprod_01.dot b/manual/APPNOTE_011_Design_Investigation/sumprod_01.dot
index d0252270..aefe7a6d 100644
--- a/manual/APPNOTE_011_Design_Investigation/sumprod_01.dot
+++ b/manual/APPNOTE_011_Design_Investigation/sumprod_01.dot
@@ -12,4 +12,4 @@ n2:e -> c9:p6:w [color="black", style="setlinewidth(3)", label=""];
n3:e -> c9:p7:w [color="black", style="setlinewidth(3)", label=""];
n4:e -> c10:p7:w [color="black", style="setlinewidth(3)", label=""];
c10:p8:e -> n5:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/sumprod_02.dot b/manual/APPNOTE_011_Design_Investigation/sumprod_02.dot
index af87651b..4646c994 100644
--- a/manual/APPNOTE_011_Design_Investigation/sumprod_02.dot
+++ b/manual/APPNOTE_011_Design_Investigation/sumprod_02.dot
@@ -2,4 +2,4 @@ digraph "sumprod" {
rankdir="LR";
remincross=true;
n1 [ shape=octagon, label="prod", color="black", fontcolor="black" ];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/sumprod_03.dot b/manual/APPNOTE_011_Design_Investigation/sumprod_03.dot
index 21155135..dcfea2b5 100644
--- a/manual/APPNOTE_011_Design_Investigation/sumprod_03.dot
+++ b/manual/APPNOTE_011_Design_Investigation/sumprod_03.dot
@@ -8,4 +8,4 @@ c5 [ shape=record, label="{{<p2> A|<p3> B}|$4\n$mul|{<p4> Y}}" ];
c5:p4:e -> n1:w [color="black", style="setlinewidth(3)", label=""];
v0:e -> c5:p2:w [color="black", style="setlinewidth(3)", label=""];
v1:e -> c5:p3:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/sumprod_04.dot b/manual/APPNOTE_011_Design_Investigation/sumprod_04.dot
index 5223577e..e77c41aa 100644
--- a/manual/APPNOTE_011_Design_Investigation/sumprod_04.dot
+++ b/manual/APPNOTE_011_Design_Investigation/sumprod_04.dot
@@ -8,4 +8,4 @@ n1 [ shape=diamond, label="$3_Y" ];
n1:e -> c7:p4:w [color="black", style="setlinewidth(3)", label=""];
n2:e -> c7:p5:w [color="black", style="setlinewidth(3)", label=""];
c7:p6:e -> n3:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/APPNOTE_011_Design_Investigation/sumprod_05.dot b/manual/APPNOTE_011_Design_Investigation/sumprod_05.dot
index 45d00134..b5444129 100644
--- a/manual/APPNOTE_011_Design_Investigation/sumprod_05.dot
+++ b/manual/APPNOTE_011_Design_Investigation/sumprod_05.dot
@@ -12,4 +12,4 @@ n2:e -> c8:p5:w [color="black", style="setlinewidth(3)", label=""];
c8:p6:e -> n3:w [color="black", style="setlinewidth(3)", label=""];
v0:e -> c7:p4:w [color="black", style="setlinewidth(3)", label=""];
v1:e -> c7:p5:w [color="black", style="setlinewidth(3)", label=""];
-};
+}
diff --git a/manual/CHAPTER_Appnotes.tex b/manual/CHAPTER_Appnotes.tex
index 959aabd2..2abfa85d 100644
--- a/manual/CHAPTER_Appnotes.tex
+++ b/manual/CHAPTER_Appnotes.tex
@@ -2,11 +2,24 @@
\chapter{Application Notes}
\label{chapter:appnotes}
-\begin{fixme}
-This appendix will cover some typical use-cases of Yosys in the form of application notes.
-\end{fixme}
+% \begin{fixme}
+% This appendix will cover some typical use-cases of Yosys in the form of application notes.
+% \end{fixme}
+%
+% \section{Synthesizing using a Cell Library in Liberty Format}
+% \section{Reverse Engeneering the MOS6502 from an NMOS Transistor Netlist}
+% \section{Reconfigurable Coarse-Grain Synthesis using Intersynth}
-\section{Synthesizing using a Cell Library in Liberty Format}
-\section{Reverse Engeneering the MOS6502 from an NMOS Transistor Netlist}
-\section{Reconfigurable Coarse-Grain Synthesis using Intersynth}
+This appendix contains copies of the Yosys application notes.
+
+\begin{itemize}
+\item Yosys AppNote 010: Converting Verilog to BLIF \dotfill Page \pageref{app:010} \hskip2cm\null
+\item Yosys AppNote 011: Interactive Design Investigation \dotfill Page \pageref{app:011} \hskip2cm\null
+\end{itemize}
+
+\eject\label{app:010}
+\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_010_Verilog_to_BLIF.pdf}
+
+\eject\label{app:011}
+\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_011_Design_Investigation.pdf}
diff --git a/manual/CHAPTER_Auxprogs.tex b/manual/CHAPTER_Auxprogs.tex
index cce3741c..a0089382 100644
--- a/manual/CHAPTER_Auxprogs.tex
+++ b/manual/CHAPTER_Auxprogs.tex
@@ -17,3 +17,9 @@ The {\tt yosys-filterlib} tool is a small utility that can be used to strip
or extract information from a Liberty file. See Sec.~\ref{sec:techmap_extern}
for details.
+\section{yosys-abc}
+
+This is a unmodified copy of ABC \citeweblink{ABC}. Not all versions of Yosys
+work with all versions of ABC. So Yosys comes with its own yosys-abc to avoid
+compatibility issues between the two.
+
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index 64d3633e..c9bf978a 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -357,7 +357,7 @@ Add a brief description of the {\tt \$fsm} cell type.
For gate level logic networks, fixed function single bit cells are used that do
not provide any parameters.
-Simulation models for these cells can be found in the file {\tt techlibs/common/stdcells\_sim.v} in the Yosys
+Simulation models for these cells can be found in the file {\tt techlibs/common/simcells.v} in the Yosys
source tree.
\begin{table}[t]
@@ -417,7 +417,7 @@ pass. The combinatorial logic cells can be mapped to physical cells from a Liber
using the {\tt abc} pass.
\begin{fixme}
-Add information about {\tt \$assert} cells.
+Add information about {\tt \$assert}, {\tt \$assume}, and {\tt \$equiv} cells.
\end{fixme}
\begin{fixme}
@@ -429,6 +429,14 @@ Add information about {\tt \$alu}, {\tt \$macc}, {\tt \$fa}, and {\tt \$lcu} cel
\end{fixme}
\begin{fixme}
+Add information about {\tt \$dffe}, {\tt \$dffsr}, {\tt \$dlatch}, and {\tt \$dlatchsr} cells.
+\end{fixme}
+
+\begin{fixme}
+Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells.
+\end{fixme}
+
+\begin{fixme}
Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
\end{fixme}
diff --git a/manual/CHAPTER_Prog.tex b/manual/CHAPTER_Prog.tex
index 3918594a..3cbc95a1 100644
--- a/manual/CHAPTER_Prog.tex
+++ b/manual/CHAPTER_Prog.tex
@@ -2,16 +2,21 @@
\chapter{Programming Yosys Extensions}
\label{chapter:prog}
-\begin{fixme}
-This chapter will contain a guided tour to the Yosys APIs and conclude
-with an example module.
-\end{fixme}
+This chapter contains some bits and pieces of information about programming
+yosys extensions. Also consult the section on programming in the ``Yosys
+Presentation'' (can be downloaded from the Yosys website as PDF) and don't
+be afraid to ask questions on the Yosys Subreddit.
-\section{Programming with RTLIL}
-\section{Internal Utility Libraries}
-\section{Loadable Modules}
+\section{The ``CodingReadme'' File}
+
+The following is an excerpt of the {\tt CodingReadme} file from the Yosys source tree.
+
+\lstinputlisting[title=CodingReadme,rangeprefix=--,rangesuffix=--,includerangemarker=false,linerange=snip-snap,numbers=left,frame=single]{../CodingReadme}
+
+\section{The ``stubsnets'' Example Module}
+
+The following is the complete code of the ``stubsnets'' example module. It is included in the Yosys source distribution as {\tt manual/CHAPTER\_Prog/stubnets.cc}.
-\section{Example Module}
\lstinputlisting[title=stubnets.cc,numbers=left,frame=single,language=C++]{CHAPTER_Prog/stubnets.cc}
diff --git a/manual/CHAPTER_Prog/.gitignore b/manual/CHAPTER_Prog/.gitignore
new file mode 100644
index 00000000..fa83c321
--- /dev/null
+++ b/manual/CHAPTER_Prog/.gitignore
@@ -0,0 +1,3 @@
+stubnets.so
+stubnets.d
+*.log
diff --git a/manual/CHAPTER_Prog/stubnets.cc b/manual/CHAPTER_Prog/stubnets.cc
index ef4b1245..4849c6a7 100644
--- a/manual/CHAPTER_Prog/stubnets.cc
+++ b/manual/CHAPTER_Prog/stubnets.cc
@@ -5,15 +5,16 @@
// binary, for any purpose, commercial or non-commercial, and by any
// means.
-#include "kernel/rtlil.h"
-#include "kernel/register.h"
+#include "kernel/yosys.h"
#include "kernel/sigtools.h"
-#include "kernel/log.h"
#include <string>
#include <map>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
// this function is called for each module in the design
static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool report_bits)
{
@@ -62,7 +63,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
// for each bit (unless it is a constant):
// check if it is used at least two times and add to stub_bits otherwise
- for (int i = 0; i < SIZE(sig); i++)
+ for (int i = 0; i < GetSize(sig); i++)
if (sig[i].wire != NULL && (bit_usage_count[sig[i]] + usage_offset) < 2)
stub_bits.insert(i);
@@ -72,7 +73,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
// report stub bits and/or stub wires, don't report single bits
// if called with report_bits set to false.
- if (SIZE(stub_bits) == SIZE(sig)) {
+ if (GetSize(stub_bits) == GetSize(sig)) {
log(" found stub wire: %s\n", RTLIL::id2cstr(wire->name));
} else {
if (!report_bits)
@@ -126,3 +127,4 @@ struct StubnetsPass : public Pass {
}
} StubnetsPass;
+PRIVATE_NAMESPACE_END
diff --git a/manual/PRESENTATION_ExAdv.tex b/manual/PRESENTATION_ExAdv.tex
index 471516b4..74350091 100644
--- a/manual/PRESENTATION_ExAdv.tex
+++ b/manual/PRESENTATION_ExAdv.tex
@@ -790,7 +790,7 @@ Unwrap in {\tt test2}:
\hfil\begin{tikzpicture}
\node at (0,0) {\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2d.pdf}};
-\node at (0,-4) {\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2e.pdf}};
+\node at (0,-4) {\includegraphics[width=8cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2e.pdf}};
\node at (1,-1.7) {\begin{lstlisting}[linewidth=5.5cm, frame=single, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
techmap -map macc_xilinx_unwrap_map.v ;;
\end{lstlisting}};
diff --git a/manual/PRESENTATION_ExOth/axis_master.v b/manual/PRESENTATION_ExOth/axis_master.v
index 25a1feee..fe9008ad 100644
--- a/manual/PRESENTATION_ExOth/axis_master.v
+++ b/manual/PRESENTATION_ExOth/axis_master.v
@@ -13,7 +13,7 @@ module axis_master(aclk, aresetn, tvalid, tready, tdata);
if (tvalid && tready)
tvalid <= 0;
if (!tvalid || !tready) begin
- // ^- should be not inverted!
+ // ^- should not be inverted!
state = state ^ state << 13;
state = state ^ state >> 7;
state = state ^ state << 17;
diff --git a/manual/PRESENTATION_ExSyn.tex b/manual/PRESENTATION_ExSyn.tex
index 80398229..b7d6b8a6 100644
--- a/manual/PRESENTATION_ExSyn.tex
+++ b/manual/PRESENTATION_ExSyn.tex
@@ -268,7 +268,7 @@ memory -nomap; techmap -map my_memory_map.v; memory_map
\end{frame}
\begin{frame}[t, fragile]{\subsecname{} -- Example 1/2}
-\vbox to 0cm{\includegraphics[width=\linewidth,trim=0cm 0cm 0cm -10cm]{PRESENTATION_ExSyn/memory_01.pdf}\vss}
+\vbox to 0cm{\includegraphics[width=0.7\linewidth,trim=0cm 0cm 0cm -10cm]{PRESENTATION_ExSyn/memory_01.pdf}\vss}
\vskip-1cm
\begin{columns}
\column[t]{5cm}
@@ -455,7 +455,7 @@ read_verilog -D WITH_MULT cpu_alu.v
hierarchy -check -top cpu_top
# high-level synthesis
-proc; opt; memory -nomap;; fsm; opt
+proc; opt; fsm;; memory -nomap; opt
# substitute block rams
techmap -map map_rams.v
@@ -497,7 +497,7 @@ the next part (Section 3, ``Advanced Synthesis'') of this presentation.}
\item Yosys provides commands for each phase of the synthesis.
\item Each command solves a (more or less) simple problem.
\item Complex commands are often only front-ends to simple commands.
-\item {\tt proc; opt; memory; opt; fsm; opt; techmap; opt; abc;;}
+\item {\tt proc; opt; fsm; opt; memory; opt; techmap; opt; abc;;}
\end{itemize}
\bigskip
diff --git a/manual/PRESENTATION_Intro.tex b/manual/PRESENTATION_Intro.tex
index 7697266d..5aeebd9f 100644
--- a/manual/PRESENTATION_Intro.tex
+++ b/manual/PRESENTATION_Intro.tex
@@ -277,7 +277,7 @@ Direct link to the files: \\ \footnotesize
\medskip
{\color{YosysGreen}\# the high-level stuff}\\
-\boxalert<3>{proc}; \boxalert<4>{opt}; \boxalert<5>{memory}; \boxalert<6>{opt}; \boxalert<7>{fsm}; \boxalert<8>{opt}
+\boxalert<3>{proc}; \boxalert<4>{opt}; \boxalert<5>{fsm}; \boxalert<6>{opt}; \boxalert<7>{memory}; \boxalert<8>{opt}
\medskip
{\color{YosysGreen}\# mapping to internal cell library}\\
@@ -308,9 +308,9 @@ Direct link to the files: \\ \footnotesize
\only<2>{hierarchy -check -top counter}%
\only<3>{proc}%
\only<4>{opt}%
-\only<5>{memory}%
+\only<5>{fsm}%
\only<6>{opt}%
-\only<7>{fsm}%
+\only<7>{memory}%
\only<8>{opt}%
\only<9>{techmap}%
\only<10>{opt}%
@@ -333,13 +333,13 @@ Direct link to the files: \\ \footnotesize
Perform some basic optimizations and cleanups.
}%
\only<5>{
- Analyze memories and create circuits to implement them.
+ Analyze and optimize finite state machines.
}%
\only<6>{
Perform some basic optimizations and cleanups.
}%
\only<7>{
- Analyze and optimize finite state machines.
+ Analyze memories and create circuits to implement them.
}%
\only<8>{
Perform some basic optimizations and cleanups.
@@ -398,7 +398,7 @@ hierarchy -check -top counter
\begin{frame}[t, fragile]{\subsecname{} -- Step 2/4}
\begin{verbatim}
-proc; opt; memory; opt; fsm; opt
+proc; opt; fsm; opt; memory; opt
\end{verbatim}
\vfill
@@ -411,7 +411,7 @@ techmap; opt
\end{verbatim}
\vfill
-\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_Intro/counter_02.pdf}
+\includegraphics[width=\linewidth,trim=0 0cm 0 2cm]{PRESENTATION_Intro/counter_02.pdf}
\end{frame}
\begin{frame}[t, fragile]{\subsecname{} -- Step 4/4}
@@ -427,6 +427,48 @@ clean
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{The synth command}
+
+\begin{frame}[fragile]{\subsecname{}}
+Yosys contains a default (recommended example) synthesis script in form of the
+{\tt synth} command. The following commands are executed by this synthesis command:
+
+\begin{columns}
+\column[t]{5cm}
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+begin:
+ hierarchy -check [-top <top>]
+
+coarse:
+ proc
+ opt
+ wreduce
+ alumacc
+ share
+ opt
+ fsm
+ opt -fast
+ memory -nomap
+ opt_clean
+\end{lstlisting}
+\column[t]{5cm}
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+fine:
+ opt -fast -full
+ memory_map
+ opt -full
+ techmap
+ opt -fast
+
+abc:
+ abc -fast
+ opt -fast
+\end{lstlisting}
+\end{columns}
+\end{frame}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
\subsection{Yosys Commands}
\begin{frame}[fragile]{\subsecname{} 1/3 \hspace{0pt plus 1 filll} (excerpt)}
@@ -500,6 +542,7 @@ Commands for writing the results:
\bigskip
Script-Commands for standard synthesis tasks:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
+ synth # generic synthesis script
synth_xilinx # synthesis for Xilinx FPGAs
\end{lstlisting}
@@ -603,12 +646,8 @@ endmodule
\begin{frame}{\subsecname}
\begin{itemize}
-\item Multi-dimensional arrays (memories)
-\item Writing to arrays using bit- and part-selects (todo for 0.4.0)
-\item The wor/wand wire types (maybe for 0.4.0)
\item Tri-state logic
-
-\bigskip
+\item The wor/wand wire types (maybe for 0.5)
\item Latched logic (is synthesized as logic with feedback loops)
\item Some non-synthesizable features that should be ignored in synthesis are not supported by the parser and cause a parser error (file a bug report if you encounter this problem)
\end{itemize}
@@ -813,10 +852,12 @@ control logic because it is simpler than setting up a commercial flow.
\item When building on other Linux distributions:
\begin{itemize}
\item Needs compiler with some C++11 support
+\item See README file for build instructions
\item Post to the subreddit if you get stuck
\end{itemize}
\item Ported to OS X (Darwin) and OpenBSD
-\item No win32 support (yet)
+\item Native win32 build with VisualStudio
+\item Cross win32 build with MXE
\end{itemize}
\end{frame}
diff --git a/manual/PRESENTATION_Prog.tex b/manual/PRESENTATION_Prog.tex
index 590451be..96189e55 100644
--- a/manual/PRESENTATION_Prog.tex
+++ b/manual/PRESENTATION_Prog.tex
@@ -89,12 +89,13 @@ left with a much simpler version of RTLIL:
\bigskip
Many commands simply choose to only work on this simpler version:
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
-if (module->processes.size() != 0 || module->memories.size() != 0)
- log_error("This command does not operate on modules with processes "
- "and/or memories! Run 'proc' and 'memory' first.\n");
+for (RTLIL::Module *module : design->selected_modules() {
+ if (module->has_memories_warn() || module->has_processes_warn())
+ continue;
+ ....
+}
\end{lstlisting}
-\bigskip
For simplicity we only discuss this version of RTLIL in this presentation.
\end{frame}
@@ -122,8 +123,9 @@ has been executed.
\subsection{The RTLIL Data Structures}
\begin{frame}{\subsecname}
-The RTLIL data structures are simple structs utilizing C++ {\tt std::}
-containers.
+The RTLIL data structures are simple structs utilizing {\tt pool<>} and
+{\tt dict<>} containers (drop-in replacementments for {\tt
+std::unordered\_set<>} and {\tt std::unordered\_map<>}).
\bigskip
\begin{itemize}
@@ -145,7 +147,9 @@ See {\tt yosys/kernel/rtlil.h} for details.
\subsubsection{RTLIL::IdString}
\begin{frame}{\subsubsecname}{}
-{\tt RTLIL::IdString} is a simple wrapper for {\tt std::string}. It is used for names of RTLIL objects.
+{\tt RTLIL::IdString} in many ways behave like a {\tt std::string}. It is used
+for names of RTLIL objects. Internally a RTLIL::IdString object is only a
+single integer.
\medskip
The first character of a {\tt RTLIL::IdString} specifies if the name is {\it public\/} or {\it private\/}:
@@ -168,25 +172,25 @@ Use the {\tt NEW\_ID} macro to create a new unique private name.
\begin{frame}[t, fragile]{\subsubsecname}
The {\tt RTLIL::Design} and {\tt RTLIL::Module} structs are the top-level RTLIL
-data structures.
-
-Yosys always operates on one active design, but can hold many designs in memory.
+data structures. Yosys always operates on one active design, but can hold many designs in memory.
\bigskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
struct RTLIL::Design {
- std::map<RTLIL::IdString, RTLIL::Module*> modules;
+ dict<RTLIL::IdString, RTLIL::Module*> modules_;
...
};
struct RTLIL::Module {
RTLIL::IdString name;
- std::map<RTLIL::IdString, RTLIL::Wire*> wires;
- std::map<RTLIL::IdString, RTLIL::Cell*> cells;
- std::vector<RTLIL::SigSig> connections;
+ dict<RTLIL::IdString, RTLIL::Wire*> wires_;
+ dict<RTLIL::IdString, RTLIL::Cell*> cells_;
+ std::vector<RTLIL::SigSig> connections_;
...
};
\end{lstlisting}
+
+(Use the various accessor functions instead of directly working with the {\tt *\_} members.)
\end{frame}
\subsubsection{The RTLIL::Wire Structure}
@@ -251,21 +255,22 @@ constants are part of the RTLIL representation itself.
\begin{frame}[t, fragile]{\subsubsecname}
The {\tt RTLIL::SigSpec} struct represents a signal vector. Each bit can either be a bit from a wire
-or a constant value. Consecutive bits from a wire or consecutive constant bits are consolidated into
-a {\tt RTLIL::SigChunk}:
+or a constant value.
\bigskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-struct RTLIL::SigChunk {
+struct RTLIL::SigBit
+{
RTLIL::Wire *wire;
- RTLIL::Const data; // only used if wire == NULL
- int width, offset;
+ union {
+ RTLIL::State data; // used if wire == NULL
+ int offset; // used if wire != NULL
+ };
...
};
struct RTLIL::SigSpec {
- std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
- int width;
+ std::vector<RTLIL::SigBit> bits_; // LSB at index 0
...
};
\end{lstlisting}
@@ -289,8 +294,8 @@ instances:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
struct RTLIL::Cell {
RTLIL::IdString name, type;
- std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
- std::map<RTLIL::IdString, RTLIL::Const> parameters;
+ dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
+ dict<RTLIL::IdString, RTLIL::Const> parameters;
...
};
\end{lstlisting}
@@ -345,7 +350,7 @@ typedef std::pair<RTLIL::SigSpec, RTLIL::SigSpec> RTLIL::SigSig;
struct RTLIL::Module {
...
- std::vector<RTLIL::SigSig> connections;
+ std::vector<RTLIL::SigSig> connections_;
...
};
\end{lstlisting}
@@ -354,8 +359,8 @@ struct RTLIL::Module {
{\tt RTLIL::SigSig::first} is the driven signal and {\tt RTLIL::SigSig::second} is the driving signal.
Example usage (setting wire {\tt foo} to value {\tt 42}):
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-module->connections.push_back(RTLIL::SigSig(module->wires.at("\\foo"),
- RTLIL::SigSpec(42, module->wires.at("\\foo")->width)));
+module->connect(module->wire("\\foo"),
+ RTLIL::SigSpec(42, module->wire("\\foo")->width));
\end{lstlisting}
\end{frame}
@@ -378,17 +383,19 @@ endmodule
RTLIL::Module *module = new RTLIL::Module;
module->name = "\\absval";
-RTLIL::Wire *a = module->new_wire(4, "\\a");
+RTLIL::Wire *a = module->addWire("\\a", 4);
a->port_input = true;
a->port_id = 1;
-RTLIL::Wire *y = module->new_wire(4, "\\y");
+RTLIL::Wire *y = module->addWire("\\y", 4);
y->port_output = true;
y->port_id = 2;
-RTLIL::Wire *a_inv = module->new_wire(4, NEW_ID);
+RTLIL::Wire *a_inv = module->addWire(NEW_ID, 4);
module->addNeg(NEW_ID, a, a_inv, true);
module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 1, 3), y);
+
+module->fixup_ports();
\end{lstlisting}
\end{frame}
@@ -431,8 +438,8 @@ In this case {\tt a}, {\tt x}, and {\tt y} are all different names for the same
\smallskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-RTLIL::SigSpec a(module->wires.at("\\a")), x(module->wires.at("\\x")),
- y(module->wires.at("\\y"));
+RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")),
+ y(module->wire("\\y"));
log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"
\end{lstlisting}
@@ -462,9 +469,9 @@ log("Mapped signal x: %s\n", log_signal(sigmap(x)));
\end{lstlisting}
\medskip
-Use {\tt RTLIL::id2cstr()} to create a C-string for an {\tt RTLIL::IdString}:
+Use {\tt log\_id()} to create a C-string for an {\tt RTLIL::IdString}:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-log("Name of this module: %s\n", RTLIL::id2cstr(module->name));
+log("Name of this module: %s\n", log_id(module->name));
\end{lstlisting}
\medskip
@@ -513,9 +520,8 @@ a new yosys command:
\bigskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-#include "kernel/rtlil.h"
-#include "kernel/register.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+USING_YOSYS_NAMESPACE
struct MyPass : public Pass {
MyPass() : Pass("my_cmd", "just a simple test") { }
@@ -526,9 +532,9 @@ struct MyPass : public Pass {
log(" %s\n", arg.c_str());
log("Modules in current design:\n");
- for (auto &mod : design->modules)
- log(" %s (%zd wires, %zd cells)\n", RTLIL::id2cstr(mod.first),
- mod.second->wires.size(), mod.second->cells.size());
+ for (auto mod : design->modules())
+ log(" %s (%d wires, %d cells)\n", log_id(mod),
+ GetSize(mod->wires), GetSize(mod->cells));
}
} MyPass;
\end{lstlisting}
@@ -550,6 +556,12 @@ yosys-config --exec --cxx --cxxflags --ldflags \
\end{lstlisting}
\bigskip
+Or shorter:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
+yosys-config --build my_cmd.so my_cmd.cc
+\end{lstlisting}
+
+\bigskip
Load the plugin using the yosys {\tt -m} option:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
yosys -m ./my_cmd.so -p 'my_cmd foo bar'
@@ -566,7 +578,7 @@ yosys -m ./my_cmd.so -p 'my_cmd foo bar'
\item \dots and even simpler if you don't need RTLIL::Memory or RTLIL::Process objects.
\bigskip
-\item Writing synthesis software? Consider learning the Yosys API and make your stuff
+\item Writing synthesis software? Consider learning the Yosys API and make your work
part of the Yosys framework.
\end{itemize}
diff --git a/manual/PRESENTATION_Prog/.gitignore b/manual/PRESENTATION_Prog/.gitignore
index 7fd56076..ccdd6bd5 100644
--- a/manual/PRESENTATION_Prog/.gitignore
+++ b/manual/PRESENTATION_Prog/.gitignore
@@ -1 +1,2 @@
my_cmd.so
+my_cmd.d
diff --git a/manual/PRESENTATION_Prog/my_cmd.cc b/manual/PRESENTATION_Prog/my_cmd.cc
index 381b0587..1d28ce97 100644
--- a/manual/PRESENTATION_Prog/my_cmd.cc
+++ b/manual/PRESENTATION_Prog/my_cmd.cc
@@ -1,6 +1,9 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct MyPass : public Pass {
MyPass() : Pass("my_cmd", "just a simple test") { }
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
@@ -12,7 +15,7 @@ struct MyPass : public Pass {
log("Modules in current design:\n");
for (auto mod : design->modules())
log(" %s (%zd wires, %zd cells)\n", log_id(mod),
- SIZE(mod->wires()), SIZE(mod->cells()));
+ GetSize(mod->wires()), GetSize(mod->cells()));
}
} MyPass;
@@ -25,6 +28,7 @@ struct Test1Pass : public Pass {
log_error("A module with the name absval already exists!\n");
RTLIL::Module *module = design->addModule("\\absval");
+ log("Name of this module: %s\n", log_id(module));
RTLIL::Wire *a = module->addWire("\\a", 4);
a->port_input = true;
@@ -38,7 +42,7 @@ struct Test1Pass : public Pass {
module->addNeg(NEW_ID, a, a_inv, true);
module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 3), y);
- log("Name of this module: %s\n", log_id(module));
+ module->fixup_ports();
}
} Test1Pass;
@@ -69,3 +73,4 @@ struct Test2Pass : public Pass {
}
} Test2Pass;
+PRIVATE_NAMESPACE_END
diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex
index 35249ed8..d653f409 100644
--- a/manual/command-reference-manual.tex
+++ b/manual/command-reference-manual.tex
@@ -15,22 +15,99 @@ library to a target architecture.
-script <file>
use the specified ABC script file instead of the default script.
+ if <file> starts with a plus sign (+), then the rest of the filename
+ string is interprated as the command string to be passed to ABC. the
+ leading plus sign is removed and all commas (,) in the string are
+ replaced with blanks before the string is passed to ABC.
+
+ if no -script parameter is given, the following scripts are used:
+
+ for -liberty without -constr:
+ strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}
+
+ for -liberty with -constr:
+ strash; scorr; ifraig; retime {D}; strash; dch -f; map {D};
+ buffer; upsize {D}; dnsize {D}; stime -p
+
+ for -lut:
+ strash; scorr; ifraig; retime; strash; dch -f; if
+
+ otherwise:
+ strash; scorr; ifraig; retime; strash; dch -f; map
+
+ -fast
+ use different default scripts that are slightly faster (at the cost
+ of output quality):
+
+ for -liberty without -constr:
+ retime {D}; map {D}
+
+ for -liberty with -constr:
+ retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p
+
+ for -lut:
+ retime; if
+
+ otherwise:
+ retime; map
+
-liberty <file>
generate netlists for the specified cell library (using the liberty
- file format). Without this option, ABC is used to optimize the netlist
- but keeps using yosys's internal gate library. This option is ignored if
- the -script option is also used.
+ file format).
-constr <file>
- pass this file with timing constraints to ABC
+ pass this file with timing constraints to ABC. use with -liberty.
+
+ a constr file contains two lines:
+ set_driving_cell <cell_name>
+ set_load <floating_point_number>
+
+ the set_driving_cell statement defines which cell type is assumed to
+ drive the primary inputs and the set_load statement sets the load in
+ femtofarads for each primary output.
+
+ -D <picoseconds>
+ set delay target. the string {D} in the default scripts above is
+ replaced by this option when used, and an empty string otherwise.
-lut <width>
generate netlist using luts of (max) the specified width.
+ -lut <w1>:<w2>
+ generate netlist using luts of (max) the specified width <w2>. All
+ luts with width <= <w1> have constant cost. for luts larger than <w1>
+ the area cost doubles with each additional input bit. the delay cost
+ is still constant for all lut widths.
+
+ -dff
+ also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many
+ clock domains are automatically partitioned in clock domains and each
+ domain is passed through ABC independently.
+
+ -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]
+ use only the specified clock domain. this is like -dff, but only FF
+ cells that belong to the specified clock domain are used.
+
+ -keepff
+ set the "keep" attribute on flip-flop output wires. (and thus preserve
+ them, for example for equivialence checking.)
+
-nocleanup
when this option is used, the temporary files created by this pass
are not removed. this is useful for debugging.
+ -showtmp
+ print the temp dir name in log. usually this is suppressed so that the
+ command output is identical across runs.
+
+ -markgroups
+ set a 'abcgroup' attribute on all objects created by ABC. The value of
+ this attribute is a unique integer for each ABC process started. This
+ is useful for debugging the partitioning of clock domains.
+
+When neither -liberty nor -lut is used, the Yosys standard cell library is
+loaded into ABC before the ABC script is executed.
+
This pass does not operate on modules with unprocessed processes in it.
(I.e. the 'proc' pass should be used first to convert processes to netlists.)
@@ -59,6 +136,15 @@ Like 'add -input', but also connect the signal between instances of the
selected modules.
\end{lstlisting}
+\section{alumacc -- extract ALU and MACC cells}
+\label{cmd:alumacc}
+\begin{lstlisting}[numbers=left,frame=single]
+ alumacc [selection]
+
+This pass translates arithmetic operations like $add, $mul, $lt, etc. to $alu
+and $macc cells.
+\end{lstlisting}
+
\section{cd -- a shortcut for 'select -module <name>'}
\label{cmd:cd}
\begin{lstlisting}[numbers=left,frame=single]
@@ -92,6 +178,129 @@ When commands are separated using the ';;;' token, this command will be executed
in -purge mode between the commands.
\end{lstlisting}
+\section{connect -- create or remove connections}
+\label{cmd:connect}
+\begin{lstlisting}[numbers=left,frame=single]
+ connect [-nomap] [-nounset] -set <lhs-expr> <rhs-expr>
+
+Create a connection. This is equivialent to adding the statement 'assign
+<lhs-expr> = <rhs-expr>;' to the verilog input. Per default, all existing
+drivers for <lhs-expr> are unconnected. This can be overwritten by using
+the -nounset option.
+
+
+ connect [-nomap] -unset <expr>
+
+Unconnect all existing drivers for the specified expression.
+
+
+ connect [-nomap] -port <cell> <port> <expr>
+
+Connect the specified cell port to the specified cell port.
+
+
+Per default signal alias names are resolved and all signal names are mapped
+the the signal name of the primary driver. Using the -nomap option deactivates
+this behavior.
+
+The connect command operates in one module only. Either only one module must
+be selected or an active module must be set using the 'cd' command.
+
+This command does not operate on module with processes.
+\end{lstlisting}
+
+\section{connwrappers -- replace undef values with defined constants}
+\label{cmd:connwrappers}
+\begin{lstlisting}[numbers=left,frame=single]
+ connwrappers [options] [selection]
+
+Wrappers are used in coarse-grain synthesis to wrap cells with smaller ports
+in wrapper cells with a (larger) constant port size. I.e. the upper bits
+of the wrapper outut are signed/unsigned bit extended. This command uses this
+knowlege to rewire the inputs of the driven cells to match the output of
+the driving cell.
+
+ -signed <cell_type> <port_name> <width_param>
+ -unsigned <cell_type> <port_name> <width_param>
+ consider the specified signed/unsigned wrapper output
+
+ -port <cell_type> <port_name> <width_param> <sign_param>
+ use the specified parameter to decide if signed or unsigned
+
+The options -signed, -unsigned, and -port can be specified multiple times.
+\end{lstlisting}
+
+\section{copy -- copy modules in the design}
+\label{cmd:copy}
+\begin{lstlisting}[numbers=left,frame=single]
+ copy old_name new_name
+
+Copy the specified module. Note that selection patterns are not supported
+by this command.
+\end{lstlisting}
+
+\section{cover -- print code coverage counters}
+\label{cmd:cover}
+\begin{lstlisting}[numbers=left,frame=single]
+ cover [options] [pattern]
+
+Print the code coverage counters collected using the cover() macro in the Yosys
+C++ code. This is useful to figure out what parts of Yosys are utilized by a
+test bench.
+
+ -q
+ Do not print output to the normal destination (console and/or log file)
+
+ -o file
+ Write output to this file, truncate if exists.
+
+ -a file
+ Write output to this file, append if exists.
+
+ -d dir
+ Write output to a newly created file in the specified directory.
+
+When one or more pattern (shell wildcards) are specified, then only counters
+matching at least one pattern are printed.
+
+
+It is also possible to instruct Yosys to print the coverage counters on program
+exit to a file using environment variables:
+
+ YOSYS_COVER_DIR="{dir-name}" yosys {args}
+
+ This will create a file (with an auto-generated name) in this
+ directory and write the coverage counters to it.
+
+ YOSYS_COVER_FILE="{file-name}" yosys {args}
+
+ This will append the coverage counters to the specified file.
+
+
+Hint: Use the following AWK command to consolidate Yosys coverage files:
+
+ gawk '{ p[$3] = $1; c[$3] += $2; } END { for (i in p)
+ printf "%-60s %10d %s\n", p[i], c[i], i; }' {files} | sort -k3
+
+
+Coverage counters are only available in Yosys for Linux.
+\end{lstlisting}
+
+\section{delete -- delete objects in the design}
+\label{cmd:delete}
+\begin{lstlisting}[numbers=left,frame=single]
+ delete [selection]
+
+Deletes the selected objects. This will also remove entire modules, if the
+whole module is selected.
+
+
+ delete {-input|-output|-port} [selection]
+
+Does not delete any object but removes the input and/or output flag on the
+selected wires, thus 'deleting' module ports.
+\end{lstlisting}
+
\section{design -- save, restore and reset current design}
\label{cmd:design}
\begin{lstlisting}[numbers=left,frame=single]
@@ -105,22 +314,75 @@ Clear the current design.
Save the current design under the given name.
+ design -stash <name>
+
+Save the current design under the given name and then clear the current design.
+
+
+ design -push
+
+Push the current design to the stack and then clear the current design.
+
+
+ design -pop
+
+Reset the current design and pop the last design from the stack.
+
+
design -load <name>
Reset the current design and load the design previously saved under the given
name.
+
+
+ design -copy-from <name> [-as <new_mod_name>] <selection>
+
+Copy modules from the specified design into the current one. The selection is
+evaluated in the other design.
+
+
+ design -copy-to <name> [-as <new_mod_name>] [selection]
+
+Copy modules from the current design into the soecified one.
+\end{lstlisting}
+
+\section{dff2dffe -- transform \$dff cells to \$dffe cells}
+\label{cmd:dff2dffe}
+\begin{lstlisting}[numbers=left,frame=single]
+ dff2dffe [selection]
+
+This pass transforms $dff cells driven by a tree of multiplexers with one or
+more feedback paths to $dffe cells. It also works on gate-level cells such as
+$_DFF_P_, $_DFF_N_ and $_MUX_.
+
+ -unmap
+ operate in the opposite direction: replace $dffe cells with combinations
+ of $dff and $mux cells. the options below are ignore in unmap mode.
+
+ -direct <internal_gate_type> <external_gate_type>
+ map directly to external gate type. <internal_gate_type> can
+ be any internal gate-level FF cell (except $_DFFE_??_). the
+ <external_gate_type> is the cell type name for a cell with an
+ identical interface to the <internal_gate_type>, except it
+ also has an high-active enable port 'E'.
+ Usually <external_gate_type> is an intemediate cell type
+ that is then translated to the final type using 'techmap'.
\end{lstlisting}
\section{dfflibmap -- technology mapping of flip-flops}
\label{cmd:dfflibmap}
\begin{lstlisting}[numbers=left,frame=single]
- dfflibmap -liberty <file> [selection]
+ dfflibmap [-prepare] -liberty <file> [selection]
Map internal flip-flop cells to the flip-flop cells in the technology
library specified in the given liberty file.
This pass may add inverters as needed. Therefore it is recommended to
first run this pass and then map the logic paths to the target technology.
+
+When called with -prepare, this command will convert the internal FF cells
+to the internal cell types that best match the cells found in the given
+liberty file.
\end{lstlisting}
\section{dump -- print parts of the design in ilang format}
@@ -138,8 +400,151 @@ ilang format.
-n
only dump the module headers if the entire module is selected
- -outfile <filename>
- Write to the specified file.
+ -o <filename>
+ write to the specified file.
+
+ -a <filename>
+ like -outfile but append instead of overwrite
+\end{lstlisting}
+
+\section{echo -- turning echoing back of commands on and off}
+\label{cmd:echo}
+\begin{lstlisting}[numbers=left,frame=single]
+ echo on
+
+Print all commands to log before executing them.
+
+
+ echo off
+
+Do not print all commands to log before executing them. (default)
+\end{lstlisting}
+
+\section{equiv\_add -- add a \$equiv cell}
+\label{cmd:equiv_add}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_add gold_sig gate_sig
+
+This command adds an $equiv cell for the specified signals.
+\end{lstlisting}
+
+\section{equiv\_induct -- proving \$equiv cells using temporal induction}
+\label{cmd:equiv_induct}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_induct [options] [selection]
+
+Uses a version of temporal induction to prove $equiv cells.
+
+Only selected $equiv cells are proven and only selected cells are used to
+perform the proof.
+
+ -undef
+ enable modelling of undef states
+
+ -seq <N>
+ the max. number of time steps to be considered (default = 4)
+
+This command is very effective in proving complex sequential circuits, when
+the internal state of the circuit quickly propagates to $equiv cells.
+
+However, this command uses a weak definition of 'equivalence': This command
+proves that the two circuits will not diverge after they produce equal
+outputs (observable points via $equiv) for at least <N> cycles (the <N>
+specified via -seq).
+
+Combined with simulation this is very powerful because simulation can give
+you confidence that the circuits start out synced for at least <N> cycles
+after reset.
+\end{lstlisting}
+
+\section{equiv\_make -- prepare a circuit for equivalence checking}
+\label{cmd:equiv_make}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_make [options] gold_module gate_module equiv_module
+
+This creates a module annotated with $equiv cells from two presumably
+equivalent modules. Use commands such as 'equiv_simple' and 'equiv_status'
+to work with the created equivalent checking module.
+
+ -inames
+ Also match cells and wires with $... names.
+
+ -blacklist <file>
+ Do not match cells or signals that match the names in the file.
+
+ -encfile <file>
+ Match FSM encodings using the desiption from the file.
+ See 'help fsm_recode' for details.
+
+Note: The circuit created by this command is not a miter (with something like
+a trigger output), but instead uses $equiv cells to encode the equivalence
+checking problem. Use 'miter -equiv' if you want to create a miter circuit.
+\end{lstlisting}
+
+\section{equiv\_miter -- extract miter from equiv circuit}
+\label{cmd:equiv_miter}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_miter [options] miter_module [selection]
+
+This creates a miter module for further analysis of the selected $equiv cells.
+
+ -trigger
+ Create a trigger output
+
+ -cmp
+ Create cmp_* outputs for individual unproven $equiv cells
+
+ -assert
+ Create a $assert cell for each unproven $equiv cell
+
+ -undef
+ Create compare logic that handles undefs correctly
+\end{lstlisting}
+
+\section{equiv\_remove -- remove \$equiv cells}
+\label{cmd:equiv_remove}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_remove [options] [selection]
+
+This command removes the selected $equiv cells. If neither -gold nor -gate is
+used then only proven cells are removed.
+
+ -gold
+ keep gold circuit
+
+ -gate
+ keep gate circuit
+\end{lstlisting}
+
+\section{equiv\_simple -- try proving simple \$equiv instances}
+\label{cmd:equiv_simple}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_simple [options] [selection]
+
+This command tries to prove $equiv cells using a simple direct SAT approach.
+
+ -v
+ verbose output
+
+ -undef
+ enable modelling of undef states
+
+ -nogroup
+ disabling grouping of $equiv cells by output wire
+
+ -seq <N>
+ the max. number of time steps to be considered (default = 1)
+\end{lstlisting}
+
+\section{equiv\_status -- print status of equivalent checking module}
+\label{cmd:equiv_status}
+\begin{lstlisting}[numbers=left,frame=single]
+ equiv_status [options] [selection]
+
+This command prints status information for all selected $equiv cells.
+
+ -assert
+ produce an error if any unproven $equiv cell is found
\end{lstlisting}
\section{eval -- evaluate the circuit given an input}
@@ -164,6 +569,38 @@ inputs.
then all output ports of the current module are used.
\end{lstlisting}
+\section{expose -- convert internal signals to module ports}
+\label{cmd:expose}
+\begin{lstlisting}[numbers=left,frame=single]
+ expose [options] [selection]
+
+This command exposes all selected internal signals of a module as additional
+outputs.
+
+ -dff
+ only consider wires that are directly driven by register cell.
+
+ -cut
+ when exposing a wire, create an input/output pair and cut the internal
+ signal path at that wire.
+
+ -shared
+ only expose those signals that are shared ammong the selected modules.
+ this is useful for preparing modules for equivialence checking.
+
+ -evert
+ also turn connections to instances of other modules to additional
+ inputs and outputs and remove the module instances.
+
+ -evert-dff
+ turn flip-flops to sets of inputs and outputs.
+
+ -sep <separator>
+ when creating new wire/port names, the original object name is suffixed
+ with this separator (default: '.') and the port name or a type
+ designator for the exposed signal.
+\end{lstlisting}
+
\section{extract -- find subcircuits and replace them with cells}
\label{cmd:extract}
\begin{lstlisting}[numbers=left,frame=single]
@@ -175,7 +612,12 @@ in the given map file and replaces them with instances of this modules. The
map file can be a verilog source file (*.v) or an ilang file (*.il).
-map <map_file>
- use the modules in this file as reference
+ use the modules in this file as reference. This option can be used
+ multiple times.
+
+ -map %<design-name>
+ use the modules in this in-memory design as reference. This option can
+ be used multiple times.
-verbose
print debug output while analyzing
@@ -209,6 +651,12 @@ map file can be a verilog source file (*.v) or an ilang file (*.il).
-wire_attr <attribute_name>
Attributes on wires with the given name must match.
+ -ignore_parameters
+ Do not use parameters when matching cells.
+
+ -ignore_param <cell_type> <parameter_name>
+ Do not use this parameter when matching cells.
+
This pass does not operate on modules with uprocessed processes in it.
(I.e. the 'proc' pass should be used first to convert processes to netlists.)
@@ -257,11 +705,27 @@ pass is using the current design as mapping library.
This pass performs functional reduction in the circuit. I.e. if two nodes are
equivialent, they are merged to one node and one of the redundant drivers is
-removed.
+disconnected. A subsequent call to 'clean' will remove the redundant drivers.
+
+ -v, -vv
+ enable verbose or very verbose output
+
+ -inv
+ enable explicit handling of inverted signals
+
+ -stop <n>
+ stop after <n> reduction operations. this is mostly used for
+ debugging the freduce command itself.
+
+ -dump <prefix>
+ dump the design to <prefix>_<module>_<num>.il after each reduction
+ operation. this is mostly used for debugging the freduce command.
- -try
- do not issue an error when the analysis fails.
- (usually beacause of logic loops in the design)
+This pass is undef-aware, i.e. it considers don't-care values for detecting
+equivialent nodes.
+
+All selected wires are considered for rewiring. The selected cells cover the
+circuit that is analyzed.
\end{lstlisting}
\section{fsm -- extract and optimize finite state machines}
@@ -297,6 +761,7 @@ Options:
-encoding tye
-fm_set_fsm_file file
+ -encfile file
passed through to fsm_recode pass
\end{lstlisting}
@@ -393,16 +858,24 @@ combination with the 'opt_clean' pass (see also 'help fsm').
\section{fsm\_recode -- recoding finite state machines}
\label{cmd:fsm_recode}
\begin{lstlisting}[numbers=left,frame=single]
- fsm_recode [-encoding type] [-fm_set_fsm_file file] [selection]
+ fsm_recode [options] [selection]
This pass reassign the state encodings for FSM cells. At the moment only
-one-hot encoding and binary encoding is supported. The option -encoding
-can be used to specify the encoding scheme used for FSMs without the
-`fsm_encoding' attribute (or with the attribute set to `auto'.
+one-hot encoding and binary encoding is supported.
+ -encoding <type>
+ specify the encoding scheme used for FSMs without the
+ 'fsm_encoding' attribute or with the attribute set to `auto'.
+
+ -fm_set_fsm_file <file>
+ generate a file containing the mapping from old to new FSM encoding
+ in form of Synopsys Formality set_fsm_* commands.
-The option -fm_set_fsm_file can be used to generate a file containing the
-mapping from old to new FSM encoding in form of Synopsys Formality set_fsm_*
-commands.
+ -encfile <file>
+ write the mappings from old to new FSM encoding to a file in the
+ following format:
+
+ .fsm <module_name> <state_signal>
+ .map <old_bitpattern> <new_bitpattern>
\end{lstlisting}
\section{help -- display help messages}
@@ -428,10 +901,24 @@ needed.
also check the design hierarchy. this generates an error when
an unknown module is used as cell type.
+ -purge_lib
+ by default the hierarchy command will not remove library (blackbox)
+ module. use this options to also remove unused blackbox modules.
+
+ -libdir <directory>
+ search for files named <module_name>.v in the specified directory
+ for unknown modules and automatically run read_verilog for each
+ unknown module.
+
-keep_positionals
per default this pass also converts positional arguments in cells
to arguments using port names. this option disables this behavior.
+ -nokeep_asserts
+ per default this pass sets the "keep" attribute on all modules
+ that directly or indirectly contain one or more $assert cells. this
+ option disables this behavior.
+
-top <module>
use the specified top module to built a design hierarchy. modules
outside this tree (unused modules) are removed.
@@ -457,6 +944,25 @@ This pass ignores the current selection and always operates on all modules
in the current design.
\end{lstlisting}
+\section{hilomap -- technology mapping of constant hi- and/or lo-drivers}
+\label{cmd:hilomap}
+\begin{lstlisting}[numbers=left,frame=single]
+ hilomap [options] [selection]
+
+Map constants to 'tielo' and 'tiehi' driver cells.
+
+ -hicell <celltype> <portname>
+ Replace constant hi bits with this cell.
+
+ -locell <celltype> <portname>
+ Replace constant lo bits with this cell.
+
+ -singleton
+ Create only one hi/lo cell and connect all constant bits
+ to that cell. Per default a separate cell is created for
+ each constant bit.
+\end{lstlisting}
+
\section{history -- show last interactive commands}
\label{cmd:history}
\begin{lstlisting}[numbers=left,frame=single]
@@ -491,39 +997,160 @@ the resulting cells to more sophisticated PAD cells.
-nameparam <param_name>
Use the specified parameter to set the port name.
+
+ -bits
+ create individual bit-wide buffers even for ports that
+ are wider. (the default behavior is to create word-wide
+ buffers using -widthparam to set the word size on the cell.)
+\end{lstlisting}
+
+\section{log -- print text and log files}
+\label{cmd:log}
+\begin{lstlisting}[numbers=left,frame=single]
+ log string
+
+Print the given string to the screen and/or the log file. This is useful for TCL
+scripts, because the TCL command "puts" only goes to stdout but not to
+logfiles.
+
+ -stdout
+ Print the output to stdout too. This is useful when all Yosys is executed
+ with a script and the -q (quiet operation) argument to notify the user.
+
+ -stderr
+ Print the output to stderr too.
+
+ -nolog
+ Don't use the internal log() command. Use either -stdout or -stderr,
+ otherwise no output will be generated at all.
+
+ -n
+ do not append a newline
\end{lstlisting}
\section{ls -- list modules or objects in modules}
\label{cmd:ls}
\begin{lstlisting}[numbers=left,frame=single]
- ls [pattern]
+ ls [selection]
-When no active module is selected, this prints a list of all modules.
+When no active module is selected, this prints a list of modules.
When an active module is selected, this prints a list of objects in the module.
+\end{lstlisting}
-If a pattern is given, the objects matching the pattern are printed
+\section{maccmap -- mapping macc cells}
+\label{cmd:maccmap}
+\begin{lstlisting}[numbers=left,frame=single]
+ maccmap [-unmap] [selection]
-Note that this command does not use the selection mechanism and always operates
-on the whole design or whole active module. Use 'select -list' to show a list
-of currently selected objects.
+This pass maps $macc cells to yosys gate primitives. When the -unmap option is
+used then the $macc cell is mapped to $and, $sub, etc. cells instead.
\end{lstlisting}
\section{memory -- translate memories to basic cells}
\label{cmd:memory}
\begin{lstlisting}[numbers=left,frame=single]
- memory [-nomap] [selection]
+ memory [-nomap] [-bram <bram_rules>] [selection]
This pass calls all the other memory_* passes in a useful order:
memory_dff
+ opt_clean
+ memory_share
+ opt_clean
memory_collect
- memory_map (skipped if called with -nomap)
+ memory_bram -rules <bram_rules> (when called with -bram)
+ memory_map (skipped if called with -nomap)
This converts memories to word-wide DFFs and address decoders
or multiport memory blocks if called with the -nomap option.
\end{lstlisting}
+\section{memory\_bram -- map memories to block rams}
+\label{cmd:memory_bram}
+\begin{lstlisting}[numbers=left,frame=single]
+ memory_bram -rules <rule_file> [selection]
+
+This pass converts the multi-port $mem memory cells into block ram instances.
+The given rules file describes the available resources and how they should be
+used.
+
+The rules file contains a set of block ram description and a sequence of match
+rules. A block ram description looks like this:
+
+ bram RAMB1024X32 # name of BRAM cell
+ abits 10 # number of address bits
+ dbits 32 # number of data bits
+ groups 2 # number of port groups
+ ports 1 1 # number of ports in each group
+ wrmode 1 0 # set to '1' if this groups is write ports
+ enable 4 0 # number of enable bits (for write ports)
+ transp 0 2 # transparatent (for read ports)
+ clocks 1 2 # clock configuration
+ clkpol 2 2 # clock polarity configuration
+ endbram
+
+For the option 'transp' the value 0 means non-transparent, 1 means transparent
+and a value greater than 1 means configurable. All groups with the same
+value greater than 1 share the same configuration bit.
+
+For the option 'clocks' the value 0 means non-clocked, and a value greater
+than 0 means clocked. All groups with the same value share the same clock
+signal.
+
+For the option 'clkpol' the value 0 means negative edge, 1 means positive edge
+and a value greater than 1 means configurable. All groups with the same value
+greater than 1 share the same configuration bit.
+
+Using the same bram name in different bram blocks will create different variants
+of the bram. Verilog configration parameters for the bram are created as needed.
+
+It is also possible to create variants by repeating statements in the bram block
+and appending '@<label>' to the individual statements.
+
+A match rule looks like this:
+
+ match RAMB1024X32
+ max waste 16384 # only use this bram if <= 16k ram bits are unused
+ min efficiency 80 # only use this bram if efficiency is at least 80%
+ endmatch
+
+It is possible to match against the following values with min/max rules:
+
+ words ........ number of words in memory in design
+ abits ........ number of address bits on memory in design
+ dbits ........ number of data bits on memory in design
+ wports ....... number of write ports on memory in design
+ rports ....... number of read ports on memory in design
+ ports ........ number of ports on memory in design
+ bits ......... number of bits in memory in design
+ dups .......... number of duplications for more read ports
+
+ awaste ....... number of unused address slots for this match
+ dwaste ....... number of unused data bits for this match
+ bwaste ....... number of unused bram bits for this match
+ waste ........ total number of unused bram bits (bwaste*dups)
+ efficiency ... total percentage of used and non-duplicated bits
+
+ acells ....... number of cells in 'address-direction'
+ dcells ....... number of cells in 'data-direction'
+ cells ........ total number of cells (acells*dcells*dups)
+
+The interface for the created bram instances is dervived from the bram
+description. Use 'techmap' to convert the created bram instances into
+instances of the actual bram cells of your target architecture.
+
+A match containing the command 'or_next_if_better' is only used if it
+has a higher efficiency than the next match (and the one after that if
+the next also has 'or_next_if_better' set, and so forth).
+
+A match containing the command 'make_transp' will add external circuitry
+to simulate 'transparent read', if necessary.
+
+A match containing the command 'shuffle_enable A' will re-organize
+the data bits to accommodate the enable pattern of port A.
+\end{lstlisting}
+
\section{memory\_collect -- creating multi-port memory cells}
\label{cmd:memory_collect}
\begin{lstlisting}[numbers=left,frame=single]
@@ -536,11 +1163,14 @@ memory cells.
\section{memory\_dff -- merge input/output DFFs into memories}
\label{cmd:memory_dff}
\begin{lstlisting}[numbers=left,frame=single]
- memory_dff [selection]
+ memory_dff [options] [selection]
This pass detects DFFs at memory ports and merges them into the memory port.
I.e. it consumes an asynchronous memory port and the flip-flops at its
interface and yields a synchronous memory port.
+
+ -wr_only
+ do not merge registers on read ports
\end{lstlisting}
\section{memory\_map -- translate multiport memories to basic cells}
@@ -552,26 +1182,101 @@ This pass converts multiport memory cells as generated by the memory_collect
pass to word-wide DFFs and address decoders.
\end{lstlisting}
+\section{memory\_share -- consolidate memory ports}
+\label{cmd:memory_share}
+\begin{lstlisting}[numbers=left,frame=single]
+ memory_share [selection]
+
+This pass merges share-able memory ports into single memory ports.
+
+The following methods are used to consolidate the number of memory ports:
+
+ - When write ports are connected to async read ports accessing the same
+ address, then this feedback path is converted to a write port with
+ byte/part enable signals.
+
+ - When multiple write ports access the same address then this is converted
+ to a single write port with a more complex data and/or enable logic path.
+
+ - When multiple write ports are never accessed at the same time (a SAT
+ solver is used to determine this), then the ports are merged into a single
+ write port.
+
+Note that in addition to the algorithms implemented in this pass, the $memrd
+and $memwr cells are also subject to generic resource sharing passes (and other
+optimizations) such as opt_share.
+\end{lstlisting}
+
+\section{memory\_unpack -- unpack multi-port memory cells}
+\label{cmd:memory_unpack}
+\begin{lstlisting}[numbers=left,frame=single]
+ memory_unpack [selection]
+
+This pass converts the multi-port $mem memory cells into individual $memrd and
+$memwr cells. It is the counterpart to the memory_collect pass.
+\end{lstlisting}
+
+\section{miter -- automatically create a miter circuit}
+\label{cmd:miter}
+\begin{lstlisting}[numbers=left,frame=single]
+ miter -equiv [options] gold_name gate_name miter_name
+
+Creates a miter circuit for equivialence checking. The gold- and gate- modules
+must have the same interfaces. The miter circuit will have all inputs of the
+two source modules, prefixed with 'in_'. The miter circuit has a 'trigger'
+output that goes high if an output mismatch between the two source modules is
+detected.
+
+ -ignore_gold_x
+ a undef (x) bit in the gold module output will match any value in
+ the gate module output.
+
+ -make_outputs
+ also route the gold- and gate-outputs to 'gold_*' and 'gate_*' outputs
+ on the miter circuit.
+
+ -make_outcmp
+ also create a cmp_* output for each gold/gate output pair.
+
+ -make_assert
+ also create an 'assert' cell that checks if trigger is always low.
+
+ -flatten
+ call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.
+\end{lstlisting}
+
\section{opt -- perform simple optimizations}
\label{cmd:opt}
\begin{lstlisting}[numbers=left,frame=single]
- opt [selection]
+ opt [options] [selection]
This pass calls all the other opt_* passes in a useful order. This performs
a series of trivial optimizations and cleanups. This pass executes the other
passes in the following order:
- opt_const
+ opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]
opt_share -nomux
do
opt_muxtree
- opt_reduce
+ opt_reduce [-fine] [-full]
opt_share
opt_rmdff
- opt_clean
- opt_const
- while [changed design]
+ opt_clean [-purge]
+ opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]
+ while <changed design>
+
+When called with -fast the following script is used instead:
+
+ do
+ opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]
+ opt_share
+ opt_rmdff
+ opt_clean [-purge]
+ while <changed design in opt_rmdff>
+
+Note: Options in square brackets (such as [-keepdc]) are passed through to
+the opt_* commands when given to 'opt'.
\end{lstlisting}
\section{opt\_clean -- remove unused cells and wires}
@@ -593,9 +1298,30 @@ This pass only operates on completely selected modules without processes.
\section{opt\_const -- perform const folding}
\label{cmd:opt_const}
\begin{lstlisting}[numbers=left,frame=single]
- opt_const [selection]
+ opt_const [options] [selection]
This pass performs const folding on internal cell types with constant inputs.
+
+ -mux_undef
+ remove 'undef' inputs from $mux, $pmux and $_MUX_ cells
+
+ -mux_bool
+ replace $mux cells with inverters or buffers when possible
+
+ -undriven
+ replace undriven nets with undef (x) constants
+
+ -fine
+ perform fine-grain optimizations
+
+ -full
+ alias for -mux_undef -mux_bool -undriven -fine
+
+ -keepdc
+ some optimizations change the behavior of the circuit with respect to
+ don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause
+ all result bits to be set to x. this behavior changes when 'a+0' is
+ replaced by 'a'. the -keepdc option disables all such optimizations.
\end{lstlisting}
\section{opt\_muxtree -- eliminate dead trees in multiplexer trees}
@@ -613,7 +1339,7 @@ This pass only operates on completely selected modules without processes.
\section{opt\_reduce -- simplify large MUXes and AND/OR gates}
\label{cmd:opt_reduce}
\begin{lstlisting}[numbers=left,frame=single]
- opt_reduce [selection]
+ opt_reduce [options] [selection]
This pass performs two interlinked optimizations:
@@ -622,6 +1348,12 @@ duplicated inputs.
2. it identifies duplicated inputs to MUXes and replaces them with a single
input with the original control signals OR'ed together.
+
+ -fine
+ perform fine-grain optimizations
+
+ -full
+ alias for -fine
\end{lstlisting}
\section{opt\_rmdff -- remove DFFs with constant inputs}
@@ -645,6 +1377,23 @@ are then merged to one cell.
Do not merge MUX cells.
\end{lstlisting}
+\section{plugin -- load and list loaded plugins}
+\label{cmd:plugin}
+\begin{lstlisting}[numbers=left,frame=single]
+ plugin [options]
+
+Load and list loaded plugins.
+
+ -i <plugin_filename>
+ Load (install) the specified plugin.
+
+ -a <alias_name>
+ Register the specified alias name for the loaded plugin
+
+ -l
+ List loaded plugins
+\end{lstlisting}
+
\section{proc -- translate processes to netlists}
\label{cmd:proc}
\begin{lstlisting}[numbers=left,frame=single]
@@ -739,14 +1488,43 @@ Load modules from an ilang file to the current design. (ilang is a text
representation of a design in yosys's internal format.)
\end{lstlisting}
+\section{read\_liberty -- read cells from liberty file}
+\label{cmd:read_liberty}
+\begin{lstlisting}[numbers=left,frame=single]
+ read_liberty [filename]
+
+Read cells from liberty file as modules into current design.
+
+ -lib
+ only create empty blackbox modules
+
+ -ignore_redef
+ ignore re-definitions of modules. (the default behavior is to
+ create an error message.)
+
+ -ignore_miss_func
+ ignore cells with missing function specification of outputs
+
+ -ignore_miss_dir
+ ignore cells with a missing or invalid direction
+ specification on a pin
+
+ -setattr <attribute_name>
+ set the specified attribute (to the value 1) on all loaded modules
+\end{lstlisting}
+
\section{read\_verilog -- read modules from verilog file}
\label{cmd:read_verilog}
\begin{lstlisting}[numbers=left,frame=single]
- read_verilog [filename]
+ read_verilog [options] [filename]
Load modules from a verilog file to the current design. A large subset of
Verilog-2005 is supported.
+ -sv
+ enable support for SystemVerilog features. (only a small subset
+ of SystemVerilog is supported)
+
-dump_ast1
dump abstract syntax tree (before simplification)
@@ -794,10 +1572,21 @@ Verilog-2005 is supported.
don't perform basic optimizations (such as const folding) in the
high-level front-end.
+ -icells
+ interpret cell types starting with '$' as internal cell types
+
-ignore_redef
ignore re-definitions of modules. (the default behavior is to
create an error message.)
+ -defer
+ only read the abstract syntax tree and defer actual compilation
+ to a later 'hierarchy' command. Useful in cases where the default
+ parameters of modules yield invalid or not synthesizable code.
+
+ -setattr <attribute_name>
+ set the specified attribute (to the value 1) on all loaded modules
+
-Dname[=definition]
define the preprocessor symbol 'name' and set its optional value
'definition'
@@ -805,6 +1594,14 @@ Verilog-2005 is supported.
-Idir
add 'dir' to the directories which are used when searching include
files
+
+The command 'verilog_defaults' can be used to register default options for
+subsequent calls to 'read_verilog'.
+
+Note that the Verilog frontend does a pretty good job of processing valid
+verilog input, but has not very good error reporting. It generally is
+recommended to use a simulator (for example icarus verilog) for checking
+the syntax of the code, rather than to rely on read_verilog for that.
\end{lstlisting}
\section{rename -- rename object in the design}
@@ -816,10 +1613,17 @@ Rename the specified object. Note that selection patterns are not supported
by this command.
- rename -enumerate [selection]
+ rename -enumerate [-pattern <pattern>] [selection]
Assign short auto-generated names to all selected wires and cells with private
-names.
+names. The -pattern option can be used to set the pattern for the new names.
+The character % in the pattern is replaced with a integer number. The default
+pattern is '_%_'.
+
+ rename -hide [selection]
+
+Assign private names (the ones with $-prefix) to all selected wires and cells
+with public names. This ignores all selected ports.
\end{lstlisting}
\section{sat -- solve a SAT problem in the circuit}
@@ -864,9 +1668,15 @@ and additional constraints passed as parameters.
show the model for the specified signal. if no -show option is
passed then a set of signals to be shown is automatically selected.
+ -show-inputs, -show-outputs, -show-ports
+ add all module (input/output) ports to the list of shown signals
+
-ignore_div_by_zero
ignore all solutions that involve a division by zero
+ -ignore_unknown_cells
+ ignore all cells that can not be matched to a SAT model
+
The following options can be used to set up a sequential problem:
-seq <N>
@@ -889,21 +1699,50 @@ The following options can be used to set up a sequential problem:
-set-init-undef
set all initial states (not set using -set-init) to undef
+ -set-init-def
+ do not force a value for the initial state but do not allow undef
+
+ -set-init-zero
+ set all initial states (not set using -set-init) to zero
+
+ -dump_vcd <vcd-file-name>
+ dump SAT model (counter example in proof) to VCD file
+
+ -dump_cnf <cnf-file-name>
+ dump CNF of SAT problem (in DIMACS format). in temporal induction
+ proofs this is the CNF of the first induction step.
+
The following additional options can be used to set up a proof. If also -seq
is passed, a temporal induction proof is performed.
+ -tempinduct
+ Perform a temporal induction proof. In a temporalinduction proof it is
+ proven that the condition holds forever after the number of time steps
+ specified using -seq.
+
+ -tempinduct-def
+ Perform a temporal induction proof. Assume an initial state with all
+ registers set to defined values for the induction step.
+
-prove <signal> <value>
- Attempt to proof that <signal> is always <value>. In a temporal
- induction proof it is proven that the condition holds forever after
- the number of time steps passed using -seq.
+ Attempt to proof that <signal> is always <value>.
-prove-x <signal> <value>
Like -prove, but an undef (x) bit in the lhs matches any value on
the right hand side. Useful for equivialence checking.
+ -prove-asserts
+ Prove that all asserts in the design hold.
+
+ -prove-skip <N>
+ Do not enforce the prove-condition for the first <N> time steps.
+
-maxsteps <N>
Set a maximum length for the induction.
+ -initsteps <N>
+ Set initial length for the induction.
+
-timeout <N>
Maximum number of seconds a single SAT instance may take.
@@ -912,6 +1751,12 @@ is passed, a temporal induction proof is performed.
-verify-no-timeout
Like -verify but do not return an error for timeouts.
+
+ -falsify
+ Return an error and stop the synthesis script if the proof succeeds.
+
+ -falsify-no-timeout
+ Like -falsify but do not return an error for timeouts.
\end{lstlisting}
\section{scatter -- add additional intermediate nets}
@@ -960,15 +1805,24 @@ design.
\section{script -- execute commands from script file}
\label{cmd:script}
\begin{lstlisting}[numbers=left,frame=single]
- script <filename>
+ script <filename> [<from_label>:<to_label>]
This command executes the yosys commands in the specified file.
+
+The 2nd argument can be used to only execute the section of the
+file between the specified labels. An empty from label is synonymous
+for the beginning of the file and an empty to label is synonymous
+for the end of the file.
+
+If only one label is specified (without ':') then only the block
+marked with that label (until the next label) is executed.
\end{lstlisting}
\section{select -- modify and view the list of selected objects}
\label{cmd:select}
\begin{lstlisting}[numbers=left,frame=single]
- select [ -add | -del | -set <name> ] <selection>
+ select [ -add | -del | -set <name> ] {-read <filename> | <selection>}
+ select [ -assert-none | -assert-any ] {-read <filename> | <selection>}
select [ -list | -write <filename> | -count | -clear ]
select -module <modname>
@@ -987,7 +1841,22 @@ described here.
-set <name>
do not modify the current selection. instead save the new selection
- under the given name (see @<name> below).
+ under the given name (see @<name> below). to save the current selection,
+ use "select -set <name> %"
+
+ -assert-none
+ do not modify the current selection. instead assert that the given
+ selection is empty. i.e. produce an error if any object matching the
+ selection is found.
+
+ -assert-any
+ do not modify the current selection. instead assert that the given
+ selection is non-empty. i.e. produce an error if no object matching
+ the selection is found.
+
+ -assert-count N
+ do not modify the current selection. instead assert that the given
+ selection contains exactly N objects.
-list
list all objects in the current selection
@@ -995,12 +1864,19 @@ described here.
-write <filename>
like -list but write the output to the specified file
+ -read <filename>
+ read the specified file (written by -write)
+
-count
count all objects in the current selection
-clear
- clear the current selection. this effectively selects the
- whole design.
+ clear the current selection. this effectively selects the whole
+ design. it also resets the selected module (see -module). use the
+ command 'select *' to select everything but stay in the current module.
+
+ -none
+ create an empty selection. the current module is unchanged.
-module <modname>
limit the current scope to the specified module.
@@ -1030,8 +1906,12 @@ Pushing (selecting) object when in -module mode:
<obj_pattern>
select the specified object(s) from the current module
-A <mod_pattern> can be a module name or wildcard expression (*, ?, [..])
-matching module names.
+A <mod_pattern> can be a module name, wildcard expression (*, ?, [..])
+matching module names, or one of the following:
+
+ A:<pattern>, A:<pattern>=<pattern>
+ all modules with an attribute matching the given pattern
+ in addition to = also <, <=, >=, and > are supported
An <obj_pattern> can be an object name, wildcard expression, or one of
the following:
@@ -1039,6 +1919,12 @@ the following:
w:<pattern>
all wires with a name matching the given wildcard pattern
+ i:<pattern>, o:<pattern>, x:<pattern>
+ all inputs (i:), outputs (o:) or any ports (x:) with matching names
+
+ s:<size>, s:<min>:<max>
+ all wires with a matching width
+
m:<pattern>
all memories with a name matching the given pattern
@@ -1055,7 +1941,11 @@ the following:
all objects with an attribute name matching the given pattern
a:<pattern>=<pattern>
- all objects with a matching attribute name-value-pair
+ all objects with a matching attribute name-value-pair.
+ in addition to = also <, <=, >=, and > are supported
+
+ r:<pattern>, r:<pattern>=<pattern>
+ cells with matching parameters. also with <, <=, >= and >.
n:<pattern>
all objects with a name matching the given pattern
@@ -1084,6 +1974,12 @@ The following actions can be performed on the top sets on the stack:
%d
pop the top set from the stack and subtract it from the new top
+ %D
+ like %d but swap the roles of two top sets on the stack
+
+ %c
+ create a copy of the top set rom the stack and push it
+
%x[<num1>|*][.<num2>][:<rule>[:<rule>..]]
expand top set <num1> num times according to the specified rules.
(i.e. select all cells connected to selected wires and select all
@@ -1101,12 +1997,96 @@ The following actions can be performed on the top sets on the stack:
%co[<num1>|*][.<num2>][:<rule>[:<rule>..]]
simmilar to %x, but only select input (%ci) or output cones (%co)
+ %a
+ expand top set by selecting all wires that are (at least in part)
+ aliases for selected wires.
+
+ %s
+ expand top set by adding all modules of instantiated cells in selected
+ modules
+
+ %m
+ expand top set by selecting all modules that contain selected objects
+
Example: the following command selects all wires that are connected to a
'GATE' input of a 'SWITCH' cell:
select */t:SWITCH %x:+[GATE] */t:SWITCH %d
\end{lstlisting}
+\section{setattr -- set/unset attributes on objects}
+\label{cmd:setattr}
+\begin{lstlisting}[numbers=left,frame=single]
+ setattr [ -mod ] [ -set name value | -unset name ]... [selection]
+
+Set/unset the given attributes on the selected objects. String values must be
+passed in double quotes (").
+
+When called with -mod, this command will set and unset attributes on modules
+instead of objects within modules.
+\end{lstlisting}
+
+\section{setparam -- set/unset parameters on objects}
+\label{cmd:setparam}
+\begin{lstlisting}[numbers=left,frame=single]
+ setparam [ -set name value | -unset name ]... [selection]
+
+Set/unset the given parameters on the selected cells. String values must be
+passed in double quotes (").
+\end{lstlisting}
+
+\section{setundef -- replace undef values with defined constants}
+\label{cmd:setundef}
+\begin{lstlisting}[numbers=left,frame=single]
+ setundef [options] [selection]
+
+This command replaced undef (x) constants with defined (0/1) constants.
+
+ -undriven
+ also set undriven nets to constant values
+
+ -zero
+ replace with bits cleared (0)
+
+ -one
+ replace with bits set (1)
+
+ -random <seed>
+ replace with random bits using the specified integer als seed
+ value for the random number generator.
+\end{lstlisting}
+
+\section{share -- perform sat-based resource sharing}
+\label{cmd:share}
+\begin{lstlisting}[numbers=left,frame=single]
+ share [options] [selection]
+
+This pass merges shareable resources into a single resource. A SAT solver
+is used to determine if two resources are share-able.
+
+ -force
+ Per default the selection of cells that is considered for sharing is
+ narrowed using a list of cell types. With this option all selected
+ cells are considered for resource sharing.
+
+ IMPORTANT NOTE: If the -all option is used then no cells with internal
+ state must be selected!
+
+ -aggressive
+ Per default some heuristics are used to reduce the number of cells
+ considered for resource sharing to only large resources. This options
+ turns this heuristics off, resulting in much more cells being considered
+ for resource sharing.
+
+ -fast
+ Only consider the simple part of the control logic in SAT solving, resulting
+ in much easier SAT problems at the cost of maybe missing some oportunities
+ for resource sharing.
+
+ -limit N
+ Only perform the first N merges, then stop. This is useful for debugging.
+\end{lstlisting}
+
\section{shell -- enter interactive command mode}
\label{cmd:shell}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1163,19 +2143,32 @@ to a graphics file (usually SVG or PostScript).
-prefix <prefix>
generate <prefix>.* instead of ~/.yosys_show.*
- -color <color> <wire>
- assign the specified color to the specified wire. The object can be
+ -color <color> <object>
+ assign the specified color to the specified object. The object can be
a single selection wildcard expressions or a saved set of objects in
the @<name> syntax (see "help select" for details).
+ -label <text> <object>
+ assign the specified label text to the specified object. The object can
+ be a single selection wildcard expressions or a saved set of objects in
+ the @<name> syntax (see "help select" for details).
+
-colors <seed>
Randomly assign colors to the wires. The integer argument is the seed
for the random number generator. Change the seed value if the colored
graph still is ambigous. A seed of zero deactivates the coloring.
+ -colorattr <attribute_name>
+ Use the specified attribute to assign colors. A unique color is
+ assigned to each unique value of this attribute.
+
-width
annotate busses with a label indicating the width of the bus.
+ -signed
+ mark ports (A, B) that are declarted as signed (using the [AB]_SIGNED
+ cell parameter) with an asterisk next to the port name.
+
-stretch
stretch the graph so all inputs are on the left side and all outputs
(including inout ports) are on the right side.
@@ -1189,8 +2182,11 @@ to a graphics file (usually SVG or PostScript).
-long
do not abbeviate objects with internal ($-prefixed) names
-When no <format> is specified, SVG is used. When no <format> and <viewer> is
-specified, 'yosys-svgviewer' is used to display the schematic.
+ -notitle
+ do not add the module name as graph title to the dot file
+
+When no <format> is specified, 'dot' is used. When no <format> and <viewer> is
+specified, 'xdot' is used to display the schematic.
The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',
unless another prefix is specified using -prefix <prefix>.
@@ -1210,6 +2206,43 @@ primitives. The following internal cell types are mapped by this pass:
$sr, $dff, $dffsr, $adff, $dlatch
\end{lstlisting}
+\section{splice -- create explicit splicing cells}
+\label{cmd:splice}
+\begin{lstlisting}[numbers=left,frame=single]
+ splice [options] [selection]
+
+This command adds $slice and $concat cells to the design to make the splicing
+of multi-bit signals explicit. This for example is useful for coarse grain
+synthesis, where dedidacted hardware is needed to splice signals.
+
+ -sel_by_cell
+ only select the cell ports to rewire by the cell. if the selection
+ contains a cell, than all cell inputs are rewired, if necessary.
+
+ -sel_by_wire
+ only select the cell ports to rewire by the wire. if the selection
+ contains a wire, than all cell ports driven by this wire are wired,
+ if necessary.
+
+ -sel_any_bit
+ it is sufficient if the driver of any bit of a cell port is selected.
+ by default all bits must be selected.
+
+ -no_outputs
+ do not rewire selected module outputs.
+
+ -port <name>
+ only rewire cell ports with the specified name. can be used multiple
+ times. implies -no_output.
+
+ -no_port <name>
+ do not rewire cell ports with the specified name. can be used multiple
+ times. can not be combined with -port <name>.
+
+By default selected output wires and all cell ports of selected cells driven
+by selected wires are rewired.
+\end{lstlisting}
+
\section{splitnets -- split up multi-bit nets}
\label{cmd:splitnets}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1217,13 +2250,18 @@ primitives. The following internal cell types are mapped by this pass:
This command splits multi-bit nets into single-bit nets.
- -format char1[char2]
+ -format char1[char2[char3]]
the first char is inserted between the net name and the bit index, the
second char is appended to the netname. e.g. -format () creates net
- names like 'mysignal(42)'. the default is '[]'.
+ names like 'mysignal(42)'. the 3rd character is the range separation
+ character when creating multi-bit wires. the default is '[]:'.
-ports
also split module ports. per default only internal signals are split.
+
+ -driver
+ don't blindly split nets in individual bits. instead look at the driver
+ and split nets so that no driver drives only part of a net.
\end{lstlisting}
\section{stat -- print some statistics}
@@ -1238,6 +2276,10 @@ design.
print design hierarchy with this module as top. if the design is fully
selected and a module has the 'top' attribute set, this module is used
default value for this option.
+
+ -width
+ annotate internal cell types with their word width.
+ e.g. $add_8 for an 8 bit wide $add cell.
\end{lstlisting}
\section{submod -- moving part of a module to a new submodule}
@@ -1263,22 +2305,70 @@ Only objects from one module might be selected. The value of the -name option
is used as the value of the 'submod' attribute above.
\end{lstlisting}
+\section{synth -- generic synthesis script}
+\label{cmd:synth}
+\begin{lstlisting}[numbers=left,frame=single]
+ synth [options]
+
+This command runs the default synthesis script. This command does not operate
+on partly selected designs.
+
+ -top <module>
+ use the specified module as top module (default='top')
+
+ -encfile <file>
+ passed to 'fsm_recode' via 'fsm'
+
+ -noabc
+ do not run abc (as if yosys was compiled without ABC support)
+
+ -run <from_label>[:<to_label>]
+ only run the commands between the labels (see below). an empty
+ from label is synonymous to 'begin', and empty to label is
+ synonymous to the end of the command list.
+
+
+The following commands are executed by this synthesis command:
+
+ begin:
+ hierarchy -check [-top <top>]
+
+ coarse:
+ proc
+ opt
+ wreduce
+ alumacc
+ share
+ opt
+ fsm
+ opt -fast
+ memory -nomap
+ opt_clean
+
+ fine:
+ opt -fast -full
+ memory_map
+ opt -full
+ techmap
+ opt -fast
+
+ abc:
+ abc -fast
+ opt -fast
+\end{lstlisting}
+
\section{synth\_xilinx -- synthesis for Xilinx FPGAs}
\label{cmd:synth_xilinx}
\begin{lstlisting}[numbers=left,frame=single]
synth_xilinx [options]
This command runs synthesis for Xilinx FPGAs. This command does not operate on
-partly selected designs.
+partly selected designs. At the moment this command creates netlists that are
+compatible with 7-Series Xilinx devices.
-top <module>
use the specified module as top module (default='top')
- -arch <arch>
- select architecture. the following architectures are supported:
- spartan6 (default), artix7, kintex7, virtex7, zynq7000
- (this parameter is not used by the command at the moment)
-
-edif <file>
write the design to the specified edif file. writing of an output file
is omitted if this parameter is not specified.
@@ -1288,40 +2378,46 @@ partly selected designs.
from label is synonymous to 'begin', and empty to label is
synonymous to the end of the command list.
+ -flatten
+ flatten design before synthesis
+
+ -retime
+ run 'abc' with -dff option
+
The following commands are executed by this synthesis command:
begin:
+ read_verilog -lib +/xilinx/cells_sim.v
hierarchy -check -top <top>
- coarse:
+ flatten: (only if -flatten)
proc
- opt
- memory
- clean
- fsm
- opt
+ flatten
+
+ coarse:
+ synth -run coarse
+ dff2dffe
+
+ bram:
+ memory_bram -rules +/xilinx/brams.txt
+ techmap -map +/xilinx/brams_map.v
fine:
- techmap
- opt
+ opt -fast -full
+ memory_map
+ opt -full
+ techmap -map +/techmap.v -map +/xilinx/arith_map.v
+ opt -fast
map_luts:
- abc -lut 6
+ abc -lut 5:8 [-dff]
clean
map_cells:
- techmap -share_map xilinx/cells.v
+ techmap -map +/xilinx/cells_map.v
clean
- clkbuf:
- select -set xilinx_clocks <top>/t:FDRE %x:+FDRE[C] <top>/t:FDRE %d
- iopadmap -inpad BUFGP O:I @xilinx_clocks
-
- iobuf:
- select -set xilinx_nonclocks <top>/w:* <top>/t:BUFGP %x:+BUFGP[I] %d
- iopadmap -outpad OBUF I:O -inpad IBUF O:I @xilinx_nonclocks
-
edif:
write_edif synth.edif
\end{lstlisting}
@@ -1340,7 +2436,7 @@ command 'proc' is wrapped using the tcl command 'procs' in order
to avoid a name collision with the tcl builting command 'proc'.
\end{lstlisting}
-\section{techmap -- simple technology mapper}
+\section{techmap -- generic technology mapper}
\label{cmd:techmap}
\begin{lstlisting}[numbers=left,frame=single]
techmap [-map filename] [selection]
@@ -1355,11 +2451,34 @@ file.
transforms the internal RTL cells to the internal gate
library.
+ -map %<design-name>
+ like -map above, but with an in-memory design instead of a file.
+
-share_map filename
like -map, but look for the file in the share directory (where the
yosys data files are). this is mainly used internally when techmap
is called from other commands.
+ -extern
+ load the cell implementations as separate modules into the design
+ instead of inlining them.
+
+ -max_iter <number>
+ only run the specified number of iterations.
+
+ -recursive
+ instead of the iterative breadth-first algorithm use a recursive
+ depth-first algorithm. both methods should yield equivialent results,
+ but may differ in performance.
+
+ -autoproc
+ Automatically call "proc" on implementations that contain processes.
+
+ -assert
+ this option will cause techmap to exit with an error if it can't map
+ a selected cell. only cell types that end on an underscore are accepted
+ as final cell types by this mode.
+
-D <define>, -I <incdir>
this options are passed as-is to the verilog frontend for loading the
map file. Note that the verilog frontend is also called with the
@@ -1372,6 +2491,13 @@ the module name will be used to match the cell.
When a module in the map file has the 'techmap_simplemap' attribute set, techmap
will use 'simplemap' (see 'help simplemap') to map cells matching the module.
+When a module in the map file has the 'techmap_maccmap' attribute set, techmap
+will use 'maccmap' (see 'help maccmap') to map cells matching the module.
+
+When a module in the map file has the 'techmap_wrap' attribute set, techmap
+will create a wrapper for the cell and then run the command string that the
+attribute is set to on the wrapper module.
+
All wires in the modules from the map file matching the pattern _TECHMAP_*
or *._TECHMAP_* are special wires that are used to pass instructions from
the mapping module to the techmap command. At the moment the following special
@@ -1396,6 +2522,20 @@ wires are supported:
wire to start out as non-constant and evaluate to a constant value
during processing of other _TECHMAP_DO_* commands.
+ A _TECHMAP_DO_* command may start with the special token 'CONSTMAP; '.
+ in this case techmap will create a copy for each distinct configuration
+ of constant inputs and shorted inputs at this point and import the
+ constant and connected bits into the map module. All further commands
+ are executed in this copy. This is a very convenient way of creating
+ optimizied specializations of techmap modules without using the special
+ parameters described below.
+
+ A _TECHMAP_DO_* command may start with the special token 'RECURSION; '.
+ then techmap will recursively replace the cells in the module with their
+ implementation. This is not affected by the -max_iter option.
+
+ It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.
+
In addition to this special wires, techmap also supports special parameters in
modules in the map file:
@@ -1403,21 +2543,70 @@ modules in the map file:
When a parameter with this name exists, it will be set to the type name
of the cell that matches the module.
+ _TECHMAP_CONSTMSK_<port-name>_
+ _TECHMAP_CONSTVAL_<port-name>_
+ When this pair of parameters is available in a module for a port, then
+ former has a 1-bit for each constant input bit and the latter has the
+ value for this bit. The unused bits of the latter are set to undef (x).
+
+ _TECHMAP_BITS_CONNMAP_
+ _TECHMAP_CONNMAP_<port-name>_
+ For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it
+ exists, will be set to an N*_TECHMAP_BITS_CONNMAP_ bit vector containing
+ N words (of _TECHMAP_BITS_CONNMAP_ bits each) that assign each single
+ bit driver a unique id. The values 0-3 are reserved for 0, 1, x, and z.
+ This can be used to detect shorted inputs.
+
When a module in the map file has a parameter where the according cell in the
design has a port, the module from the map file is only used if the port in
the design is connected to a constant value. The parameter is then set to the
constant value.
+A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name
+of the cell that is beeing replaced.
+
See 'help extract' for a pass that does the opposite thing.
See 'help flatten' for a pass that does flatten the design (which is
esentially techmap but using the design itself as map library).
\end{lstlisting}
-\section{write\_autotest -- generate simple test benches}
-\label{cmd:write_autotest}
+\section{tee -- redirect command output to file}
+\label{cmd:tee}
\begin{lstlisting}[numbers=left,frame=single]
- write_autotest [filename]
+ tee [-q] [-o logfile|-a logfile] cmd
+
+Execute the specified command, optionally writing the commands output to the
+specified logfile(s).
+
+ -q
+ Do not print output to the normal destination (console and/or log file)
+
+ -o logfile
+ Write output to this file, truncate if exists.
+
+ -a logfile
+ Write output to this file, append if exists.
+\end{lstlisting}
+
+\section{test\_abcloop -- automatically test handling of loops in abc command}
+\label{cmd:test_abcloop}
+\begin{lstlisting}[numbers=left,frame=single]
+ test_abcloop [options]
+
+Test handling of logic loops in ABC.
+
+ -n {integer}
+ create this number of circuits and test them (default = 100).
+
+ -s {positive_integer}
+ use this value as rng seed value (default = unix time).
+\end{lstlisting}
+
+\section{test\_autotb -- generate simple test benches}
+\label{cmd:test_autotb}
+\begin{lstlisting}[numbers=left,frame=single]
+ test_autotb [options] [filename]
Automatically create primitive verilog test benches for all modules in the
design. The generated testbenches toggle the input pins of the module in
@@ -1433,6 +2622,156 @@ be forced to be interpreted as clock signal by setting the attribute
The attribute 'gentb_constant' can be used to force a signal to a constant
value after initialization. This can e.g. be used to force a reset signal
low in order to explore more inner states in a state machine.
+
+ -n <int>
+ number of iterations the test bench shuld run (default = 1000)
+\end{lstlisting}
+
+\section{test\_cell -- automatically test the implementation of a cell type}
+\label{cmd:test_cell}
+\begin{lstlisting}[numbers=left,frame=single]
+ test_cell [options] {cell-types}
+
+Tests the internal implementation of the given cell type (for example '$add')
+by comparing SAT solver, EVAL and TECHMAP implementations of the cell types..
+
+Run with 'all' instead of a cell type to run the test on all supported
+cell types. Use for example 'all /$add' for all cell types except $add.
+
+ -n {integer}
+ create this number of cell instances and test them (default = 100).
+
+ -s {positive_integer}
+ use this value as rng seed value (default = unix time).
+
+ -f {ilang_file}
+ don't generate circuits. instead load the specified ilang file.
+
+ -w {filename_prefix}
+ don't test anything. just generate the circuits and write them
+ to ilang files with the specified prefix
+
+ -map {filename}
+ pass this option to techmap.
+
+ -simlib
+ use "techmap -map +/simlib.v -max_iter 2 -autoproc"
+
+ -muxdiv
+ when creating test benches with dividers, create an additional mux
+ to mask out the division-by-zero case
+
+ -script {script_file}
+ instead of calling "techmap", call "script {script_file}".
+
+ -const
+ set some input bits to random constant values
+
+ -nosat
+ do not check SAT model or run SAT equivalence checking
+
+ -v
+ print additional debug information to the console
+
+ -vlog {filename}
+ create a verilog test bench to test simlib and write_verilog
+\end{lstlisting}
+
+\section{trace -- redirect command output to file}
+\label{cmd:trace}
+\begin{lstlisting}[numbers=left,frame=single]
+ trace cmd
+
+Execute the specified command, logging all changes the command performs on
+the design in real time.
+\end{lstlisting}
+
+\section{verific -- load Verilog and VHDL designs using Verific}
+\label{cmd:verific}
+\begin{lstlisting}[numbers=left,frame=single]
+ verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv} <verilog-file>..
+
+Load the specified Verilog/SystemVerilog files into Verific.
+
+
+ verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008} <vhdl-file>..
+
+Load the specified VHDL files into Verific.
+
+
+ verific -import [-gates] {-all | <top-module>..}
+
+Elaborate the design for the sepcified top modules, import to Yosys and
+reset the internal state of Verific. A gate-level netlist is created
+when called with -gates.
+
+Visit http://verific.com/ for more information on Verific.
+\end{lstlisting}
+
+\section{verilog\_defaults -- set default options for read\_verilog}
+\label{cmd:verilog_defaults}
+\begin{lstlisting}[numbers=left,frame=single]
+ verilog_defaults -add [options]
+
+Add the sepcified options to the list of default options to read_verilog.
+
+
+ verilog_defaults -clear
+Clear the list of verilog default options.
+
+
+ verilog_defaults -push verilog_defaults -pop
+Push or pop the list of default options to a stack. Note that -push does
+not imply -clear.
+\end{lstlisting}
+
+\section{vhdl2verilog -- importing VHDL designs using vhdl2verilog}
+\label{cmd:vhdl2verilog}
+\begin{lstlisting}[numbers=left,frame=single]
+ vhdl2verilog [options] <vhdl-file>..
+
+This command reads VHDL source files using the 'vhdl2verilog' tool and the
+Yosys Verilog frontend.
+
+ -out <out_file>
+ do not import the vhdl2verilog output. instead write it to the
+ specified file.
+
+ -vhdl2verilog_dir <directory>
+ do use the specified vhdl2verilog installation. this is the directory
+ that contains the setup_env.sh file. when this option is not present,
+ it is assumed that vhdl2verilog is in the PATH environment variable.
+
+ -top <top-entity-name>
+ The name of the top entity. This option is mandatory.
+
+The following options are passed as-is to vhdl2verilog:
+
+ -arch <architecture_name>
+ -unroll_generate
+ -nogenericeval
+ -nouniquify
+ -oldparser
+ -suppress <list>
+ -quiet
+ -nobanner
+ -mapfile <file>
+
+vhdl2verilog can be obtained from:
+http://www.edautils.com/vhdl2verilog.html
+\end{lstlisting}
+
+\section{wreduce -- reduce the word size of operations is possible}
+\label{cmd:wreduce}
+\begin{lstlisting}[numbers=left,frame=single]
+ wreduce [options] [selection]
+
+This command reduces the word size of operations. For example it will replace
+the 32 bit adders in the following code with adders of more appropriate widths:
+
+ module test(input [3:0] a, b, c, output [7:0] y);
+ assign y = a + b + c + 1;
+ endmodule
\end{lstlisting}
\section{write\_blif -- write design to BLIF file}
@@ -1448,24 +2787,50 @@ Write the current design to an BLIF file.
-buf <cell-type> <in-port> <out-port>
use cells of type <cell-type> with the specified port names for buffers
+ -unbuf <cell-type> <in-port> <out-port>
+ replace buffer cells with the specified name and port names with
+ a .names statement that models a buffer
+
-true <cell-type> <out-port>
-false <cell-type> <out-port>
- use the specified cell types to drive nets that are constant 1 or 0
+ -undef <cell-type> <out-port>
+ use the specified cell types to drive nets that are constant 1, 0, or
+ undefined. when '-' is used as <cell-type>, then <out-port> specifies
+ the wire name to be used for the constant signal and no cell driving
+ that wire is generated.
The following options can be useful when the generated file is not going to be
read by a BLIF parser but a custom tool. It is recommended to not name the output
file *.blif when any of this options is used.
- -subckt
+ -icells
do not translate Yosys's internal gates to generic BLIF logic
- functions. Instead create .subckt lines for all cells.
+ functions. Instead create .subckt or .gate lines for all cells.
+
+ -gates
+ print .gate instead of .subckt lines for all cells that are not
+ instantiations of other modules from this design.
-conn
do not generate buffers for connected wires. instead use the
non-standard .conn statement.
+ -param
+ use the non-standard .param statement to write module parameters
+
+ -blackbox
+ write blackbox cells with .blackbox statement.
+
-impltf
- do not write definitions for the $true and $false wires.
+ do not write definitions for the $true, $false and $undef wires.
+\end{lstlisting}
+
+\section{write\_btor -- write design to BTOR file}
+\label{cmd:write_btor}
+\begin{lstlisting}[numbers=left,frame=single]
+ write_btor [filename]
+
+Write the current design to an BTOR file.
\end{lstlisting}
\section{write\_edif -- write design to EDIF netlist file}
@@ -1484,6 +2849,24 @@ necessary to make small modifications to this command when a different tool
is targeted.
\end{lstlisting}
+\section{write\_file -- write a text to a file}
+\label{cmd:write_file}
+\begin{lstlisting}[numbers=left,frame=single]
+ write_file [options] output_file [input_file]
+
+Write the text fron the input file to the output file.
+
+ -a
+ Append to output file (instead of overwriting)
+
+
+Inside a script the input file can also can a here-document:
+
+ write_file hello.txt <<EOT
+ Hello World!
+ EOT
+\end{lstlisting}
+
\section{write\_ilang -- write design to ilang file}
\label{cmd:write_ilang}
\begin{lstlisting}[numbers=left,frame=single]
@@ -1520,6 +2903,83 @@ a tool for Coarse-Grain Example-Driven Interconnect Synthesis.
http://www.clifford.at/intersynth/
\end{lstlisting}
+\section{write\_smt2 -- write design to SMT-LIBv2 file}
+\label{cmd:write_smt2}
+\begin{lstlisting}[numbers=left,frame=single]
+ write_smt2 [options] [filename]
+
+Write a SMT-LIBv2 [1] description of the current design. For a module with name
+'<mod>' this will declare the sort '<mod>_s' (state of the module) and the the
+function '<mod>_t' (state transition function).
+
+The '<mod>_s' sort represents a module state. Additional '<mod>_n' functions
+are provided that can be used to access the values of the signals in the module.
+Only ports, and signals with the 'keep' attribute set are made available via
+such functions. Without the -bv option, multi-bit wires are exported as
+separate functions of type Bool for the individual bits. With the -bv option
+multi-bit wires are exported as single functions of type BitVec.
+
+The '<mod>_t' function evaluates to 'true' when the given pair of states
+describes a valid state transition.
+
+ -bv
+ enable support for BitVec (FixedSizeBitVectors theory). with this
+ option set multi-bit wires are represented using the BitVec sort and
+ support for coarse grain cells (incl. arithmetic) is enabled.
+
+ -tpl <template_file>
+ use the given template file. the line containing only the token '%%'
+ is replaced with the regular output of this command.
+
+[1] For more information on SMT-LIBv2 visit http://smt-lib.org/ or read David
+R. Cok's tutorial: http://www.grammatech.com/resources/smt/SMTLIBTutorial.pdf
+
+---------------------------------------------------------------------------
+
+Example:
+
+Consider the following module (test.v). We want to prove that the output can
+never transition from a non-zero value to a zero value.
+
+ module test(input clk, output reg [3:0] y);
+ always @(posedge clk)
+ y <= (y << 1) | ^y;
+ endmodule
+
+For this proof we create the following template (test.tpl).
+
+ ; we need QF_UFBV for this poof
+ (set-logic QF_UFBV)
+
+ ; insert the auto-generated code here
+ %%
+
+ ; declare two state variables s1 and s2
+ (declare-fun s1 () test_s)
+ (declare-fun s2 () test_s)
+
+ ; state s2 is the successor of state s1
+ (assert (test_t s1 s2))
+
+ ; we are looking for a model with y non-zero in s1
+ (assert (distinct (|test_n y| s1) #b0000))
+
+ ; we are looking for a model with y zero in s2
+ (assert (= (|test_n y| s2) #b0000))
+
+ ; is there such a model?
+ (check-sat)
+
+The following yosys script will create a 'test.smt2' file for our proof:
+
+ read_verilog test.v
+ hierarchy; proc; techmap; opt -fast
+ write_smt2 -bv -tpl test.tpl test.smt2
+
+Running 'cvc4 test.smt2' will print 'unsat' because y can never transition
+from non-zero to zero in the test design.
+\end{lstlisting}
+
\section{write\_spice -- write design to SPICE netlist file}
\label{cmd:write_spice}
\begin{lstlisting}[numbers=left,frame=single]
diff --git a/manual/manual.tex b/manual/manual.tex
index 19d3b7b2..84be86e5 100644
--- a/manual/manual.tex
+++ b/manual/manual.tex
@@ -61,6 +61,7 @@ bookmarksopen=false%
\usepackage{multibib}
\usepackage{multirow}
\usepackage{booktabs}
+\usepackage{pdfpages}
\usepackage{listings}
\usepackage{pifont}
@@ -202,7 +203,7 @@ YOSYS & Yosys Open SYnthesis Suite \\
\include{CHAPTER_Verilog}
\include{CHAPTER_Optimize}
\include{CHAPTER_Techmap}
-\include{CHAPTER_Eval}
+% \include{CHAPTER_Eval}
\appendix
@@ -214,7 +215,7 @@ YOSYS & Yosys Open SYnthesis Suite \\
\input{command-reference-manual}
\include{CHAPTER_Appnotes}
-\include{CHAPTER_StateOfTheArt}
+% \include{CHAPTER_StateOfTheArt}
\bibliography{literature}
\bibliographystyle{alphadin}
diff --git a/manual/presentation.sh b/manual/presentation.sh
index 980e1772..ca8a6c93 100755
--- a/manual/presentation.sh
+++ b/manual/presentation.sh
@@ -24,8 +24,10 @@ done
PDFTEX_OPT="-shell-escape -halt-on-error"
+set -ex
+
if ! $fast_mode; then
- md5sum *.aux *.snm *.nav *.toc > autoloop.old
+ ! md5sum *.aux *.snm *.nav *.toc > autoloop.old
make -C PRESENTATION_Intro
make -C PRESENTATION_ExSyn
make -C PRESENTATION_ExAdv
diff --git a/manual/presentation.tex b/manual/presentation.tex
index 9a876de0..dc512775 100644
--- a/manual/presentation.tex
+++ b/manual/presentation.tex
@@ -74,7 +74,7 @@
{\usebeamerfont{subsection name}\usebeamercolor[fg]{subsection name}of \sectionname~\insertsectionnumber}
\vskip1em\par
\setbeamercolor{graybox}{bg=gray}
-\begin{beamercolorbox}[sep=8pt,center,bg=gray]{graybox}
+\begin{beamercolorbox}[sep=8pt,center]{graybox}
\usebeamerfont{subsection title}\insertsection\par
\end{beamercolorbox}
\end{centering}}
@@ -133,7 +133,7 @@ I like writing open source software. For example:
\item OpenSCAD (now maintained by Marius Kintel)
\item SPL (a not very popular scripting language)
\item EmbedVM (a very simple compiler+vm for 8 bit micros)
-\item Lib(X)SVF (a library to play SVF/XSVF files over JTAG, used at LHC)
+\item Lib(X)SVF (a library to play SVF/XSVF files over JTAG)
\item ROCK Linux (discontinued since 2010)
\end{itemize}
\end{frame}
diff --git a/misc/create_vcxsrc.sh b/misc/create_vcxsrc.sh
new file mode 100644
index 00000000..215e27c5
--- /dev/null
+++ b/misc/create_vcxsrc.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+set -ex
+vcxsrc="$1-$2"
+yosysver="$2"
+gitsha="$3"
+
+rm -rf YosysVS-Tpl-v1.zip YosysVS
+wget http://www.clifford.at/yosys/nogit/YosysVS-Tpl-v1.zip
+
+unzip YosysVS-Tpl-v1.zip
+rm -f YosysVS-Tpl-v1.zip
+mv YosysVS "$vcxsrc"
+
+{
+ n=$(grep -B999 '<ItemGroup>' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l)
+ head -n$n "$vcxsrc"/YosysVS/YosysVS.vcxproj
+ egrep '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,<ClInclude Include="../yosys/&" />,'
+ egrep -v '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,<ClCompile Include="../yosys/&" />,'
+ echo '<ClCompile Include="../yosys/kernel/version.cc" />'
+ tail -n +$((n+1)) "$vcxsrc"/YosysVS/YosysVS.vcxproj
+} > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
+
+mv "$vcxsrc"/YosysVS/YosysVS.vcxproj.new "$vcxsrc"/YosysVS/YosysVS.vcxproj
+
+mkdir -p "$vcxsrc"/yosys
+tar -cf - -T srcfiles.txt | tar -xf - -C "$vcxsrc"/yosys
+cp -r share "$vcxsrc"/
+
+echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys" \
+ "$yosysver (git sha1 $gitsha, Visual Studio)\"; }" > "$vcxsrc"/yosys/kernel/version.cc
+
+cat > "$vcxsrc"/readme-git.txt << EOT
+Want to use a git working copy for the yosys source code?
+Open "Git Bash" in this directory and run:
+
+ mv yosys yosys.bak
+ git clone https://github.com/cliffordwolf/yosys.git yosys
+ cd yosys
+ git checkout -B master $(git rev-parse HEAD | cut -c1-10)
+ unzip ../genfiles.zip
+EOT
+
+cat > "$vcxsrc"/readme-abc.txt << EOT
+Yosys is using "ABC" for gate-level optimizations and technology
+mapping. Download yosys-win32-mxebin-$yosysver.zip and copy the
+following files from it into this directory:
+
+ pthreadVC2.dll
+ yosys-abc.exe
+EOT
+
+sed -i 's/$/\r/; s/\r\r*/\r/g;' "$vcxsrc"/YosysVS/YosysVS.vcxproj "$vcxsrc"/readme-git.txt "$vcxsrc"/readme-abc.txt
+
diff --git a/misc/example.cc b/misc/example.cc
new file mode 100644
index 00000000..a8244ac4
--- /dev/null
+++ b/misc/example.cc
@@ -0,0 +1,21 @@
+// clang -o example -std=c++11 -I/usr/include/tcl8.5 -I include/ example.cc objs/*.o -lstdc++ -lm -lrt -lreadline -lffi -ldl -ltcl8.5
+
+#include <yosys.h>
+
+int main()
+{
+ Yosys::log_streams.push_back(&std::cout);
+ Yosys::log_error_stderr = true;
+
+ Yosys::yosys_setup();
+ Yosys::yosys_banner();
+
+ Yosys::run_pass("read_verilog example.v");
+ Yosys::run_pass("synth -noabc");
+ Yosys::run_pass("clean -purge");
+ Yosys::run_pass("write_blif example.blif");
+
+ Yosys::yosys_shutdown();
+ return 0;
+}
+
diff --git a/yosys-config.in b/misc/yosys-config.in
index 8f8dd06c..1473948c 100644
--- a/yosys-config.in
+++ b/misc/yosys-config.in
@@ -3,7 +3,8 @@
help() {
{
echo ""
- echo "Usage: $0 [-exec] [--prefix pf] args.."
+ echo "Usage: $0 [--exec] [--prefix pf] args.."
+ echo " $0 --build modname.so cppsources.."
echo ""
echo "Replecement args:"
echo " --cxx @CXX@"
@@ -13,12 +14,16 @@ help() {
echo " --bindir @BINDIR@"
echo " --datdir @DATDIR@"
echo ""
- echo "All other args are passed trhough as they are."
+ echo "All other args are passed through as they are."
echo ""
- echo "Use -exec to call a command instead of generating output. Example usage:"
+ echo "Use --exec to call a command instead of generating output. Example usage:"
echo ""
echo " yosys-config --exec --cxx --cxxflags --ldflags -o plugin.so -shared plugin.cc --ldlibs"
echo ""
+ echo "The above command can be abbreviated as:"
+ echo ""
+ echo " yosys-config --build plugin.so plugin.cc"
+ echo ""
echo "Use --prefix to change the prefix for the special args from '--' to"
echo "something else. Example:"
echo ""
@@ -37,6 +42,11 @@ if [ $# -eq 0 ]; then
help
fi
+if [ "$1" == "--build" ]; then
+ modname="$2"; shift 2
+ set -- --exec --cxx --cxxflags --ldflags -o "$modname" -shared "$@" --ldlibs
+fi
+
prefix="--"
get_prefix=false
exec_mode=false
diff --git a/misc/yosysjs/demo01.html b/misc/yosysjs/demo01.html
new file mode 100644
index 00000000..3f9f737e
--- /dev/null
+++ b/misc/yosysjs/demo01.html
@@ -0,0 +1,197 @@
+<html><head>
+ <title>YosysJS Example Application #01</title>
+ <script type="text/javascript" src="yosysjs.js"></script>
+</head><body onload="document.getElementById('command').focus()">
+ <h1>YosysJS Example Application #01</h1>
+ <table width="100%"><tr><td><div id="tabs"></div></td><td align="right"><tt>[ <span onclick="load_example()">load example</span> ]</tt></td></tr></table>
+ <svg id="svg" style="display: none; position: absolute; padding: 10px; width: calc(100% - 40px); height: 480px;"></svg>
+ <div><textarea id="output" style="width: 100%; height: 500px"></textarea></div>
+ <div id="wait" style="display: block"><br/><b><span id="waitmsg">Loading...</span></b></div>
+ <div id="input" style="display: none"><form onsubmit="window.setTimeout(run_command); return false"><br/><tt><span id="prompt">
+ </span></tt><input id="command" type="text" onkeydown="history(event)" style="font-family: monospace; font-weight: bold;" size="100"></form></div>
+ <script type='text/javascript'>
+ function print_output(text) {
+ var el = document.getElementById('output');
+ el.value += text + "\n";
+ }
+
+ YosysJS.load_viz();
+ var ys = YosysJS.create("", function() {
+ print_output(ys.print_buffer);
+
+ document.getElementById('wait').style.display = 'none';
+ document.getElementById('input').style.display = 'block';
+ document.getElementById('waitmsg').textContent = 'Waiting for yosys.js...';
+ document.getElementById('prompt').textContent = ys.prompt();
+
+ update_tabs();
+ });
+
+ ys.echo = true;
+
+ var history_log = [];
+ var history_index = 0;
+ var history_bak = "";
+
+ function history(ev) {
+ if (ev.keyCode == 38) {
+ el = document.getElementById('command');
+ if (history_index == history_log.length)
+ history_bak = el.value
+ if (history_index > 0)
+ el.value = history_log[--history_index];
+ }
+ if (ev.keyCode == 40) {
+ if (history_index < history_log.length) {
+ el = document.getElementById('command');
+ if (++history_index < history_log.length)
+ el.value = history_log[history_index];
+ else
+ el.value = history_bak;
+ }
+ }
+ }
+
+ var current_file = "";
+ var console_messages = "";
+ var svg_cache = { };
+
+ function update_tabs() {
+ var f, html = "", flist = ys.read_dir('.');
+ if (current_file == "") {
+ html += '<tt>[ <b>Console</b>';
+ } else {
+ html += '<tt>[ <span onclick="open_file(\'\')">Console</span>';
+ }
+ for (i in flist) {
+ f = flist[i]
+ if (f == "." || f == "..")
+ continue;
+ if (current_file == f) {
+ html += ' | <b>' + f + '</b>';
+ } else {
+ html += ' | <span onclick="open_file(\'' + f + '\')">' + f + '</span>';
+ }
+ }
+ html += ' | <span onclick="open_file(prompt(\'Filename:\'))">new file</span> ]</tt>';
+ document.getElementById('tabs').innerHTML = html;
+ if (current_file == "" || /\.dot$/.test(current_file)) {
+ var element = document.getElementById('output');
+ element.readOnly = true;
+ element.scrollTop = element.scrollHeight; // focus on bottom
+ document.getElementById('command').focus();
+ } else {
+ document.getElementById('output').readOnly = false;
+ document.getElementById('output').focus();
+ }
+ }
+
+ function open_file(filename)
+ {
+ if (current_file == "")
+ console_messages = document.getElementById('output').value;
+ else if (!/\.dot$/.test(current_file))
+ ys.write_file(current_file, document.getElementById('output').value);
+
+ if (filename == "") {
+ document.getElementById('output').value = console_messages;
+ } else {
+ try {
+ document.getElementById('output').value = ys.read_file(filename);
+ } catch (e) {
+ document.getElementById('output').value = "";
+ ys.write_file(filename, document.getElementById('output').value);
+ }
+ }
+
+ if (/\.dot$/.test(filename)) {
+ dot = document.getElementById('output').value;
+ YosysJS.dot_into_svg(dot, 'svg');
+ document.getElementById('svg').style.display = 'block';
+ document.getElementById('output').value = '';
+ } else {
+ document.getElementById('svg').innerHTML = '';
+ document.getElementById('svg').style.display = 'none';
+ }
+
+ current_file = filename;
+ update_tabs()
+ }
+
+ function startup() {
+ }
+
+ function load_example() {
+ open_file('')
+
+ var txt = "";
+ txt += "// a simple yosys.js example. run \"script example.ys\".\n";
+ txt += "\n";
+ txt += "module example(input clk, input rst, input inc, output reg [3:0] cnt);\n";
+ txt += " always @(posedge clk) begin\n";
+ txt += " if (rst)\n";
+ txt += " cnt <= 0;\n";
+ txt += " else if (inc)\n";
+ txt += " cnt <= cnt + 1;\n";
+ txt += " end\n";
+ txt += "endmodule\n";
+ txt += "\n";
+ ys.write_file('example.v', txt);
+
+ var txt = "";
+ txt += "# a simple yosys.js example. run \"script example.ys\".\n";
+ txt += "\n";
+ txt += "design -reset\n";
+ txt += "read_verilog example.v\n";
+ txt += "proc\n";
+ txt += "opt\n";
+ txt += "show\n";
+ txt += "\n";
+ ys.write_file('example.ys', txt);
+
+ open_file('example.ys')
+ document.getElementById('command').focus();
+ }
+
+ function run_command() {
+ var cmd = document.getElementById('command').value;
+ document.getElementById('command').value = '';
+ if (history_log.length == 0 || history_log[history_log.length-1] != cmd)
+ history_log.push(cmd);
+ history_index = history_log.length;
+
+ var show_dot_before = "";
+ try { show_dot_before = ys.read_file('show.dot'); } catch (e) { }
+
+ open_file('');
+
+ document.getElementById('wait').style.display = 'block';
+ document.getElementById('input').style.display = 'none';
+
+ function run_command_bh() {
+ try {
+ ys.run(cmd);
+ } catch (e) {
+ ys.write('Caught JavaScript exception. (see JavaScript console for details.)');
+ console.log(e);
+ }
+ print_output(ys.print_buffer);
+
+ document.getElementById('wait').style.display = 'none';
+ document.getElementById('input').style.display = 'block';
+ document.getElementById('prompt').textContent = ys.prompt();
+
+ var show_dot_after = "";
+ try { show_dot_after = ys.read_file('show.dot'); } catch (e) { }
+
+ if (show_dot_before != show_dot_after)
+ open_file('show.dot');
+
+ update_tabs();
+ }
+
+ window.setTimeout(run_command_bh, 50);
+ return false;
+ }
+ </script>
+</body></html>
diff --git a/misc/yosysjs/demo02.html b/misc/yosysjs/demo02.html
new file mode 100644
index 00000000..d36e223c
--- /dev/null
+++ b/misc/yosysjs/demo02.html
@@ -0,0 +1,102 @@
+<html><head>
+ <title>YosysJS Example Application #02</title>
+ <script type="text/javascript" src="yosysjs.js"></script>
+</head><body>
+ <div id="popup" style="position: fixed; left: 0; top: 0; width:100%; height:100%; text-align:center; z-index: 1000;"><div
+ style="width:300px; margin: 200px auto; background-color: #88f; border:3px dashed #000;
+ padding:15px; text-align:center;"><span id="popupmsg">Loading...</span></div>
+ </div>
+ <h1>YosysJS Example Application #02</h1>
+ <iframe id="ys" style="width: 800px; height: 100px;"></iframe><p/>
+ <textarea id="code" style="width: 800px; height: 300px;">
+// borrowed with some modifications from
+// http://www.ee.ed.ac.uk/~gerard/Teach/Verilog/manual/Example/lrgeEx2/cooley.html
+module up3down5(clock, data_in, up, down, carry_out, borrow_out, count_out, parity_out);
+
+input [8:0] data_in;
+input clock, up, down;
+
+output reg [8:0] count_out;
+output reg carry_out, borrow_out, parity_out;
+
+reg [9:0] cnt_up, cnt_dn;
+reg [8:0] count_nxt;
+
+always @(posedge clock)
+begin
+ cnt_dn = count_out - 3'b 101;
+ cnt_up = count_out + 2'b 11;
+
+ case ({up,down})
+ 2'b 00 : count_nxt = data_in;
+ 2'b 01 : count_nxt = cnt_dn;
+ 2'b 10 : count_nxt = cnt_up;
+ 2'b 11 : count_nxt = count_out;
+ default : count_nxt = 9'bX;
+ endcase
+
+ parity_out &lt;= ^count_nxt;
+ carry_out &lt;= up &amp; cnt_up[9];
+ borrow_out &lt;= down &amp; cnt_dn[9];
+ count_out &lt;= count_nxt;
+end
+
+endmodule
+ </textarea><p/>
+ <input type="button" value="Before Behavioral Synth" onclick="synth1()">
+ <input type="button" value="After Behavioral Synth" onclick="synth2()">
+ <input type="button" value="After RTL Synth" onclick="synth3()">
+ <input type="button" value="After Gate-Level Synth" onclick="synth4()"><p/>
+ <svg id="svg" width="800"></svg>
+ </td></tr></table>
+ <script type="text/javascript">
+ YosysJS.load_viz();
+ function on_ys_ready() {
+ document.getElementById('popup').style.visibility = 'hidden';
+ document.getElementById('popupmsg').textContent = 'Please wait..';
+ }
+ function synth1() {
+ function work() {
+ ys.write_file("input.v", document.getElementById('code').value);
+ ys.run('design -reset; read_verilog input.v; show -stretch');
+ YosysJS.dot_into_svg(ys.read_file('show.dot'), 'svg');
+ document.getElementById('popup').style.visibility = 'hidden';
+ }
+ document.getElementById('popup').style.visibility = 'visible';
+ window.setTimeout(work, 100);
+ }
+ function synth2() {
+ function work() {
+ ys.write_file("input.v", document.getElementById('code').value);
+ ys.run('design -reset; read_verilog input.v; proc; opt_clean; show -stretch');
+ YosysJS.dot_into_svg(ys.read_file('show.dot'), 'svg');
+ document.getElementById('popup').style.visibility = 'hidden';
+ }
+ document.getElementById('popup').style.visibility = 'visible';
+ window.setTimeout(work, 100);
+ }
+ function synth3() {
+ function work() {
+ ys.write_file("input.v", document.getElementById('code').value);
+ ys.run('design -reset; read_verilog input.v; synth -run coarse; show -stretch');
+ YosysJS.dot_into_svg(ys.read_file('show.dot'), 'svg');
+ document.getElementById('popup').style.visibility = 'hidden';
+ }
+ document.getElementById('popup').style.visibility = 'visible';
+ window.setTimeout(work, 100);
+ }
+ function synth4() {
+ function work() {
+ ys.write_file("input.v", document.getElementById('code').value);
+ ys.run('design -reset; read_verilog input.v; synth -run coarse; synth -run fine; show -stretch');
+ YosysJS.dot_into_svg(ys.read_file('show.dot'), 'svg');
+ document.getElementById('popup').style.visibility = 'hidden';
+ }
+ document.getElementById('popup').style.visibility = 'visible';
+ window.setTimeout(work, 100);
+ }
+ var ys = YosysJS.create('ys', on_ys_ready);
+ ys.verbose = true;
+ ys.echo = true;
+ </script>
+</body></html>
diff --git a/misc/yosysjs/demo03.html b/misc/yosysjs/demo03.html
new file mode 100644
index 00000000..3dc465cb
--- /dev/null
+++ b/misc/yosysjs/demo03.html
@@ -0,0 +1,103 @@
+<html><head>
+<title>YosysJS Example Application #02</title>
+<script type="text/javascript" src="yosysjs.js"></script>
+<script src="http://wavedrom.com/skins/default.js" type="text/javascript"></script>
+<script src="http://wavedrom.com/WaveDrom.js" type="text/javascript"></script>
+<style type="text/css">
+.noedit { color: #666; }
+</style>
+<script id="golden_verilog" type="text/plain">
+module ref(input clk, reset, input [7:0] A, output reg [7:0] Y);
+ always @(posedge clk) begin
+ if (reset)
+ Y <= 0;
+ else
+ Y <= ((Y << 5) + Y) ^ A;
+ end
+endmodule
+</script>
+</head><body>
+ <div id="popup" style="position: fixed; left: 0; top: 0; width:100%; height:100%; text-align:center; z-index: 1000;
+ background-color: rgba(100, 100, 100, 0.5);"><div style="width:300px; margin: 200px auto; background-color: #88f;
+ border:3px dashed #000; padding:15px; text-align:center;"><span id="popupmsg">Loading...</span></div>
+ </div>
+ <h1>YosysJS Example Application #03</h1>
+ <b>Your mission:</b> Create a behavioral Verilog model for the following circuit:
+ <p/>
+ <div id="main" style="visibility: hidden">
+ <svg id="schem" width="800"></svg>
+ <p/>
+ <pre id="code" style="width: 800px; border:2px solid #000; padding: 0.5em;"><span class="noedit">module top(input clk, reset, input [7:0] A, output reg [7:0] Y);
+ always @(posedge clock) begin</span><span class="edit" contenteditable="true">
+ Y &lt;= A | {4{reset}};
+ </span><span class="noedit">end
+endmodule</span></pre><p/>
+ <input type="button" value="Check Model" onclick="check_model()"> <span id="checkmessage"></span>
+ <p/>
+ <p id="wave">&nbsp;</p>
+ </div>
+ <script type="text/javascript">
+ function on_ys_ready() {
+ ys.write_file('golden.v', document.getElementById('golden_verilog').textContent);
+ ys.run('echo on; read_verilog golden.v; proc;;');
+ ys.run('show -notitle -width -stretch');
+ YosysJS.dot_into_svg(ys.read_file('show.dot'), 'schem');
+ document.getElementById('popup').style.visibility = 'hidden';
+ document.getElementById('popupmsg').textContent = 'Please wait..';
+ document.getElementById('main').style.visibility = 'visible';
+ }
+ function check_model() {
+ function work() {
+ ys.remove_file('wave.json');
+ ys.write_file('code.v', document.getElementById('code').textContent);
+ ys.errmsg = '';
+ ys.run('design -reset; read_verilog code.v; hierarchy -top top; proc; opt; flatten; hierarchy; ' +
+ 'read_verilog golden.v; proc; miter -equiv -ignore_gold_x -make_outputs -flatten ref top miter; ' +
+ 'hierarchy -top miter; clean -purge; sat -set-init-undef -seq 8 -dump_json wave.json -show-ports ' +
+ '-max_undef -prove trigger 0 miter');
+ w = document.getElementById('wave')
+ if (ys.errmsg) {
+ w.innerHTML = '<b><pre>ERROR: ' + ys.errmsg.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;') + '</pre></b>';
+ } else {
+ wdata = ys.read_file('wave.json');
+ if (wdata) {
+ wdata = JSON.parse(wdata);
+ function wsignal(signame, newname) {
+ for (i = 0; i < wdata["signal"].length; i++)
+ if (wdata["signal"][i].name == signame) {
+ if (newname)
+ wdata["signal"][i].name = newname;
+ return wdata["signal"][i];
+ }
+ return {};
+ }
+ wdata2 = {
+ "signal" : [
+ { name: 'clk', wave: 'P........' },
+ wsignal("trigger"),
+ {},
+ [ "Inputs", wsignal("in_reset", "reset"), wsignal("in_A", "A") ],
+ {},
+ [ "Y Output", wsignal("gold_Y", "Ref"), wsignal("gate_Y", "UUT") ],
+ ],
+ "config" : wdata["config"]
+ };
+ wdata2 = JSON.stringify(wdata2)
+ w.innerHTML = '<b>The model did not pass verification:</b><p/>' +
+ '<script type="WaveDrom">' + wdata2 + '<\/script>';
+ WaveDrom.ProcessAll();
+ } else {
+ w.innerHTML = '<b>Congratulations! The model did pass verification.</b><p/>';
+ }
+ }
+ document.getElementById('popup').style.visibility = 'hidden';
+ }
+ document.getElementById('popup').style.visibility = 'visible';
+ window.setTimeout(work, 100);
+ }
+
+ YosysJS.load_viz();
+ var ys = YosysJS.create('', on_ys_ready);
+ ys.logprint = true;
+ </script>
+</body></html>
diff --git a/misc/yosysjs/yosysjs.js b/misc/yosysjs/yosysjs.js
new file mode 100644
index 00000000..2c78451d
--- /dev/null
+++ b/misc/yosysjs/yosysjs.js
@@ -0,0 +1,223 @@
+var YosysJS = new function() {
+ this.script_element = document.currentScript;
+ this.viz_element = undefined;
+ this.viz_ready = true;
+
+ this.url_prefix = this.script_element.src.replace(/[^/]+$/, '')
+
+ this.load_viz = function() {
+ if (this.viz_element)
+ return;
+
+ this.viz_element = document.createElement('iframe')
+ this.viz_element.style.display = 'none'
+ document.body.appendChild(this.viz_element);
+
+ this.viz_element.contentWindow.document.open();
+ this.viz_element.contentWindow.document.write('<script type="text/javascript" onload="viz_ready = true;" src="' + this.url_prefix + 'viz.js"></' + 'script>');
+ this.viz_element.contentWindow.document.close();
+
+ var that = this;
+ function check_viz_ready() {
+ if (that.viz_element.contentWindow.viz_ready) {
+ console.log("YosysJS: Successfully loaded Viz.");
+ that.viz_ready = true;
+ } else
+ window.setTimeout(check_viz_ready, 100);
+ }
+
+ this.viz_ready = false;
+ window.setTimeout(check_viz_ready, 100);
+ }
+
+ this.dot_to_svg = function(dot_text) {
+ return this.viz_element.contentWindow.Viz(dot_text, "svg");
+ }
+
+ this.dot_into_svg = function(dot_text, svg_element) {
+ if (typeof(svg_element) == 'string' && svg_element != "")
+ svg_element = document.getElementById(svg_element);
+ svg_element.innerHTML = this.dot_to_svg(dot_text);
+ c = svg_element.firstChild;
+ while (c) {
+ if (c.tagName == 'svg') {
+ while (c.firstChild)
+ svg_element.appendChild(c.firstChild);
+ svg_element.setAttribute('viewBox', c.getAttribute('viewBox'));
+ // svg_element.removeChild(c);
+ break;
+ }
+ c = c.nextSibling;
+ }
+ }
+
+ this.create = function(reference_element, on_ready) {
+ var ys = new Object();
+ ys.YosysJS = this;
+ ys.init_script = "";
+ ys.ready = false;
+ ys.verbose = false;
+ ys.logprint = false;
+ ys.echo = false;
+ ys.errmsg = "";
+
+ if (typeof(reference_element) == 'string' && reference_element != "")
+ reference_element = document.getElementById(reference_element);
+
+ if (reference_element) {
+ if (reference_element.tagName == 'textarea')
+ ys.init_script = reference_element.value;
+
+ if (reference_element.tagName == 'iframe') {
+ ys.iframe_element = reference_element;
+ } else {
+ ys.iframe_element = document.createElement('iframe');
+ ys.iframe_element.id = reference_element.id;
+ for (i in reference_element.style)
+ ys.iframe_element.style[i] = reference_element.style[i];
+ reference_element.parentNode.insertBefore(ys.iframe_element, reference_element);
+ reference_element.parentNode.removeChild(reference_element);
+ }
+ } else {
+ ys.iframe_element = document.createElement('iframe');
+ ys.iframe_element.style.display = 'none';
+ document.body.appendChild(ys.iframe_element);
+ }
+
+ ys.print_buffer = "";
+ ys.last_line_empty = false;
+ ys.got_normal_log_message = false;
+ ys.window = ys.iframe_element.contentWindow;
+
+ var doc = ys.window.document;
+ var mod = ys.window.Module = {
+ print: function(text) {
+ if (typeof(text) == 'number')
+ return;
+ ys.print_buffer += text + "\n";
+ ys.got_normal_log_message = true;
+ if (ys.logprint)
+ console.log(text);
+ if (ys.verbose) {
+ ys.last_line_empty = text == "";
+ if (text == "") {
+ span = doc.createElement('br');
+ } else {
+ span = doc.createElement('span');
+ span.textContent = text + "\n";
+ span.style.fontFamily = 'monospace';
+ span.style.whiteSpace = 'pre';
+ }
+ doc.firstChild.appendChild(span);
+ if (doc.body)
+ ys.window.scrollTo(0, doc.body.scrollHeight);
+ else
+ ys.window.scrollBy(0, 100);
+ }
+ ys.ready = true;
+ },
+ printErr: function(text) {
+ if (typeof(text) == 'number')
+ return;
+ if (ys.logprint)
+ console.log(text);
+ if (ys.got_normal_log_message) {
+ ys.print_buffer += text + "\n";
+ ys.last_line_empty = text == "";
+ if (text == "") {
+ span = doc.createElement('br');
+ } else {
+ span = doc.createElement('span');
+ span.textContent = text + "\n";
+ span.style.fontFamily = 'monospace';
+ span.style.whiteSpace = 'pre';
+ span.style.color = 'red';
+ }
+ doc.firstChild.appendChild(span);
+ if (doc.body)
+ ys.window.scrollTo(0, doc.body.scrollHeight);
+ else
+ ys.window.scrollBy(0, 100);
+ } else
+ if (!ys.logprint)
+ console.log(text);
+ },
+ };
+
+ ys.write = function(text) {
+ ys.print_buffer += text + "\n";
+ ys.last_line_empty = text == "";
+ span = doc.createElement('span');
+ span.textContent = text + "\n";
+ span.style.fontFamily = 'monospace';
+ span.style.whiteSpace = 'pre';
+ doc.firstChild.appendChild(span);
+ if (doc.body)
+ ys.window.scrollTo(0, doc.body.scrollHeight);
+ else
+ ys.window.scrollBy(0, 100);
+ }
+
+ ys.prompt = function() {
+ return mod.ccall('prompt', 'string', [], [])
+ }
+
+ ys.run = function(cmd) {
+ ys.print_buffer = "";
+ if (ys.echo) {
+ if (!ys.last_line_empty)
+ ys.write("");
+ ys.write(ys.prompt() + cmd);
+ }
+ try {
+ mod.ccall('run', '', ['string'], [cmd]);
+ } catch (e) {
+ ys.errmsg = mod.ccall('errmsg', 'string', [], []);;
+ }
+ return ys.print_buffer;
+ }
+
+ ys.read_file = function(filename) {
+ try {
+ return ys.window.FS.readFile(filename, {encoding: 'utf8'});
+ } catch (e) {
+ return "";
+ }
+ }
+
+ ys.write_file = function(filename, text) {
+ return ys.window.FS.writeFile(filename, text, {encoding: 'utf8'});
+ }
+
+ ys.read_dir = function(dirname) {
+ return ys.window.FS.readdir(dirname);
+ }
+
+ ys.remove_file = function(filename) {
+ try {
+ ys.window.FS.unlink(filename);
+ } catch (e) { }
+ }
+
+ doc.open();
+ doc.write('<script type="text/javascript" src="' + this.url_prefix + 'yosys.js"></' + 'script>');
+ doc.close();
+
+ if (on_ready || ys.init_script) {
+ function check_ready() {
+ if (ys.ready && ys.YosysJS.viz_ready) {
+ if (ys.init_script) {
+ ys.write_file("/script.ys", ys.init_script);
+ ys.run("script /script.ys");
+ }
+ if (on_ready)
+ on_ready(ys);
+ } else
+ window.setTimeout(check_ready, 100);
+ }
+ window.setTimeout(check_ready, 100);
+ }
+
+ return ys;
+ }
+}
diff --git a/passes/abc/abc.cc b/passes/abc/abc.cc
index f1d56b23..8cd0211c 100644
--- a/passes/abc/abc.cc
+++ b/passes/abc/abc.cc
@@ -29,33 +29,42 @@
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558–562, doi:10.1145/368996.369025
// http://en.wikipedia.org/wiki/Topological_sorting
-#define ABC_COMMAND_LIB "strash; scorr -v; ifraig -v; retime -v {D}; strash; dch -vf; map -v {D}"
-#define ABC_COMMAND_CTR "strash; scorr -v; ifraig -v; retime -v {D}; strash; dch -vf; map -v {D}; buffer -v; upsize -v {D}; dnsize -v {D}; stime -p"
-#define ABC_COMMAND_LUT "strash; scorr -v; ifraig -v; retime -v; strash; dch -vf; if -v"
-#define ABC_COMMAND_DFL "strash; scorr -v; ifraig -v; retime -v; strash; dch -vf; map -v"
+#define ABC_COMMAND_LIB "strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}"
+#define ABC_COMMAND_CTR "strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_COMMAND_LUT "strash; scorr; ifraig; retime; strash; dch -f; if"
+#define ABC_COMMAND_DFL "strash; scorr; ifraig; retime; strash; dch -f; map"
-#define ABC_FAST_COMMAND_LIB "retime -v {D}; map -v {D}"
-#define ABC_FAST_COMMAND_CTR "retime -v {D}; map -v {D}; buffer -v; upsize -v {D}; dnsize -v {D}; stime -p"
-#define ABC_FAST_COMMAND_LUT "retime -v; if -v"
-#define ABC_FAST_COMMAND_DFL "retime -v; map -v"
+#define ABC_FAST_COMMAND_LIB "retime {D}; map {D}"
+#define ABC_FAST_COMMAND_CTR "retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_FAST_COMMAND_LUT "retime; if"
+#define ABC_FAST_COMMAND_DFL "retime; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/cost.h"
#include "kernel/log.h"
-#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <dirent.h>
#include <cerrno>
#include <sstream>
#include <climits>
+#ifndef _WIN32
+# include <unistd.h>
+# include <dirent.h>
+#endif
+
#include "blifparse.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
enum class gate_type_t {
G_NONE,
G_FF,
+ G_BUF,
G_NOT,
G_AND,
G_NAND,
@@ -81,16 +90,17 @@ struct gate_t
RTLIL::SigBit bit;
};
-static int map_autoidx;
-static SigMap assign_map;
-static RTLIL::Module *module;
-static std::vector<gate_t> signal_list;
-static std::map<RTLIL::SigBit, int> signal_map;
+bool markgroups;
+int map_autoidx;
+SigMap assign_map;
+RTLIL::Module *module;
+std::vector<gate_t> signal_list;
+std::map<RTLIL::SigBit, int> signal_map;
-static bool clk_polarity;
-static RTLIL::SigSpec clk_sig;
+bool clk_polarity, en_polarity;
+RTLIL::SigSpec clk_sig, en_sig;
-static int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1)
+int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1)
{
assign_map.apply(bit);
@@ -124,14 +134,14 @@ static int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in
return gate.id;
}
-static void mark_port(RTLIL::SigSpec sig)
+void mark_port(RTLIL::SigSpec sig)
{
for (auto &bit : assign_map(sig))
if (bit.wire != NULL && signal_map.count(bit) > 0)
signal_list[signal_map[bit]].is_port = true;
}
-static void extract_cell(RTLIL::Cell *cell, bool keepff)
+void extract_cell(RTLIL::Cell *cell, bool keepff)
{
if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
{
@@ -139,7 +149,26 @@ static void extract_cell(RTLIL::Cell *cell, bool keepff)
return;
if (clk_sig != assign_map(cell->getPort("\\C")))
return;
+ if (GetSize(en_sig) != 0)
+ return;
+ goto matching_dff;
+ }
+
+ if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+ {
+ if (clk_polarity != (cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_"))
+ return;
+ if (en_polarity != (cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_"))
+ return;
+ if (clk_sig != assign_map(cell->getPort("\\C")))
+ return;
+ if (en_sig != assign_map(cell->getPort("\\E")))
+ return;
+ goto matching_dff;
+ }
+ if (0) {
+ matching_dff:
RTLIL::SigSpec sig_d = cell->getPort("\\D");
RTLIL::SigSpec sig_q = cell->getPort("\\Q");
@@ -157,7 +186,7 @@ static void extract_cell(RTLIL::Cell *cell, bool keepff)
return;
}
- if (cell->type == "$_NOT_")
+ if (cell->type.in("$_BUF_", "$_NOT_"))
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
@@ -165,7 +194,7 @@ static void extract_cell(RTLIL::Cell *cell, bool keepff)
assign_map.apply(sig_a);
assign_map.apply(sig_y);
- map_signal(sig_y, G(NOT), map_signal(sig_a));
+ map_signal(sig_y, cell->type == "$_BUF_" ? G(BUF) : G(NOT), map_signal(sig_a));
module->remove(cell);
return;
@@ -273,14 +302,14 @@ static void extract_cell(RTLIL::Cell *cell, bool keepff)
}
}
-static std::string remap_name(RTLIL::IdString abc_name)
+std::string remap_name(RTLIL::IdString abc_name)
{
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
return sstr.str();
}
-static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std::set<int> &workpool, std::vector<int> &in_counts)
+void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std::set<int> &workpool, std::vector<int> &in_counts)
{
if (f == NULL)
return;
@@ -309,7 +338,7 @@ static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edge
fprintf(f, "}\n");
}
-static void handle_loops()
+void handle_loops()
{
// http://en.wikipedia.org/wiki/Topological_sorting
// (Kahn, Arthur B. (1962), "Topological sorting of large networks")
@@ -442,7 +471,7 @@ static void handle_loops()
fclose(dot_f);
}
-static std::string add_echos_to_abc_cmd(std::string str)
+std::string add_echos_to_abc_cmd(std::string str)
{
std::string new_str, token;
for (size_t i = 0; i < str.size(); i++) {
@@ -450,8 +479,6 @@ static std::string add_echos_to_abc_cmd(std::string str)
if (str[i] == ';') {
while (i+1 < str.size() && str[i+1] == ' ')
i++;
- if (!new_str.empty())
- new_str += "echo; ";
new_str += "echo + " + token + " " + token + " ";
token.clear();
}
@@ -459,14 +486,14 @@ static std::string add_echos_to_abc_cmd(std::string str)
if (!token.empty()) {
if (!new_str.empty())
- new_str += "echo; echo + " + token + "; ";
+ new_str += "echo + " + token + "; ";
new_str += token;
}
return new_str;
}
-static std::string fold_abc_cmd(std::string str)
+std::string fold_abc_cmd(std::string str)
{
std::string token, new_str = " ";
int char_counter = 10;
@@ -485,63 +512,165 @@ static std::string fold_abc_cmd(std::string str)
return new_str;
}
-static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
- std::string liberty_file, std::string constr_file, bool cleanup, int lut_mode, bool dff_mode, std::string clk_str,
- bool keepff, std::string delay_target, bool fast_mode)
+std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir)
+{
+ if (show_tempdir)
+ return text;
+
+ while (1) {
+ size_t pos = text.find(tempdir_name);
+ if (pos == std::string::npos)
+ break;
+ text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(tempdir_name));
+ }
+
+ std::string selfdir_name = proc_self_dirname();
+ while (1) {
+ size_t pos = text.find(selfdir_name);
+ if (pos == std::string::npos)
+ break;
+ text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
+ }
+
+ return text;
+}
+
+struct abc_output_filter
+{
+ bool got_cr;
+ int escape_seq_state;
+ std::string linebuf;
+ std::string tempdir_name;
+ bool show_tempdir;
+
+ abc_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir)
+ {
+ got_cr = false;
+ escape_seq_state = 0;
+ }
+
+ void next_char(char ch)
+ {
+ if (escape_seq_state == 0 && ch == '\033') {
+ escape_seq_state = 1;
+ return;
+ }
+ if (escape_seq_state == 1) {
+ escape_seq_state = ch == '[' ? 2 : 0;
+ return;
+ }
+ if (escape_seq_state == 2) {
+ if ((ch < '0' || '9' < ch) && ch != ';')
+ escape_seq_state = 0;
+ return;
+ }
+ escape_seq_state = 0;
+ if (ch == '\r') {
+ got_cr = true;
+ return;
+ }
+ if (ch == '\n') {
+ log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str());
+ got_cr = false, linebuf.clear();
+ return;
+ }
+ if (got_cr)
+ got_cr = false, linebuf.clear();
+ linebuf += ch;
+ }
+
+ void next_line(const std::string &line)
+ {
+ for (char ch : line)
+ next_char(ch);
+ }
+};
+
+void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
+ std::string liberty_file, std::string constr_file, bool cleanup, int lut_mode, int lut_mode2, bool dff_mode, std::string clk_str,
+ bool keepff, std::string delay_target, bool fast_mode, const std::vector<RTLIL::Cell*> &cells, bool show_tempdir)
{
module = current_module;
map_autoidx = autoidx++;
signal_map.clear();
signal_list.clear();
- assign_map.set(module);
- clk_polarity = true;
- clk_sig = RTLIL::SigSpec();
+ if (clk_str != "$")
+ {
+ assign_map.set(module);
+
+ clk_polarity = true;
+ clk_sig = RTLIL::SigSpec();
- char tempdir_name[] = "/tmp/yosys-abc-XXXXXX";
+ en_polarity = true;
+ en_sig = RTLIL::SigSpec();
+ }
+
+ std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
if (!cleanup)
tempdir_name[0] = tempdir_name[4] = '_';
- char *p = mkdtemp(tempdir_name);
- log_header("Extracting gate netlist of module `%s' to `%s/input.blif'..\n", module->name.c_str(), tempdir_name);
- if (p == NULL)
- log_error("For some reason mkdtemp() failed!\n");
+ tempdir_name = make_temp_dir(tempdir_name);
+ log_header("Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
+ module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
+
+ std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str());
+
+ if (!liberty_file.empty()) {
+ abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
+ if (!constr_file.empty())
+ abc_script += stringf("read_constr -v %s; ", constr_file.c_str());
+ } else
+ if (lut_mode)
+ abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
+ else
+ abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str());
- std::string abc_command;
if (!script_file.empty()) {
if (script_file[0] == '+') {
for (size_t i = 1; i < script_file.size(); i++)
if (script_file[i] == '\'')
- abc_command += "'\\''";
+ abc_script += "'\\''";
else if (script_file[i] == ',')
- abc_command += " ";
+ abc_script += " ";
else
- abc_command += script_file[i];
+ abc_script += script_file[i];
} else
- abc_command = stringf("source %s", script_file.c_str());
+ abc_script += stringf("source %s", script_file.c_str());
} else if (lut_mode)
- abc_command = fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
+ abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
else if (!liberty_file.empty())
- abc_command = constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
+ abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
else
- abc_command = fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
+ abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
- for (size_t pos = abc_command.find("{D}"); pos != std::string::npos; pos = abc_command.find("{D}", pos))
- abc_command = abc_command.substr(0, pos) + delay_target + abc_command.substr(pos+3);
+ for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+ abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
- abc_command = add_echos_to_abc_cmd(abc_command);
+ abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
+ abc_script = add_echos_to_abc_cmd(abc_script);
- if (abc_command.size() > 128) {
- for (size_t i = 0; i+1 < abc_command.size(); i++)
- if (abc_command[i] == ';' && abc_command[i+1] == ' ')
- abc_command[i+1] = '\n';
- FILE *f = fopen(stringf("%s/abc.script", tempdir_name).c_str(), "wt");
- fprintf(f, "%s\n", abc_command.c_str());
- fclose(f);
- abc_command = stringf("source %s/abc.script", tempdir_name);
- }
+ for (size_t i = 0; i+1 < abc_script.size(); i++)
+ if (abc_script[i] == ';' && abc_script[i+1] == ' ')
+ abc_script[i+1] = '\n';
+
+ FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt");
+ fprintf(f, "%s\n", abc_script.c_str());
+ fclose(f);
- if (clk_str.empty()) {
+ if (!clk_str.empty() && clk_str != "$")
+ {
+ if (clk_str.find(',') != std::string::npos) {
+ int pos = clk_str.find(',');
+ std::string en_str = clk_str.substr(pos+1);
+ clk_str = clk_str.substr(0, pos);
+ if (en_str[0] == '!') {
+ en_polarity = false;
+ en_str = en_str.substr(1);
+ }
+ if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
+ en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
+ }
if (clk_str[0] == '!') {
clk_polarity = false;
clk_str = clk_str.substr(1);
@@ -550,41 +679,21 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
}
- if (dff_mode && clk_sig.size() == 0)
- {
- int best_dff_counter = 0;
- std::map<std::pair<bool, RTLIL::SigSpec>, int> dff_counters;
+ if (dff_mode && clk_sig.empty())
+ log_error("Clock domain %s not found.\n", clk_str.c_str());
- for (auto &it : module->cells_)
- {
- RTLIL::Cell *cell = it.second;
- if (cell->type != "$_DFF_N_" && cell->type != "$_DFF_P_")
- continue;
-
- std::pair<bool, RTLIL::SigSpec> key(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")));
- if (++dff_counters[key] > best_dff_counter) {
- best_dff_counter = dff_counters[key];
- clk_polarity = key.first;
- clk_sig = key.second;
- }
- }
- }
-
- if (dff_mode || !clk_str.empty()) {
+ if (dff_mode || !clk_str.empty())
+ {
if (clk_sig.size() == 0)
- log("No (matching) clock domain found. Not extracting any FF cells.\n");
- else
- log("Found (matching) %s clock domain: %s\n", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
+ log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching");
+ else {
+ log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
+ if (en_sig.size() != 0)
+ log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
+ log("\n");
+ }
}
- if (clk_sig.size() != 0)
- mark_port(clk_sig);
-
- std::vector<RTLIL::Cell*> cells;
- cells.reserve(module->cells_.size());
- for (auto &it : module->cells_)
- if (design->selected(current_module, it.second))
- cells.push_back(it.second);
for (auto c : cells)
extract_cell(c, keepff);
@@ -596,14 +705,19 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
for (auto &cell_it : module->cells_)
for (auto &port_it : cell_it.second->connections())
mark_port(port_it.second);
-
+
+ if (clk_sig.size() != 0)
+ mark_port(clk_sig);
+
+ if (en_sig.size() != 0)
+ mark_port(en_sig);
+
handle_loops();
- if (asprintf(&p, "%s/input.blif", tempdir_name) < 0) log_abort();
- FILE *f = fopen(p, "wt");
+ std::string buffer = stringf("%s/input.blif", tempdir_name.c_str());
+ f = fopen(buffer.c_str(), "wt");
if (f == NULL)
- log_error("Opening %s for writing failed: %s\n", p, strerror(errno));
- free(p);
+ log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
fprintf(f, ".model netlist\n");
@@ -642,7 +756,10 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
int count_gates = 0;
for (auto &si : signal_list) {
- if (si.type == G(NOT)) {
+ if (si.type == G(BUF)) {
+ fprintf(f, ".names n%d 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, "0 1\n");
} else if (si.type == G(AND)) {
@@ -700,132 +817,64 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
fprintf(f, ".end\n");
fclose(f);
- log("Extracted %d gates and %zd wires to a netlist network with %d inputs and %d outputs.\n",
- count_gates, signal_list.size(), count_input, count_output);
+ 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("Executing ABC.\n");
- if (asprintf(&p, "%s/stdcells.genlib", tempdir_name) < 0) log_abort();
- f = fopen(p, "wt");
+ buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
+ f = fopen(buffer.c_str(), "wt");
if (f == NULL)
- log_error("Opening %s for writing failed: %s\n", p, strerror(errno));
- fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
- fprintf(f, "GATE ONE 1 Y=CONST1;\n");
- fprintf(f, "GATE BUF 1 Y=A; PIN * NONINV 1 999 1 0 1 0\n");
- fprintf(f, "GATE NOT 1 Y=!A; PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE AND 1 Y=A*B; PIN * NONINV 1 999 1 0 1 0\n");
- fprintf(f, "GATE NAND 1 Y=!(A*B); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE OR 1 Y=A+B; PIN * NONINV 1 999 1 0 1 0\n");
- fprintf(f, "GATE NOR 1 Y=!(A+B); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE XOR 1 Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n");
- fprintf(f, "GATE XNOR 1 Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n");
- fprintf(f, "GATE MUX 1 Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n");
- fprintf(f, "GATE AOI3 1 Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE OAI3 1 Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE AOI4 1 Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE OAI4 1 Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n");
+ log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
+ fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
+ fprintf(f, "GATE ONE 1 Y=CONST1;\n");
+ fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
+ fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
+ fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
+ fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
+ fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
+ fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
+ fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
+ fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
+ fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
+ fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
+ fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
+ fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
+ fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
fclose(f);
- free(p);
if (lut_mode) {
- if (asprintf(&p, "%s/lutdefs.txt", tempdir_name) < 0) log_abort();
- f = fopen(p, "wt");
+ buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str());
+ f = fopen(buffer.c_str(), "wt");
if (f == NULL)
- log_error("Opening %s for writing failed: %s\n", p, strerror(errno));
+ log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
for (int i = 0; i < lut_mode; i++)
fprintf(f, "%d 1.00 1.00\n", i+1);
+ for (int i = lut_mode; i < lut_mode2; i++)
+ fprintf(f, "%d %d.00 1.00\n", i+1, 2 << (i - lut_mode));
fclose(f);
- free(p);
}
- std::string buffer;
- if (!liberty_file.empty()) {
- buffer += stringf("%s -s -c 'read_blif %s/input.blif; read_lib -w %s; ",
- exe_file.c_str(), tempdir_name, liberty_file.c_str());
- if (!constr_file.empty())
- buffer += stringf("read_constr -v %s; ", constr_file.c_str());
- buffer += abc_command + "; ";
- } else
- if (lut_mode)
- buffer += stringf("%s -s -c 'read_blif %s/input.blif; read_lut %s/lutdefs.txt; %s; ",
- exe_file.c_str(), tempdir_name, tempdir_name, abc_command.c_str());
- else
- buffer += stringf("%s -s -c 'read_blif %s/input.blif; read_library %s/stdcells.genlib; %s; ",
- exe_file.c_str(), tempdir_name, tempdir_name, abc_command.c_str());
- buffer += stringf("write_blif %s/output.blif' 2>&1", tempdir_name);
+ buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
+ log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
- log("%s\n", buffer.c_str());
+ abc_output_filter filt(tempdir_name, show_tempdir);
+ int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
+ if (ret != 0)
+ log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
- errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
- f = popen(buffer.c_str(), "r");
+ buffer = stringf("%s/%s", tempdir_name.c_str(), "output.blif");
+ f = fopen(buffer.c_str(), "rt");
if (f == NULL)
- log_error("Opening pipe to `%s' for reading failed: %s\n", buffer.c_str(), strerror(errno));
-#if 0
- char logbuf[1024];
- while (fgets(logbuf, 1024, f) != NULL)
- log("ABC: %s", logbuf);
-#else
- bool got_cr = false;
- int escape_seq_state = 0;
- std::string linebuf;
- char logbuf[1024];
- while (fgets(logbuf, 1024, f) != NULL)
- for (char *p = logbuf; *p; p++) {
- if (escape_seq_state == 0 && *p == '\033') {
- escape_seq_state = 1;
- continue;
- }
- if (escape_seq_state == 1) {
- escape_seq_state = *p == '[' ? 2 : 0;
- continue;
- }
- if (escape_seq_state == 2) {
- if ((*p < '0' || '9' < *p) && *p != ';')
- escape_seq_state = 0;
- continue;
- }
- escape_seq_state = 0;
- if (*p == '\r') {
- got_cr = true;
- continue;
- }
- if (*p == '\n') {
- log("ABC: %s\n", linebuf.c_str());
- got_cr = false, linebuf.clear();
- continue;
- }
- if (got_cr)
- got_cr = false, linebuf.clear();
- linebuf += *p;
- }
- if (!linebuf.empty())
- log("ABC: %s\n", linebuf.c_str());
-#endif
- errno = 0;
- int ret = pclose(f);
- if (ret < 0)
- log_error("Closing pipe to `%s' failed: %s\n", buffer.c_str(), strerror(errno));
- if (WEXITSTATUS(ret) != 0) {
- switch (WEXITSTATUS(ret)) {
- case 127: log_error("ABC: execution of command \"%s\" failed: Command not found\n", exe_file.c_str()); break;
- case 126: log_error("ABC: execution of command \"%s\" failed: Command not executable\n", exe_file.c_str()); break;
- default: log_error("ABC: execution of command \"%s\" failed: the shell returned %d\n", exe_file.c_str(), WEXITSTATUS(ret)); break;
- }
- }
-
- if (asprintf(&p, "%s/%s", tempdir_name, "output.blif") < 0) log_abort();
- f = fopen(p, "rt");
- if (f == NULL)
- log_error("Can't open ABC output file `%s'.\n", p);
+ log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
bool builtin_lib = liberty_file.empty() && script_file.empty() && !lut_mode;
RTLIL::Design *mapped_design = abc_parse_blif(f, builtin_lib ? "\\DFF" : "\\_dff_");
fclose(f);
- free(p);
log_header("Re-integrating ABC results.\n");
RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"];
@@ -834,6 +883,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
for (auto &it : mapped_mod->wires_) {
RTLIL::Wire *w = it.second;
RTLIL::Wire *wire = module->addWire(remap_name(w->name));
+ if (markgroups) wire->attributes["\\abcgroup"] = map_autoidx;
design->select(module, wire);
}
@@ -859,6 +909,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\NOT") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_NOT_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
design->select(module, cell);
@@ -866,6 +917,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" || c->type == "\\XNOR") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
@@ -874,6 +926,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\MUX") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
@@ -883,6 +936,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\AOI3" || c->type == "\\OAI3") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
@@ -892,6 +946,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\AOI4" || c->type == "\\OAI4") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
@@ -902,7 +957,15 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\DFF") {
log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ RTLIL::Cell *cell;
+ if (en_sig.size() == 0) {
+ cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ } else {
+ log_assert(en_sig.size() == 1);
+ cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
+ cell->setPort("\\E", en_sig);
+ }
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
cell->setPort("\\C", clk_sig);
@@ -927,7 +990,15 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\_dff_") {
log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ RTLIL::Cell *cell;
+ if (en_sig.size() == 0) {
+ cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ } else {
+ log_assert(en_sig.size() == 1);
+ cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
+ cell->setPort("\\E", en_sig);
+ }
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
cell->setPort("\\C", clk_sig);
@@ -935,6 +1006,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
continue;
}
RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->parameters = c->parameters;
for (auto &conn : c->connections()) {
RTLIL::SigSpec newsig;
@@ -990,23 +1062,8 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
if (cleanup)
{
- log_header("Removing temp directory `%s':\n", tempdir_name);
-
- struct dirent **namelist;
- int n = scandir(tempdir_name, &namelist, 0, alphasort);
- log_assert(n >= 0);
- for (int i = 0; i < n; i++) {
- if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
- if (asprintf(&p, "%s/%s", tempdir_name, namelist[i]->d_name) < 0) log_abort();
- log("Removing `%s'.\n", p);
- remove(p);
- free(p);
- }
- free(namelist[i]);
- }
- free(namelist);
- log("Removing `%s'.\n", tempdir_name);
- rmdir(tempdir_name);
+ log("Removing temp directory.\n");
+ remove_directory(tempdir_name);
}
log_pop();
@@ -1087,15 +1144,20 @@ struct AbcPass : public Pass {
log(" -lut <width>\n");
log(" generate netlist using luts of (max) the specified width.\n");
log("\n");
+ log(" -lut <w1>:<w2>\n");
+ log(" generate netlist using luts of (max) the specified width <w2>. All\n");
+ log(" luts with width <= <w1> have constant cost. for luts larger than <w1>\n");
+ log(" the area cost doubles with each additional input bit. the delay cost\n");
+ log(" is still constant for all lut widths.\n");
+ log("\n");
log(" -dff\n");
- log(" also pass $_DFF_?_ cells through ABC (only one clock domain, if many\n");
- log(" clock domains are present in a module, the one with the largest number\n");
- log(" of $_DFF_?_ cells in it is used)\n");
+ log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
+ log(" clock domains are automatically partitioned in clock domains and each\n");
+ log(" domain is passed through ABC independently.\n");
log("\n");
- log(" -clk [!]<signal-name>\n");
- log(" use the specified clock domain. (when this option is used in combination\n");
- log(" with -dff, then it falls back to the automatic dection of clock domain\n");
- log(" if the specified clock is not found in a module.)\n");
+ log(" -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
+ log(" use only the specified clock domain. this is like -dff, but only FF\n");
+ log(" cells that belong to the specified clock domain are used.\n");
log("\n");
log(" -keepff\n");
log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
@@ -1105,6 +1167,15 @@ struct AbcPass : public Pass {
log(" when this option is used, the temporary files created by this pass\n");
log(" are not removed. this is useful for debugging.\n");
log("\n");
+ log(" -showtmp\n");
+ log(" print the temp dir name in log. usually this is suppressed so that the\n");
+ log(" command output is identical across runs.\n");
+ log("\n");
+ log(" -markgroups\n");
+ log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n");
+ log(" this attribute is a unique integer for each ABC process started. This\n");
+ log(" is useful for debugging the partitioning of clock domains.\n");
+ log("\n");
log("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");
@@ -1122,7 +1193,14 @@ struct AbcPass : public Pass {
std::string exe_file = proc_self_dirname() + "yosys-abc";
std::string script_file, liberty_file, constr_file, clk_str, delay_target;
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
- int lut_mode = 0;
+ bool show_tempdir = false;
+ int lut_mode = 0, lut_mode2 = 0;
+ markgroups = false;
+
+#ifdef _WIN32
+ if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
+ exe_file = proc_self_dirname() + "..\\yosys-abc";
+#endif
size_t argidx;
char pwd [PATH_MAX];
@@ -1138,19 +1216,19 @@ struct AbcPass : public Pass {
}
if (arg == "-script" && argidx+1 < args.size()) {
script_file = args[++argidx];
- if (!script_file.empty() && script_file[0] != '/' && script_file[0] != '+')
+ if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
script_file = std::string(pwd) + "/" + script_file;
continue;
}
if (arg == "-liberty" && argidx+1 < args.size()) {
liberty_file = args[++argidx];
- if (!liberty_file.empty() && liberty_file[0] != '/')
+ if (!liberty_file.empty() && !is_absolute_path(liberty_file))
liberty_file = std::string(pwd) + "/" + liberty_file;
continue;
}
if (arg == "-constr" && argidx+1 < args.size()) {
constr_file = args[++argidx];
- if (!constr_file.empty() && constr_file[0] != '/')
+ if (!constr_file.empty() && !is_absolute_path(constr_file))
constr_file = std::string(pwd) + "/" + constr_file;
continue;
}
@@ -1159,7 +1237,15 @@ struct AbcPass : public Pass {
continue;
}
if (arg == "-lut" && argidx+1 < args.size()) {
- lut_mode = atoi(args[++argidx].c_str());
+ string arg = args[++argidx];
+ size_t pos = arg.find_first_of(':');
+ if (pos != string::npos) {
+ lut_mode = atoi(arg.substr(0, pos).c_str());
+ lut_mode2 = atoi(arg.substr(pos+1).c_str());
+ } else {
+ lut_mode = atoi(arg.c_str());
+ lut_mode2 = lut_mode;
+ }
continue;
}
if (arg == "-fast") {
@@ -1172,6 +1258,7 @@ struct AbcPass : public Pass {
}
if (arg == "-clk" && argidx+1 < args.size()) {
clk_str = args[++argidx];
+ dff_mode = true;
continue;
}
if (arg == "-keepff") {
@@ -1182,6 +1269,14 @@ struct AbcPass : public Pass {
cleanup = false;
continue;
}
+ if (arg == "-showtmp") {
+ show_tempdir = true;
+ continue;
+ }
+ if (arg == "-markgroups") {
+ markgroups = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -1191,12 +1286,158 @@ struct AbcPass : public Pass {
if (!constr_file.empty() && liberty_file.empty())
log_cmd_error("Got -constr but no -liberty!\n");
- for (auto &mod_it : design->modules_)
- if (design->selected(mod_it.second)) {
- if (mod_it.second->processes.size() > 0)
- log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
- else
- abc_module(design, mod_it.second, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, dff_mode, clk_str, keepff, delay_target, fast_mode);
+ for (auto mod : design->selected_modules())
+ if (mod->processes.size() > 0)
+ log("Skipping module %s as it contains processes.\n", log_id(mod));
+ else if (!dff_mode || !clk_str.empty())
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, lut_mode2, dff_mode, clk_str, keepff, delay_target, fast_mode, mod->selected_cells(), show_tempdir);
+ else
+ {
+ assign_map.set(mod);
+ CellTypes ct(design);
+
+ std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
+ std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
+
+ std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
+ std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
+ std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
+
+ typedef std::tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
+ std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
+ std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
+
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
+
+ for (auto cell : all_cells)
+ {
+ clkdomain_t key;
+
+ for (auto &conn : cell->connections())
+ for (auto bit : conn.second) {
+ bit = assign_map(bit);
+ if (bit.wire != nullptr) {
+ cell_to_bit[cell].insert(bit);
+ bit_to_cell[bit].insert(cell);
+ if (ct.cell_input(cell->type, conn.first)) {
+ cell_to_bit_up[cell].insert(bit);
+ bit_to_cell_down[bit].insert(cell);
+ }
+ if (ct.cell_output(cell->type, conn.first)) {
+ cell_to_bit_down[cell].insert(bit);
+ bit_to_cell_up[bit].insert(cell);
+ }
+ }
+ }
+
+ if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+ {
+ key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec());
+ }
+ else
+ if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+ {
+ bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_";
+ bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_";
+ key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E")));
+ }
+ else
+ continue;
+
+ unassigned_cells.erase(cell);
+ expand_queue.insert(cell);
+ expand_queue_up.insert(cell);
+ expand_queue_down.insert(cell);
+
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
+ }
+
+ while (!expand_queue_up.empty() || !expand_queue_down.empty())
+ {
+ if (!expand_queue_up.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue_up.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue_up.erase(cell);
+
+ for (auto bit : cell_to_bit_up[cell])
+ for (auto c : bit_to_cell_up[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue_up.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ expand_queue.insert(c);
+ }
+ }
+
+ if (!expand_queue_down.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue_down.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue_down.erase(cell);
+
+ for (auto bit : cell_to_bit_down[cell])
+ for (auto c : bit_to_cell_down[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue_up.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ expand_queue.insert(c);
+ }
+ }
+
+ if (expand_queue_up.empty() && expand_queue_down.empty()) {
+ expand_queue_up.swap(next_expand_queue_up);
+ expand_queue_down.swap(next_expand_queue_down);
+ }
+ }
+
+ while (!expand_queue.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue.erase(cell);
+
+ for (auto bit : cell_to_bit.at(cell)) {
+ for (auto c : bit_to_cell[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ }
+ bit_to_cell[bit].clear();
+ }
+
+ if (expand_queue.empty())
+ expand_queue.swap(next_expand_queue);
+ }
+
+ clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
+ for (auto cell : unassigned_cells) {
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
+ }
+
+ log_header("Summary of detected clock domains:\n");
+ for (auto &it : assigned_cells)
+ log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
+ std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
+ std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
+
+ for (auto &it : assigned_cells) {
+ clk_polarity = std::get<0>(it.first);
+ clk_sig = assign_map(std::get<1>(it.first));
+ en_polarity = std::get<2>(it.first);
+ en_sig = assign_map(std::get<3>(it.first));
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, lut_mode2,
+ !clk_sig.empty(), "$", keepff, delay_target, fast_mode, it.second, show_tempdir);
+ assign_map.set(mod);
+ }
}
assign_map.clear();
@@ -1207,3 +1448,4 @@ struct AbcPass : public Pass {
}
} AbcPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/abc/blifparse.cc b/passes/abc/blifparse.cc
index 1fbb5720..db87eec4 100644
--- a/passes/abc/blifparse.cc
+++ b/passes/abc/blifparse.cc
@@ -18,9 +18,8 @@
*/
#include "blifparse.h"
-#include "kernel/log.h"
-#include <stdio.h>
-#include <string.h>
+
+YOSYS_NAMESPACE_BEGIN
static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count, FILE *f)
{
@@ -130,7 +129,8 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
if (p == NULL)
goto error;
- RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(p));
+ IdString celltype = RTLIL::escape_id(p);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, celltype);
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
char *q = strchr(p, '=');
@@ -240,3 +240,5 @@ error:
// return NULL;
}
+YOSYS_NAMESPACE_END
+
diff --git a/passes/abc/blifparse.h b/passes/abc/blifparse.h
index 272e4e64..31f5b2e5 100644
--- a/passes/abc/blifparse.h
+++ b/passes/abc/blifparse.h
@@ -20,9 +20,12 @@
#ifndef ABC_BLIFPARSE
#define ABC_BLIFPARSE
-#include "kernel/rtlil.h"
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
extern RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name);
-#endif
+YOSYS_NAMESPACE_END
+#endif
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index eba61d1d..e4b40c41 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -14,11 +14,12 @@ OBJS += passes/cmds/setattr.o
OBJS += passes/cmds/copy.o
OBJS += passes/cmds/splice.o
OBJS += passes/cmds/scc.o
-OBJS += passes/cmds/log.o
+OBJS += passes/cmds/logcmd.o
OBJS += passes/cmds/tee.o
OBJS += passes/cmds/write_file.o
OBJS += passes/cmds/connwrappers.o
OBJS += passes/cmds/cover.o
OBJS += passes/cmds/trace.o
OBJS += passes/cmds/plugin.o
+OBJS += passes/cmds/check.o
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index e3fde855..054cfc1c 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -17,9 +17,10 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string name, int width, bool flag_input, bool flag_output, bool flag_global)
{
@@ -150,3 +151,4 @@ struct AddPass : public Pass {
}
} AddPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
new file mode 100644
index 00000000..bb8fe78e
--- /dev/null
+++ b/passes/cmds/check.cc
@@ -0,0 +1,154 @@
+/*
+ * 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"
+#include "kernel/utils.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct CheckPass : public Pass {
+ CheckPass() : Pass("check", "check for obvious problems in the design") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" check [options] [selection]\n");
+ log("\n");
+ log("This pass identifies the following problems in the current design:\n");
+ log("\n");
+ log(" - combinatorical loops\n");
+ log("\n");
+ log(" - two or more conflicting drivers for one wire\n");
+ log("\n");
+ log(" - used wires that do not have a driver\n");
+ log("\n");
+ log("When called with -noinit then this command also checks for wires which have\n");
+ log("the 'init' attribute set.\n");
+ log("\n");
+ log("When called with -assert then the command will produce an error if any\n");
+ log("problems are found in the current design.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ int counter = 0;
+ bool noinit = false;
+ bool assert_mode = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-noinit") {
+ noinit = true;
+ continue;
+ }
+ if (args[argidx] == "-assert") {
+ assert_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ log_header("Executing CHECK pass (checking for obvious problems).\n");
+
+ for (auto module : design->selected_whole_modules_warn())
+ {
+ if (module->has_processes_warn())
+ continue;
+
+ log("checking module %s..\n", log_id(module));
+
+ SigMap sigmap(module);
+ dict<SigBit, vector<string>> wire_drivers;
+ pool<SigBit> used_wires;
+ TopoSort<string> topo;
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections()) {
+ SigSpec sig = sigmap(conn.second);
+ bool logic_cell = yosys_celltypes.cell_evaluable(cell->type);
+ if (cell->input(conn.first))
+ for (auto bit : sig)
+ if (bit.wire) {
+ if (logic_cell)
+ topo.edge(stringf("wire %s", log_signal(bit)),
+ stringf("cell %s (%s)", log_id(cell), log_id(cell->type)));
+ used_wires.insert(bit);
+ }
+ if (cell->output(conn.first))
+ for (int i = 0; i < GetSize(sig); i++) {
+ if (logic_cell)
+ topo.edge(stringf("cell %s (%s)", log_id(cell), log_id(cell->type)),
+ stringf("wire %s", log_signal(sig[i])));
+ wire_drivers[sig[i]].push_back(stringf("port %s[%d] of cell %s (%s)",
+ log_id(conn.first), i, log_id(cell), log_id(cell->type)));
+ }
+ }
+
+ for (auto wire : module->wires()) {
+ if (wire->port_input) {
+ SigSpec sig = sigmap(wire);
+ for (int i = 0; i < GetSize(sig); i++)
+ wire_drivers[sig[i]].push_back(stringf("module input %s[%d]", log_id(wire), i));
+ }
+ if (wire->port_output)
+ for (auto bit : sigmap(wire))
+ if (bit.wire) used_wires.insert(bit);
+ if (noinit && wire->attributes.count("\\init")) {
+ log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire));
+ counter++;
+ }
+ }
+
+ for (auto it : wire_drivers)
+ if (GetSize(it.second) > 1) {
+ string message = stringf("multiple conflicting drivers for %s.%s:\n", log_id(module), log_signal(it.first));
+ for (auto str : it.second)
+ message += stringf(" %s\n", str.c_str());
+ log_warning("%s", message.c_str());
+ counter++;
+ }
+
+ for (auto bit : used_wires)
+ if (!wire_drivers.count(bit)) {
+ log_warning("Wire %s.%s is used but has no driver.\n", log_id(module), log_signal(bit));
+ counter++;
+ }
+
+ topo.sort();
+ for (auto &loop : topo.loops) {
+ string message = stringf("found logic loop in module %s:\n", log_id(module));
+ for (auto &str : loop)
+ message += stringf(" %s\n", str.c_str());
+ log_warning("%s", message.c_str());
+ counter++;
+ }
+ }
+
+ log("found and reported %d problems.\n", counter);
+
+ if (assert_mode && counter > 0)
+ log_error("Found %d problems in 'check -assert'.\n", counter);
+ }
+} CheckPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc
index 30c80f73..e17c1b1c 100644
--- a/passes/cmds/connect.cc
+++ b/passes/cmds/connect.cc
@@ -23,6 +23,9 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, RTLIL::SigSpec &sig)
{
CellTypes ct(design);
@@ -183,3 +186,4 @@ struct ConnectPass : public Pass {
}
} ConnectPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
index aac11716..a65a6364 100644
--- a/passes/cmds/connwrappers.cc
+++ b/passes/cmds/connwrappers.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct ConnwrappersWorker
{
struct portdecl_t {
@@ -203,3 +206,4 @@ struct ConnwrappersPass : public Pass {
}
} ConnwrappersPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/copy.cc b/passes/cmds/copy.cc
index be775820..459e5b0e 100644
--- a/passes/cmds/copy.cc
+++ b/passes/cmds/copy.cc
@@ -21,6 +21,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct CopyPass : public Pass {
CopyPass() : Pass("copy", "copy modules in the design") { }
virtual void help()
@@ -53,3 +56,4 @@ struct CopyPass : public Pass {
}
} CopyPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index ac72ba53..5644066a 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -17,14 +17,22 @@
*
*/
+#include "kernel/yosys.h"
#include <sys/types.h>
-#include <unistd.h>
-#include <fnmatch.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct CoverPass : public Pass {
CoverPass() : Pass("cover", "print code coverage counters") { }
virtual void help()
@@ -72,7 +80,7 @@ struct CoverPass : public Pass {
log(" printf \"%%-60s %%10d %%s\\n\", p[i], c[i], i; }' {files} | sort -k3\n");
log("\n");
log("\n");
- log("Coverage counters are only available in debug builds of Yosys for Linux.\n");
+ log("Coverage counters are only available in Yosys for Linux.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
@@ -92,9 +100,13 @@ struct CoverPass : public Pass {
const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
std::string filename = args[++argidx];
if (args[argidx-1] == "-d") {
+ #ifdef _WIN32
+ log_cmd_error("The 'cover -d' option is not supported on win32.\n");
+ #else
char filename_buffer[4096];
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
filename = mkstemps(filename_buffer, 4);
+ #endif
}
FILE *f = fopen(filename.c_str(), open_mode);
if (f == NULL) {
@@ -116,11 +128,11 @@ struct CoverPass : public Pass {
log("\n");
}
-#ifdef COVER_ACTIVE
+#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
for (auto &it : get_coverage_data()) {
if (!patterns.empty()) {
for (auto &p : patterns)
- if (!fnmatch(p.c_str(), it.first.c_str(), 0))
+ if (patmatch(p.c_str(), it.first.c_str()))
goto pattern_match;
continue;
}
@@ -134,7 +146,7 @@ struct CoverPass : public Pass {
for (auto f : out_files)
fclose(f);
- log_cmd_error("Coverage counters are only available in debug builds of Yosys for Linux.\n");
+ log_cmd_error("This version of Yosys was not built with support for code coverage counters.\n");
#endif
for (auto f : out_files)
@@ -142,3 +154,4 @@ struct CoverPass : public Pass {
}
} CoverPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc
index 2a91bc9e..b4362887 100644
--- a/passes/cmds/delete.cc
+++ b/passes/cmds/delete.cc
@@ -17,9 +17,10 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
struct DeletePass : public Pass {
DeletePass() : Pass("delete", "delete objects in the design") { }
@@ -90,10 +91,10 @@ struct DeletePass : public Pass {
continue;
}
- std::set<RTLIL::Wire*> delete_wires;
- std::set<RTLIL::Cell*> delete_cells;
- std::set<RTLIL::IdString> delete_procs;
- std::set<RTLIL::IdString> delete_mems;
+ pool<RTLIL::Wire*> delete_wires;
+ pool<RTLIL::Cell*> delete_cells;
+ pool<RTLIL::IdString> delete_procs;
+ pool<RTLIL::IdString> delete_mems;
for (auto &it : module->wires_)
if (design->selected(module, it.second))
@@ -140,3 +141,4 @@ struct DeletePass : public Pass {
}
} DeletePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/log.cc b/passes/cmds/logcmd.cc
index 34db0eed..85386f3d 100644
--- a/passes/cmds/log.cc
+++ b/passes/cmds/logcmd.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct LogPass : public Pass {
LogPass() : Pass("log", "print text and log files") { }
virtual void help()
@@ -76,3 +79,4 @@ struct LogPass : public Pass {
}
} LogPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
index 4e8234d1..f7c65bbd 100644
--- a/passes/cmds/plugin.cc
+++ b/passes/cmds/plugin.cc
@@ -28,9 +28,9 @@ YOSYS_NAMESPACE_BEGIN
std::map<std::string, void*> loaded_plugins;
std::map<std::string, std::string> loaded_plugin_aliases;
+#ifdef YOSYS_ENABLE_PLUGINS
void load_plugin(std::string filename, std::vector<std::string> aliases)
{
-#ifdef YOSYS_ENABLE_PLUGINS
if (filename.find('/') == std::string::npos)
filename = "./" + filename;
@@ -44,10 +44,13 @@ void load_plugin(std::string filename, std::vector<std::string> aliases)
for (auto &alias : aliases)
loaded_plugin_aliases[alias] = filename;
+}
#else
+void load_plugin(std::string, std::vector<std::string>)
+{
log_error("This version of yosys is built without plugin support.\n");
-#endif
}
+#endif
struct PluginPass : public Pass {
PluginPass() : Pass("plugin", "load and list loaded plugins") { }
@@ -112,7 +115,7 @@ struct PluginPass : public Pass {
log("\n");
int max_alias_len = 1;
for (auto &it : loaded_plugin_aliases)
- max_alias_len = std::max(max_alias_len, SIZE(it.first));
+ max_alias_len = std::max(max_alias_len, GetSize(it.first));
for (auto &it : loaded_plugin_aliases)
log("Alias: %-*s %s\n", max_alias_len, it.first.c_str(), it.second.c_str());
}
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 91de364f..17d803e9 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -21,6 +21,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name)
{
from_name = RTLIL::escape_id(from_name);
@@ -31,8 +34,11 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
for (auto &it : module->wires_)
if (it.first == from_name) {
- log("Renaming wire %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
- module->rename(it.second, to_name);
+ Wire *w = it.second;
+ log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
+ module->rename(w, to_name);
+ if (w->port_id)
+ module->fixup_ports();
return;
}
@@ -113,7 +119,7 @@ struct RenamePass : public Pass {
if (!design->selected(module))
continue;
- std::map<RTLIL::IdString, RTLIL::Wire*> new_wires;
+ dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
for (auto &it : module->wires_) {
if (it.first[0] == '$' && design->selected(module, it.second))
do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
@@ -121,8 +127,9 @@ struct RenamePass : public Pass {
new_wires[it.second->name] = it.second;
}
module->wires_.swap(new_wires);
+ module->fixup_ports();
- std::map<RTLIL::IdString, RTLIL::Cell*> new_cells;
+ dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
for (auto &it : module->cells_) {
if (it.first[0] == '$' && design->selected(module, it.second))
do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
@@ -143,7 +150,7 @@ struct RenamePass : public Pass {
if (!design->selected(module))
continue;
- std::map<RTLIL::IdString, RTLIL::Wire*> new_wires;
+ dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
for (auto &it : module->wires_) {
if (design->selected(module, it.second))
if (it.first[0] == '\\' && it.second->port_id == 0)
@@ -151,8 +158,9 @@ struct RenamePass : public Pass {
new_wires[it.second->name] = it.second;
}
module->wires_.swap(new_wires);
+ module->fixup_ports();
- std::map<RTLIL::IdString, RTLIL::Cell*> new_cells;
+ dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
for (auto &it : module->cells_) {
if (design->selected(module, it.second))
if (it.first[0] == '\\')
@@ -196,3 +204,4 @@ struct RenamePass : public Pass {
}
} RenamePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc
index e09c0012..1cd55ecb 100644
--- a/passes/cmds/scatter.cc
+++ b/passes/cmds/scatter.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct ScatterPass : public Pass {
ScatterPass() : Pass("scatter", "add additional intermediate nets") { }
virtual void help()
@@ -67,3 +70,4 @@ struct ScatterPass : public Pass {
}
} ScatterPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index 5224f5bc..f4eeac07 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -29,6 +29,9 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SccWorker
{
RTLIL::Design *design;
@@ -97,7 +100,8 @@ struct SccWorker
}
}
- SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool allCellTypes, int maxDepth) : design(design), module(module), sigmap(module)
+ SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, int maxDepth) :
+ design(design), module(module), sigmap(module)
{
if (module->processes.size() > 0) {
log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
@@ -164,11 +168,23 @@ struct SccWorker
labelCounter = 0;
cellLabels.clear();
- while (workQueue.size() > 0) {
+ while (workQueue.size() > 0)
+ {
RTLIL::Cell *cell = *workQueue.begin();
log_assert(cellStack.size() == 0);
cellDepth.clear();
- run(cell, 0, maxDepth);
+
+ if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
+ log("Found an SCC:");
+ std::set<RTLIL::Cell*> scc;
+ log(" %s", RTLIL::id2cstr(cell->name));
+ cell2scc[cell] = sccList.size();
+ scc.insert(cell);
+ sccList.push_back(scc);
+ workQueue.erase(cell);
+ log("\n");
+ } else
+ run(cell, 0, maxDepth);
}
log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
@@ -209,10 +225,18 @@ struct SccPass : public Pass {
log("This command identifies strongly connected components (aka logic loops) in the\n");
log("design.\n");
log("\n");
+ log(" -expect <num>\n");
+ log(" expect to find exactly <num> SSCs. A different number of SSCs will\n");
+ log(" produce an error.\n");
+ log("\n");
log(" -max_depth <num>\n");
- log(" limit to loops not longer than the specified number of cells. This can\n");
- log(" e.g. be useful in identifying local loops in a module that turns out\n");
- log(" to be one gigantic SCC.\n");
+ log(" limit to loops not longer than the specified number of cells. This\n");
+ log(" can e.g. be useful in identifying small local loops in a module that\n");
+ log(" implements one large SCC.\n");
+ log("\n");
+ log(" -nofeedback\n");
+ log(" do not count cells that have their output fed back into one of their\n");
+ log(" inputs as single-cell scc.\n");
log("\n");
log(" -all_cell_types\n");
log(" Usually this command only considers internal non-memory cells. With\n");
@@ -236,7 +260,9 @@ struct SccPass : public Pass {
std::map<std::string, std::string> setCellAttr, setWireAttr;
bool allCellTypes = false;
bool selectMode = false;
+ bool nofeedbackMode = false;
int maxDepth = -1;
+ int expect = -1;
log_header("Executing SCC pass (detecting logic loops).\n");
@@ -246,6 +272,14 @@ struct SccPass : public Pass {
maxDepth = atoi(args[++argidx].c_str());
continue;
}
+ if (args[argidx] == "-expect" && argidx+1 < args.size()) {
+ expect = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-nofeedback") {
+ nofeedbackMode = true;
+ continue;
+ }
if (args[argidx] == "-all_cell_types") {
allCellTypes = true;
continue;
@@ -279,16 +313,26 @@ struct SccPass : public Pass {
log_cmd_error("The -set*_attr options are not implemented at the moment!\n");
RTLIL::Selection newSelection(false);
+ int scc_counter = 0;
for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
{
- SccWorker worker(design, mod_it.second, allCellTypes, maxDepth);
+ SccWorker worker(design, mod_it.second, nofeedbackMode, allCellTypes, maxDepth);
+ scc_counter += GetSize(worker.sccList);
if (selectMode)
worker.select(newSelection);
}
+ if (expect >= 0) {
+ if (scc_counter == expect)
+ log("Found and expected %d SCCs.\n", scc_counter);
+ else
+ log_error("Found %d SCCs but expected %d.\n", scc_counter, expect);
+ } else
+ log("Found %d SCCs.\n", scc_counter);
+
if (selectMode) {
log_assert(origSelectPos >= 0);
design->selection_stack[origSelectPos] = newSelection;
@@ -297,3 +341,4 @@ struct SccPass : public Pass {
}
} SccPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index 4c540ca6..53ff4d47 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -17,14 +17,15 @@
*
*/
-#include "kernel/register.h"
+#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
-#include "kernel/log.h"
#include <string.h>
-#include <fnmatch.h>
#include <errno.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
static std::vector<RTLIL::Selection> work_stack;
@@ -35,9 +36,9 @@ static bool match_ids(RTLIL::IdString id, std::string pattern)
return true;
if (id.size() > 0 && id[0] == '\\' && id.substr(1) == pattern)
return true;
- if (!fnmatch(pattern.c_str(), id.c_str(), 0))
+ if (patmatch(pattern.c_str(), id.c_str()))
return true;
- if (id.size() > 0 && id[0] == '\\' && !fnmatch(pattern.c_str(), id.substr(1).c_str(), 0))
+ if (id.size() > 0 && id[0] == '\\' && patmatch(pattern.c_str(), id.substr(1).c_str()))
return true;
if (id.size() > 0 && id[0] == '$' && pattern.size() > 0 && pattern[0] == '$') {
const char *p = id.c_str();
@@ -80,7 +81,7 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char
std::string value_str = value.decode_string();
if (match_op == '=')
- if (!fnmatch(pattern.c_str(), value.decode_string().c_str(), FNM_NOESCAPE))
+ if (patmatch(pattern.c_str(), value.decode_string().c_str()))
return true;
if (match_op == '=')
@@ -100,13 +101,13 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char
log_abort();
}
-static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes, std::string name_pat, std::string value_pat, char match_op)
+static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, std::string name_pat, std::string value_pat, char match_op)
{
if (name_pat.find('*') != std::string::npos || name_pat.find('?') != std::string::npos || name_pat.find('[') != std::string::npos) {
for (auto &it : attributes) {
- if (!fnmatch(name_pat.c_str(), it.first.c_str(), FNM_NOESCAPE) && match_attr_val(it.second, value_pat, match_op))
+ if (patmatch(name_pat.c_str(), it.first.c_str()) && match_attr_val(it.second, value_pat, match_op))
return true;
- if (it.first.size() > 0 && it.first[0] == '\\' && !fnmatch(name_pat.c_str(), it.first.substr(1).c_str(), FNM_NOESCAPE) && match_attr_val(it.second, value_pat, match_op))
+ if (it.first.size() > 0 && it.first[0] == '\\' && patmatch(name_pat.c_str(), it.first.substr(1).c_str()) && match_attr_val(it.second, value_pat, match_op))
return true;
}
} else {
@@ -118,7 +119,7 @@ static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes
return false;
}
-static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes, std::string match_expr)
+static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, std::string match_expr)
{
size_t pos = match_expr.find_first_of("<!=>");
@@ -364,7 +365,7 @@ static int parse_comma_list(std::set<RTLIL::IdString> &tokens, std::string str,
}
}
-static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::vector<expand_rule_t> &rules, std::set<RTLIL::IdString> &limits, int max_objects, char mode, CellTypes &ct)
+static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::vector<expand_rule_t> &rules, std::set<RTLIL::IdString> &limits, int max_objects, char mode, CellTypes &ct, bool eval_only)
{
int sel_objects = 0;
bool is_input, is_output;
@@ -375,6 +376,7 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
RTLIL::Module *mod = mod_it.second;
std::set<RTLIL::Wire*> selected_wires;
+ auto selected_members = lhs.selected_members[mod->name];
for (auto &it : mod->wires_)
if (lhs.selected_member(mod_it.first, it.first) && limits.count(it.first) == 0)
@@ -388,9 +390,9 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
for (size_t i = 0; i < conn_lhs.size(); i++) {
if (conn_lhs[i].wire == NULL || conn_rhs[i].wire == NULL)
continue;
- if (mode != 'i' && selected_wires.count(conn_rhs[i].wire) && lhs.selected_members[mod->name].count(conn_lhs[i].wire->name) == 0)
+ if (mode != 'i' && selected_wires.count(conn_rhs[i].wire) && selected_members.count(conn_lhs[i].wire->name) == 0)
lhs.selected_members[mod->name].insert(conn_lhs[i].wire->name), sel_objects++, max_objects--;
- if (mode != 'o' && selected_wires.count(conn_lhs[i].wire) && lhs.selected_members[mod->name].count(conn_rhs[i].wire->name) == 0)
+ if (mode != 'o' && selected_wires.count(conn_lhs[i].wire) && selected_members.count(conn_rhs[i].wire->name) == 0)
lhs.selected_members[mod->name].insert(conn_rhs[i].wire->name), sel_objects++, max_objects--;
}
}
@@ -399,6 +401,8 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
for (auto &conn : cell.second->connections())
{
char last_mode = '-';
+ if (eval_only && !yosys_celltypes.cell_evaluable(cell.second->type))
+ goto exclude_match;
for (auto &rule : rules) {
last_mode = rule.mode;
if (rule.cell_types.size() > 0 && rule.cell_types.count(cell.second->type) == 0)
@@ -417,10 +421,10 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
is_output = mode == 'x' || ct.cell_output(cell.second->type, conn.first);
for (auto &chunk : conn.second.chunks())
if (chunk.wire != NULL) {
- if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && lhs.selected_members[mod->name].count(cell.first) == 0)
+ if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && selected_members.count(cell.first) == 0)
if (mode == 'x' || (mode == 'i' && is_output) || (mode == 'o' && is_input))
lhs.selected_members[mod->name].insert(cell.first), sel_objects++, max_objects--;
- if (max_objects != 0 && lhs.selected_members[mod->name].count(cell.first) > 0 && limits.count(cell.first) == 0 && lhs.selected_members[mod->name].count(chunk.wire->name) == 0)
+ if (max_objects != 0 && selected_members.count(cell.first) > 0 && limits.count(cell.first) == 0 && selected_members.count(chunk.wire->name) == 0)
if (mode == 'x' || (mode == 'i' && is_input) || (mode == 'o' && is_output))
lhs.selected_members[mod->name].insert(chunk.wire->name), sel_objects++, max_objects--;
}
@@ -431,9 +435,10 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
return sel_objects;
}
-static void select_op_expand(RTLIL::Design *design, std::string arg, char mode)
+static void select_op_expand(RTLIL::Design *design, std::string arg, char mode, bool eval_only)
{
- int pos = mode == 'x' ? 2 : 3, levels = 1, rem_objects = -1;
+ int pos = (mode == 'x' ? 2 : 3) + (eval_only ? 1 : 0);
+ int levels = 1, rem_objects = -1;
std::vector<expand_rule_t> rules;
std::set<RTLIL::IdString> limits;
@@ -524,14 +529,14 @@ static void select_op_expand(RTLIL::Design *design, std::string arg, char mode)
#endif
while (levels-- > 0 && rem_objects != 0) {
- int num_objects = select_op_expand(design, work_stack.back(), rules, limits, rem_objects, mode, ct);
+ int num_objects = select_op_expand(design, work_stack.back(), rules, limits, rem_objects, mode, ct, eval_only);
if (num_objects == 0)
break;
rem_objects -= num_objects;
}
if (rem_objects == 0)
- log("Warning: reached configured limit at `%s'.\n", arg.c_str());
+ log_warning("reached configured limit at `%s'.\n", arg.c_str());
}
static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &sel)
@@ -631,17 +636,32 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (arg == "%x" || (arg.size() > 2 && arg.substr(0, 2) == "%x" && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%x.\n");
- select_op_expand(design, arg, 'x');
+ select_op_expand(design, arg, 'x', false);
} else
if (arg == "%ci" || (arg.size() > 3 && arg.substr(0, 3) == "%ci" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%ci.\n");
- select_op_expand(design, arg, 'i');
+ select_op_expand(design, arg, 'i', false);
} else
if (arg == "%co" || (arg.size() > 3 && arg.substr(0, 3) == "%co" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%co.\n");
- select_op_expand(design, arg, 'o');
+ select_op_expand(design, arg, 'o', false);
+ } else
+ if (arg == "%xe" || (arg.size() > 3 && arg.substr(0, 3) == "%x" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on the stack for operator %%xe.\n");
+ select_op_expand(design, arg, 'x', true);
+ } else
+ if (arg == "%cie" || (arg.size() > 4 && arg.substr(0, 4) == "%cie" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on the stack for operator %%cie.\n");
+ select_op_expand(design, arg, 'i', true);
+ } else
+ if (arg == "%coe" || (arg.size() > 4 && arg.substr(0, 4) == "%coe" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on the stack for operator %%coe.\n");
+ select_op_expand(design, arg, 'o', true);
} else
log_cmd_error("Unknown selection operator '%s'.\n", arg.c_str());
if (work_stack.size() >= 1)
@@ -795,8 +815,11 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
select_filter_active_mod(design, work_stack.back());
}
+PRIVATE_NAMESPACE_END
+YOSYS_NAMESPACE_BEGIN
+
// used in kernel/register.cc and maybe other locations, extern decl. in register.h
-void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design)
+void handle_extra_select_args(Pass *pass, vector<string> args, size_t argidx, size_t args_size, RTLIL::Design *design)
{
work_stack.clear();
for (; argidx < args_size; argidx++) {
@@ -812,20 +835,46 @@ void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t
select_op_union(design, work_stack.front(), work_stack.back());
work_stack.pop_back();
}
- if (work_stack.size() > 0)
- design->selection_stack.push_back(work_stack.back());
- else
+ if (work_stack.empty())
design->selection_stack.push_back(RTLIL::Selection(false));
+ else
+ design->selection_stack.push_back(work_stack.back());
}
+// extern decl. in register.h
+RTLIL::Selection eval_select_args(const vector<string> &args, RTLIL::Design *design)
+{
+ work_stack.clear();
+ for (auto &arg : args)
+ select_stmt(design, arg);
+ while (work_stack.size() > 1) {
+ select_op_union(design, work_stack.front(), work_stack.back());
+ work_stack.pop_back();
+ }
+ if (work_stack.empty())
+ return RTLIL::Selection(false);
+ return work_stack.back();
+}
+
+// extern decl. in register.h
+void eval_select_op(vector<RTLIL::Selection> &work, const string &op, RTLIL::Design *design)
+{
+ work_stack.swap(work);
+ select_stmt(design, op);
+ work_stack.swap(work);
+}
+
+YOSYS_NAMESPACE_END
+PRIVATE_NAMESPACE_BEGIN
+
struct SelectPass : public Pass {
SelectPass() : Pass("select", "modify and view the list of selected objects") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" select [ -add | -del | -set <name> ] <selection>\n");
- log(" select [ -assert-none | -assert-any ] <selection>\n");
+ log(" select [ -add | -del | -set <name> ] {-read <filename> | <selection>}\n");
+ log(" select [ -assert-none | -assert-any ] {-read <filename> | <selection>}\n");
log(" select [ -list | -write <filename> | -count | -clear ]\n");
log(" select -module <modname>\n");
log("\n");
@@ -867,6 +916,9 @@ struct SelectPass : public Pass {
log(" -write <filename>\n");
log(" like -list but write the output to the specified file\n");
log("\n");
+ log(" -read <filename>\n");
+ log(" read the specified file (written by -write)\n");
+ log("\n");
log(" -count\n");
log(" count all objects in the current selection\n");
log("\n");
@@ -997,6 +1049,9 @@ struct SelectPass : public Pass {
log(" %%co[<num1>|*][.<num2>][:<rule>[:<rule>..]]\n");
log(" simmilar to %%x, but only select input (%%ci) or output cones (%%co)\n");
log("\n");
+ log(" %%xe[...] %%cie[...] %%coe\n");
+ log(" like %%x, %%ci, and %%co but only consider combinatorial cells\n");
+ log("\n");
log(" %%a\n");
log(" expand top set by selecting all wires that are (at least in part)\n");
log(" aliases for selected wires.\n");
@@ -1026,9 +1081,8 @@ struct SelectPass : public Pass {
bool assert_none = false;
bool assert_any = false;
int assert_count = -1;
- std::string write_file;
- std::string set_name;
- std::string sel_str;
+ std::string write_file, read_file;
+ std::string set_name, sel_str;
work_stack.clear();
@@ -1072,6 +1126,10 @@ struct SelectPass : public Pass {
write_file = args[++argidx];
continue;
}
+ if (arg == "-read" && argidx+1 < args.size()) {
+ read_file = args[++argidx];
+ continue;
+ }
if (arg == "-count") {
count_mode = true;
continue;
@@ -1094,6 +1152,34 @@ struct SelectPass : public Pass {
sel_str += " " + arg;
}
+ if (!read_file.empty())
+ {
+ if (!sel_str.empty())
+ log_cmd_error("Option -read can not be combined with a selection expression.\n");
+
+ std::ifstream f(read_file);
+ if (f.fail())
+ log_error("Can't open '%s' for reading: %s\n", read_file.c_str(), strerror(errno));
+
+ RTLIL::Selection sel(false);
+ string line;
+
+ while (std::getline(f, line)) {
+ size_t slash_pos = line.find('/');
+ if (slash_pos == string::npos) {
+ log_warning("Ignoring line without slash in 'select -read': %s\n", line.c_str());
+ continue;
+ }
+ IdString mod_name = RTLIL::escape_id(line.substr(0, slash_pos));
+ IdString obj_name = RTLIL::escape_id(line.substr(slash_pos+1));
+ sel.selected_members[mod_name].insert(obj_name);
+ }
+
+ select_filter_active_mod(design, sel);
+ sel.optimize(design);
+ work_stack.push_back(sel);
+ }
+
if (clear_mode && args.size() != 2)
log_cmd_error("Option -clear can not be combined with any other options.\n");
@@ -1135,7 +1221,7 @@ struct SelectPass : public Pass {
if (list_mode || count_mode || !write_file.empty())
{
- #define LOG_OBJECT(...) do { if (list_mode) log(__VA_ARGS__); if (f != NULL) fprintf(f, __VA_ARGS__); total_count++; } while (0)
+ #define LOG_OBJECT(...) { if (list_mode) log(__VA_ARGS__); if (f != NULL) fprintf(f, __VA_ARGS__); total_count++; }
int total_count = 0;
FILE *f = NULL;
if (!write_file.empty()) {
@@ -1154,16 +1240,16 @@ struct SelectPass : public Pass {
if (sel->selected_module(mod_it.first)) {
for (auto &it : mod_it.second->wires_)
if (sel->selected_member(mod_it.first, it.first))
- LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ LOG_OBJECT("%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))
- LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ LOG_OBJECT("%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))
- LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ LOG_OBJECT("%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))
- LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first))
}
}
if (count_mode)
@@ -1320,21 +1406,20 @@ struct CdPass : public Pass {
} CdPass;
template<typename T>
-static int log_matches(const char *title, std::string pattern, T list)
+static void log_matches(const char *title, Module *module, T list)
{
- std::vector<RTLIL::IdString> matches;
+ std::vector<IdString> matches;
for (auto &it : list)
- if (pattern.empty() || match_ids(it.first, pattern))
+ if (module->selected(it.second))
matches.push_back(it.first);
- if (matches.empty())
- return 0;
-
- log("\n%d %s:\n", int(matches.size()), title);
- for (auto &id : matches)
- log(" %s\n", RTLIL::id2cstr(id));
- return matches.size();
+ if (!matches.empty()) {
+ log("\n%d %s:\n", int(matches.size()), title);
+ std::sort(matches.begin(), matches.end(), RTLIL::sort_by_id_str());
+ for (auto id : matches)
+ log(" %s\n", RTLIL::id2cstr(id));
+ }
}
struct LsPass : public Pass {
@@ -1343,44 +1428,42 @@ struct LsPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" ls [pattern]\n");
+ log(" ls [selection]\n");
log("\n");
- log("When no active module is selected, this prints a list of all modules.\n");
+ log("When no active module is selected, this prints a list of modules.\n");
log("\n");
log("When an active module is selected, this prints a list of objects in the module.\n");
log("\n");
- log("If a pattern is given, the objects matching the pattern are printed\n");
- log("\n");
- log("Note that this command does not use the selection mechanism and always operates\n");
- log("on the whole design or whole active module. Use 'select -list' to show a list\n");
- log("of currently selected objects.\n");
- log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- std::string pattern;
- int counter = 0;
-
- if (args.size() != 1 && args.size() != 2)
- log_cmd_error("Invalid number of arguments.\n");
- if (args.size() == 2)
- pattern = args.at(1);
+ size_t argidx = 1;
+ extra_args(args, argidx, design);
if (design->selected_active_module.empty())
{
- counter += log_matches("modules", pattern, design->modules_);
+ std::vector<IdString> matches;
+
+ for (auto mod : design->selected_modules())
+ matches.push_back(mod->name);
+
+ if (!matches.empty()) {
+ log("\n%d %s:\n", int(matches.size()), "modules");
+ std::sort(matches.begin(), matches.end(), RTLIL::sort_by_id_str());
+ for (auto id : matches)
+ log(" %s%s\n", log_id(id), design->selected_whole_module(design->module(id)) ? "" : "*");
+ }
}
else
- if (design->modules_.count(design->selected_active_module) > 0)
+ if (design->module(design->selected_active_module) != nullptr)
{
- RTLIL::Module *module = design->modules_.at(design->selected_active_module);
- counter += log_matches("wires", pattern, module->wires_);
- counter += log_matches("memories", pattern, module->memories);
- counter += log_matches("cells", pattern, module->cells_);
- counter += log_matches("processes", pattern, module->processes);
+ RTLIL::Module *module = design->module(design->selected_active_module);
+ log_matches("wires", module, module->wires_);
+ log_matches("memories", module, module->memories);
+ log_matches("cells", module, module->cells_);
+ log_matches("processes", module, module->processes);
}
-
- // log("\nfound %d item%s.\n", counter, counter == 1 ? "" : "s");
}
} LsPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 029c0ec7..9a6d8a03 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -21,6 +21,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct setunset_t
{
RTLIL::IdString name;
@@ -47,7 +50,7 @@ struct setunset_t
}
};
-static void do_setunset(std::map<RTLIL::IdString, RTLIL::Const> &attrs, std::vector<setunset_t> &list)
+static void do_setunset(dict<RTLIL::IdString, RTLIL::Const> &attrs, std::vector<setunset_t> &list)
{
for (auto &item : list)
if (item.unset)
@@ -178,3 +181,4 @@ struct SetparamPass : public Pass {
}
} SetparamPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index c72e64b8..b9a29b7d 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -23,6 +23,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SetundefWorker
{
int next_bit_mode;
@@ -153,3 +156,4 @@ struct SetundefPass : public Pass {
}
} SetundefPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 2218eded..81321665 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -21,12 +21,18 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string.h>
-#include <dirent.h>
+
+#ifndef _WIN32
+# include <dirent.h>
+#endif
#ifdef YOSYS_ENABLE_READLINE
# include <readline/readline.h>
#endif
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
#undef CLUSTER_CELLS_AND_PORTBOXES
@@ -58,6 +64,10 @@ struct ShowWorker
const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections;
const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections;
+ std::map<RTLIL::Const, int> colorattr_cache;
+ RTLIL::IdString colorattr;
+
+
static uint32_t xorshift32(uint32_t x) {
x ^= x << 13;
x ^= x >> 17;
@@ -69,7 +79,7 @@ struct ShowWorker
{
if (currentColor == 0)
return "color=\"black\"";
- return stringf("colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", currentColor%8+1);
+ return stringf("colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", currentColor%8+1, currentColor%8+1);
}
std::string nextColor(std::string presetColor)
@@ -122,7 +132,25 @@ struct ShowWorker
dot_escape_store.push_back(stringf(", color=\"%s\"", s.first.c_str()));
return dot_escape_store.back().c_str();
}
- return "";
+
+ RTLIL::Const colorattr_value;
+ RTLIL::Cell *cell = module->cell(member_name);
+ RTLIL::Wire *wire = module->wire(member_name);
+
+ if (cell && cell->attributes.count(colorattr))
+ colorattr_value = cell->attributes.at(colorattr);
+ else if (wire && wire->attributes.count(colorattr))
+ colorattr_value = wire->attributes.at(colorattr);
+ else
+ return "";
+
+ if (colorattr_cache.count(colorattr_value) == 0) {
+ int next_id = GetSize(colorattr_cache);
+ colorattr_cache[colorattr_value] = (next_id % 8) + 1;
+ }
+
+ dot_escape_store.push_back(stringf(", colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", colorattr_cache.at(colorattr_value), colorattr_cache.at(colorattr_value)));
+ return dot_escape_store.back().c_str();
}
const char *findLabel(std::string member_name)
@@ -175,7 +203,7 @@ struct ShowWorker
std::string gen_signode_simple(RTLIL::SigSpec sig, bool range_check = true)
{
- if (SIZE(sig) == 0) {
+ if (GetSize(sig) == 0) {
fprintf(f, "v%d [ label=\"\" ];\n", single_idx_count);
return stringf("v%d", single_idx_count++);
}
@@ -203,22 +231,24 @@ struct ShowWorker
std::string label_string;
int pos = sig.size()-1;
int idx = single_idx_count++;
- for (int i = int(sig.chunks().size())-1; i >= 0; i--) {
+ for (int rep, i = int(sig.chunks().size())-1; i >= 0; i -= rep) {
const RTLIL::SigChunk &c = sig.chunks().at(i);
net = gen_signode_simple(c, false);
log_assert(!net.empty());
+ for (rep = 1; i-rep >= 0 && c == sig.chunks().at(i-rep); rep++) {}
+ std::string repinfo = rep > 1 ? stringf("%dx ", rep) : "";
if (driver) {
- label_string += stringf("<s%d> %d:%d - %d:%d |", i, pos, pos-c.width+1, c.offset+c.width-1, c.offset);
+ label_string += stringf("<s%d> %d:%d - %s%d:%d |", i, pos, pos-c.width+1, repinfo.c_str(), c.offset+c.width-1, c.offset);
net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
- net_conn_map[net].bits = c.width;
+ net_conn_map[net].bits = rep*c.width;
net_conn_map[net].color = nextColor(c, net_conn_map[net].color);
} else {
- label_string += stringf("<s%d> %d:%d - %d:%d |", i, c.offset+c.width-1, c.offset, pos, pos-c.width+1);
+ label_string += stringf("<s%d> %s%d:%d - %d:%d |", i, repinfo.c_str(), c.offset+c.width-1, c.offset, pos, pos-rep*c.width+1);
net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i));
- net_conn_map[net].bits = c.width;
+ net_conn_map[net].bits = rep*c.width;
net_conn_map[net].color = nextColor(c, net_conn_map[net].color);
}
- pos -= c.width;
+ pos -= rep * c.width;
}
if (label_string[label_string.size()-1] == '|')
label_string = label_string.substr(0, label_string.size()-1);
@@ -452,8 +482,8 @@ struct ShowWorker
if (left_node[0] == 'x' && right_node[0] == 'x') {
currentColor = xorshift32(currentColor);
- fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor(conn).c_str(), widthLabel(conn.first.size()).c_str());
- } else {
+ fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor(conn).c_str(), widthLabel(conn.first.size()).c_str());
+ } else {
net_conn_map[right_node].bits = conn.first.size();
net_conn_map[right_node].color = nextColor(conn, net_conn_map[right_node].color);
net_conn_map[left_node].bits = conn.first.size();
@@ -499,10 +529,10 @@ struct ShowWorker
ShowWorker(FILE *f, RTLIL::Design *design, std::vector<RTLIL::Design*> &libs, uint32_t colorSeed, bool genWidthLabels,
bool genSignedLabels, bool stretchIO, bool enumerateIds, bool abbreviateIds, bool notitle,
const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections,
- const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections) :
+ const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections, RTLIL::IdString colorattr) :
f(f), design(design), currentColor(colorSeed), genWidthLabels(genWidthLabels),
genSignedLabels(genSignedLabels), stretchIO(stretchIO), enumerateIds(enumerateIds), abbreviateIds(abbreviateIds),
- notitle(notitle), color_selections(color_selections), label_selections(label_selections)
+ notitle(notitle), color_selections(color_selections), label_selections(label_selections), colorattr(colorattr)
{
ct.setup_internals();
ct.setup_internals_mem();
@@ -560,6 +590,10 @@ struct ShowPass : public Pass {
log(" inputs or outputs. This option can be used multiple times to specify\n");
log(" more than one library.\n");
log("\n");
+ log(" note: in most cases it is better to load the library before calling\n");
+ log(" show with 'read_verilog -lib <filename>'. it is also possible to\n");
+ log(" load liberty files with 'read_liberty -lib <filename>'.\n");
+ log("\n");
log(" -prefix <prefix>\n");
log(" generate <prefix>.* instead of ~/.yosys_show.*\n");
log("\n");
@@ -578,6 +612,10 @@ struct ShowPass : public Pass {
log(" for the random number generator. Change the seed value if the colored\n");
log(" graph still is ambigous. A seed of zero deactivates the coloring.\n");
log("\n");
+ log(" -colorattr <attribute_name>\n");
+ log(" Use the specified attribute to assign colors. A unique color is\n");
+ 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("\n");
@@ -607,6 +645,9 @@ struct ShowPass : public Pass {
log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
log("unless another prefix is specified using -prefix <prefix>.\n");
log("\n");
+ log("Yosys on Windows and YosysJS use different defaults: The output is written\n");
+ log("to 'show.dot' in the current directory and new viewer is launched.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -616,9 +657,14 @@ struct ShowPass : public Pass {
std::vector<std::pair<std::string, RTLIL::Selection>> color_selections;
std::vector<std::pair<std::string, RTLIL::Selection>> label_selections;
+#if defined(EMSCRIPTEN) || defined(_WIN32)
+ std::string format = "dot";
+ std::string prefix = "show";
+#else
std::string format;
- std::string viewer_exe;
std::string prefix = stringf("%s/.yosys_show", getenv("HOME") ? getenv("HOME") : ".");
+#endif
+ std::string viewer_exe;
std::vector<std::string> libfiles;
std::vector<RTLIL::Design*> libs;
uint32_t colorSeed = 0;
@@ -629,6 +675,7 @@ struct ShowPass : public Pass {
bool flag_enum = false;
bool flag_abbeviate = true;
bool flag_notitle = false;
+ RTLIL::IdString colorattr;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -670,6 +717,10 @@ struct ShowPass : public Pass {
colorSeed = ShowWorker::xorshift32(colorSeed);
continue;
}
+ if (arg == "-colorattr" && argidx+1 < args.size()) {
+ colorattr = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
if (arg == "-format" && argidx+1 < args.size()) {
format = args[++argidx];
continue;
@@ -745,7 +796,7 @@ struct ShowPass : public Pass {
delete lib;
log_cmd_error("Can't open dot file `%s' for writing.\n", dot_file.c_str());
}
- ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_signed, flag_stretch, flag_enum, flag_abbeviate, flag_notitle, color_selections, label_selections);
+ ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_signed, flag_stretch, flag_enum, flag_abbeviate, flag_notitle, color_selections, label_selections, colorattr);
fclose(f);
for (auto lib : libs)
@@ -755,22 +806,22 @@ struct ShowPass : public Pass {
log_cmd_error("Nothing there to show.\n");
if (format != "dot" && !format.empty()) {
- std::string cmd = stringf("dot -T%s -o '%s' '%s'", format.c_str(), out_file.c_str(), dot_file.c_str());
+ std::string cmd = stringf("dot -T%s -o '%s.new' '%s' && mv '%s.new' '%s'", format.c_str(), out_file.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str());
log("Exec: %s\n", cmd.c_str());
- if (system(cmd.c_str()) != 0)
+ if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
}
if (!viewer_exe.empty()) {
std::string cmd = stringf("%s '%s' &", viewer_exe.c_str(), out_file.c_str());
log("Exec: %s\n", cmd.c_str());
- if (system(cmd.c_str()) != 0)
+ if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
} else
if (format.empty()) {
- std::string cmd = stringf("fuser -s '%s' || xdot '%s' < '%s' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
+ std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
log("Exec: %s\n", cmd.c_str());
- if (system(cmd.c_str()) != 0)
+ if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
}
@@ -795,3 +846,4 @@ struct ShowPass : public Pass {
}
} ShowPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index d03aaf3b..3e0158c5 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -24,6 +24,9 @@
#include "kernel/log.h"
#include <tuple>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SpliceWorker
{
RTLIL::Design *design;
@@ -179,11 +182,13 @@ struct SpliceWorker
if (design->selected(module, it.second))
selected_bits.add(sigmap(it.second));
- for (auto &it : module->cells_) {
- if (!sel_by_wire && !design->selected(module, it.second))
+ std::vector<Cell*> mod_cells = module->cells();
+
+ for (auto cell : mod_cells) {
+ if (!sel_by_wire && !design->selected(module, cell))
continue;
- for (auto &conn : it.second->connections_)
- if (ct.cell_input(it.second->type, conn.first)) {
+ for (auto &conn : cell->connections_)
+ if (ct.cell_input(cell->type, conn.first)) {
if (ports.size() > 0 && !ports.count(conn.first))
continue;
if (no_ports.size() > 0 && no_ports.count(conn.first))
@@ -202,24 +207,25 @@ struct SpliceWorker
}
std::vector<std::pair<RTLIL::Wire*, RTLIL::SigSpec>> rework_wires;
+ std::vector<Wire*> mod_wires = module->wires();
- for (auto &it : module->wires_)
- if (!no_outputs && it.second->port_output) {
- if (!design->selected(module, it.second))
+ for (auto mod : mod_wires)
+ if (!no_outputs && mod->port_output) {
+ if (!design->selected(module, mod))
continue;
- RTLIL::SigSpec sig = sigmap(it.second);
+ RTLIL::SigSpec sig = sigmap(mod);
if (driven_chunks.count(sig) > 0)
continue;
RTLIL::SigSpec new_sig = get_spliced_signal(sig);
if (new_sig != sig)
- rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, new_sig));
+ rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(mod, new_sig));
} else
- if (!it.second->port_input) {
- RTLIL::SigSpec sig = sigmap(it.second);
+ if (!mod->port_input) {
+ RTLIL::SigSpec sig = sigmap(mod);
if (spliced_signals_cache.count(sig) && spliced_signals_cache.at(sig) != sig)
- rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, spliced_signals_cache.at(sig)));
+ rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(mod, spliced_signals_cache.at(sig)));
else if (sliced_signals_cache.count(sig) && sliced_signals_cache.at(sig) != sig)
- rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, sliced_signals_cache.at(sig)));
+ rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(mod, sliced_signals_cache.at(sig)));
}
for (auto &it : rework_wires)
@@ -349,3 +355,4 @@ struct SplicePass : public Pass {
}
} SplicePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index 344b03fc..d4e721a5 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SplitnetsWorker
{
std::map<RTLIL::Wire*, std::vector<RTLIL::SigBit>> splitmap;
@@ -173,7 +176,7 @@ struct SplitnetsPass : public Pass {
module->rewrite_sigspecs(worker);
- std::set<RTLIL::Wire*> delete_wires;
+ pool<RTLIL::Wire*> delete_wires;
for (auto &it : worker.splitmap)
delete_wires.insert(it.first);
module->remove(delete_wires);
@@ -183,3 +186,4 @@ struct SplitnetsPass : public Pass {
}
} SplitnetsPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 19cdaa62..bd3a43ac 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -21,145 +21,145 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
-namespace
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct statdata_t
{
- struct statdata_t
+ #define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
+ X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
+
+ #define X(_name) int _name;
+ STAT_INT_MEMBERS
+ #undef X
+
+ std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
+
+ statdata_t operator+(const statdata_t &other) const
{
- #define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
- X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
+ statdata_t sum = other;
+ #define X(_name) sum._name += _name;
+ STAT_INT_MEMBERS
+ #undef X
+ for (auto &it : num_cells_by_type)
+ sum.num_cells_by_type[it.first] += it.second;
+ return sum;
+ }
+
+ statdata_t operator*(int other) const
+ {
+ statdata_t sum = *this;
+ #define X(_name) sum._name *= other;
+ STAT_INT_MEMBERS
+ #undef X
+ for (auto &it : sum.num_cells_by_type)
+ it.second *= other;
+ return sum;
+ }
- #define X(_name) int _name;
+ statdata_t()
+ {
+ #define X(_name) _name = 0;
STAT_INT_MEMBERS
- #undef X
+ #undef X
+ }
- std::map<RTLIL::IdString, int> num_cells_by_type;
+ statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode)
+ {
+ #define X(_name) _name = 0;
+ STAT_INT_MEMBERS
+ #undef X
- statdata_t operator+(const statdata_t &other) const
+ for (auto &it : mod->wires_)
{
- statdata_t sum = other;
- #define X(_name) sum._name += _name;
- STAT_INT_MEMBERS
- #undef X
- for (auto &it : num_cells_by_type)
- sum.num_cells_by_type[it.first] += it.second;
- return sum;
- }
+ if (!design->selected(mod, it.second))
+ continue;
- statdata_t operator*(int other) const
- {
- statdata_t sum = *this;
- #define X(_name) sum._name *= other;
- STAT_INT_MEMBERS
- #undef X
- for (auto &it : sum.num_cells_by_type)
- it.second *= other;
- return sum;
+ if (it.first[0] == '\\') {
+ num_pub_wires++;
+ num_pub_wire_bits += it.second->width;
+ }
+
+ num_wires++;
+ num_wire_bits += it.second->width;
}
- statdata_t()
- {
- #define X(_name) _name = 0;
- STAT_INT_MEMBERS
- #undef X
+ for (auto &it : mod->memories) {
+ if (!design->selected(mod, it.second))
+ continue;
+ num_memories++;
+ num_memory_bits += it.second->width * it.second->size;
}
- statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode)
+ for (auto &it : mod->cells_)
{
- #define X(_name) _name = 0;
- STAT_INT_MEMBERS
- #undef X
-
- for (auto &it : mod->wires_)
- {
- if (!design->selected(mod, it.second))
- continue;
-
- if (it.first[0] == '\\') {
- num_pub_wires++;
- num_pub_wire_bits += it.second->width;
- }
-
- num_wires++;
- num_wire_bits += it.second->width;
- }
+ if (!design->selected(mod, it.second))
+ continue;
- for (auto &it : mod->memories) {
- if (!design->selected(mod, it.second))
- continue;
- num_memories++;
- num_memory_bits += it.second->width * it.second->size;
- }
+ RTLIL::IdString cell_type = it.second->type;
- for (auto &it : mod->cells_)
+ if (width_mode)
{
- if (!design->selected(mod, it.second))
- continue;
-
- RTLIL::IdString cell_type = it.second->type;
-
- if (width_mode)
- {
- if (cell_type.in("$not", "$pos", "$neg",
- "$logic_not", "$logic_and", "$logic_or",
- "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
- "$lut", "$and", "$or", "$xor", "$xnor",
- "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
- "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
- "$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
- int width_a = it.second->hasPort("\\A") ? SIZE(it.second->getPort("\\A")) : 0;
- int width_b = it.second->hasPort("\\B") ? SIZE(it.second->getPort("\\B")) : 0;
- int width_y = it.second->hasPort("\\Y") ? SIZE(it.second->getPort("\\Y")) : 0;
- cell_type = stringf("%s_%d", cell_type.c_str(), std::max<int>({width_a, width_b, width_y}));
- }
- else if (cell_type.in("$mux", "$pmux"))
- cell_type = stringf("%s_%d", cell_type.c_str(), SIZE(it.second->getPort("\\Y")));
- else if (cell_type.in("$sr", "$dff", "$dffsr", "$adff", "$dlatch", "$dlatchsr"))
- cell_type = stringf("%s_%d", cell_type.c_str(), SIZE(it.second->getPort("\\Q")));
+ if (cell_type.in("$not", "$pos", "$neg",
+ "$logic_not", "$logic_and", "$logic_or",
+ "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
+ "$lut", "$and", "$or", "$xor", "$xnor",
+ "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
+ "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
+ "$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
+ int width_a = it.second->hasPort("\\A") ? GetSize(it.second->getPort("\\A")) : 0;
+ int width_b = it.second->hasPort("\\B") ? GetSize(it.second->getPort("\\B")) : 0;
+ int width_y = it.second->hasPort("\\Y") ? GetSize(it.second->getPort("\\Y")) : 0;
+ cell_type = stringf("%s_%d", cell_type.c_str(), std::max<int>({width_a, width_b, width_y}));
}
-
- num_cells++;
- num_cells_by_type[cell_type]++;
+ else if (cell_type.in("$mux", "$pmux"))
+ cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort("\\Y")));
+ else if (cell_type.in("$sr", "$dff", "$dffsr", "$adff", "$dlatch", "$dlatchsr"))
+ cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort("\\Q")));
}
- for (auto &it : mod->processes) {
- if (!design->selected(mod, it.second))
- continue;
- num_processes++;
- }
+ num_cells++;
+ num_cells_by_type[cell_type]++;
}
- void log_data()
- {
- log(" Number of wires: %6d\n", num_wires);
- log(" Number of wire bits: %6d\n", num_wire_bits);
- log(" Number of public wires: %6d\n", num_pub_wires);
- log(" Number of public wire bits: %6d\n", num_pub_wire_bits);
- log(" Number of memories: %6d\n", num_memories);
- log(" Number of memory bits: %6d\n", num_memory_bits);
- log(" Number of processes: %6d\n", num_processes);
- log(" Number of cells: %6d\n", num_cells);
- for (auto &it : num_cells_by_type)
- log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
+ for (auto &it : mod->processes) {
+ if (!design->selected(mod, it.second))
+ continue;
+ num_processes++;
}
- };
+ }
- statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level)
+ void log_data()
{
- statdata_t mod_data = mod_stat.at(mod);
- std::map<RTLIL::IdString, int> num_cells_by_type;
- num_cells_by_type.swap(mod_data.num_cells_by_type);
-
+ log(" Number of wires: %6d\n", num_wires);
+ log(" Number of wire bits: %6d\n", num_wire_bits);
+ log(" Number of public wires: %6d\n", num_pub_wires);
+ log(" Number of public wire bits: %6d\n", num_pub_wire_bits);
+ log(" Number of memories: %6d\n", num_memories);
+ log(" Number of memory bits: %6d\n", num_memory_bits);
+ log(" Number of processes: %6d\n", num_processes);
+ log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type)
- if (mod_stat.count(it.first) > 0) {
- log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, RTLIL::id2cstr(it.first), it.second);
- mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second;
- mod_data.num_cells -= it.second;
- } else {
- mod_data.num_cells_by_type[it.first] += it.second;
- }
-
- return mod_data;
+ log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
}
+};
+
+statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level)
+{
+ statdata_t mod_data = mod_stat.at(mod);
+ std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
+ num_cells_by_type.swap(mod_data.num_cells_by_type);
+
+ for (auto &it : num_cells_by_type)
+ if (mod_stat.count(it.first) > 0) {
+ log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, RTLIL::id2cstr(it.first), it.second);
+ mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second;
+ mod_data.num_cells -= it.second;
+ } else {
+ mod_data.num_cells_by_type[it.first] += it.second;
+ }
+
+ return mod_data;
}
struct StatPass : public Pass {
@@ -208,20 +208,17 @@ struct StatPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &it : design->modules_)
+ for (auto mod : design->selected_modules())
{
- if (!design->selected_module(it.first))
- continue;
-
if (!top_mod && design->full_selection())
- if (it.second->get_bool_attribute("\\top"))
- top_mod = it.second;
+ if (mod->get_bool_attribute("\\top"))
+ top_mod = mod;
- statdata_t data(design, it.second, width_mode);
- mod_stat[it.first] = data;
+ statdata_t data(design, mod, width_mode);
+ mod_stat[mod->name] = data;
log("\n");
- log("=== %s%s ===\n", RTLIL::id2cstr(it.first), design->selected_whole_module(it.first) ? "" : " (partially selected)");
+ log("=== %s%s ===\n", RTLIL::id2cstr(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
log("\n");
data.log_data();
}
@@ -243,3 +240,4 @@ struct StatPass : public Pass {
}
} StatPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index 6f80ef72..a0484090 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct TeePass : public Pass {
TeePass() : Pass("tee", "redirect command output to file") { }
virtual void help()
@@ -73,11 +76,11 @@ struct TeePass : public Pass {
try {
std::vector<std::string> new_args(args.begin() + argidx, args.end());
Pass::call(design, new_args);
- } catch (log_cmd_error_expection) {
+ } catch (...) {
for (auto cf : files_to_close)
fclose(cf);
log_files = backup_log_files;
- throw log_cmd_error_expection();
+ throw;
}
for (auto cf : files_to_close)
@@ -86,3 +89,4 @@ struct TeePass : public Pass {
}
} TeePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc
index 09293a86..1a5f873f 100644
--- a/passes/cmds/trace.cc
+++ b/passes/cmds/trace.cc
@@ -20,38 +20,39 @@
#include "kernel/yosys.h"
+USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct TraceMonitor : public RTLIL::Monitor
{
- virtual void notify_module_add(RTLIL::Module *module) OVERRIDE
+ virtual void notify_module_add(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Module add: %s\n", log_id(module));
}
- virtual void notify_module_del(RTLIL::Module *module) OVERRIDE
+ virtual void notify_module_del(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Module delete: %s\n", log_id(module));
}
- virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE
+ virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
{
log("#TRACE# Cell connect: %s.%s.%s = %s (was: %s)\n", log_id(cell->module), log_id(cell), log_id(port), log_signal(sig), log_signal(old_sig));
}
- virtual void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) OVERRIDE
+ virtual void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) YS_OVERRIDE
{
log("#TRACE# Connection in module %s: %s = %s\n", log_id(module), log_signal(sigsig.first), log_signal(sigsig.second));
}
- virtual void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) OVERRIDE
+ virtual void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) YS_OVERRIDE
{
log("#TRACE# New connections in module %s:\n", log_id(module));
for (auto &sigsig : sigsig_vec)
log("## %s = %s\n", log_signal(sigsig.first), log_signal(sigsig.second));
}
- virtual void notify_blackout(RTLIL::Module *module) OVERRIDE
+ virtual void notify_blackout(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Blackout in module %s:\n", log_id(module));
}
@@ -84,9 +85,9 @@ struct TracePass : public Pass {
try {
std::vector<std::string> new_args(args.begin() + argidx, args.end());
Pass::call(design, new_args);
- } catch (log_cmd_error_expection) {
+ } catch (...) {
design->monitors.erase(&monitor);
- throw log_cmd_error_expection();
+ throw;
}
design->monitors.erase(&monitor);
diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc
index 813e215b..25ec4acc 100644
--- a/passes/cmds/write_file.cc
+++ b/passes/cmds/write_file.cc
@@ -20,6 +20,9 @@
#include "kernel/yosys.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct WriteFileFrontend : public Frontend {
WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { }
virtual void help()
@@ -65,12 +68,13 @@ struct WriteFileFrontend : public Frontend {
FILE *of = fopen(output_filename.c_str(), append_mode ? "a" : "w");
char buffer[64 * 1024];
- size_t bytes;
+ int bytes;
- while (0 < (bytes = f->readsome(buffer, sizeof(buffer))))
+ while (0 < (bytes = readsome(*f, buffer, sizeof(buffer))))
fwrite(buffer, bytes, 1, of);
fclose(of);
}
} WriteFileFrontend;
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/Makefile.inc b/passes/equiv/Makefile.inc
new file mode 100644
index 00000000..548eaca3
--- /dev/null
+++ b/passes/equiv/Makefile.inc
@@ -0,0 +1,9 @@
+
+OBJS += passes/equiv/equiv_make.o
+OBJS += passes/equiv/equiv_miter.o
+OBJS += passes/equiv/equiv_simple.o
+OBJS += passes/equiv/equiv_status.o
+OBJS += passes/equiv/equiv_add.o
+OBJS += passes/equiv/equiv_remove.o
+OBJS += passes/equiv/equiv_induct.o
+
diff --git a/passes/equiv/equiv_add.cc b/passes/equiv/equiv_add.cc
new file mode 100644
index 00000000..a6e2f01b
--- /dev/null
+++ b/passes/equiv/equiv_add.cc
@@ -0,0 +1,89 @@
+/*
+ * 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 EquivAddPass : public Pass {
+ EquivAddPass() : Pass("equiv_add", "add a $equiv cell") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_add gold_sig gate_sig\n");
+ log("\n");
+ log("This command adds an $equiv cell for the specified signals.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ if (GetSize(args) != 3)
+ cmd_error(args, GetSize(args)-1, "Invalid number of arguments.");
+
+ if (design->selected_active_module.empty())
+ log_cmd_error("This command must be executed in module context!\n");
+
+ Module *module = design->module(design->selected_active_module);
+ log_assert(module != nullptr);
+
+ SigSpec gold_signal, gate_signal;
+
+ if (!SigSpec::parse(gate_signal, module, args[2]))
+ log_cmd_error("Error in gate signal: %s\n", args[2].c_str());
+
+ if (!SigSpec::parse_rhs(gate_signal, gold_signal, module, args[1]))
+ log_cmd_error("Error in gold signal: %s\n", args[1].c_str());
+
+ log_assert(GetSize(gold_signal) == GetSize(gate_signal));
+ SigSpec equiv_signal = module->addWire(NEW_ID, GetSize(gold_signal));
+
+ SigMap sigmap(module);
+ sigmap.apply(gold_signal);
+ sigmap.apply(gate_signal);
+
+ dict<SigBit, SigBit> to_equiv_bits;
+ pool<Cell*> added_equiv_cells;
+
+ for (int i = 0; i < GetSize(gold_signal); i++) {
+ Cell *equiv_cell = module->addEquiv(NEW_ID, gold_signal[i], gate_signal[i], equiv_signal[i]);
+ equiv_cell->set_bool_attribute("\\keep");
+ to_equiv_bits[gold_signal[i]] = equiv_signal[i];
+ to_equiv_bits[gate_signal[i]] = equiv_signal[i];
+ added_equiv_cells.insert(equiv_cell);
+ }
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections())
+ if (!added_equiv_cells.count(cell) && cell->input(conn.first)) {
+ SigSpec new_sig;
+ for (auto bit : conn.second)
+ if (to_equiv_bits.count(sigmap(bit)))
+ new_sig.append(to_equiv_bits.at(sigmap(bit)));
+ else
+ new_sig.append(bit);
+ if (conn.second != new_sig)
+ cell->setPort(conn.first, new_sig);
+ }
+ }
+} EquivAddPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc
new file mode 100644
index 00000000..a56730d4
--- /dev/null
+++ b/passes/equiv/equiv_induct.cc
@@ -0,0 +1,241 @@
+/*
+ * 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/satgen.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivInductWorker
+{
+ Module *module;
+ SigMap sigmap;
+
+ vector<Cell*> cells;
+ pool<Cell*> workset;
+
+ ezSatPtr ez;
+ SatGen satgen;
+
+ int max_seq;
+ int success_counter;
+
+ dict<int, int> ez_step_is_consistent;
+ pool<Cell*> cell_warn_cache;
+ SigPool undriven_signals;
+
+ EquivInductWorker(Module *module, const pool<Cell*> &unproven_equiv_cells, bool model_undef, int max_seq) : module(module), sigmap(module),
+ cells(module->selected_cells()), workset(unproven_equiv_cells),
+ satgen(ez.get(), &sigmap), max_seq(max_seq), success_counter(0)
+ {
+ satgen.model_undef = model_undef;
+ }
+
+ void create_timestep(int step)
+ {
+ vector<int> ez_equal_terms;
+
+ for (auto cell : cells) {
+ if (!satgen.importCell(cell, step) && !cell_warn_cache.count(cell)) {
+ log_warning("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
+ cell_warn_cache.insert(cell);
+ }
+ if (cell->type == "$equiv") {
+ SigBit bit_a = sigmap(cell->getPort("\\A")).to_single_sigbit();
+ SigBit bit_b = sigmap(cell->getPort("\\B")).to_single_sigbit();
+ if (bit_a != bit_b) {
+ int ez_a = satgen.importSigBit(bit_a, step);
+ int ez_b = satgen.importSigBit(bit_b, step);
+ int cond = ez->IFF(ez_a, ez_b);
+ if (satgen.model_undef)
+ cond = ez->OR(cond, satgen.importUndefSigBit(bit_a, step));
+ ez_equal_terms.push_back(cond);
+ }
+ }
+ }
+
+ if (satgen.model_undef) {
+ for (auto bit : undriven_signals.export_all())
+ ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step)));
+ }
+
+ log_assert(!ez_step_is_consistent.count(step));
+ ez_step_is_consistent[step] = ez->expression(ez->OpAnd, ez_equal_terms);
+ }
+
+ void run()
+ {
+ log("Found %d unproven $equiv cells in module %s:\n", GetSize(workset), log_id(module));
+
+ if (satgen.model_undef) {
+ for (auto cell : cells)
+ if (yosys_celltypes.cell_known(cell->type))
+ for (auto &conn : cell->connections())
+ if (yosys_celltypes.cell_input(cell->type, conn.first))
+ undriven_signals.add(sigmap(conn.second));
+ for (auto cell : cells)
+ if (yosys_celltypes.cell_known(cell->type))
+ for (auto &conn : cell->connections())
+ if (yosys_celltypes.cell_output(cell->type, conn.first))
+ undriven_signals.del(sigmap(conn.second));
+ }
+
+ create_timestep(1);
+
+ if (satgen.model_undef) {
+ for (auto bit : satgen.initial_state.export_all())
+ ez->assume(ez->NOT(satgen.importUndefSigBit(bit, 1)));
+ log(" Undef modelling: force def on %d initial reg values and %d inputs.\n",
+ GetSize(satgen.initial_state), GetSize(undriven_signals));
+ }
+
+ for (int step = 1; step <= max_seq; step++)
+ {
+ ez->assume(ez_step_is_consistent[step]);
+
+ log(" Proving existence of base case for step %d. (%d clauses over %d variables)\n", step, ez->numCnfClauses(), ez->numCnfVariables());
+ if (!ez->solve()) {
+ log(" Proof for base case failed. Circuit inherently diverges!\n");
+ return;
+ }
+
+ create_timestep(step+1);
+ int new_step_not_consistent = ez->NOT(ez_step_is_consistent[step+1]);
+ ez->bind(new_step_not_consistent);
+
+ log(" Proving induction step %d. (%d clauses over %d variables)\n", step, ez->numCnfClauses(), ez->numCnfVariables());
+ if (!ez->solve(new_step_not_consistent)) {
+ log(" Proof for induction step holds. Entire workset of %d cells proven!\n", GetSize(workset));
+ for (auto cell : workset)
+ cell->setPort("\\B", cell->getPort("\\A"));
+ success_counter += GetSize(workset);
+ return;
+ }
+
+ log(" Proof for induction step failed. %s\n", step != max_seq ? "Extending to next time step." : "Trying to prove individual $equiv from workset.");
+ }
+
+ workset.sort();
+
+ for (auto cell : workset)
+ {
+ SigBit bit_a = sigmap(cell->getPort("\\A")).to_single_sigbit();
+ SigBit bit_b = sigmap(cell->getPort("\\B")).to_single_sigbit();
+
+ log(" Trying to prove $equiv for %s:", log_signal(sigmap(cell->getPort("\\Y"))));
+
+ int ez_a = satgen.importSigBit(bit_a, max_seq+1);
+ int ez_b = satgen.importSigBit(bit_b, max_seq+1);
+ int cond = ez->XOR(ez_a, ez_b);
+
+ if (satgen.model_undef)
+ cond = ez->AND(cond, ez->NOT(satgen.importUndefSigBit(bit_a, max_seq+1)));
+
+ if (!ez->solve(cond)) {
+ log(" success!\n");
+ cell->setPort("\\B", cell->getPort("\\A"));
+ success_counter++;
+ } else {
+ log(" failed.\n");
+ }
+ }
+ }
+};
+
+struct EquivInductPass : public Pass {
+ EquivInductPass() : Pass("equiv_induct", "proving $equiv cells using temporal induction") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_induct [options] [selection]\n");
+ log("\n");
+ log("Uses a version of temporal induction to prove $equiv cells.\n");
+ log("\n");
+ log("Only selected $equiv cells are proven and only selected cells are used to\n");
+ log("perform the proof.\n");
+ log("\n");
+ log(" -undef\n");
+ log(" enable modelling of undef states\n");
+ log("\n");
+ log(" -seq <N>\n");
+ log(" the max. number of time steps to be considered (default = 4)\n");
+ log("\n");
+ log("This command is very effective in proving complex sequential circuits, when\n");
+ log("the internal state of the circuit quickly propagates to $equiv cells.\n");
+ log("\n");
+ log("However, this command uses a weak definition of 'equivalence': This command\n");
+ log("proves that the two circuits will not diverge after they produce equal\n");
+ log("outputs (observable points via $equiv) for at least <N> cycles (the <N>\n");
+ log("specified via -seq).\n");
+ log("\n");
+ log("Combined with simulation this is very powerful because simulation can give\n");
+ log("you confidence that the circuits start out synced for at least <N> cycles\n");
+ log("after reset.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ int success_counter = 0;
+ bool model_undef = false;
+ int max_seq = 4;
+
+ log_header("Executing EQUIV_INDUCT pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-undef") {
+ model_undef = true;
+ continue;
+ }
+ if (args[argidx] == "-seq" && argidx+1 < args.size()) {
+ max_seq = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ pool<Cell*> unproven_equiv_cells;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv") {
+ if (cell->getPort("\\A") != cell->getPort("\\B"))
+ unproven_equiv_cells.insert(cell);
+ }
+
+ if (unproven_equiv_cells.empty()) {
+ log("No selected unproven $equiv cells found in %s.\n", log_id(module));
+ continue;
+ }
+
+ EquivInductWorker worker(module, unproven_equiv_cells, model_undef, max_seq);
+ worker.run();
+ success_counter += worker.success_counter;
+ }
+
+ log("Proved %d previously unproven $equiv cells.\n", success_counter);
+ }
+} EquivInductPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
new file mode 100644
index 00000000..5635e7a7
--- /dev/null
+++ b/passes/equiv/equiv_make.cc
@@ -0,0 +1,474 @@
+/*
+ * 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 EquivMakeWorker
+{
+ Module *gold_mod, *gate_mod, *equiv_mod;
+ pool<IdString> wire_names, cell_names;
+ CellTypes ct;
+
+ bool inames;
+ vector<string> blacklists;
+ vector<string> encfiles;
+
+ pool<IdString> blacklist_names;
+ dict<IdString, dict<Const, Const>> encdata;
+
+ pool<SigBit> undriven_bits;
+ SigMap assign_map;
+
+ void read_blacklists()
+ {
+ for (auto fn : blacklists)
+ {
+ std::ifstream f(fn);
+ if (f.fail())
+ log_cmd_error("Can't open blacklist file '%s'!\n", fn.c_str());
+
+ string line, token;
+ while (std::getline(f, line)) {
+ while (1) {
+ token = next_token(line);
+ if (token.empty())
+ break;
+ blacklist_names.insert(RTLIL::escape_id(token));
+ }
+ }
+ }
+ }
+
+ void read_encfiles()
+ {
+ for (auto fn : encfiles)
+ {
+ std::ifstream f(fn);
+ if (f.fail())
+ log_cmd_error("Can't open encfile '%s'!\n", fn.c_str());
+
+ dict<Const, Const> *ed = nullptr;
+ string line, token;
+ while (std::getline(f, line))
+ {
+ token = next_token(line);
+ if (token.empty() || token[0] == '#')
+ continue;
+
+ if (token == ".fsm") {
+ IdString modname = RTLIL::escape_id(next_token(line));
+ IdString signame = RTLIL::escape_id(next_token(line));
+ if (encdata.count(signame))
+ log_cmd_error("Re-definition of signal '%s' in encfile '%s'!\n", signame.c_str(), fn.c_str());
+ encdata[signame] = dict<Const, Const>();
+ ed = &encdata[signame];
+ continue;
+ }
+
+ if (token == ".map") {
+ Const gold_bits = Const::from_string(next_token(line));
+ Const gate_bits = Const::from_string(next_token(line));
+ (*ed)[gold_bits] = gate_bits;
+ continue;
+ }
+
+ log_cmd_error("Syntax error in encfile '%s'!\n", fn.c_str());
+ }
+ }
+ }
+
+ void copy_to_equiv()
+ {
+ Module *gold_clone = gold_mod->clone();
+ Module *gate_clone = gate_mod->clone();
+
+ for (auto it : gold_clone->wires().to_vector()) {
+ if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ wire_names.insert(it->name);
+ gold_clone->rename(it, it->name.str() + "_gold");
+ }
+
+ for (auto it : gold_clone->cells().to_vector()) {
+ if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ cell_names.insert(it->name);
+ gold_clone->rename(it, it->name.str() + "_gold");
+ }
+
+ for (auto it : gate_clone->wires().to_vector()) {
+ if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ wire_names.insert(it->name);
+ gate_clone->rename(it, it->name.str() + "_gate");
+ }
+
+ for (auto it : gate_clone->cells().to_vector()) {
+ if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ cell_names.insert(it->name);
+ gate_clone->rename(it, it->name.str() + "_gate");
+ }
+
+ gold_clone->cloneInto(equiv_mod);
+ gate_clone->cloneInto(equiv_mod);
+ delete gold_clone;
+ delete gate_clone;
+ }
+
+ void find_same_wires()
+ {
+ SigMap assign_map(equiv_mod);
+ SigMap rd_signal_map;
+
+ // list of cells without added $equiv cells
+ auto cells_list = equiv_mod->cells().to_vector();
+
+ for (auto id : wire_names)
+ {
+ IdString gold_id = id.str() + "_gold";
+ IdString gate_id = id.str() + "_gate";
+
+ Wire *gold_wire = equiv_mod->wire(gold_id);
+ Wire *gate_wire = equiv_mod->wire(gate_id);
+
+ if (encdata.count(id))
+ {
+ log("Creating encoder/decoder for signal %s.\n", log_id(id));
+
+ Wire *dec_wire = equiv_mod->addWire(id.str() + "_decoded", gold_wire->width);
+ Wire *enc_wire = equiv_mod->addWire(id.str() + "_encoded", gate_wire->width);
+
+ SigSpec dec_a, dec_b, dec_s;
+ SigSpec enc_a, enc_b, enc_s;
+
+ dec_a = SigSpec(State::Sx, dec_wire->width);
+ enc_a = SigSpec(State::Sx, enc_wire->width);
+
+ for (auto &it : encdata.at(id))
+ {
+ SigSpec dec_sig = gate_wire, dec_pat = it.second;
+ SigSpec enc_sig = dec_wire, enc_pat = it.first;
+
+ if (GetSize(dec_sig) != GetSize(dec_pat))
+ log_error("Invalid pattern %s for signal %s of size %d!\n",
+ log_signal(dec_pat), log_signal(dec_sig), GetSize(dec_sig));
+
+ if (GetSize(enc_sig) != GetSize(enc_pat))
+ log_error("Invalid pattern %s for signal %s of size %d!\n",
+ log_signal(enc_pat), log_signal(enc_sig), GetSize(enc_sig));
+
+ SigSpec reduced_dec_sig, reduced_dec_pat;
+ for (int i = 0; i < GetSize(dec_sig); i++)
+ if (dec_pat[i] == State::S0 || dec_pat[i] == State::S1) {
+ reduced_dec_sig.append(dec_sig[i]);
+ reduced_dec_pat.append(dec_pat[i]);
+ }
+
+ SigSpec reduced_enc_sig, reduced_enc_pat;
+ for (int i = 0; i < GetSize(enc_sig); i++)
+ if (enc_pat[i] == State::S0 || enc_pat[i] == State::S1) {
+ reduced_enc_sig.append(enc_sig[i]);
+ reduced_enc_pat.append(enc_pat[i]);
+ }
+
+ SigSpec dec_result = it.first;
+ for (auto &bit : dec_result)
+ if (bit != State::S1) bit = State::S0;
+
+ SigSpec enc_result = it.second;
+ for (auto &bit : enc_result)
+ if (bit != State::S1) bit = State::S0;
+
+ SigSpec dec_eq = equiv_mod->addWire(NEW_ID);
+ SigSpec enc_eq = equiv_mod->addWire(NEW_ID);
+
+ equiv_mod->addEq(NEW_ID, reduced_dec_sig, reduced_dec_pat, dec_eq);
+ cells_list.push_back(equiv_mod->addEq(NEW_ID, reduced_enc_sig, reduced_enc_pat, enc_eq));
+
+ dec_s.append(dec_eq);
+ enc_s.append(enc_eq);
+ dec_b.append(dec_result);
+ enc_b.append(enc_result);
+ }
+
+ equiv_mod->addPmux(NEW_ID, dec_a, dec_b, dec_s, dec_wire);
+ equiv_mod->addPmux(NEW_ID, enc_a, enc_b, enc_s, enc_wire);
+
+ rd_signal_map.add(assign_map(gate_wire), enc_wire);
+ gate_wire = dec_wire;
+ }
+
+ if (gold_wire == nullptr || gate_wire == nullptr || gold_wire->width != gate_wire->width) {
+ if (gold_wire && gold_wire->port_id)
+ log_error("Can't match gold port `%s' to a gate port.\n", log_id(gold_wire));
+ if (gate_wire && gate_wire->port_id)
+ log_error("Can't match gate port `%s' to a gold port.\n", log_id(gate_wire));
+ continue;
+ }
+
+ log("Presumably equivalent wires: %s (%s), %s (%s) -> %s\n",
+ log_id(gold_wire), log_signal(assign_map(gold_wire)),
+ log_id(gate_wire), log_signal(assign_map(gate_wire)), log_id(id));
+
+ if (gold_wire->port_output || gate_wire->port_output)
+ {
+ Wire *wire = equiv_mod->addWire(id, gold_wire->width);
+ wire->port_output = true;
+ gold_wire->port_input = false;
+ gate_wire->port_input = false;
+ gold_wire->port_output = false;
+ gate_wire->port_output = false;
+
+ for (int i = 0; i < wire->width; i++)
+ equiv_mod->addEquiv(NEW_ID, SigSpec(gold_wire, i), SigSpec(gate_wire, i), SigSpec(wire, i));
+
+ rd_signal_map.add(assign_map(gold_wire), wire);
+ rd_signal_map.add(assign_map(gate_wire), wire);
+ }
+ else
+ if (gold_wire->port_input || gate_wire->port_input)
+ {
+ Wire *wire = equiv_mod->addWire(id, gold_wire->width);
+ wire->port_input = true;
+ gold_wire->port_input = false;
+ gate_wire->port_input = false;
+ equiv_mod->connect(gold_wire, wire);
+ equiv_mod->connect(gate_wire, wire);
+ }
+ else
+ {
+ Wire *wire = equiv_mod->addWire(id, gold_wire->width);
+ SigSpec rdmap_gold, rdmap_gate, rdmap_equiv;
+
+ for (int i = 0; i < wire->width; i++) {
+ if (undriven_bits.count(assign_map(SigBit(gold_wire, i)))) {
+ log(" Skipping signal bit %d: undriven on gold side.\n", i);
+ continue;
+ }
+ if (undriven_bits.count(assign_map(SigBit(gate_wire, i)))) {
+ log(" Skipping signal bit %d: undriven on gate side.\n", i);
+ continue;
+ }
+ equiv_mod->addEquiv(NEW_ID, SigSpec(gold_wire, i), SigSpec(gate_wire, i), SigSpec(wire, i));
+ rdmap_gold.append(SigBit(gold_wire, i));
+ rdmap_gate.append(SigBit(gate_wire, i));
+ rdmap_equiv.append(SigBit(wire, i));
+ }
+
+ rd_signal_map.add(rdmap_gold, rdmap_equiv);
+ rd_signal_map.add(rdmap_gate, rdmap_equiv);
+ }
+ }
+
+ for (auto c : cells_list)
+ for (auto &conn : c->connections())
+ if (ct.cell_input(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);
+ }
+ }
+
+ equiv_mod->fixup_ports();
+ }
+
+ void find_same_cells()
+ {
+ SigMap assign_map(equiv_mod);
+
+ for (auto id : cell_names)
+ {
+ IdString gold_id = id.str() + "_gold";
+ IdString gate_id = id.str() + "_gate";
+
+ Cell *gold_cell = equiv_mod->cell(gold_id);
+ Cell *gate_cell = equiv_mod->cell(gate_id);
+
+ if (gold_cell == nullptr || gate_cell == nullptr || gold_cell->type != gate_cell->type || !ct.cell_known(gold_cell->type) ||
+ gold_cell->parameters != gate_cell->parameters || GetSize(gold_cell->connections()) != GetSize(gate_cell->connections()))
+ try_next_cell_name:
+ continue;
+
+ for (auto gold_conn : gold_cell->connections())
+ if (!gate_cell->connections().count(gold_conn.first))
+ goto try_next_cell_name;
+
+ log("Presumably equivalent cells: %s %s (%s) -> %s\n",
+ log_id(gold_cell), log_id(gate_cell), log_id(gold_cell->type), log_id(id));
+
+ for (auto gold_conn : gold_cell->connections())
+ {
+ SigSpec gold_sig = assign_map(gold_conn.second);
+ SigSpec gate_sig = assign_map(gate_cell->getPort(gold_conn.first));
+
+ if (ct.cell_output(gold_cell->type, gold_conn.first)) {
+ equiv_mod->connect(gate_sig, gold_sig);
+ continue;
+ }
+
+ for (int i = 0; i < GetSize(gold_sig); i++)
+ if (gold_sig[i] != gate_sig[i]) {
+ Wire *w = equiv_mod->addWire(NEW_ID);
+ equiv_mod->addEquiv(NEW_ID, gold_sig[i], gate_sig[i], w);
+ gold_sig[i] = w;
+ }
+
+ gold_cell->setPort(gold_conn.first, gold_sig);
+ }
+
+ equiv_mod->remove(gate_cell);
+ equiv_mod->rename(gold_cell, id);
+ }
+ }
+
+ void find_undriven_nets(bool mark)
+ {
+ undriven_bits.clear();
+ assign_map.set(equiv_mod);
+
+ for (auto wire : equiv_mod->wires()) {
+ for (auto bit : assign_map(wire))
+ if (bit.wire)
+ undriven_bits.insert(bit);
+ }
+
+ for (auto wire : equiv_mod->wires()) {
+ if (wire->port_input)
+ for (auto bit : assign_map(wire))
+ undriven_bits.erase(bit);
+ }
+
+ for (auto cell : equiv_mod->cells()) {
+ for (auto &conn : cell->connections())
+ if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
+ for (auto bit : assign_map(conn.second))
+ undriven_bits.erase(bit);
+ }
+
+ if (mark) {
+ SigSpec undriven_sig(undriven_bits);
+ undriven_sig.sort_and_unify();
+
+ for (auto chunk : undriven_sig.chunks()) {
+ log("Setting undriven nets to undef: %s\n", log_signal(chunk));
+ equiv_mod->connect(chunk, SigSpec(State::Sx, chunk.width));
+ }
+ }
+ }
+
+ void run()
+ {
+ copy_to_equiv();
+ find_undriven_nets(false);
+ find_same_wires();
+ find_same_cells();
+ find_undriven_nets(true);
+ }
+};
+
+struct EquivMakePass : public Pass {
+ EquivMakePass() : Pass("equiv_make", "prepare a circuit for equivalence checking") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_make [options] gold_module gate_module equiv_module\n");
+ log("\n");
+ log("This creates a module annotated with $equiv cells from two presumably\n");
+ log("equivalent modules. Use commands such as 'equiv_simple' and 'equiv_status'\n");
+ log("to work with the created equivalent checking module.\n");
+ log("\n");
+ log(" -inames\n");
+ log(" Also match cells and wires with $... names.\n");
+ log("\n");
+ log(" -blacklist <file>\n");
+ log(" Do not match cells or signals that match the names in the file.\n");
+ log("\n");
+ log(" -encfile <file>\n");
+ log(" Match FSM encodings using the desiption from the file.\n");
+ log(" See 'help fsm_recode' for details.\n");
+ log("\n");
+ log("Note: The circuit created by this command is not a miter (with something like\n");
+ log("a trigger output), but instead uses $equiv cells to encode the equivalence\n");
+ log("checking problem. Use 'miter -equiv' if you want to create a miter circuit.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ EquivMakeWorker worker;
+ worker.ct.setup(design);
+ worker.inames = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-inames") {
+ worker.inames = true;
+ continue;
+ }
+ if (args[argidx] == "-blacklist" && argidx+1 < args.size()) {
+ worker.blacklists.push_back(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-encfile" && argidx+1 < args.size()) {
+ worker.encfiles.push_back(args[++argidx]);
+ continue;
+ }
+ break;
+ }
+
+ if (argidx+3 != args.size())
+ log_cmd_error("Invalid number of arguments.\n");
+
+ worker.gold_mod = design->module(RTLIL::escape_id(args[argidx]));
+ worker.gate_mod = design->module(RTLIL::escape_id(args[argidx+1]));
+ worker.equiv_mod = design->module(RTLIL::escape_id(args[argidx+2]));
+
+ if (worker.gold_mod == nullptr)
+ log_cmd_error("Can't find gold module %s.\n", args[argidx].c_str());
+
+ if (worker.gate_mod == nullptr)
+ log_cmd_error("Can't find gate module %s.\n", args[argidx+1].c_str());
+
+ if (worker.equiv_mod != nullptr)
+ log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str());
+
+ if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes())
+ log_cmd_error("Gold module contains memories or procresses. Run 'memory' or 'proc' respectively.\n");
+
+ if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes())
+ log_cmd_error("Gate module contains memories or procresses. Run 'memory' or 'proc' respectively.\n");
+
+ worker.read_blacklists();
+ worker.read_encfiles();
+
+ log_header("Executing EQUIV_MAKE pass (creating equiv checking module).\n");
+
+ worker.equiv_mod = design->addModule(RTLIL::escape_id(args[argidx+2]));
+ worker.run();
+ }
+} EquivMakePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc
new file mode 100644
index 00000000..23b34818
--- /dev/null
+++ b/passes/equiv/equiv_miter.cc
@@ -0,0 +1,343 @@
+/*
+ * 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 EquivMiterWorker
+{
+ CellTypes ct;
+ SigMap sigmap;
+
+ bool mode_trigger;
+ bool mode_cmp;
+ bool mode_assert;
+ bool mode_undef;
+
+ IdString miter_name;
+ Module *miter_module;
+ Module *source_module;
+
+ dict<SigBit, Cell*> bit_to_driver;
+ pool<Cell*> seed_cells, miter_cells;
+ pool<Wire*> miter_wires;
+
+ void follow_cone(pool<Cell*> &cone, pool<Cell*> &leaves, Cell *c, bool gold_mode)
+ {
+ if (cone.count(c))
+ return;
+
+ if (c->type == "$equiv" && !seed_cells.count(c)) {
+ leaves.insert(c);
+ return;
+ }
+
+ cone.insert(c);
+
+ for (auto &conn : c->connections()) {
+ if (!ct.cell_input(c->type, conn.first))
+ continue;
+ if (c->type == "$equiv" && (conn.first == "\\A") != gold_mode)
+ continue;
+ for (auto bit : sigmap(conn.second))
+ if (bit_to_driver.count(bit))
+ follow_cone(cone, leaves, bit_to_driver.at(bit), gold_mode);
+ }
+ }
+
+ void find_miter_cells_wires()
+ {
+ sigmap.set(source_module);
+
+ // initialize bit_to_driver
+
+ for (auto c : source_module->cells())
+ for (auto &conn : c->connections())
+ if (ct.cell_output(c->type, conn.first))
+ for (auto bit : sigmap(conn.second))
+ if (bit.wire)
+ bit_to_driver[bit] = c;
+
+ // find seed cells
+
+ for (auto c : source_module->selected_cells())
+ if (c->type == "$equiv") {
+ log("Seed $equiv cell: %s\n", log_id(c));
+ seed_cells.insert(c);
+ }
+
+ // follow cone from seed cells to next $equiv
+
+ while (1)
+ {
+ pool<Cell*> gold_cone, gold_leaves;
+ pool<Cell*> gate_cone, gate_leaves;
+
+ for (auto c : seed_cells) {
+ follow_cone(gold_cone, gold_leaves, c, true);
+ follow_cone(gate_cone, gate_leaves, c, false);
+ }
+
+ log("Gold cone: %d cells (%d leaves).\n", GetSize(gold_cone), GetSize(gold_leaves));
+ log("Gate cone: %d cells (%d leaves).\n", GetSize(gate_cone), GetSize(gate_leaves));
+
+ // done if all leaves are shared leaves
+
+ if (gold_leaves == gate_leaves) {
+ miter_cells = gold_cone;
+ miter_cells.insert(gate_cone.begin(), gate_cone.end());
+ log("Selected %d miter cells.\n", GetSize(miter_cells));
+ break;
+ }
+
+ // remove shared leaves
+
+ for (auto it = gold_leaves.begin(); it != gold_leaves.end(); ) {
+ auto it2 = gate_leaves.find(*it);
+ if (it2 != gate_leaves.end()) {
+ it = gold_leaves.erase(it);
+ gate_leaves.erase(it2);
+ } else
+ ++it;
+ }
+
+ // add remaining leaves to seeds and re-run
+
+ log("Adding %d gold and %d gate seed cells.\n", GetSize(gold_leaves), GetSize(gate_leaves));
+ seed_cells.insert(gold_leaves.begin(), gold_leaves.end());
+ seed_cells.insert(gate_leaves.begin(), gate_leaves.end());
+ }
+
+ for (auto c : miter_cells)
+ for (auto &conn : c->connections())
+ for (auto bit : sigmap(conn.second))
+ if (bit.wire)
+ miter_wires.insert(bit.wire);
+ log("Selected %d miter wires.\n", GetSize(miter_wires));
+ }
+
+ void copy_to_miter()
+ {
+ // copy wires and cells
+
+ for (auto w : miter_wires)
+ miter_module->addWire(w->name, w->width);
+ for (auto c : miter_cells) {
+ miter_module->addCell(c->name, c);
+ auto mc = miter_module->cell(c->name);
+ for (auto &conn : mc->connections())
+ mc->setPort(conn.first, sigmap(conn.second));
+ }
+
+ // fixup wire references in cells
+
+ sigmap.clear();
+
+ struct RewriteSigSpecWorker {
+ RTLIL::Module * mod;
+ void operator()(SigSpec &sig) {
+ vector<RTLIL::SigChunk> chunks = sig.chunks();
+ for (auto &c : chunks)
+ if (c.wire != NULL)
+ c.wire = mod->wires_.at(c.wire->name);
+ sig = chunks;
+ }
+ };
+
+ RewriteSigSpecWorker rewriteSigSpecWorker;
+ rewriteSigSpecWorker.mod = miter_module;
+ miter_module->rewrite_sigspecs(rewriteSigSpecWorker);
+
+ // find undriven or unused wires
+
+ pool<SigBit> driven_bits, used_bits;
+
+ for (auto c : miter_module->cells())
+ for (auto &conn : c->connections()) {
+ if (ct.cell_input(c->type, conn.first))
+ for (auto bit : conn.second)
+ if (bit.wire)
+ used_bits.insert(bit);
+ if (ct.cell_output(c->type, conn.first))
+ for (auto bit : conn.second)
+ if (bit.wire)
+ driven_bits.insert(bit);
+ }
+
+ // create ports
+
+ for (auto w : miter_module->wires()) {
+ for (auto bit : SigSpec(w)) {
+ if (driven_bits.count(bit) && !used_bits.count(bit))
+ w->port_output = true;
+ if (!driven_bits.count(bit) && used_bits.count(bit))
+ w->port_input = true;
+ }
+ if (w->port_output && w->port_input)
+ log("Created miter inout port %s.\n", log_id(w));
+ else if (w->port_output)
+ log("Created miter output port %s.\n", log_id(w));
+ else if (w->port_input)
+ log("Created miter input port %s.\n", log_id(w));
+ }
+
+ miter_module->fixup_ports();
+ }
+
+ void make_stuff()
+ {
+ if (!mode_trigger && !mode_cmp && !mode_assert)
+ return;
+
+ SigSpec trigger_signals;
+ vector<Cell*> equiv_cells;
+
+ for (auto c : miter_module->cells())
+ if (c->type == "$equiv" && c->getPort("\\A") != c->getPort("\\B"))
+ equiv_cells.push_back(c);
+
+ for (auto c : equiv_cells)
+ {
+ SigSpec cmp = mode_undef ?
+ miter_module->LogicOr(NEW_ID, miter_module->Eqx(NEW_ID, c->getPort("\\A"), State::Sx),
+ miter_module->Eqx(NEW_ID, c->getPort("\\A"), c->getPort("\\B"))) :
+ miter_module->Eq(NEW_ID, c->getPort("\\A"), c->getPort("\\B"));
+
+ if (mode_cmp) {
+ string cmp_name = string("\\cmp") + log_signal(c->getPort("\\Y"));
+ for (int i = 1; i < GetSize(cmp_name); i++)
+ if (cmp_name[i] == '\\')
+ cmp_name[i] = '_';
+ else if (cmp_name[i] == ' ')
+ cmp_name = cmp_name.substr(0, i) + cmp_name.substr(i+1);
+ auto w = miter_module->addWire(cmp_name);
+ w->port_output = true;
+ miter_module->connect(w, cmp);
+ }
+
+ if (mode_assert)
+ miter_module->addAssert(NEW_ID, cmp, State::S1);
+
+ trigger_signals.append(miter_module->Not(NEW_ID, cmp));
+ }
+
+ if (mode_trigger) {
+ auto w = miter_module->addWire("\\trigger");
+ w->port_output = true;
+ miter_module->addReduceOr(NEW_ID, trigger_signals, w);
+ }
+
+ miter_module->fixup_ports();
+ }
+
+ void run()
+ {
+ log("Creating miter %s from module %s.\n", log_id(miter_module), log_id(source_module));
+ find_miter_cells_wires();
+ copy_to_miter();
+ make_stuff();
+ }
+};
+
+struct EquivMiterPass : public Pass {
+ EquivMiterPass() : Pass("equiv_miter", "extract miter from equiv circuit") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_miter [options] miter_module [selection]\n");
+ log("\n");
+ log("This creates a miter module for further analysis of the selected $equiv cells.\n");
+ log("\n");
+ log(" -trigger\n");
+ log(" Create a trigger output\n");
+ log("\n");
+ log(" -cmp\n");
+ log(" Create cmp_* outputs for individual unproven $equiv cells\n");
+ log("\n");
+ log(" -assert\n");
+ log(" Create a $assert cell for each unproven $equiv cell\n");
+ log("\n");
+ log(" -undef\n");
+ log(" Create compare logic that handles undefs correctly\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ EquivMiterWorker worker;
+ worker.ct.setup(design);
+ worker.mode_trigger = false;
+ worker.mode_cmp = false;
+ worker.mode_assert = false;
+ worker.mode_undef = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-trigger") {
+ worker.mode_trigger = true;
+ continue;
+ }
+ if (args[argidx] == "-cmp") {
+ worker.mode_cmp = true;
+ continue;
+ }
+ if (args[argidx] == "-assert") {
+ worker.mode_assert = true;
+ continue;
+ }
+ if (args[argidx] == "-undef") {
+ worker.mode_undef = true;
+ continue;
+ }
+ break;
+ }
+
+ if (argidx >= args.size())
+ log_cmd_error("Invalid number of arguments.\n");
+
+ worker.miter_name = RTLIL::escape_id(args[argidx++]);
+ extra_args(args, argidx, design);
+
+ if (design->module(worker.miter_name))
+ log_cmd_error("Miter module %s already exists.\n", log_id(worker.miter_name));
+
+ worker.source_module = nullptr;
+ for (auto m : design->selected_modules()) {
+ if (worker.source_module != nullptr)
+ goto found_two_modules;
+ worker.source_module = m;
+ }
+
+ if (worker.source_module == nullptr)
+ found_two_modules:
+ log_cmd_error("Exactly one module must be selected for 'equiv_miter'!\n");
+
+ log_header("Executing EQUIV_MITER pass.\n");
+
+ worker.miter_module = design->addModule(worker.miter_name);
+ worker.run();
+ }
+} EquivMiterPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_remove.cc b/passes/equiv/equiv_remove.cc
new file mode 100644
index 00000000..b6e232f9
--- /dev/null
+++ b/passes/equiv/equiv_remove.cc
@@ -0,0 +1,83 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivRemovePass : public Pass {
+ EquivRemovePass() : Pass("equiv_remove", "remove $equiv cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_remove [options] [selection]\n");
+ log("\n");
+ log("This command removes the selected $equiv cells. If neither -gold nor -gate is\n");
+ log("used then only proven cells are removed.\n");
+ log("\n");
+ log(" -gold\n");
+ log(" keep gold circuit\n");
+ log("\n");
+ log(" -gate\n");
+ log(" keep gate circuit\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ bool mode_gold = false;
+ bool mode_gate = false;
+ int remove_count = 0;
+
+ log_header("Executing EQUIV_REMOVE pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-gold") {
+ mode_gold = true;
+ continue;
+ }
+ if (args[argidx] == "-gate") {
+ mode_gate = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (mode_gold && mode_gate)
+ log_cmd_error("Options -gold and -gate are exclusive.\n");
+
+ for (auto module : design->selected_modules())
+ {
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv" && (mode_gold || mode_gate || cell->getPort("\\A") == cell->getPort("\\B"))) {
+ log("Removing $equiv cell %s.%s (%s).\n", log_id(module), log_id(cell), log_signal(cell->getPort("\\Y")));
+ module->connect(cell->getPort("\\Y"), mode_gate ? cell->getPort("\\B") : cell->getPort("\\A"));
+ module->remove(cell);
+ remove_count++;
+ }
+ }
+
+ log("Removed a total of %d $equiv cells.\n", remove_count);
+ }
+} EquivRemovePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc
new file mode 100644
index 00000000..f1b66432
--- /dev/null
+++ b/passes/equiv/equiv_simple.cc
@@ -0,0 +1,358 @@
+/*
+ * 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/satgen.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivSimpleWorker
+{
+ Module *module;
+ const vector<Cell*> &equiv_cells;
+ Cell *equiv_cell;
+
+ SigMap &sigmap;
+ dict<SigBit, Cell*> &bit2driver;
+
+ ezSatPtr ez;
+ SatGen satgen;
+ int max_seq;
+ bool verbose;
+
+ pool<pair<Cell*, int>> imported_cells_cache;
+
+ EquivSimpleWorker(const vector<Cell*> &equiv_cells, SigMap &sigmap, dict<SigBit, Cell*> &bit2driver, int max_seq, bool verbose, bool model_undef) :
+ module(equiv_cells.front()->module), equiv_cells(equiv_cells), equiv_cell(nullptr),
+ sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), verbose(verbose)
+ {
+ satgen.model_undef = model_undef;
+ }
+
+ bool find_input_cone(pool<SigBit> &next_seed, pool<Cell*> &cells_cone, pool<SigBit> &bits_cone, const pool<Cell*> &cells_stop, const pool<SigBit> &bits_stop, pool<SigBit> *input_bits, Cell *cell)
+ {
+ if (cells_cone.count(cell))
+ return false;
+
+ cells_cone.insert(cell);
+
+ if (cells_stop.count(cell))
+ return true;
+
+ for (auto &conn : cell->connections())
+ if (yosys_celltypes.cell_input(cell->type, conn.first))
+ for (auto bit : sigmap(conn.second)) {
+ if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_")) {
+ if (!conn.first.in("\\CLK", "\\C"))
+ next_seed.insert(bit);
+ } else
+ find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit);
+ }
+ return false;
+ }
+
+ void find_input_cone(pool<SigBit> &next_seed, pool<Cell*> &cells_cone, pool<SigBit> &bits_cone, const pool<Cell*> &cells_stop, const pool<SigBit> &bits_stop, pool<SigBit> *input_bits, SigBit bit)
+ {
+ if (bits_cone.count(bit))
+ return;
+
+ bits_cone.insert(bit);
+
+ if (bits_stop.count(bit)) {
+ if (input_bits != nullptr) input_bits->insert(bit);
+ return;
+ }
+
+ if (!bit2driver.count(bit))
+ return;
+
+ if (find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit2driver.at(bit)))
+ if (input_bits != nullptr) input_bits->insert(bit);
+ }
+
+ bool run_cell()
+ {
+ SigBit bit_a = sigmap(equiv_cell->getPort("\\A")).to_single_sigbit();
+ SigBit bit_b = sigmap(equiv_cell->getPort("\\B")).to_single_sigbit();
+ int ez_context = ez->frozen_literal();
+
+ if (satgen.model_undef)
+ {
+ int ez_a = satgen.importSigBit(bit_a, max_seq+1);
+ int ez_b = satgen.importDefSigBit(bit_b, max_seq+1);
+ int ez_undef_a = satgen.importUndefSigBit(bit_a, max_seq+1);
+
+ ez->assume(ez->XOR(ez_a, ez_b), ez_context);
+ ez->assume(ez->NOT(ez_undef_a), ez_context);
+ }
+ else
+ {
+ int ez_a = satgen.importSigBit(bit_a, max_seq+1);
+ int ez_b = satgen.importSigBit(bit_b, max_seq+1);
+ ez->assume(ez->XOR(ez_a, ez_b), ez_context);
+ }
+
+ pool<SigBit> seed_a = { bit_a };
+ pool<SigBit> seed_b = { bit_b };
+
+ if (verbose) {
+ log(" Trying to prove $equiv cell %s:\n", log_id(equiv_cell));
+ log(" A = %s, B = %s, Y = %s\n", log_signal(bit_a), log_signal(bit_b), log_signal(equiv_cell->getPort("\\Y")));
+ } else {
+ log(" Trying to prove $equiv for %s:", log_signal(equiv_cell->getPort("\\Y")));
+ }
+
+ int step = max_seq;
+ while (1)
+ {
+ pool<Cell*> no_stop_cells;
+ pool<SigBit> no_stop_bits;
+
+ pool<Cell*> full_cells_cone_a, full_cells_cone_b;
+ pool<SigBit> full_bits_cone_a, full_bits_cone_b;
+
+ pool<SigBit> next_seed_a, next_seed_b;
+
+ for (auto bit_a : seed_a)
+ find_input_cone(next_seed_a, full_cells_cone_a, full_bits_cone_a, no_stop_cells, no_stop_bits, nullptr, bit_a);
+ next_seed_a.clear();
+
+ for (auto bit_b : seed_b)
+ find_input_cone(next_seed_b, full_cells_cone_b, full_bits_cone_b, no_stop_cells, no_stop_bits, nullptr, bit_b);
+ next_seed_b.clear();
+
+ pool<Cell*> short_cells_cone_a, short_cells_cone_b;
+ pool<SigBit> short_bits_cone_a, short_bits_cone_b;
+ pool<SigBit> input_bits;
+
+ for (auto bit_a : seed_a)
+ find_input_cone(next_seed_a, short_cells_cone_a, short_bits_cone_a, full_cells_cone_b, full_bits_cone_b, &input_bits, bit_a);
+ next_seed_a.swap(seed_a);
+
+ for (auto bit_b : seed_b)
+ find_input_cone(next_seed_b, short_cells_cone_b, short_bits_cone_b, full_cells_cone_a, full_bits_cone_a, &input_bits, bit_b);
+ next_seed_b.swap(seed_b);
+
+ pool<Cell*> problem_cells;
+ problem_cells.insert(short_cells_cone_a.begin(), short_cells_cone_a.end());
+ problem_cells.insert(short_cells_cone_b.begin(), short_cells_cone_b.end());
+
+ if (verbose)
+ log(" Adding %d new cells to the problem (%d A, %d B, %d shared).\n",
+ GetSize(problem_cells), GetSize(short_cells_cone_a), GetSize(short_cells_cone_b),
+ (GetSize(short_cells_cone_a) + GetSize(short_cells_cone_b)) - GetSize(problem_cells));
+
+ for (auto cell : problem_cells) {
+ auto key = pair<Cell*, int>(cell, step+1);
+ if (!imported_cells_cache.count(key) && !satgen.importCell(cell, step+1))
+ log_cmd_error("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
+ imported_cells_cache.insert(key);
+ }
+
+ if (satgen.model_undef) {
+ for (auto bit : input_bits)
+ ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step+1)));
+ }
+
+ if (verbose)
+ log(" Problem size at t=%d: %d literals, %d clauses\n", step, ez->numCnfVariables(), ez->numCnfClauses());
+
+ if (!ez->solve(ez_context)) {
+ log(verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n");
+ equiv_cell->setPort("\\B", equiv_cell->getPort("\\A"));
+ ez->assume(ez->NOT(ez_context));
+ return true;
+ }
+
+ if (verbose)
+ log(" Failed to prove equivalence with sequence length %d.\n", max_seq - step);
+
+ if (--step < 0) {
+ if (verbose)
+ log(" Reached sequence limit.\n");
+ break;
+ }
+
+ if (seed_a.empty() && seed_b.empty()) {
+ if (verbose)
+ log(" No nets to continue in previous time step.\n");
+ break;
+ }
+
+ if (seed_a.empty()) {
+ if (verbose)
+ log(" No nets on A-side to continue in previous time step.\n");
+ break;
+ }
+
+ if (seed_b.empty()) {
+ if (verbose)
+ log(" No nets on B-side to continue in previous time step.\n");
+ break;
+ }
+
+ if (verbose) {
+ #if 0
+ log(" Continuing analysis in previous time step with the following nets:\n");
+ for (auto bit : seed_a)
+ log(" A: %s\n", log_signal(bit));
+ for (auto bit : seed_b)
+ log(" B: %s\n", log_signal(bit));
+ #else
+ log(" Continuing analysis in previous time step with %d A- and %d B-nets.\n", GetSize(seed_a), GetSize(seed_b));
+ #endif
+ }
+ }
+
+ if (!verbose)
+ log(" failed.\n");
+
+ ez->assume(ez->NOT(ez_context));
+ return false;
+ }
+
+ int run()
+ {
+ if (GetSize(equiv_cells) > 1) {
+ SigSpec sig;
+ for (auto c : equiv_cells)
+ sig.append(sigmap(c->getPort("\\Y")));
+ log(" Grouping SAT models for %s:\n", log_signal(sig));
+ }
+
+ int counter = 0;
+ for (auto c : equiv_cells) {
+ equiv_cell = c;
+ if (run_cell())
+ counter++;
+ }
+ return counter;
+ }
+
+};
+
+struct EquivSimplePass : public Pass {
+ EquivSimplePass() : Pass("equiv_simple", "try proving simple $equiv instances") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_simple [options] [selection]\n");
+ log("\n");
+ log("This command tries to prove $equiv cells using a simple direct SAT approach.\n");
+ log("\n");
+ log(" -v\n");
+ log(" verbose output\n");
+ log("\n");
+ log(" -undef\n");
+ log(" enable modelling of undef states\n");
+ log("\n");
+ log(" -nogroup\n");
+ log(" disabling grouping of $equiv cells by output wire\n");
+ log("\n");
+ log(" -seq <N>\n");
+ log(" the max. number of time steps to be considered (default = 1)\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ bool verbose = false, model_undef = false, nogroup = false;
+ int success_counter = 0;
+ int max_seq = 1;
+
+ log_header("Executing EQUIV_SIMPLE pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-v") {
+ verbose = true;
+ continue;
+ }
+ if (args[argidx] == "-undef") {
+ model_undef = true;
+ continue;
+ }
+ if (args[argidx] == "-nogroup") {
+ nogroup = true;
+ continue;
+ }
+ if (args[argidx] == "-seq" && argidx+1 < args.size()) {
+ max_seq = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ CellTypes ct;
+ ct.setup_internals();
+ ct.setup_stdcells();
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ dict<SigBit, Cell*> bit2driver;
+ dict<SigBit, dict<SigBit, Cell*>> unproven_equiv_cells;
+ int unproven_cells_counter = 0;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv" && cell->getPort("\\A") != cell->getPort("\\B")) {
+ auto bit = sigmap(cell->getPort("\\Y").to_single_sigbit());
+ auto bit_group = bit;
+ if (!nogroup && bit_group.wire)
+ bit_group.offset = 0;
+ unproven_equiv_cells[bit_group][bit] = cell;
+ unproven_cells_counter++;
+ }
+
+ if (unproven_equiv_cells.empty())
+ continue;
+
+ log("Found %d unproven $equiv cells (%d groups) in %s:\n",
+ unproven_cells_counter, GetSize(unproven_equiv_cells), log_id(module));
+
+ for (auto cell : module->cells()) {
+ if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_"))
+ continue;
+ for (auto &conn : cell->connections())
+ if (yosys_celltypes.cell_output(cell->type, conn.first))
+ for (auto bit : sigmap(conn.second))
+ bit2driver[bit] = cell;
+ }
+
+ unproven_equiv_cells.sort();
+ for (auto it : unproven_equiv_cells)
+ {
+ it.second.sort();
+
+ vector<Cell*> cells;
+ for (auto it2 : it.second)
+ cells.push_back(it2.second);
+
+ EquivSimpleWorker worker(cells, sigmap, bit2driver, max_seq, verbose, model_undef);
+ success_counter += worker.run();
+ }
+ }
+
+ log("Proved %d previously unproven $equiv cells.\n", success_counter);
+ }
+} EquivSimplePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_status.cc b/passes/equiv/equiv_status.cc
new file mode 100644
index 00000000..8ca1aacd
--- /dev/null
+++ b/passes/equiv/equiv_status.cc
@@ -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.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivStatusPass : public Pass {
+ EquivStatusPass() : Pass("equiv_status", "print status of equivalent checking module") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_status [options] [selection]\n");
+ log("\n");
+ log("This command prints status information for all selected $equiv cells.\n");
+ log("\n");
+ log(" -assert\n");
+ log(" produce an error if any unproven $equiv cell is found\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ bool assert_mode = false;
+ int unproven_count = 0;
+
+ log_header("Executing EQUIV_STATUS pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-assert") {
+ assert_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ vector<Cell*> unproven_equiv_cells;
+ int proven_equiv_cells = 0;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv") {
+ if (cell->getPort("\\A") != cell->getPort("\\B"))
+ unproven_equiv_cells.push_back(cell);
+ else
+ proven_equiv_cells++;
+ }
+
+ if (unproven_equiv_cells.empty() && !proven_equiv_cells) {
+ log("No $equiv cells found in %s.\n", log_id(module));
+ continue;
+ }
+
+ log("Found %d $equiv cells in %s:\n", GetSize(unproven_equiv_cells) + proven_equiv_cells, log_id(module));
+ log(" Of those cells %d are proven and %d are unproven.\n", proven_equiv_cells, GetSize(unproven_equiv_cells));
+ if (unproven_equiv_cells.empty()) {
+ log(" Equivalence successfully proven!\n");
+ } else {
+ for (auto cell : unproven_equiv_cells)
+ log(" Unproven $equiv %s: %s %s\n", log_id(cell), log_signal(cell->getPort("\\A")), log_signal(cell->getPort("\\B")));
+ }
+
+ unproven_count += GetSize(unproven_equiv_cells);
+ }
+
+ if (unproven_count != 0) {
+ log("Found a total of %d unproven $equiv cells.\n", unproven_count);
+ if (assert_mode && unproven_count != 0)
+ log_error("Found %d unproven $equiv cells in 'equiv_status -assert'.\n", unproven_count);
+ }
+ }
+} EquivStatusPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index 2fae7609..e76be40c 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -22,6 +22,9 @@
#include <stdlib.h>
#include <stdio.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmPass : public Pass {
FsmPass() : Pass("fsm", "extract and optimize finite state machines") { }
virtual void help()
@@ -58,6 +61,7 @@ struct FsmPass : public Pass {
log("\n");
log(" -encoding tye\n");
log(" -fm_set_fsm_file file\n");
+ log(" -encfile file\n");
log(" passed through to fsm_recode pass\n");
log("\n");
}
@@ -69,6 +73,7 @@ struct FsmPass : public Pass {
bool flag_expand = false;
bool flag_export = false;
std::string fm_set_fsm_file_opt;
+ std::string encfile_opt;
std::string encoding_opt;
log_header("Executing FSM pass (extract and optimize FSM).\n");
@@ -81,7 +86,11 @@ struct FsmPass : public Pass {
fm_set_fsm_file_opt = " -fm_set_fsm_file " + args[++argidx];
continue;
}
- if (arg == "-encoding" && argidx+1 < args.size() && fm_set_fsm_file_opt.empty()) {
+ if (arg == "-encfile" && argidx+1 < args.size() && encfile_opt.empty()) {
+ encfile_opt = " -encfile " + args[++argidx];
+ continue;
+ }
+ if (arg == "-encoding" && argidx+1 < args.size() && encoding_opt.empty()) {
encoding_opt = " -encoding " + args[++argidx];
continue;
}
@@ -124,7 +133,7 @@ struct FsmPass : public Pass {
}
if (!flag_norecode)
- Pass::call(design, "fsm_recode" + fm_set_fsm_file_opt + encoding_opt);
+ Pass::call(design, "fsm_recode" + fm_set_fsm_file_opt + encfile_opt + encoding_opt);
Pass::call(design, "fsm_info");
if (flag_export)
@@ -137,3 +146,4 @@ struct FsmPass : public Pass {
}
} FsmPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index 2c846a4c..c89553c6 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -24,6 +24,9 @@
#include "kernel/celltypes.h"
#include "fsmdata.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static RTLIL::Module *module;
static SigMap assign_map;
typedef std::pair<RTLIL::Cell*, RTLIL::IdString> sig2driver_entry_t;
@@ -40,7 +43,7 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, Sig
return true;
if (recursion_monitor.check_any(sig)) {
- log("Warning: logic loop in mux tree at signal %s in module %s.\n",
+ log_warning("logic loop in mux tree at signal %s in module %s.\n",
log_signal(sig), RTLIL::id2cstr(module->name));
return false;
}
@@ -189,3 +192,4 @@ struct FsmDetectPass : public Pass {
}
} FsmDetectPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index d1364391..a261eb22 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -25,6 +25,9 @@
#include "fsmdata.h"
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmExpand
{
RTLIL::Module *module;
@@ -236,7 +239,7 @@ struct FsmExpand
if (merged_set.size() > 0 && !already_optimized)
FsmData::optimize_fsm(fsm_cell, module);
- log(" merged %zd cells into FSM.\n", merged_set.size());
+ log(" merged %d cells into FSM.\n", GetSize(merged_set));
}
};
@@ -273,3 +276,4 @@ struct FsmExpandPass : public Pass {
}
} FsmExpandPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index b4a6b3f7..ad927033 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -28,6 +28,9 @@
#include <iostream>
#include <fstream>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
/**
* Convert a signal into a KISS-compatible textual representation.
*/
@@ -47,7 +50,7 @@ std::string kiss_convert_signal(const RTLIL::SigSpec &sig) {
* @param cell pointer to the FSM cell which should be exported.
*/
void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::string filename, bool origenc) {
- std::map<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
+ dict<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
FsmData fsm_data;
FsmData::transition_t tr;
std::ofstream kiss_file;
@@ -142,7 +145,7 @@ struct FsmExportPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- std::map<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
+ dict<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
std::string arg;
bool flag_noauto = false;
std::string filename;
@@ -182,3 +185,5 @@ struct FsmExportPass : public Pass {
}
}
} FsmExportPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index 451f00fc..68667ef0 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -29,6 +29,9 @@
#include "kernel/celltypes.h"
#include "fsmdata.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static RTLIL::Module *module;
static SigMap assign_map;
typedef std::pair<RTLIL::IdString, RTLIL::IdString> sig2driver_entry_t;
@@ -37,7 +40,7 @@ static std::map<RTLIL::SigBit, std::set<RTLIL::SigBit>> exclusive_ctrls;
static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL::SigSpec &ctrl, std::map<RTLIL::Const, int> &states, RTLIL::Const *reset_state = NULL)
{
- sig.extend(dff_out.size(), false);
+ sig.extend_u0(dff_out.size(), false);
if (sig == dff_out)
return true;
@@ -70,9 +73,9 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL
sig_aa.replace(sig_y, sig_a);
RTLIL::SigSpec sig_bb;
- for (int i = 0; i < SIZE(sig_b)/SIZE(sig_a); i++) {
+ for (int i = 0; i < GetSize(sig_b)/GetSize(sig_a); i++) {
RTLIL::SigSpec s = sig;
- s.replace(sig_y, sig_b.extract(i*SIZE(sig_a), SIZE(sig_a)));
+ s.replace(sig_y, sig_b.extract(i*GetSize(sig_a), GetSize(sig_a)));
sig_bb.append(s);
}
@@ -95,8 +98,8 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL
if (!find_states(sig_aa, dff_out, ctrl, states))
return false;
- for (int i = 0; i < SIZE(sig_bb)/SIZE(sig_aa); i++) {
- if (!find_states(sig_bb.extract(i*SIZE(sig_aa), SIZE(sig_aa)), dff_out, ctrl, states))
+ for (int i = 0; i < GetSize(sig_bb)/GetSize(sig_aa); i++) {
+ if (!find_states(sig_bb.extract(i*GetSize(sig_aa), GetSize(sig_aa)), dff_out, ctrl, states))
return false;
}
}
@@ -107,7 +110,7 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL
static RTLIL::Const sig2const(ConstEval &ce, RTLIL::SigSpec sig, RTLIL::State noconst_state, RTLIL::SigSpec dont_care = RTLIL::SigSpec())
{
if (dont_care.size() > 0) {
- for (int i = 0; i < SIZE(sig); i++)
+ for (int i = 0; i < GetSize(sig); i++)
if (dont_care.extract(sig[i]).size() > 0)
sig[i] = noconst_state;
}
@@ -115,7 +118,7 @@ static RTLIL::Const sig2const(ConstEval &ce, RTLIL::SigSpec sig, RTLIL::State no
ce.assign_map.apply(sig);
ce.values_map.apply(sig);
- for (int i = 0; i < SIZE(sig); i++)
+ for (int i = 0; i < GetSize(sig); i++)
if (sig[i].wire != NULL)
sig[i] = noconst_state;
@@ -145,7 +148,7 @@ undef_bit_in_next_state:
tr.ctrl_out = sig2const(ce, ctrl_out, RTLIL::State::Sx);
std::map<RTLIL::SigBit, int> ctrl_in_bit_indices;
- for (int i = 0; i < SIZE(ctrl_in); i++)
+ for (int i = 0; i < GetSize(ctrl_in); i++)
ctrl_in_bit_indices[ctrl_in[i]] = i;
for (auto &it : ctrl_in_bit_indices)
@@ -287,7 +290,7 @@ static void extract_fsm(RTLIL::Wire *wire)
log(" fsm extraction failed: state selection tree is not closed.\n");
return;
}
- if (SIZE(states) <= 1) {
+ if (GetSize(states) <= 1) {
log(" fsm extraction failed: at least two states are required.\n");
return;
}
@@ -456,3 +459,4 @@ struct FsmExtractPass : public Pass {
}
} FsmExtractPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
index 45d68a90..4a1f1d9a 100644
--- a/passes/fsm/fsm_info.cc
+++ b/passes/fsm/fsm_info.cc
@@ -25,6 +25,9 @@
#include "fsmdata.h"
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmInfoPass : public Pass {
FsmInfoPass() : Pass("fsm_info", "print information on finite state machines") { }
virtual void help()
@@ -56,3 +59,4 @@ struct FsmInfoPass : public Pass {
}
} FsmInfoPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index ab6d5671..155801a3 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -25,10 +25,13 @@
#include "fsmdata.h"
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static bool pattern_is_subset(const RTLIL::Const &super_pattern, const RTLIL::Const &sub_pattern)
{
- log_assert(SIZE(super_pattern.bits) == SIZE(sub_pattern.bits));
- for (int i = 0; i < SIZE(super_pattern.bits); i++)
+ log_assert(GetSize(super_pattern.bits) == GetSize(sub_pattern.bits));
+ for (int i = 0; i < GetSize(super_pattern.bits); i++)
if (sub_pattern.bits[i] == RTLIL::State::S0 || sub_pattern.bits[i] == RTLIL::State::S1) {
if (super_pattern.bits[i] == RTLIL::State::S0 || super_pattern.bits[i] == RTLIL::State::S1) {
if (super_pattern.bits[i] != sub_pattern.bits[i])
@@ -88,7 +91,7 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const
if (pattern_is_subset(pattern, it2.first))
complete_in_state_cache.insert(it2.second.begin(), it2.second.end());
- if (SIZE(complete_in_state_cache) < num_states)
+ if (GetSize(complete_in_state_cache) < num_states)
{
if (or_sig.size() == 1)
{
@@ -221,9 +224,12 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
}
}
+ if (encoding_is_onehot)
+ state_wire->set_bool_attribute("\\onehot");
+
// generate next_state signal
- if (SIZE(fsm_data.state_table) == 1)
+ if (GetSize(fsm_data.state_table) == 1)
{
module->connect(next_state_wire, fsm_data.state_table.front());
}
@@ -345,3 +351,4 @@ struct FsmMapPass : public Pass {
}
} FsmMapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index a0e1885e..4b93d79f 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -25,6 +25,9 @@
#include "fsmdata.h"
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmOpt
{
FsmData fsm_data;
@@ -40,7 +43,7 @@ struct FsmOpt
std::vector<RTLIL::Const> new_state_table;
std::map<int, int> old_to_new_state;
- for (int i = 0; i < SIZE(fsm_data.state_table); i++)
+ for (int i = 0; i < GetSize(fsm_data.state_table); i++)
if (i != fsm_data.reset_state)
unreachable_states.insert(i);
@@ -50,12 +53,12 @@ struct FsmOpt
if (unreachable_states.empty())
break;
- for (int i = 0; i < SIZE(fsm_data.state_table); i++) {
+ for (int i = 0; i < GetSize(fsm_data.state_table); i++) {
if (unreachable_states.count(i)) {
log(" Removing unreachable state %s.\n", log_signal(fsm_data.state_table[i]));
continue;
}
- old_to_new_state[i] = SIZE(new_state_table);
+ old_to_new_state[i] = GetSize(new_state_table);
new_state_table.push_back(fsm_data.state_table[i]);
}
@@ -309,11 +312,15 @@ struct FsmOpt
}
};
-void FsmData::optimize_fsm(RTLIL::Cell *cell, RTLIL::Module *module)
+PRIVATE_NAMESPACE_END
+
+void YOSYS_NAMESPACE_PREFIX FsmData::optimize_fsm(RTLIL::Cell *cell, RTLIL::Module *module)
{
FsmOpt fsmopt(cell, module);
}
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmOptPass : public Pass {
FsmOptPass() : Pass("fsm_opt", "optimize finite state machines") { }
virtual void help()
@@ -335,9 +342,10 @@ struct FsmOptPass : public Pass {
for (auto &mod_it : design->modules_) {
if (design->selected(mod_it.second))
for (auto &cell_it : mod_it.second->cells_)
- if (cell_it.second->type == "$fsm" and design->selected(mod_it.second, cell_it.second))
+ if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
FsmData::optimize_fsm(cell_it.second, mod_it.second);
}
}
} FsmOptPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index 873ee7a1..16996810 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -27,6 +27,9 @@
#include <string.h>
#include <errno.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static void fm_set_fsm_print(RTLIL::Cell *cell, RTLIL::Module *module, FsmData &fsm_data, const char *prefix, FILE *f)
{
std::string name = cell->parameters["\\NAME"].decode_string();
@@ -38,9 +41,9 @@ static void fm_set_fsm_print(RTLIL::Cell *cell, RTLIL::Module *module, FsmData &
prefix, RTLIL::unescape_id(module->name).c_str());
fprintf(f, "set_fsm_encoding {");
- for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
- fprintf(f, " s%zd=2#", i);
- for (int j = int(fsm_data.state_table[i].bits.size())-1; j >= 0; j--)
+ for (int i = 0; i < GetSize(fsm_data.state_table); i++) {
+ fprintf(f, " s%d=2#", i);
+ for (int j = GetSize(fsm_data.state_table[i].bits)-1; j >= 0; j--)
fprintf(f, "%c", fsm_data.state_table[i].bits[j] == RTLIL::State::S1 ? '1' : '0');
}
fprintf(f, " } -name {%s_%s} {%s:/WORK/%s}\n",
@@ -48,7 +51,7 @@ static void fm_set_fsm_print(RTLIL::Cell *cell, RTLIL::Module *module, FsmData &
prefix, RTLIL::unescape_id(module->name).c_str());
}
-static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fsm_file, std::string default_encoding)
+static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fsm_file, FILE *encfile, std::string default_encoding)
{
std::string encoding = cell->attributes.count("\\fsm_encoding") ? cell->attributes.at("\\fsm_encoding").decode_string() : "auto";
@@ -74,7 +77,7 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
if (!default_encoding.empty())
encoding = default_encoding;
else
- encoding = SIZE(fsm_data.state_table) < 32 ? "one-hot" : "binary";
+ encoding = GetSize(fsm_data.state_table) < 32 ? "one-hot" : "binary";
log(" mapping auto encoding to `%s` for this FSM.\n", encoding.c_str());
}
@@ -91,6 +94,9 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
} else
log_error("FSM encoding `%s' is not supported!\n", encoding.c_str());
+ if (encfile)
+ fprintf(encfile, ".fsm %s %s\n", log_id(module), RTLIL::unescape_id(cell->parameters["\\NAME"].decode_string()).c_str());
+
int state_idx_counter = fsm_data.reset_state >= 0 ? 1 : 0;
for (int i = 0; i < int(fsm_data.state_table.size()); i++)
{
@@ -107,6 +113,8 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
log_abort();
log(" %s -> %s\n", fsm_data.state_table[i].as_string().c_str(), new_code.as_string().c_str());
+ if (encfile)
+ fprintf(encfile, ".map %s %s\n", fsm_data.state_table[i].as_string().c_str(), new_code.as_string().c_str());
fsm_data.state_table[i] = new_code;
}
@@ -122,21 +130,31 @@ struct FsmRecodePass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" fsm_recode [-encoding type] [-fm_set_fsm_file file] [selection]\n");
+ log(" fsm_recode [options] [selection]\n");
log("\n");
log("This pass reassign the state encodings for FSM cells. At the moment only\n");
- log("one-hot encoding and binary encoding is supported. The option -encoding\n");
- log("can be used to specify the encoding scheme used for FSMs without the\n");
- log("`fsm_encoding' attribute (or with the attribute set to `auto'.\n");
+ log("one-hot encoding and binary encoding is supported.\n");
+
+ log(" -encoding <type>\n");
+ log(" specify the encoding scheme used for FSMs without the\n");
+ log(" 'fsm_encoding' attribute or with the attribute set to `auto'.\n");
+ log("\n");
+ log(" -fm_set_fsm_file <file>\n");
+ log(" generate a file containing the mapping from old to new FSM encoding\n");
+ log(" in form of Synopsys Formality set_fsm_* commands.\n");
log("\n");
- log("The option -fm_set_fsm_file can be used to generate a file containing the\n");
- log("mapping from old to new FSM encoding in form of Synopsys Formality set_fsm_*\n");
- log("commands.\n");
+ log(" -encfile <file>\n");
+ log(" write the mappings from old to new FSM encoding to a file in the\n");
+ log(" following format:\n");
+ log("\n");
+ log(" .fsm <module_name> <state_signal>\n");
+ log(" .map <old_bitpattern> <new_bitpattern>\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
FILE *fm_set_fsm_file = NULL;
+ FILE *encfile = NULL;
std::string default_encoding;
log_header("Executing FSM_RECODE pass (re-assigning FSM state encoding).\n");
@@ -149,7 +167,13 @@ struct FsmRecodePass : public Pass {
log_error("Can't open fm_set_fsm_file `%s' for writing: %s\n", args[argidx].c_str(), strerror(errno));
continue;
}
- if (arg == "-encoding" && argidx+1 < args.size() && fm_set_fsm_file == NULL) {
+ if (arg == "-encfile" && argidx+1 < args.size() && encfile == NULL) {
+ encfile = fopen(args[++argidx].c_str(), "w");
+ if (encfile == NULL)
+ log_error("Can't open encfile `%s' for writing: %s\n", args[argidx].c_str(), strerror(errno));
+ continue;
+ }
+ if (arg == "-encoding" && argidx+1 < args.size() && default_encoding.empty()) {
default_encoding = args[++argidx];
continue;
}
@@ -161,10 +185,13 @@ struct FsmRecodePass : public Pass {
if (design->selected(mod_it.second))
for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
- fsm_recode(cell_it.second, mod_it.second, fm_set_fsm_file, default_encoding);
+ fsm_recode(cell_it.second, mod_it.second, fm_set_fsm_file, encfile, default_encoding);
if (fm_set_fsm_file != NULL)
fclose(fm_set_fsm_file);
+ if (encfile != NULL)
+ fclose(encfile);
}
} FsmRecodePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsmdata.h b/passes/fsm/fsmdata.h
index 7a44dd45..5671d000 100644
--- a/passes/fsm/fsmdata.h
+++ b/passes/fsm/fsmdata.h
@@ -20,8 +20,9 @@
#ifndef FSMDATA_H
#define FSMDATA_H
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
struct FsmData
{
@@ -142,24 +143,24 @@ struct FsmData
log("\n");
log(" Input signals:\n");
RTLIL::SigSpec sig_in = cell->getPort("\\CTRL_IN");
- for (int i = 0; i < SIZE(sig_in); i++)
+ for (int i = 0; i < GetSize(sig_in); i++)
log(" %3d: %s\n", i, log_signal(sig_in[i]));
log("\n");
log(" Output signals:\n");
RTLIL::SigSpec sig_out = cell->getPort("\\CTRL_OUT");
- for (int i = 0; i < SIZE(sig_out); i++)
+ for (int i = 0; i < GetSize(sig_out); i++)
log(" %3d: %s\n", i, log_signal(sig_out[i]));
log("\n");
log(" State encoding:\n");
- for (int i = 0; i < SIZE(state_table); i++)
+ for (int i = 0; i < GetSize(state_table); i++)
log(" %3d: %10s%s\n", i, log_signal(state_table[i], false),
int(i) == reset_state ? " <RESET STATE>" : "");
log("\n");
log(" Transition Table (state_in, ctrl_in, state_out, ctrl_out):\n");
- for (int i = 0; i < SIZE(transition_table); i++) {
+ for (int i = 0; i < GetSize(transition_table); i++) {
transition_t &tr = transition_table[i];
log(" %5d: %5d %s -> %5d %s\n", i, tr.state_in, log_signal(tr.ctrl_in), tr.state_out, log_signal(tr.ctrl_out));
}
@@ -172,4 +173,6 @@ struct FsmData
static void optimize_fsm(RTLIL::Cell *cell, RTLIL::Module *module);
};
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 14bf8d1b..a393343d 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -17,23 +17,26 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
#include <stdlib.h>
#include <stdio.h>
-#include <fnmatch.h>
#include <set>
-#include <unistd.h>
-
-namespace {
- struct generate_port_decl_t {
- bool input, output;
- RTLIL::IdString portname;
- int index;
- };
-}
-static void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct generate_port_decl_t {
+ bool input, output;
+ string portname;
+ int index;
+};
+
+void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
{
std::set<RTLIL::IdString> found_celltypes;
@@ -46,7 +49,7 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
if (cell->type.substr(0, 1) == "$" && cell->type.substr(0, 3) != "$__")
continue;
for (auto &pattern : celltypes)
- if (!fnmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str(), FNM_NOESCAPE))
+ if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str()))
found_celltypes.insert(cell->type);
}
@@ -96,9 +99,9 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
while (portnames.size() > 0) {
RTLIL::IdString portname = *portnames.begin();
for (auto &decl : portdecls)
- if (decl.index == 0 && !fnmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str(), FNM_NOESCAPE)) {
+ if (decl.index == 0 && patmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str())) {
generate_port_decl_t d = decl;
- d.portname = portname;
+ d.portname = portname.str();
d.index = *indices.begin();
log_assert(!indices.empty());
indices.erase(d.index);
@@ -135,7 +138,7 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
}
}
-static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
+bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
{
bool did_something = false;
std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
@@ -171,7 +174,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
for (auto &dir : libdirs)
{
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
- if (access(filename.c_str(), F_OK) == 0) {
+ if (check_file_exists(filename)) {
std::vector<std::string> args;
args.push_back(filename);
Frontend::frontend_call(design, NULL, filename, "verilog");
@@ -179,7 +182,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
}
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
- if (access(filename.c_str(), F_OK) == 0) {
+ if (check_file_exists(filename)) {
std::vector<std::string> args;
args.push_back(filename);
Frontend::frontend_call(design, NULL, filename, "ilang");
@@ -196,6 +199,19 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
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
+ if (flag_check)
+ {
+ RTLIL::Module *mod = design->module(cell->type);
+ 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))
+ log_error("Module `%s' referenced in module `%s' in cell `%s' has only %d ports, requested port %d.\n",
+ log_id(cell->type), log_id(module), log_id(cell), GetSize(mod->ports), id);
+ } 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));
}
if (cell->parameters.size() == 0)
@@ -245,24 +261,31 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
return did_something;
}
-static void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent)
+void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent)
{
if (used.count(mod) > 0)
return;
if (indent == 0)
log("Top module: %s\n", mod->name.c_str());
- else
+ else if (!mod->get_bool_attribute("\\blackbox"))
log("Used module: %*s%s\n", indent, "", mod->name.c_str());
used.insert(mod);
- for (auto &it : mod->cells_) {
- if (design->modules_.count(it.second->type) > 0)
- hierarchy_worker(design, used, design->modules_[it.second->type], indent+4);
+ 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);
+ }
+ if (design->module(celltype))
+ hierarchy_worker(design, used, design->module(celltype), indent+4);
}
}
-static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool first_pass)
+void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
{
std::set<RTLIL::Module*> used;
hierarchy_worker(design, used, top, 0);
@@ -272,17 +295,41 @@ static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib,
if (used.count(it.second) == 0)
del_modules.push_back(it.second);
+ int del_counter = 0;
for (auto mod : del_modules) {
- if (first_pass && mod->name.substr(0, 9) == "$abstract")
+ if (mod->name.substr(0, 9) == "$abstract")
continue;
if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
continue;
log("Removing unused module `%s'.\n", mod->name.c_str());
design->modules_.erase(mod->name);
+ del_counter++;
delete mod;
}
- log("Removed %zd unused modules.\n", del_modules.size());
+ log("Removed %d unused modules.\n", del_counter);
+}
+
+bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
+{
+ if (cache.count(mod) == 0)
+ for (auto c : mod->cells()) {
+ RTLIL::Module *m = mod->design->module(c->type);
+ if ((m != nullptr && set_keep_assert(cache, m)) || c->type == "$assert")
+ return cache[mod] = true;
+ }
+ return cache[mod];
+}
+
+int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
+{
+ if (db.count(module) == 0) {
+ db[module] = 0;
+ for (auto cell : module->cells())
+ if (design->module(cell->type))
+ db[module] = std::max(db[module], find_top_mod_score(design, design->module(cell->type), db) + 1);
+ }
+ return db.at(module);
}
struct HierarchyPass : public Pass {
@@ -305,7 +352,7 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n");
- log(" module. use this options to also remove unused blackbox modules.\n");
+ log(" modules. use this option to also remove unused blackbox modules.\n");
log("\n");
log(" -libdir <directory>\n");
log(" search for files named <module_name>.v in the specified directory\n");
@@ -316,6 +363,11 @@ struct HierarchyPass : public Pass {
log(" per default this pass also converts positional arguments in cells\n");
log(" to arguments using port names. this option disables this behavior.\n");
log("\n");
+ log(" -nokeep_asserts\n");
+ log(" per default this pass sets the \"keep\" attribute on all modules\n");
+ log(" that directly or indirectly contain one or more $assert cells. this\n");
+ log(" option disables this behavior.\n");
+ log("\n");
log(" -top <module>\n");
log(" use the specified top module to built a design hierarchy. modules\n");
log(" outside this tree (unused modules) are removed.\n");
@@ -324,6 +376,9 @@ struct HierarchyPass : public Pass {
log(" specified top module. otherwise a module with the 'top' attribute set\n");
log(" will implicitly be used as top module, if such a module exists.\n");
log("\n");
+ log(" -auto-top\n");
+ log(" automatically determine the top of the design hierarchy and mark it.\n");
+ log("\n");
log("In -generate mode this pass generates blackbox modules for the given cell\n");
log("types (wildcards supported). For this the design is searched for cells that\n");
log("match the given types and then the given port declarations are used to\n");
@@ -350,8 +405,10 @@ struct HierarchyPass : public Pass {
RTLIL::Module *top_mod = NULL;
std::vector<std::string> libdirs;
+ bool auto_top_mode = false;
bool generate_mode = false;
bool keep_positionals = false;
+ bool nokeep_asserts = false;
std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports;
@@ -409,6 +466,10 @@ struct HierarchyPass : public Pass {
keep_positionals = true;
continue;
}
+ if (args[argidx] == "-nokeep_asserts") {
+ nokeep_asserts = true;
+ continue;
+ }
if (args[argidx] == "-libdir" && argidx+1 < args.size()) {
libdirs.push_back(args[++argidx]);
continue;
@@ -418,7 +479,7 @@ struct HierarchyPass : public Pass {
log_cmd_error("Option -top requires an additional argument!\n");
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
- std::map<RTLIL::IdString, RTLIL::Const> empty_parameters;
+ dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
@@ -426,6 +487,10 @@ struct HierarchyPass : public Pass {
log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
continue;
}
+ if (args[argidx] == "-auto-top") {
+ auto_top_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design, false);
@@ -437,35 +502,47 @@ struct HierarchyPass : public Pass {
log_push();
- if (top_mod == NULL)
+ if (top_mod == nullptr)
for (auto &mod_it : design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_mod = mod_it.second;
- if (top_mod != NULL)
- hierarchy(design, top_mod, purge_lib, true);
+ if (top_mod == nullptr && auto_top_mode) {
+ log_header("Finding top of design hierarchy..\n");
+ dict<Module*, int> db;
+ for (Module *mod : design->modules()) {
+ int score = find_top_mod_score(design, mod, db);
+ log("root of %3d design levels: %-20s\n", score, log_id(mod));
+ if (!top_mod || score > db[top_mod])
+ top_mod = mod;
+ }
+ if (top_mod != nullptr)
+ log("Automatically selected %s as design top module.\n", log_id(top_mod));
+ }
bool did_something = true;
- bool did_something_once = false;
- while (did_something) {
+ while (did_something)
+ {
did_something = false;
- std::vector<RTLIL::IdString> modnames;
- modnames.reserve(design->modules_.size());
- for (auto &mod_it : design->modules_)
- modnames.push_back(mod_it.first);
- for (auto &modname : modnames) {
- if (design->modules_.count(modname) == 0)
- continue;
- if (expand_module(design, design->modules_[modname], flag_check, libdirs))
+
+ std::set<RTLIL::Module*> used_modules;
+ if (top_mod != NULL) {
+ log_header("Analyzing design hierarchy..\n");
+ hierarchy_worker(design, used_modules, top_mod, 0);
+ } else {
+ for (auto mod : design->modules())
+ used_modules.insert(mod);
+ }
+
+ for (auto module : used_modules) {
+ if (expand_module(design, module, flag_check, libdirs))
did_something = true;
}
- if (did_something)
- did_something_once = true;
}
- if (top_mod != NULL && did_something_once) {
- log_header("Re-running hierarchy analysis..\n");
- hierarchy(design, top_mod, purge_lib, false);
+ if (top_mod != NULL) {
+ log_header("Analyzing design hierarchy..\n");
+ hierarchy_clean(design, top_mod, purge_lib);
}
if (top_mod != NULL) {
@@ -476,6 +553,15 @@ struct HierarchyPass : public Pass {
mod_it.second->attributes.erase("\\top");
}
+ if (!nokeep_asserts) {
+ std::map<RTLIL::Module*, bool> cache;
+ for (auto mod : design->modules())
+ if (set_keep_assert(cache, mod)) {
+ log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod));
+ mod->set_bool_attribute("\\keep");
+ }
+ }
+
if (!keep_positionals)
{
std::set<RTLIL::Module*> pos_mods;
@@ -507,7 +593,7 @@ struct HierarchyPass : public Pass {
RTLIL::Cell *cell = work.second;
log("Mapping positional arguments of cell %s.%s (%s).\n",
RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
- std::map<RTLIL::IdString, RTLIL::SigSpec> new_connections;
+ dict<RTLIL::IdString, RTLIL::SigSpec> new_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);
@@ -528,3 +614,4 @@ struct HierarchyPass : public Pass {
}
} HierarchyPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index 1b03ab55..8d4012c5 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -24,6 +24,9 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SubmodWorker
{
CellTypes ct;
@@ -82,7 +85,7 @@ struct SubmodWorker
for (auto &conn : cell->connections())
flag_signal(conn.second, true, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first), false, false);
} else {
- log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
+ log_warning("Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
for (auto &conn : cell->connections())
flag_signal(conn.second, true, true, true, false, false);
}
@@ -99,7 +102,7 @@ struct SubmodWorker
for (auto &conn : cell->connections())
flag_signal(conn.second, false, false, false, true, true);
if (flag_found_something)
- log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
+ log_warning("Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
}
}
@@ -347,3 +350,4 @@ struct SubmodPass : public Pass {
}
} SubmodPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc
index 026c5ff8..aeff225d 100644
--- a/passes/memory/Makefile.inc
+++ b/passes/memory/Makefile.inc
@@ -4,5 +4,6 @@ OBJS += passes/memory/memory_dff.o
OBJS += passes/memory/memory_share.o
OBJS += passes/memory/memory_collect.o
OBJS += passes/memory/memory_unpack.o
+OBJS += passes/memory/memory_bram.o
OBJS += passes/memory/memory_map.o
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index fc309553..866efae7 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -22,13 +22,16 @@
#include <stdlib.h>
#include <stdio.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct MemoryPass : public Pass {
MemoryPass() : Pass("memory", "translate memories to basic cells") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" memory [-nomap] [selection]\n");
+ log(" memory [-nomap] [-bram <bram_rules>] [selection]\n");
log("\n");
log("This pass calls all the other memory_* passes in a useful order:\n");
log("\n");
@@ -37,7 +40,8 @@ struct MemoryPass : public Pass {
log(" memory_share\n");
log(" opt_clean\n");
log(" memory_collect\n");
- log(" memory_map (skipped if called with -nomap)\n");
+ log(" memory_bram -rules <bram_rules> (when called with -bram)\n");
+ log(" memory_map (skipped if called with -nomap)\n");
log("\n");
log("This converts memories to word-wide DFFs and address decoders\n");
log("or multiport memory blocks if called with the -nomap option.\n");
@@ -46,6 +50,7 @@ struct MemoryPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
bool flag_nomap = false;
+ string memory_bram_opts;
log_header("Executing MEMORY pass.\n");
log_push();
@@ -56,6 +61,10 @@ struct MemoryPass : public Pass {
flag_nomap = true;
continue;
}
+ if (argidx+1 < args.size() && args[argidx] == "-bram") {
+ memory_bram_opts += " -rules " + args[++argidx];
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -66,6 +75,9 @@ struct MemoryPass : public Pass {
Pass::call(design, "opt_clean");
Pass::call(design, "memory_collect");
+ if (!memory_bram_opts.empty())
+ Pass::call(design, "memory_bram" + memory_bram_opts);
+
if (!flag_nomap)
Pass::call(design, "memory_map");
@@ -73,3 +85,4 @@ struct MemoryPass : public Pass {
}
} MemoryPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
new file mode 100644
index 00000000..958cc88b
--- /dev/null
+++ b/passes/memory/memory_bram.cc
@@ -0,0 +1,1174 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct rules_t
+{
+ struct portinfo_t {
+ int group, index, dupidx;
+ int wrmode, enable, transp, clocks, clkpol;
+
+ SigBit sig_clock;
+ SigSpec sig_addr, sig_data, sig_en;
+ bool effective_clkpol;
+ bool make_transp;
+ int mapped_port;
+ };
+
+ struct bram_t {
+ IdString name;
+ int variant;
+
+ int groups, abits, dbits, init;
+ vector<int> ports, wrmode, enable, transp, clocks, clkpol;
+
+ void dump_config() const
+ {
+ log(" bram %s # variant %d\n", log_id(name), variant);
+ log(" init %d\n", init);
+ log(" abits %d\n", abits);
+ log(" dbits %d\n", dbits);
+ log(" groups %d\n", groups);
+
+ log(" ports "); for (int v : ports) log("%4d", v); log("\n");
+ log(" wrmode"); for (int v : wrmode) log("%4d", v); log("\n");
+ log(" enable"); for (int v : enable) log("%4d", v); log("\n");
+ log(" transp"); for (int v : transp) log("%4d", v); log("\n");
+ log(" clocks"); for (int v : clocks) log("%4d", v); log("\n");
+ log(" clkpol"); for (int v : clkpol) log("%4d", v); log("\n");
+ log(" endbram\n");
+ }
+
+ void check_vectors() const
+ {
+ if (groups != GetSize(ports)) log_error("Bram %s variant %d has %d groups but only %d entries in 'ports'.\n", log_id(name), variant, groups, GetSize(ports));
+ if (groups != GetSize(wrmode)) log_error("Bram %s variant %d has %d groups but only %d entries in 'wrmode'.\n", log_id(name), variant, groups, GetSize(wrmode));
+ if (groups != GetSize(enable)) log_error("Bram %s variant %d has %d groups but only %d entries in 'enable'.\n", log_id(name), variant, groups, GetSize(enable));
+ if (groups != GetSize(transp)) log_error("Bram %s variant %d has %d groups but only %d entries in 'transp'.\n", log_id(name), variant, groups, GetSize(transp));
+ if (groups != GetSize(clocks)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clocks'.\n", log_id(name), variant, groups, GetSize(clocks));
+ if (groups != GetSize(clkpol)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clkpol'.\n", log_id(name), variant, groups, GetSize(clkpol));
+ }
+
+ vector<portinfo_t> make_portinfos() const
+ {
+ vector<portinfo_t> portinfos;
+ for (int i = 0; i < groups; i++)
+ for (int j = 0; j < ports[i]; j++) {
+ portinfo_t pi;
+ pi.group = i;
+ pi.index = j;
+ pi.dupidx = 0;
+ pi.wrmode = wrmode[i];
+ pi.enable = enable[i];
+ pi.transp = transp[i];
+ pi.clocks = clocks[i];
+ pi.clkpol = clkpol[i];
+ pi.mapped_port = -1;
+ pi.make_transp = false;
+ pi.effective_clkpol = false;
+ portinfos.push_back(pi);
+ }
+ return portinfos;
+ }
+
+ void find_variant_params(dict<IdString, Const> &variant_params, const bram_t &other) const
+ {
+ log_assert(name == other.name);
+
+ if (groups != other.groups)
+ log_error("Bram %s variants %d and %d have different values for 'groups'.\n", log_id(name), variant, other.variant);
+
+ if (abits != other.abits)
+ variant_params["\\CFG_ABITS"] = abits;
+ if (dbits != other.dbits)
+ variant_params["\\CFG_DBITS"] = dbits;
+ if (init != other.init)
+ variant_params["\\CFG_INIT"] = init;
+
+ for (int i = 0; i < groups; i++)
+ {
+ if (ports[i] != other.ports[i])
+ log_error("Bram %s variants %d and %d have different number of %c-ports.\n", log_id(name), variant, other.variant, 'A'+i);
+ if (wrmode[i] != other.wrmode[i])
+ variant_params[stringf("\\CFG_WRMODE_%c", 'A' + i)] = wrmode[1];
+ if (enable[i] != other.enable[i])
+ variant_params[stringf("\\CFG_ENABLE_%c", 'A' + i)] = enable[1];
+ if (transp[i] != other.transp[i])
+ variant_params[stringf("\\CFG_TRANSP_%c", 'A' + i)] = transp[1];
+ if (clocks[i] != other.clocks[i])
+ variant_params[stringf("\\CFG_CLOCKS_%c", 'A' + i)] = clocks[1];
+ if (clkpol[i] != other.clkpol[i])
+ variant_params[stringf("\\CFG_CLKPOL_%c", 'A' + i)] = clkpol[1];
+ }
+ }
+ };
+
+ struct match_t {
+ IdString name;
+ dict<string, int> min_limits, max_limits;
+ bool or_next_if_better, make_transp;
+ char shuffle_enable;
+ };
+
+ dict<IdString, vector<bram_t>> brams;
+ vector<match_t> matches;
+
+ std::ifstream infile;
+ vector<string> tokens;
+ vector<string> labels;
+ int linecount;
+
+ void syntax_error()
+ {
+ if (tokens.empty())
+ log_error("Unexpected end of rules file in line %d.\n", linecount);
+ log_error("Syntax error in rules file line %d.\n", linecount);
+ }
+
+ bool next_line()
+ {
+ string line;
+ while (std::getline(infile, line)) {
+ tokens.clear();
+ labels.clear();
+ linecount++;
+ for (string tok = next_token(line); !tok.empty(); tok = next_token(line)) {
+ if (tok[0] == '@') {
+ labels.push_back(tok.substr(1));
+ continue;
+ }
+ if (tok[0] == '#')
+ break;
+ tokens.push_back(tok);
+ }
+ if (!tokens.empty())
+ return true;
+ }
+ return false;
+ }
+
+ bool parse_single_int(const char *stmt, int &value)
+ {
+ if (GetSize(tokens) == 2 && tokens[0] == stmt) {
+ value = atoi(tokens[1].c_str());
+ return true;
+ }
+ return false;
+ }
+
+ bool parse_int_vect(const char *stmt, vector<int> &value)
+ {
+ if (GetSize(tokens) >= 2 && tokens[0] == stmt) {
+ value.resize(GetSize(tokens)-1);
+ for (int i = 1; i < GetSize(tokens); i++)
+ value[i-1] = atoi(tokens[i].c_str());
+ return true;
+ }
+ return false;
+ }
+
+ void parse_bram()
+ {
+ IdString bram_name = RTLIL::escape_id(tokens[1]);
+
+ if (GetSize(tokens) != 2)
+ syntax_error();
+
+ vector<vector<string>> lines_nolabels;
+ std::map<string, vector<vector<string>>> lines_labels;
+
+ while (next_line())
+ {
+ if (GetSize(tokens) == 1 && tokens[0] == "endbram")
+ break;
+ if (labels.empty())
+ lines_nolabels.push_back(tokens);
+ for (auto lab : labels)
+ lines_labels[lab].push_back(tokens);
+ }
+
+ std::map<string, vector<vector<string>>> variant_lines;
+
+ if (lines_labels.empty())
+ variant_lines[""] = lines_nolabels;
+ for (auto &it : lines_labels) {
+ variant_lines[it.first] = lines_nolabels;
+ variant_lines[it.first].insert(variant_lines[it.first].end(), it.second.begin(), it.second.end());
+ }
+
+ for (auto &it : variant_lines)
+ {
+ bram_t data;
+ data.name = bram_name;
+ data.variant = GetSize(brams[data.name]) + 1;
+ data.groups = 0;
+ data.abits = 0;
+ data.dbits = 0;
+ data.init = 0;
+
+ for (auto &line_tokens : it.second)
+ {
+ tokens = line_tokens;
+
+ if (parse_single_int("groups", data.groups))
+ continue;
+
+ if (parse_single_int("abits", data.abits))
+ continue;
+
+ if (parse_single_int("dbits", data.dbits))
+ continue;
+
+ if (parse_single_int("init", data.init))
+ continue;
+
+ if (parse_int_vect("ports", data.ports))
+ continue;
+
+ if (parse_int_vect("wrmode", data.wrmode))
+ continue;
+
+ if (parse_int_vect("enable", data.enable))
+ continue;
+
+ if (parse_int_vect("transp", data.transp))
+ continue;
+
+ if (parse_int_vect("clocks", data.clocks))
+ continue;
+
+ if (parse_int_vect("clkpol", data.clkpol))
+ continue;
+
+ syntax_error();
+ }
+
+ data.check_vectors();
+ brams[data.name].push_back(data);
+ }
+ }
+
+ void parse_match()
+ {
+ if (GetSize(tokens) != 2)
+ syntax_error();
+
+ match_t data;
+ data.name = RTLIL::escape_id(tokens[1]);
+ data.or_next_if_better = false;
+ data.make_transp = false;
+ data.shuffle_enable = 0;
+
+ while (next_line())
+ {
+ if (!labels.empty())
+ syntax_error();
+
+ if (GetSize(tokens) == 1 && tokens[0] == "endmatch") {
+ matches.push_back(data);
+ break;
+ }
+
+ if (GetSize(tokens) == 3 && tokens[0] == "min") {
+ data.min_limits[tokens[1]] = atoi(tokens[2].c_str());
+ continue;
+ }
+
+ if (GetSize(tokens) == 3 && tokens[0] == "max") {
+ data.max_limits[tokens[1]] = atoi(tokens[2].c_str());
+ continue;
+ }
+
+ if (GetSize(tokens) == 2 && tokens[0] == "shuffle_enable" && GetSize(tokens[1]) == 1 && 'A' <= tokens[1][0] && tokens[1][0] <= 'Z') {
+ data.shuffle_enable = tokens[1][0];
+ continue;
+ }
+
+ if (GetSize(tokens) == 1 && tokens[0] == "make_transp") {
+ data.make_transp = true;
+ continue;
+ }
+
+ if (GetSize(tokens) == 1 && tokens[0] == "or_next_if_better") {
+ data.or_next_if_better = true;
+ continue;
+ }
+
+ syntax_error();
+ }
+ }
+
+ void parse(string filename)
+ {
+ if (filename.substr(0, 2) == "+/")
+ filename = proc_share_dirname() + filename.substr(1);
+
+ infile.open(filename);
+ linecount = 0;
+
+ if (infile.fail())
+ log_error("Can't open rules file `%s'.\n", filename.c_str());
+
+ while (next_line())
+ {
+ if (!labels.empty())
+ syntax_error();
+
+ if (tokens[0] == "bram") {
+ parse_bram();
+ continue;
+ }
+
+ if (tokens[0] == "match") {
+ parse_match();
+ continue;
+ }
+
+ syntax_error();
+ }
+
+ infile.close();
+ }
+};
+
+bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, const rules_t::match_t &match, dict<string, int> &match_properties, int mode)
+{
+ Module *module = cell->module;
+
+ auto portinfos = bram.make_portinfos();
+ int dup_count = 1;
+
+ pair<SigBit, bool> make_transp_clk;
+ bool enable_make_transp = false;
+ int make_transp_enbits = 0;
+
+ dict<int, pair<SigBit, bool>> clock_domains;
+ dict<int, bool> clock_polarities;
+ dict<int, bool> read_transp;
+ pool<int> clocks_wr_ports;
+ pool<int> clkpol_wr_ports;
+ int clocks_max = 0;
+ int clkpol_max = 0;
+ int transp_max = 0;
+
+ clock_polarities[0] = false;
+ clock_polarities[1] = true;
+
+ for (auto &pi : portinfos) {
+ if (pi.wrmode) {
+ clocks_wr_ports.insert(pi.clocks);
+ if (pi.clkpol > 1)
+ clkpol_wr_ports.insert(pi.clkpol);
+ }
+ clocks_max = std::max(clocks_max, pi.clocks);
+ clkpol_max = std::max(clkpol_max, pi.clkpol);
+ transp_max = std::max(transp_max, pi.transp);
+ }
+
+ log(" Mapping to bram type %s (variant %d):\n", log_id(bram.name), bram.variant);
+ // bram.dump_config();
+
+ int mem_size = cell->getParam("\\SIZE").as_int();
+ int mem_abits = cell->getParam("\\ABITS").as_int();
+ int mem_width = cell->getParam("\\WIDTH").as_int();
+ // int mem_offset = cell->getParam("\\OFFSET").as_int();
+
+ int wr_ports = cell->getParam("\\WR_PORTS").as_int();
+ auto wr_clken = SigSpec(cell->getParam("\\WR_CLK_ENABLE"));
+ auto wr_clkpol = SigSpec(cell->getParam("\\WR_CLK_POLARITY"));
+ wr_clken.extend_u0(wr_ports);
+ wr_clkpol.extend_u0(wr_ports);
+
+ SigSpec wr_en = cell->getPort("\\WR_EN");
+ SigSpec wr_clk = cell->getPort("\\WR_CLK");
+ SigSpec wr_data = cell->getPort("\\WR_DATA");
+ SigSpec wr_addr = cell->getPort("\\WR_ADDR");
+
+ int rd_ports = cell->getParam("\\RD_PORTS").as_int();
+ auto rd_clken = SigSpec(cell->getParam("\\RD_CLK_ENABLE"));
+ auto rd_clkpol = SigSpec(cell->getParam("\\RD_CLK_POLARITY"));
+ auto rd_transp = SigSpec(cell->getParam("\\RD_TRANSPARENT"));
+ rd_clken.extend_u0(rd_ports);
+ rd_clkpol.extend_u0(rd_ports);
+ rd_transp.extend_u0(rd_ports);
+
+ SigSpec rd_clk = cell->getPort("\\RD_CLK");
+ SigSpec rd_data = cell->getPort("\\RD_DATA");
+ SigSpec rd_addr = cell->getPort("\\RD_ADDR");
+
+ if (match.shuffle_enable && bram.dbits >= portinfos.at(match.shuffle_enable - 'A').enable*2 && portinfos.at(match.shuffle_enable - 'A').enable > 0)
+ {
+ int bucket_size = bram.dbits / portinfos.at(match.shuffle_enable - 'A').enable;
+ log(" Shuffle bit order to accommodate enable buckets of size %d..\n", bucket_size);
+
+ // extract unshuffled data/enable bits
+
+ std::vector<SigSpec> old_wr_en;
+ std::vector<SigSpec> old_wr_data;
+ std::vector<SigSpec> old_rd_data;
+
+ for (int i = 0; i < wr_ports; i++) {
+ old_wr_en.push_back(wr_en.extract(i*mem_width, mem_width));
+ old_wr_data.push_back(wr_data.extract(i*mem_width, mem_width));
+ }
+
+ for (int i = 0; i < rd_ports; i++)
+ old_rd_data.push_back(rd_data.extract(i*mem_width, mem_width));
+
+ // analyze enable structure
+
+ std::vector<SigSpec> en_order;
+ dict<SigSpec, vector<int>> bits_wr_en;
+
+ for (int i = 0; i < mem_width; i++) {
+ SigSpec sig;
+ for (int j = 0; j < wr_ports; j++)
+ sig.append(old_wr_en[j][i]);
+ if (bits_wr_en.count(sig) == 0)
+ en_order.push_back(sig);
+ bits_wr_en[sig].push_back(i);
+ }
+
+ // re-create memory ports
+
+ 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<int> shuffle_map;
+
+ for (auto &it : en_order)
+ {
+ auto &bits = bits_wr_en.at(it);
+ int buckets = (GetSize(bits) + bucket_size - 1) / bucket_size;
+ int fillbits = buckets*bucket_size - GetSize(bits);
+ SigBit fillbit;
+
+ for (int i = 0; i < GetSize(bits); i++) {
+ for (int j = 0; j < wr_ports; j++) {
+ new_wr_en[j].append(old_wr_en[j][bits[i]]);
+ new_wr_data[j].append(old_wr_data[j][bits[i]]);
+ fillbit = old_wr_en[j][bits[i]];
+ }
+ for (int j = 0; j < rd_ports; j++)
+ new_rd_data[j].append(old_rd_data[j][bits[i]]);
+ shuffle_map.push_back(bits[i]);
+ }
+
+ for (int i = 0; i < fillbits; i++) {
+ for (int j = 0; j < wr_ports; j++) {
+ new_wr_en[j].append(fillbit);
+ new_wr_data[j].append(State::S0);
+ }
+ for (int j = 0; j < rd_ports; j++)
+ new_rd_data[j].append(State::Sx);
+ shuffle_map.push_back(-1);
+ }
+ }
+
+ log(" Results of bit order shuffling:");
+ for (int v : shuffle_map)
+ log(" %d", v);
+ log("\n");
+
+ // update mem_*, wr_*, and rd_* variables
+
+ mem_width = GetSize(new_wr_en.front());
+ wr_en = SigSpec(0, wr_ports * mem_width);
+ wr_data = SigSpec(0, wr_ports * mem_width);
+ rd_data = SigSpec(0, rd_ports * mem_width);
+
+ for (int i = 0; i < wr_ports; i++) {
+ wr_en.replace(i*mem_width, new_wr_en[i]);
+ wr_data.replace(i*mem_width, new_wr_data[i]);
+ }
+
+ for (int i = 0; i < rd_ports; i++)
+ rd_data.replace(i*mem_width, new_rd_data[i]);
+ }
+
+ // assign write ports
+
+ 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;
+ bool clkpol = wr_clkpol[cell_port_i] == State::S1;
+ SigBit clksig = wr_clk[cell_port_i];
+
+ pair<SigBit, bool> clkdom(clksig, clkpol);
+ if (!clken)
+ clkdom = pair<SigBit, bool>(State::S1, false);
+
+ log(" Write port #%d is in clock domain %s%s.\n",
+ cell_port_i, clkdom.second ? "" : "!",
+ clken ? log_signal(clkdom.first) : "~async~");
+
+ for (; bram_port_i < GetSize(portinfos); bram_port_i++)
+ {
+ auto &pi = portinfos[bram_port_i];
+ make_transp_enbits = pi.enable;
+ make_transp_clk = clkdom;
+
+ if (pi.wrmode != 1)
+ skip_bram_wport:
+ continue;
+
+ if (clken) {
+ if (pi.clocks == 0) {
+ log(" Bram port %c%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ if (clock_domains.count(pi.clocks) && clock_domains.at(pi.clocks) != clkdom) {
+ log(" Bram port %c%d is in a different clock domain.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != clkpol) {
+ log(" Bram port %c%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ } else {
+ if (pi.clocks != 0) {
+ log(" Bram port %c%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ }
+
+ SigSpec sig_en;
+ SigBit last_en_bit = State::S1;
+ for (int i = 0; i < mem_width; i++) {
+ if (pi.enable && i % (bram.dbits / pi.enable) == 0) {
+ last_en_bit = wr_en[i + cell_port_i*mem_width];
+ sig_en.append(last_en_bit);
+ }
+ if (last_en_bit != wr_en[i + cell_port_i*mem_width]) {
+ log(" Bram port %c%d has incompatible enable structure.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ }
+
+ log(" Mapped to bram port %c%d.\n", pi.group + 'A', pi.index + 1);
+ pi.mapped_port = cell_port_i;
+
+ if (clken) {
+ clock_domains[pi.clocks] = clkdom;
+ clock_polarities[pi.clkpol] = clkdom.second;
+ pi.sig_clock = clkdom.first;
+ pi.effective_clkpol = clkdom.second;
+ }
+
+ pi.sig_en = sig_en;
+ pi.sig_addr = wr_addr.extract(cell_port_i*mem_abits, mem_abits);
+ pi.sig_data = wr_data.extract(cell_port_i*mem_width, mem_width);
+
+ bram_port_i++;
+ goto mapped_wr_port;
+ }
+
+ log(" Failed to map write port #%d.\n", cell_port_i);
+ return false;
+ mapped_wr_port:;
+ }
+
+ // houskeeping stuff for growing more read ports and restarting read port assignments
+
+ int grow_read_ports_cursor = -1;
+ bool try_growing_more_read_ports = false;
+ auto backup_clock_domains = clock_domains;
+ auto backup_clock_polarities = clock_polarities;
+
+ if (0) {
+grow_read_ports:;
+ vector<rules_t::portinfo_t> new_portinfos;
+ for (auto &pi : portinfos) {
+ if (pi.wrmode == 0) {
+ pi.mapped_port = -1;
+ pi.sig_clock = SigBit();
+ pi.sig_addr = SigSpec();
+ pi.sig_data = SigSpec();
+ pi.sig_en = SigSpec();
+ }
+ new_portinfos.push_back(pi);
+ if (pi.dupidx == dup_count-1) {
+ if (pi.clocks && !clocks_wr_ports[pi.clocks])
+ pi.clocks += clocks_max;
+ if (pi.clkpol > 1 && !clkpol_wr_ports[pi.clkpol])
+ pi.clkpol += clkpol_max;
+ if (pi.transp > 1)
+ pi.transp += transp_max;
+ pi.dupidx++;
+ new_portinfos.push_back(pi);
+ }
+ }
+ try_growing_more_read_ports = false;
+ portinfos.swap(new_portinfos);
+ clock_domains = backup_clock_domains;
+ clock_polarities = backup_clock_polarities;
+ dup_count++;
+ }
+
+ read_transp.clear();
+ read_transp[0] = false;
+ read_transp[1] = true;
+
+ // assign read ports
+
+ for (int cell_port_i = 0; cell_port_i < rd_ports; cell_port_i++)
+ {
+ bool clken = rd_clken[cell_port_i] == State::S1;
+ bool clkpol = rd_clkpol[cell_port_i] == State::S1;
+ bool transp = rd_transp[cell_port_i] == State::S1;
+ SigBit clksig = rd_clk[cell_port_i];
+
+ pair<SigBit, bool> clkdom(clksig, clkpol);
+ if (!clken)
+ clkdom = pair<SigBit, bool>(State::S1, false);
+
+ log(" Read port #%d is in clock domain %s%s.\n",
+ cell_port_i, clkdom.second ? "" : "!",
+ clken ? log_signal(clkdom.first) : "~async~");
+
+ for (int bram_port_i = 0; bram_port_i < GetSize(portinfos); bram_port_i++)
+ {
+ auto &pi = portinfos[bram_port_i];
+
+ if (pi.wrmode != 0 || pi.mapped_port >= 0)
+ skip_bram_rport:
+ continue;
+
+ if (clken) {
+ if (pi.clocks == 0) {
+ log(" Bram port %c%d.%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ if (clock_domains.count(pi.clocks) && clock_domains.at(pi.clocks) != clkdom) {
+ log(" Bram port %c%d.%d is in a different clock domain.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != clkpol) {
+ log(" Bram port %c%d.%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ 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;
+ } else {
+ log(" Bram port %c%d.%d has incompatible read transparancy.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ }
+ } else {
+ if (pi.clocks != 0) {
+ log(" Bram port %c%d.%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ }
+
+ log(" Mapped to bram port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ pi.mapped_port = cell_port_i;
+
+ if (clken) {
+ clock_domains[pi.clocks] = clkdom;
+ clock_polarities[pi.clkpol] = clkdom.second;
+ read_transp[pi.transp] = transp;
+ pi.sig_clock = clkdom.first;
+ pi.effective_clkpol = clkdom.second;
+ }
+
+ pi.sig_addr = rd_addr.extract(cell_port_i*mem_abits, mem_abits);
+ pi.sig_data = rd_data.extract(cell_port_i*mem_width, mem_width);
+
+ if (grow_read_ports_cursor < cell_port_i) {
+ grow_read_ports_cursor = cell_port_i;
+ try_growing_more_read_ports = true;
+ }
+
+ goto mapped_rd_port;
+ }
+
+ log(" Failed to map read port #%d.\n", cell_port_i);
+ if (try_growing_more_read_ports) {
+ log(" Growing more read ports by duplicating bram cells.\n");
+ goto grow_read_ports;
+ }
+ return false;
+ mapped_rd_port:;
+ }
+
+ // update properties and re-check conditions
+
+ if (mode <= 1)
+ {
+ match_properties["dups"] = dup_count;
+ match_properties["waste"] = match_properties["dups"] * match_properties["bwaste"];
+
+ int cells = ((mem_width + bram.dbits - 1) / bram.dbits) * ((mem_size + (1 << bram.abits) - 1) / (1 << bram.abits));
+ match_properties["efficiency"] = (100 * match_properties["bits"]) / (dup_count * cells * bram.dbits * (1 << bram.abits));
+
+ match_properties["dcells"] = ((mem_width + bram.dbits - 1) / bram.dbits);
+ match_properties["acells"] = ((mem_size + (1 << bram.abits) - 1) / (1 << bram.abits));
+ match_properties["cells"] = match_properties["dcells"] * match_properties["acells"] * match_properties["dups"];
+
+ log(" Updated properties: dups=%d waste=%d efficiency=%d\n",
+ match_properties["dups"], match_properties["waste"], match_properties["efficiency"]);
+
+ for (auto it : match.min_limits) {
+ if (!match_properties.count(it.first))
+ log_error("Unknown property '%s' in match rule for bram type %s.\n",
+ it.first.c_str(), log_id(match.name));
+ if (match_properties[it.first] >= it.second)
+ continue;
+ log(" Rule for bram type %s rejected: requirement 'min %s %d' not met.\n",
+ log_id(match.name), it.first.c_str(), it.second);
+ return false;
+ }
+ for (auto it : match.max_limits) {
+ if (!match_properties.count(it.first))
+ log_error("Unknown property '%s' in match rule for bram type %s.\n",
+ it.first.c_str(), log_id(match.name));
+ if (match_properties[it.first] <= it.second)
+ continue;
+ log(" Rule for bram type %s rejected: requirement 'max %s %d' not met.\n",
+ log_id(match.name), it.first.c_str(), it.second);
+ return false;
+ }
+
+ if (mode == 1)
+ return true;
+ }
+
+ // prepare variant parameters
+
+ dict<IdString, Const> variant_params;
+ for (auto &other_bram : rules.brams.at(bram.name))
+ bram.find_variant_params(variant_params, other_bram);
+
+ // actually replace that memory cell
+
+ dict<SigSpec, pair<SigSpec, SigSpec>> dout_cache;
+
+ for (int grid_d = 0; grid_d*bram.dbits < mem_width; grid_d++)
+ {
+ SigSpec mktr_wraddr, mktr_wrdata, mktr_wrdata_q;
+ vector<SigSpec> mktr_wren;
+
+ if (enable_make_transp) {
+ mktr_wraddr = module->addWire(NEW_ID, bram.abits);
+ mktr_wrdata = module->addWire(NEW_ID, bram.dbits);
+ mktr_wrdata_q = module->addWire(NEW_ID, bram.dbits);
+ module->addDff(NEW_ID, make_transp_clk.first, mktr_wrdata, mktr_wrdata_q, make_transp_clk.second);
+ for (int grid_a = 0; grid_a*(1 << bram.abits) < mem_size; grid_a++)
+ mktr_wren.push_back(module->addWire(NEW_ID, make_transp_enbits));
+ }
+
+ for (int grid_a = 0; grid_a*(1 << bram.abits) < mem_size; grid_a++)
+ for (int dupidx = 0; dupidx < dup_count; dupidx++)
+ {
+ Cell *c = module->addCell(module->uniquify(stringf("%s.%d.%d.%d", cell->name.c_str(), grid_d, grid_a, dupidx)), bram.name);
+ log(" Creating %s cell at grid position <%d %d %d>: %s\n", log_id(bram.name), grid_d, grid_a, dupidx, log_id(c));
+
+ for (auto &vp : variant_params)
+ c->setParam(vp.first, vp.second);
+
+ for (auto &pi : portinfos)
+ {
+ if (pi.dupidx != dupidx)
+ continue;
+
+ string prefix = stringf("%c%d", pi.group + 'A', pi.index + 1);
+ const char *pf = prefix.c_str();
+
+ if (pi.clocks && (!c->hasPort(stringf("\\CLK%d", (pi.clocks-1) % clocks_max + 1)) || pi.sig_clock.wire)) {
+ c->setPort(stringf("\\CLK%d", (pi.clocks-1) % clocks_max + 1), pi.sig_clock);
+ if (pi.clkpol > 1 && pi.sig_clock.wire)
+ c->setParam(stringf("\\CLKPOL%d", (pi.clkpol-1) % clkpol_max + 1), clock_polarities.at(pi.clkpol));
+ if (pi.transp > 1 && pi.sig_clock.wire)
+ c->setParam(stringf("\\TRANSP%d", (pi.transp-1) % transp_max + 1), read_transp.at(pi.transp));
+ }
+
+ SigSpec addr_ok;
+ if (GetSize(pi.sig_addr) > bram.abits) {
+ SigSpec extra_addr = pi.sig_addr.extract(bram.abits, GetSize(pi.sig_addr) - bram.abits);
+ SigSpec extra_addr_sel = SigSpec(grid_a, GetSize(extra_addr));
+ addr_ok = module->Eq(NEW_ID, extra_addr, extra_addr_sel);
+ }
+
+ if (pi.enable)
+ {
+ SigSpec sig_en = pi.sig_en;
+ sig_en.extend_u0((grid_d+1) * pi.enable);
+ sig_en = sig_en.extract(grid_d * pi.enable, pi.enable);
+
+ if (!addr_ok.empty())
+ sig_en = module->Mux(NEW_ID, SigSpec(0, GetSize(sig_en)), sig_en, addr_ok);
+
+ c->setPort(stringf("\\%sEN", pf), sig_en);
+
+ if (pi.wrmode == 1 && enable_make_transp)
+ module->connect(mktr_wren[grid_a], sig_en);
+ }
+
+ SigSpec sig_addr = pi.sig_addr;
+ sig_addr.extend_u0(bram.abits);
+ c->setPort(stringf("\\%sADDR", pf), sig_addr);
+
+ if (pi.wrmode == 1 && enable_make_transp && grid_a == 0)
+ module->connect(mktr_wraddr, sig_addr);
+
+ SigSpec sig_data = pi.sig_data;
+ sig_data.extend_u0((grid_d+1) * bram.dbits);
+ sig_data = sig_data.extract(grid_d * bram.dbits, bram.dbits);
+
+ if (pi.wrmode == 1) {
+ c->setPort(stringf("\\%sDATA", pf), sig_data);
+ if (enable_make_transp && grid_a == 0)
+ module->connect(mktr_wrdata, sig_data);
+ } else {
+ SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits);
+ c->setPort(stringf("\\%sDATA", pf), bram_dout);
+
+ 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),
+ mktr_wren[grid_a], module->Eq(NEW_ID, mktr_wraddr, sig_addr));
+
+ SigSpec transp_en_q = module->addWire(NEW_ID, make_transp_enbits);
+ module->addDff(NEW_ID, make_transp_clk.first, transp_en_d, transp_en_q, make_transp_clk.second);
+
+ for (int i = 0; i < make_transp_enbits; i++) {
+ int en_width = bram.dbits / make_transp_enbits;
+ SigSpec orig_bram_dout = bram_dout.extract(i * en_width, en_width);
+ SigSpec bypass_dout = mktr_wrdata_q.extract(i * en_width, en_width);
+ bram_dout.replace(i * en_width, module->Mux(NEW_ID, orig_bram_dout, bypass_dout, transp_en_q[i]));
+ }
+ }
+
+ for (int i = bram.dbits-1; i >= 0; i--)
+ if (sig_data[i].wire == nullptr) {
+ sig_data.remove(i);
+ bram_dout.remove(i);
+ }
+
+ SigSpec addr_ok_q = addr_ok;
+ if (pi.clocks && !addr_ok.empty()) {
+ addr_ok_q = module->addWire(NEW_ID);
+ module->addDff(NEW_ID, pi.sig_clock, addr_ok, addr_ok_q, pi.effective_clkpol);
+ }
+
+ dout_cache[sig_data].first.append(addr_ok_q);
+ dout_cache[sig_data].second.append(bram_dout);
+ }
+ }
+ }
+ }
+
+ for (auto &it : dout_cache)
+ {
+ if (it.second.first.empty())
+ {
+ log_assert(GetSize(it.first) == GetSize(it.second.second));
+ module->connect(it.first, it.second.second);
+ }
+ else
+ {
+ log_assert(GetSize(it.first)*GetSize(it.second.first) == GetSize(it.second.second));
+ module->addPmux(NEW_ID, SigSpec(State::Sx, GetSize(it.first)), it.second.second, it.second.first, it.first);
+ }
+ }
+
+ module->remove(cell);
+ return true;
+}
+
+void handle_cell(Cell *cell, const rules_t &rules)
+{
+ log("Processing %s.%s:\n", log_id(cell->module), log_id(cell));
+
+ if (!SigSpec(cell->getParam("\\INIT")).is_fully_undef()) {
+ log(" initialized memories are not supported yet.");
+ return;
+ }
+
+ dict<string, int> match_properties;
+ match_properties["words"] = cell->getParam("\\SIZE").as_int();
+ match_properties["abits"] = cell->getParam("\\ABITS").as_int();
+ match_properties["dbits"] = cell->getParam("\\WIDTH").as_int();
+ match_properties["wports"] = cell->getParam("\\WR_PORTS").as_int();
+ match_properties["rports"] = cell->getParam("\\RD_PORTS").as_int();
+ match_properties["bits"] = match_properties["words"] * match_properties["dbits"];
+ match_properties["ports"] = match_properties["wports"] + match_properties["rports"];
+
+ log(" Properties:");
+ for (auto &it : match_properties)
+ log(" %s=%d", it.first.c_str(), it.second);
+ log("\n");
+
+ pool<pair<IdString, int>> failed_brams;
+ dict<pair<int, int>, std::tuple<int, int, int>> best_rule_cache;
+
+ for (int i = 0; i < GetSize(rules.matches); i++)
+ {
+ auto &match = rules.matches.at(i);
+
+ if (!rules.brams.count(rules.matches[i].name))
+ log_error("No bram description for resource %s found!\n", log_id(rules.matches[i].name));
+
+ for (int vi = 0; vi < GetSize(rules.brams.at(match.name)); vi++)
+ {
+ auto &bram = rules.brams.at(match.name).at(vi);
+ bool or_next_if_better = match.or_next_if_better || vi+1 < GetSize(rules.brams.at(match.name));
+
+ if (failed_brams.count(pair<IdString, int>(bram.name, bram.variant)))
+ continue;
+
+ int avail_rd_ports = 0;
+ int avail_wr_ports = 0;
+ for (int j = 0; j < bram.groups; j++) {
+ if (GetSize(bram.wrmode) < j || bram.wrmode.at(j) == 0)
+ avail_rd_ports += GetSize(bram.ports) < j ? bram.ports.at(j) : 0;
+ if (GetSize(bram.wrmode) < j || bram.wrmode.at(j) != 0)
+ avail_wr_ports += GetSize(bram.ports) < j ? bram.ports.at(j) : 0;
+ }
+
+ log(" Checking rule #%d for bram type %s (variant %d):\n", i+1, log_id(bram.name), bram.variant);
+ log(" Bram geometry: abits=%d dbits=%d wports=%d rports=%d\n", bram.abits, bram.dbits, avail_wr_ports, avail_rd_ports);
+
+ int dups = avail_rd_ports ? (match_properties["rports"] + avail_rd_ports - 1) / avail_rd_ports : 1;
+ match_properties["dups"] = dups;
+
+ log(" Estimated number of duplicates for more read ports: dups=%d\n", match_properties["dups"]);
+
+ int aover = match_properties["words"] % (1 << bram.abits);
+ int awaste = aover ? (1 << bram.abits) - aover : 0;
+ match_properties["awaste"] = awaste;
+
+ int dover = match_properties["dbits"] % bram.dbits;
+ int dwaste = dover ? bram.dbits - dover : 0;
+ match_properties["dwaste"] = dwaste;
+
+ int bwaste = awaste * bram.dbits + dwaste * (1 << bram.abits) - awaste * dwaste;
+ match_properties["bwaste"] = bwaste;
+
+ int waste = match_properties["dups"] * bwaste;
+ match_properties["waste"] = waste;
+
+ int cells = ((match_properties["dbits"] + bram.dbits - 1) / bram.dbits) * ((match_properties["words"] + (1 << bram.abits) - 1) / (1 << bram.abits));
+ int efficiency = (100 * match_properties["bits"]) / (dups * cells * bram.dbits * (1 << bram.abits));
+ match_properties["efficiency"] = efficiency;
+
+ log(" Metrics for %s: awaste=%d dwaste=%d bwaste=%d waste=%d efficiency=%d\n",
+ log_id(match.name), awaste, dwaste, bwaste, waste, efficiency);
+
+ for (auto it : match.min_limits) {
+ if (it.first == "waste" || it.first == "dups" || it.first == "acells" || it.first == "dcells" || it.first == "cells")
+ continue;
+ if (!match_properties.count(it.first))
+ log_error("Unknown property '%s' in match rule for bram type %s.\n",
+ it.first.c_str(), log_id(match.name));
+ if (match_properties[it.first] >= it.second)
+ continue;
+ log(" Rule #%d for bram type %s (variant %d) rejected: requirement 'min %s %d' not met.\n",
+ i+1, log_id(bram.name), bram.variant, it.first.c_str(), it.second);
+ goto next_match_rule;
+ }
+ for (auto it : match.max_limits) {
+ if (it.first == "acells" || it.first == "dcells" || it.first == "cells")
+ continue;
+ if (!match_properties.count(it.first))
+ log_error("Unknown property '%s' in match rule for bram type %s.\n",
+ it.first.c_str(), log_id(match.name));
+ if (match_properties[it.first] <= it.second)
+ continue;
+ log(" Rule #%d for bram type %s (variant %d) rejected: requirement 'max %s %d' not met.\n",
+ i+1, log_id(bram.name), bram.variant, it.first.c_str(), it.second);
+ goto next_match_rule;
+ }
+
+ log(" Rule #%d for bram type %s (variant %d) accepted.\n", i+1, log_id(bram.name), bram.variant);
+
+ if (or_next_if_better || !best_rule_cache.empty())
+ {
+ if (or_next_if_better && i+1 == GetSize(rules.matches) && vi+1 == GetSize(rules.brams.at(match.name)))
+ log_error("Found 'or_next_if_better' in last match rule.\n");
+
+ if (!replace_cell(cell, rules, bram, match, match_properties, 1)) {
+ log(" Mapping to bram type %s failed.\n", log_id(match.name));
+ failed_brams.insert(pair<IdString, int>(bram.name, bram.variant));
+ goto next_match_rule;
+ }
+
+ log(" Storing for later selection.\n");
+ best_rule_cache[pair<int, int>(i, vi)] = std::tuple<int, int, int>(match_properties["efficiency"], -match_properties["cells"], -match_properties["acells"]);
+
+ if (or_next_if_better)
+ goto next_match_rule;
+
+ next_match_rule:
+ if (or_next_if_better || best_rule_cache.empty())
+ continue;
+
+ log(" Selecting best of %d rules:\n", GetSize(best_rule_cache));
+ pair<int, int> best_rule = best_rule_cache.begin()->first;
+
+ for (auto &it : best_rule_cache) {
+ if (it.second > best_rule_cache[best_rule])
+ best_rule = it.first;
+ log(" Efficiency for rule %d.%d: efficiency=%d, cells=%d, acells=%d\n", it.first.first+1, it.first.second+1,
+ std::get<0>(it.second), -std::get<1>(it.second), -std::get<2>(it.second));
+ }
+
+ log(" Selected rule %d.%d with efficiency %d.\n", best_rule.first+1, best_rule.second+1, std::get<0>(best_rule_cache[best_rule]));
+ best_rule_cache.clear();
+
+ auto &best_bram = rules.brams.at(rules.matches.at(best_rule.first).name).at(best_rule.second);
+ if (!replace_cell(cell, rules, best_bram, rules.matches.at(best_rule.first), match_properties, 2))
+ log_error("Mapping to bram type %s (variant %d) after pre-selection failed.\n", log_id(best_bram.name), best_bram.variant);
+ return;
+ }
+
+ if (!replace_cell(cell, rules, bram, match, match_properties, 0)) {
+ log(" Mapping to bram type %s failed.\n", log_id(match.name));
+ failed_brams.insert(pair<IdString, int>(bram.name, bram.variant));
+ goto next_match_rule;
+ }
+ return;
+ }
+ }
+
+ log(" No acceptable bram resources found.\n");
+}
+
+struct MemoryBramPass : public Pass {
+ MemoryBramPass() : Pass("memory_bram", "map memories to block rams") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" memory_bram -rules <rule_file> [selection]\n");
+ log("\n");
+ log("This pass converts the multi-port $mem memory cells into block ram instances.\n");
+ log("The given rules file describes the available resources and how they should be\n");
+ log("used.\n");
+ log("\n");
+ log("The rules file contains a set of block ram description and a sequence of match\n");
+ log("rules. A block ram description looks like this:\n");
+ log("\n");
+ log(" bram RAMB1024X32 # name of BRAM cell\n");
+ // log(" init 1 # set to '1' if BRAM can be initialized\n");
+ log(" abits 10 # number of address bits\n");
+ log(" dbits 32 # number of data bits\n");
+ log(" groups 2 # number of port groups\n");
+ log(" ports 1 1 # number of ports in each group\n");
+ log(" wrmode 1 0 # set to '1' if this groups is write ports\n");
+ log(" enable 4 0 # number of enable bits (for write ports)\n");
+ log(" transp 0 2 # transparatent (for read ports)\n");
+ log(" clocks 1 2 # clock configuration\n");
+ log(" clkpol 2 2 # clock polarity configuration\n");
+ log(" endbram\n");
+ log("\n");
+ log("For the option 'transp' the value 0 means non-transparent, 1 means transparent\n");
+ log("and a value greater than 1 means configurable. All groups with the same\n");
+ log("value greater than 1 share the same configuration bit.\n");
+ log("\n");
+ log("For the option 'clocks' the value 0 means non-clocked, and a value greater\n");
+ log("than 0 means clocked. All groups with the same value share the same clock\n");
+ log("signal.\n");
+ log("\n");
+ log("For the option 'clkpol' the value 0 means negative edge, 1 means positive edge\n");
+ log("and a value greater than 1 means configurable. All groups with the same value\n");
+ log("greater than 1 share the same configuration bit.\n");
+ log("\n");
+ log("Using the same bram name in different bram blocks will create different variants\n");
+ log("of the bram. Verilog configration parameters for the bram are created as needed.\n");
+ log("\n");
+ log("It is also possible to create variants by repeating statements in the bram block\n");
+ log("and appending '@<label>' to the individual statements.\n");
+ log("\n");
+ log("A match rule looks like this:\n");
+ log("\n");
+ log(" match RAMB1024X32\n");
+ log(" max waste 16384 # only use this bram if <= 16k ram bits are unused\n");
+ log(" min efficiency 80 # only use this bram if efficiency is at least 80%%\n");
+ log(" endmatch\n");
+ log("\n");
+ log("It is possible to match against the following values with min/max rules:\n");
+ log("\n");
+ log(" words ........ number of words in memory in design\n");
+ log(" abits ........ number of address bits on memory in design\n");
+ log(" dbits ........ number of data bits on memory in design\n");
+ log(" wports ....... number of write ports on memory in design\n");
+ log(" rports ....... number of read ports on memory in design\n");
+ log(" ports ........ number of ports on memory in design\n");
+ log(" bits ......... number of bits in memory in design\n");
+ log(" dups .......... number of duplications for more read ports\n");
+ log("\n");
+ log(" awaste ....... number of unused address slots for this match\n");
+ log(" dwaste ....... number of unused data bits for this match\n");
+ log(" bwaste ....... number of unused bram bits for this match\n");
+ log(" waste ........ total number of unused bram bits (bwaste*dups)\n");
+ log(" efficiency ... total percentage of used and non-duplicated bits\n");
+ log("\n");
+ log(" acells ....... number of cells in 'address-direction'\n");
+ log(" dcells ....... number of cells in 'data-direction'\n");
+ log(" cells ........ total number of cells (acells*dcells*dups)\n");
+ log("\n");
+ log("The interface for the created bram instances is dervived from the bram\n");
+ log("description. Use 'techmap' to convert the created bram instances into\n");
+ log("instances of the actual bram cells of your target architecture.\n");
+ log("\n");
+ log("A match containing the command 'or_next_if_better' is only used if it\n");
+ log("has a higher efficiency than the next match (and the one after that if\n");
+ log("the next also has 'or_next_if_better' set, and so forth).\n");
+ log("\n");
+ log("A match containing the command 'make_transp' will add external circuitry\n");
+ log("to simulate 'transparent read', if necessary.\n");
+ log("\n");
+ log("A match containing the command 'shuffle_enable A' will re-organize\n");
+ log("the data bits to accommodate the enable pattern of port A.\n");
+ log("\n");
+ }
+ virtual void execute(vector<string> args, Design *design)
+ {
+ rules_t rules;
+
+ log_header("Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-rules" && argidx+1 < args.size()) {
+ rules.parse(args[++argidx]);
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules())
+ for (auto cell : mod->selected_cells())
+ if (cell->type == "$mem")
+ handle_cell(cell, rules);
+ }
+} MemoryBramPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 9c670f00..96d0ada0 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -17,13 +17,13 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/log.h"
-#include <sstream>
-#include <algorithm>
-#include <stdlib.h>
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
-static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
{
if (a->type == "$memrd" && b->type == "$memrd")
return a->name < b->name;
@@ -32,14 +32,15 @@ static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
return a->parameters.at("\\PRIORITY").as_int() < b->parameters.at("\\PRIORITY").as_int();
}
-static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
+void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
{
- log("Collecting $memrd and $memwr for memory `%s' in module `%s':\n",
+ log("Collecting $memrd, $memwr and $meminit for memory `%s' in module `%s':\n",
memory->name.c_str(), module->name.c_str());
int addr_bits = 0;
- while ((1 << addr_bits) < memory->size)
- addr_bits++;
+
+ Const init_data(State::Sx, memory->size * memory->width);
+ SigMap sigmap(module);
int wr_ports = 0;
RTLIL::SigSpec sig_wr_clk;
@@ -57,37 +58,64 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
RTLIL::SigSpec sig_rd_addr;
RTLIL::SigSpec sig_rd_data;
- std::vector<RTLIL::Cell*> del_cells;
std::vector<RTLIL::Cell*> memcells;
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
- if ((cell->type == "$memwr" || cell->type == "$memrd") && memory->name == cell->parameters["\\MEMID"].decode_string())
+ if (cell->type.in("$memrd", "$memwr", "$meminit") && memory->name == cell->parameters["\\MEMID"].decode_string()) {
+ addr_bits = std::max(addr_bits, cell->getParam("\\ABITS").as_int());
memcells.push_back(cell);
+ }
+ }
+
+ if (memcells.empty()) {
+ log(" no cells found. removing memory.\n");
+ return;
}
std::sort(memcells.begin(), memcells.end(), memcells_cmp);
for (auto cell : memcells)
{
- if (cell->type == "$memwr" && memory->name == cell->parameters["\\MEMID"].decode_string())
+ log(" %s (%s)\n", log_id(cell), log_id(cell->type));
+
+ if (cell->type == "$meminit")
{
- wr_ports++;
- del_cells.push_back(cell);
-
- RTLIL::SigSpec clk = cell->getPort("\\CLK");
- RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
- RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
- RTLIL::SigSpec addr = cell->getPort("\\ADDR");
- RTLIL::SigSpec data = cell->getPort("\\DATA");
- RTLIL::SigSpec en = cell->getPort("\\EN");
-
- clk.extend(1, false);
- clk_enable.extend(1, false);
- clk_polarity.extend(1, false);
- addr.extend(addr_bits, false);
- data.extend(memory->width, false);
- en.extend(memory->width, false);
+ SigSpec addr = sigmap(cell->getPort("\\ADDR"));
+ SigSpec data = sigmap(cell->getPort("\\DATA"));
+
+ if (!addr.is_fully_const())
+ log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr), log_id(cell));
+ if (!data.is_fully_const())
+ log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell));
+
+ int offset = (addr.as_int() - memory->start_offset) * memory->width;
+
+ if (offset < 0 || offset + GetSize(data) > GetSize(init_data))
+ log_warning("Address %s in memory initialization %s is out-of-bounds.\n", log_signal(addr), log_id(cell));
+
+ for (int i = 0; i < GetSize(data); i++)
+ if (0 <= i+offset && i+offset < GetSize(init_data))
+ init_data.bits[i+offset] = data[i].data;
+
+ continue;
+ }
+
+ if (cell->type == "$memwr")
+ {
+ SigSpec clk = sigmap(cell->getPort("\\CLK"));
+ SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
+ SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
+ SigSpec addr = sigmap(cell->getPort("\\ADDR"));
+ SigSpec data = sigmap(cell->getPort("\\DATA"));
+ SigSpec en = sigmap(cell->getPort("\\EN"));
+
+ clk.extend_u0(1, false);
+ clk_enable.extend_u0(1, false);
+ clk_polarity.extend_u0(1, false);
+ addr.extend_u0(addr_bits, false);
+ data.extend_u0(memory->width, false);
+ en.extend_u0(memory->width, false);
sig_wr_clk.append(clk);
sig_wr_clk_enable.append(clk_enable);
@@ -95,26 +123,26 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
sig_wr_addr.append(addr);
sig_wr_data.append(data);
sig_wr_en.append(en);
+
+ wr_ports++;
+ continue;
}
- if (cell->type == "$memrd" && memory->name == cell->parameters["\\MEMID"].decode_string())
+ if (cell->type == "$memrd")
{
- rd_ports++;
- del_cells.push_back(cell);
-
- RTLIL::SigSpec clk = cell->getPort("\\CLK");
- RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
- RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
- RTLIL::SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]);
- RTLIL::SigSpec addr = cell->getPort("\\ADDR");
- RTLIL::SigSpec data = cell->getPort("\\DATA");
-
- clk.extend(1, false);
- clk_enable.extend(1, false);
- clk_polarity.extend(1, false);
- transparent.extend(1, false);
- addr.extend(addr_bits, false);
- data.extend(memory->width, false);
+ SigSpec clk = sigmap(cell->getPort("\\CLK"));
+ SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
+ SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
+ SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]);
+ SigSpec addr = sigmap(cell->getPort("\\ADDR"));
+ SigSpec data = sigmap(cell->getPort("\\DATA"));
+
+ clk.extend_u0(1, false);
+ clk_enable.extend_u0(1, false);
+ clk_polarity.extend_u0(1, false);
+ transparent.extend_u0(1, false);
+ addr.extend_u0(addr_bits, false);
+ data.extend_u0(memory->width, false);
sig_rd_clk.append(clk);
sig_rd_clk_enable.append(clk_enable);
@@ -122,6 +150,9 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
sig_rd_transparent.append(transparent);
sig_rd_addr.append(addr);
sig_rd_data.append(data);
+
+ rd_ports++;
+ continue;
}
}
@@ -135,6 +166,10 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
mem->parameters["\\SIZE"] = RTLIL::Const(memory->size);
mem->parameters["\\ABITS"] = RTLIL::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);
log_assert(sig_wr_clk_enable.size() == wr_ports && sig_wr_clk_enable.is_fully_const());
log_assert(sig_wr_clk_polarity.size() == wr_ports && sig_wr_clk_polarity.is_fully_const());
@@ -166,7 +201,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
mem->setPort("\\RD_ADDR", sig_rd_addr);
mem->setPort("\\RD_DATA", sig_rd_data);
- for (auto c : del_cells)
+ for (auto c : memcells)
module->remove(c);
}
@@ -205,3 +240,4 @@ struct MemoryCollectPass : public Pass {
}
} MemoryCollectPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 302ab3ab..d3cc681a 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -22,13 +22,16 @@
#include <stdlib.h>
#include <sstream>
-static void normalize_sig(RTLIL::Module *module, RTLIL::SigSpec &sig)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void normalize_sig(RTLIL::Module *module, RTLIL::SigSpec &sig)
{
for (auto &conn : module->connections())
sig.replace(conn.first, conn.second);
}
-static bool find_sig_before_dff(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
+bool find_sig_before_dff(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
{
normalize_sig(module, sig);
@@ -66,7 +69,7 @@ static bool find_sig_before_dff(RTLIL::Module *module, std::vector<RTLIL::Cell*>
return true;
}
-static void handle_wr_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
+void handle_wr_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
{
log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
@@ -105,7 +108,7 @@ static void handle_wr_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff
log("no (compatible) $dff found.\n");
}
-static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
+void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
{
normalize_sig(module, sig);
sig.sort_and_unify();
@@ -123,7 +126,7 @@ static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
}
}
-static void handle_rd_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
+void handle_rd_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
{
log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
@@ -161,7 +164,7 @@ static void handle_rd_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff
log("no (compatible) $dff found.\n");
}
-static void handle_module(RTLIL::Module *module, bool flag_wr_only)
+void handle_module(RTLIL::Module *module, bool flag_wr_only)
{
std::vector<RTLIL::Cell*> dff_cells;
@@ -216,3 +219,4 @@ struct MemoryDffPass : public Pass {
}
} MemoryDffPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index eecb6f35..41c4a7b1 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -23,6 +23,9 @@
#include <set>
#include <stdlib.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct MemoryMapWorker
{
RTLIL::Design *design;
@@ -55,21 +58,21 @@ struct MemoryMapWorker
RTLIL::Wire *addr_decode(RTLIL::SigSpec addr_sig, RTLIL::SigSpec addr_val)
{
std::pair<RTLIL::SigSpec, RTLIL::SigSpec> key(addr_sig, addr_val);
- log_assert(SIZE(addr_sig) == SIZE(addr_val));
+ log_assert(GetSize(addr_sig) == GetSize(addr_val));
if (decoder_cache.count(key) == 0) {
- if (SIZE(addr_sig) < 2) {
+ if (GetSize(addr_sig) < 2) {
decoder_cache[key] = module->Eq(NEW_ID, addr_sig, addr_val);
} else {
- int split_at = SIZE(addr_sig) / 2;
+ int split_at = GetSize(addr_sig) / 2;
RTLIL::SigBit left_eq = addr_decode(addr_sig.extract(0, split_at), addr_val.extract(0, split_at));
- RTLIL::SigBit right_eq = addr_decode(addr_sig.extract(split_at, SIZE(addr_sig) - split_at), addr_val.extract(split_at, SIZE(addr_val) - split_at));
+ RTLIL::SigBit right_eq = addr_decode(addr_sig.extract(split_at, GetSize(addr_sig) - split_at), addr_val.extract(split_at, GetSize(addr_val) - split_at));
decoder_cache[key] = module->And(NEW_ID, left_eq, right_eq);
}
}
RTLIL::SigBit bit = decoder_cache.at(key);
- log_assert(bit.wire != nullptr && SIZE(bit.wire) == 1);
+ log_assert(bit.wire != nullptr && GetSize(bit.wire) == 1);
return bit.wire;
}
@@ -77,11 +80,15 @@ struct MemoryMapWorker
{
std::set<int> static_ports;
std::map<int, RTLIL::SigSpec> static_cells_map;
+
int mem_size = cell->parameters["\\SIZE"].as_int();
int mem_width = cell->parameters["\\WIDTH"].as_int();
int mem_offset = cell->parameters["\\OFFSET"].as_int();
int mem_abits = cell->parameters["\\ABITS"].as_int();
+ SigSpec init_data = cell->getParam("\\INIT");
+ init_data.extend_u0(mem_size*mem_width, true);
+
// delete unused memory cell
if (cell->parameters["\\RD_PORTS"].as_int() == 0 && cell->parameters["\\WR_PORTS"].as_int() == 0) {
module->remove(cell);
@@ -107,7 +114,7 @@ struct MemoryMapWorker
// FIXME: Actually we should check for wr_en.is_fully_const() also and
// create a $adff cell with this ports wr_en input as reset pin when wr_en
// is not a simple static 1.
- static_cells_map[wr_addr.as_int()] = wr_data;
+ static_cells_map[wr_addr.as_int() - mem_offset] = wr_data;
static_ports.insert(i);
continue;
}
@@ -162,7 +169,10 @@ struct MemoryMapWorker
w_out_name = genid(cell->name, "", i, "$q");
RTLIL::Wire *w_out = module->addWire(w_out_name, mem_width);
- w_out->start_offset = mem_offset;
+ SigSpec w_init = init_data.extract(i*mem_width, mem_width);
+
+ if (!w_init.is_fully_undef())
+ w_out->attributes["\\init"] = w_init.as_const();
data_reg_out.push_back(RTLIL::SigSpec(w_out));
c->setPort("\\Q", data_reg_out.back());
@@ -177,6 +187,9 @@ struct MemoryMapWorker
{
RTLIL::SigSpec rd_addr = cell->getPort("\\RD_ADDR").extract(i*mem_abits, mem_abits);
+ if (mem_offset)
+ rd_addr = module->Sub(NEW_ID, rd_addr, SigSpec(mem_offset, GetSize(rd_addr)));
+
std::vector<RTLIL::SigSpec> rd_signals;
rd_signals.push_back(cell->getPort("\\RD_DATA").extract(i*mem_width, mem_width));
@@ -253,6 +266,10 @@ struct MemoryMapWorker
RTLIL::SigSpec wr_addr = cell->getPort("\\WR_ADDR").extract(j*mem_abits, mem_abits);
RTLIL::SigSpec wr_data = cell->getPort("\\WR_DATA").extract(j*mem_width, mem_width);
RTLIL::SigSpec wr_en = cell->getPort("\\WR_EN").extract(j*mem_width, mem_width);
+
+ if (mem_offset)
+ wr_addr = module->Sub(NEW_ID, wr_addr, SigSpec(mem_offset, GetSize(wr_addr)));
+
RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i, mem_abits));
int wr_offset = 0;
@@ -339,3 +356,4 @@ struct MemoryMapPass : public Pass {
}
} MemoryMapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index 3ae0cd2c..3d241433 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -22,9 +22,10 @@
#include "kernel/sigtools.h"
#include "kernel/modtools.h"
+USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
+bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
{
if (a->type == "$memrd" && b->type == "$memrd")
return a->name < b->name;
@@ -488,8 +489,8 @@ struct MemoryShareWorker
if (wr_ports.size() <= 1)
return;
- ezDefaultSAT ez;
- SatGen satgen(&ez, &modwalker.sigmap);
+ ezSatPtr ez;
+ SatGen satgen(ez.get(), &modwalker.sigmap);
// find list of considered ports and port pairs
@@ -543,6 +544,7 @@ struct MemoryShareWorker
// create SAT representation of common input cone of all considered EN signals
+ pool<Wire*> one_hot_wires;
std::set<RTLIL::Cell*> sat_cells;
std::set<RTLIL::SigBit> bits_queue;
std::map<int, int> port_to_sat_variable;
@@ -551,7 +553,7 @@ struct MemoryShareWorker
if (considered_port_pairs.count(i) || considered_port_pairs.count(i+1))
{
RTLIL::SigSpec sig = modwalker.sigmap(wr_ports[i]->getPort("\\EN"));
- port_to_sat_variable[i] = ez.expression(ez.OpOr, satgen.importSigSpec(sig));
+ port_to_sat_variable[i] = ez->expression(ez->OpOr, satgen.importSigSpec(sig));
std::vector<RTLIL::SigBit> bits = sig;
bits_queue.insert(bits.begin(), bits.end());
@@ -559,24 +561,36 @@ struct MemoryShareWorker
while (!bits_queue.empty())
{
- std::set<ModWalker::PortBit> portbits;
+ for (auto bit : bits_queue)
+ if (bit.wire && bit.wire->get_bool_attribute("\\onehot"))
+ one_hot_wires.insert(bit.wire);
+
+ pool<ModWalker::PortBit> portbits;
modwalker.get_drivers(portbits, bits_queue);
bits_queue.clear();
for (auto &pbit : portbits)
if (sat_cells.count(pbit.cell) == 0 && cone_ct.cell_known(pbit.cell->type)) {
- std::set<RTLIL::SigBit> &cell_inputs = modwalker.cell_inputs[pbit.cell];
+ pool<RTLIL::SigBit> &cell_inputs = modwalker.cell_inputs[pbit.cell];
bits_queue.insert(cell_inputs.begin(), cell_inputs.end());
sat_cells.insert(pbit.cell);
}
}
+ for (auto wire : one_hot_wires) {
+ log(" Adding one-hot constraint for wire %s.\n", log_id(wire));
+ vector<int> ez_wire_bits = satgen.importSigSpec(wire);
+ for (int i : ez_wire_bits)
+ for (int j : ez_wire_bits)
+ if (i != j) ez->assume(ez->NOT(i), j);
+ }
+
log(" Common input cone for all EN signals: %d cells.\n", int(sat_cells.size()));
for (auto cell : sat_cells)
satgen.importCell(cell);
- log(" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez.numCnfVariables(), ez.numCnfClauses());
+ log(" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez->numCnfVariables(), ez->numCnfClauses());
// merge subsequent ports if possible
@@ -585,13 +599,13 @@ struct MemoryShareWorker
if (!considered_port_pairs.count(i))
continue;
- if (ez.solve(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i))) {
+ if (ez->solve(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i))) {
log(" According to SAT solver sharing of port %d with port %d is not possible.\n", i-1, i);
continue;
}
log(" Merging port %d into port %d.\n", i-1, i);
- port_to_sat_variable.at(i) = ez.OR(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i));
+ port_to_sat_variable.at(i) = ez->OR(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i));
RTLIL::SigSpec last_addr = wr_ports[i-1]->getPort("\\ADDR");
RTLIL::SigSpec last_data = wr_ports[i-1]->getPort("\\DATA");
@@ -741,4 +755,3 @@ struct MemorySharePass : public Pass {
} MemorySharePass;
PRIVATE_NAMESPACE_END
-
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 5a4c4eac..e650facb 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -23,7 +23,10 @@
#include <algorithm>
#include <stdlib.h>
-static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
{
log("Creating $memrd and $memwr for memory `%s' in module `%s':\n",
memory->name.c_str(), module->name.c_str());
@@ -76,7 +79,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
module->remove(memory);
}
-static void handle_module(RTLIL::Design *design, RTLIL::Module *module)
+void handle_module(RTLIL::Design *design, RTLIL::Module *module)
{
std::vector<RTLIL::IdString> memcells;
for (auto &cell_it : module->cells_)
@@ -107,3 +110,4 @@ struct MemoryUnpackPass : public Pass {
}
} MemoryUnpackPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 3a8d27f9..6b075cd9 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -6,6 +6,9 @@ OBJS += passes/opt/opt_reduce.o
OBJS += passes/opt/opt_rmdff.o
OBJS += passes/opt/opt_clean.o
OBJS += passes/opt/opt_const.o
+
+ifneq ($(SMALL),1)
OBJS += passes/opt/share.o
OBJS += passes/opt/wreduce.o
+endif
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index b20521d1..5ca57a14 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -22,6 +22,9 @@
#include <stdlib.h>
#include <stdio.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct OptPass : public Pass {
OptPass() : Pass("opt", "perform simple optimizations") { }
virtual void help()
@@ -34,22 +37,22 @@ struct OptPass : public Pass {
log("a series of trivial optimizations and cleanups. This pass executes the other\n");
log("passes in the following order:\n");
log("\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]\n");
log(" opt_share -nomux\n");
log("\n");
log(" do\n");
log(" opt_muxtree\n");
- log(" opt_reduce [-fine]\n");
+ log(" opt_reduce [-fine] [-full]\n");
log(" opt_share\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]\n");
log(" while <changed design>\n");
log("\n");
log("When called with -fast the following script is used instead:\n");
log("\n");
log(" do\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]\n");
log(" opt_share\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
@@ -93,6 +96,11 @@ struct OptPass : public Pass {
opt_reduce_args += " -fine";
continue;
}
+ if (args[argidx] == "-full") {
+ opt_const_args += " -full";
+ opt_reduce_args += " -full";
+ continue;
+ }
if (args[argidx] == "-keepdc") {
opt_const_args += " -keepdc";
continue;
@@ -137,8 +145,13 @@ struct OptPass : public Pass {
}
}
- log_header(fast_mode ? "Finished fast OPT passes." : "Finished OPT passes. (There is nothing left to do.)\n");
+ design->optimize();
+ design->sort();
+ design->check();
+
+ log_header(fast_mode ? "Finished fast OPT passes.\n" : "Finished OPT passes. (There is nothing left to do.)\n");
log_pop();
}
} OptPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 5046752f..9d2a262a 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -25,65 +25,61 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
-static CellTypes ct, ct_reg, ct_all;
-static int count_rm_cells, count_rm_wires;
+CellTypes ct, ct_reg, ct_all;
+int count_rm_cells, count_rm_wires;
-static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
+void rmunused_module_cells(Module *module, bool verbose)
{
- SigMap assign_map(module);
- std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> queue, unused;
+ SigMap sigmap(module);
+ pool<Cell*> queue, unused;
+ dict<SigBit, pool<Cell*>> wire2driver;
- SigSet<RTLIL::Cell*> wire2driver;
for (auto &it : module->cells_) {
- RTLIL::Cell *cell = it.second;
+ Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
- if (!ct.cell_input(cell->type, it2.first)) {
- RTLIL::SigSpec sig = it2.second;
- assign_map.apply(sig);
- wire2driver.insert(sig, cell);
- }
+ if (!ct.cell_input(cell->type, it2.first))
+ for (auto bit : sigmap(it2.second))
+ if (bit.wire != nullptr)
+ wire2driver[bit].insert(cell);
}
- if (cell->type == "$memwr" || cell->type == "$assert" || cell->get_bool_attribute("\\keep"))
+ if (cell->type.in("$memwr", "$meminit", "$assert", "$assume") || cell->has_keep_attr())
queue.insert(cell);
- unused.insert(cell);
+ else
+ unused.insert(cell);
}
for (auto &it : module->wires_) {
- RTLIL::Wire *wire = it.second;
+ Wire *wire = it.second;
if (wire->port_output || wire->get_bool_attribute("\\keep")) {
- std::set<RTLIL::Cell*> cell_list;
- RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
- assign_map.apply(sig);
- wire2driver.find(sig, cell_list);
- for (auto cell : cell_list)
- queue.insert(cell);
+ for (auto bit : sigmap(wire))
+ for (auto c : wire2driver[bit])
+ queue.insert(c), unused.erase(c);
}
}
- while (queue.size() > 0)
+ while (!queue.empty())
{
- std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> new_queue;
+ pool<SigBit> bits;
for (auto cell : queue)
- unused.erase(cell);
- for (auto cell : queue) {
- for (auto &it : cell->connections()) {
- if (!ct.cell_output(cell->type, it.first)) {
- std::set<RTLIL::Cell*> cell_list;
- RTLIL::SigSpec sig = it.second;
- assign_map.apply(sig);
- wire2driver.find(sig, cell_list);
- for (auto cell : cell_list) {
- if (unused.count(cell) > 0)
- new_queue.insert(cell);
- }
- }
- }
- }
- queue.swap(new_queue);
+ for (auto &it : cell->connections())
+ if (!ct.cell_output(cell->type, it.first))
+ for (auto bit : sigmap(it.second))
+ bits.insert(bit);
+
+ queue.clear();
+ for (auto bit : bits)
+ for (auto c : wire2driver[bit])
+ if (unused.count(c))
+ queue.insert(c), unused.erase(c);
}
+ unused.sort(RTLIL::sort_by_name_id<RTLIL::Cell>());
+
for (auto cell : unused) {
if (verbose)
log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
@@ -93,7 +89,7 @@ static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
}
}
-static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
+int count_nontrivial_wire_attrs(RTLIL::Wire *w)
{
int count = w->attributes.size();
count -= w->attributes.count("\\src");
@@ -101,7 +97,7 @@ static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
return count;
}
-static bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPool &conns, std::set<RTLIL::Wire*> &direct_wires)
+bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPool &conns, pool<RTLIL::Wire*> &direct_wires)
{
RTLIL::Wire *w1 = s1.wire;
RTLIL::Wire *w2 = s2.wire;
@@ -116,7 +112,7 @@ static bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs,
if (regs.check_any(s1) != regs.check_any(s2))
return regs.check_any(s2);
if (direct_wires.count(w1) != direct_wires.count(w2))
- return direct_wires.count(w2);
+ return direct_wires.count(w2) != 0;
if (conns.check_any(s1) != conns.check_any(s2))
return conns.check_any(s2);
}
@@ -136,7 +132,7 @@ static bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs,
return w2->name < w1->name;
}
-static bool check_public_name(RTLIL::IdString id)
+bool check_public_name(RTLIL::IdString id)
{
const std::string &id_str = id.str();
if (id_str[0] == '$')
@@ -148,7 +144,7 @@ static bool check_public_name(RTLIL::IdString id)
return true;
}
-static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
+void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
{
SigPool register_signals;
SigPool connected_signals;
@@ -165,8 +161,8 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
}
SigMap assign_map(module);
- std::set<RTLIL::SigSpec> direct_sigs;
- std::set<RTLIL::Wire*> direct_wires;
+ pool<RTLIL::SigSpec> direct_sigs;
+ pool<RTLIL::Wire*> direct_wires;
for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
if (ct_all.cell_known(cell->type))
@@ -226,9 +222,9 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
maybe_del_wires.push_back(wire);
} else {
- log_assert(SIZE(s1) == SIZE(s2));
+ log_assert(GetSize(s1) == GetSize(s2));
RTLIL::SigSig new_conn;
- for (int i = 0; i < SIZE(s1); i++)
+ for (int i = 0; i < GetSize(s1); i++)
if (s1[i] != s2[i]) {
new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]);
@@ -247,7 +243,7 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
if (!used_signals_nodrivers.check_any(sig)) {
std::string unused_bits;
- for (int i = 0; i < SIZE(sig); i++) {
+ for (int i = 0; i < GetSize(sig); i++) {
if (sig[i].wire == NULL)
continue;
if (!used_signals_nodrivers.check(sig[i])) {
@@ -266,7 +262,7 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
}
- std::set<RTLIL::Wire*> del_wires;
+ pool<RTLIL::Wire*> del_wires;
int del_wires_count = 0;
for (auto wire : maybe_del_wires)
@@ -285,11 +281,30 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
log(" removed %d unused temporary wires.\n", del_wires_count);
}
-static void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
+void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
{
if (verbose)
log("Finding unused cells or wires in module %s..\n", module->name.c_str());
+ std::vector<RTLIL::Cell*> delcells;
+ for (auto cell : module->cells())
+ if (cell->type.in("$pos", "$_BUF_")) {
+ bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool();
+ RTLIL::SigSpec a = cell->getPort("\\A");
+ RTLIL::SigSpec y = cell->getPort("\\Y");
+ a.extend_u0(GetSize(y), is_signed);
+ module->connect(y, a);
+ delcells.push_back(cell);
+ }
+ for (auto cell : delcells) {
+ if (verbose)
+ log(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
+ log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A")));
+ module->remove(cell);
+ }
+ if (!delcells.empty())
+ module->design->scratchpad_set_bool("opt.did_something", true);
+
rmunused_module_cells(module, verbose);
rmunused_module_signals(module, purge_mode, verbose);
}
@@ -338,19 +353,16 @@ struct OptCleanPass : public Pass {
ct_reg.setup_internals_mem();
ct_reg.setup_stdcells_mem();
- for (auto &mod_it : design->modules_) {
- if (!design->selected_whole_module(mod_it.first)) {
- if (design->selected(mod_it.second))
- log("Skipping module %s as it is only partially selected.\n", id2cstr(mod_it.second->name));
+ for (auto module : design->selected_whole_modules_warn()) {
+ if (module->has_processes_warn())
continue;
- }
- if (mod_it.second->processes.size() > 0) {
- log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
- } else {
- rmunused_module(mod_it.second, purge_mode, true);
- }
+ rmunused_module(module, purge_mode, true);
}
+ design->optimize();
+ design->sort();
+ design->check();
+
ct.clear();
ct_reg.clear();
log_pop();
@@ -402,20 +414,23 @@ struct CleanPass : public Pass {
count_rm_cells = 0;
count_rm_wires = 0;
- for (auto &mod_it : design->modules_) {
- if (design->selected_whole_module(mod_it.first) && mod_it.second->processes.size() == 0)
- do {
- design->scratchpad_unset("opt.did_something");
- rmunused_module(mod_it.second, purge_mode, false);
- } while (design->scratchpad_get_bool("opt.did_something"));
+ for (auto module : design->selected_whole_modules()) {
+ if (module->has_processes())
+ continue;
+ rmunused_module(module, purge_mode, false);
}
if (count_rm_cells > 0 || count_rm_wires > 0)
log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires);
+ design->optimize();
+ design->sort();
+ design->check();
+
ct.clear();
ct_reg.clear();
ct_all.clear();
}
} CleanPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc
index f9b78c05..1758a34f 100644
--- a/passes/opt/opt_const.cc
+++ b/passes/opt/opt_const.cc
@@ -26,9 +26,12 @@
#include <stdio.h>
#include <algorithm>
-static bool did_something;
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
-static void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
+bool did_something;
+
+void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
{
CellTypes ct(design);
SigMap sigmap(module);
@@ -70,7 +73,7 @@ static void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
}
}
-static void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
+void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
{
RTLIL::SigSpec Y = cell->getPort(out_port);
out_val.extend_u0(Y.size(), false);
@@ -85,7 +88,7 @@ static void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell
did_something = true;
}
-static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
+bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
{
std::string b_name = cell->hasPort("\\B") ? "\\B" : "\\A";
@@ -104,7 +107,7 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com
enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_N };
std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, std::set<RTLIL::SigBit>> grouped_bits[GRP_N];
- for (int i = 0; i < SIZE(bits_y); i++)
+ for (int i = 0; i < GetSize(bits_y); i++)
{
int group_idx = GRP_DYN;
RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
@@ -128,7 +131,7 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com
}
for (int i = 0; i < GRP_N; i++)
- if (SIZE(grouped_bits[i]) == SIZE(bits_y))
+ if (GetSize(grouped_bits[i]) == GetSize(bits_y))
return false;
log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
@@ -139,7 +142,7 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com
if (grouped_bits[i].empty())
continue;
- RTLIL::Wire *new_y = module->addWire(NEW_ID, SIZE(grouped_bits[i]));
+ RTLIL::Wire *new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i]));
RTLIL::SigSpec new_a, new_b;
RTLIL::SigSig new_conn;
@@ -183,7 +186,7 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com
return true;
}
-static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc)
+void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc)
{
if (!design->selected(module))
return;
@@ -193,11 +196,11 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
ct_combinational.setup_stdcells();
SigMap assign_map(module);
- std::map<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
+ dict<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
- TopoSort<RTLIL::Cell*> cells;
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
+ TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
+ dict<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
+ dict<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
for (auto cell : module->cells())
if (design->selected(module, cell) && cell->type[0] == '$') {
@@ -483,12 +486,12 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
RTLIL::SigSpec new_a, new_b;
- log_assert(SIZE(a) == SIZE(b));
- for (int i = 0; i < SIZE(a); i++) {
+ log_assert(GetSize(a) == GetSize(b));
+ for (int i = 0; i < GetSize(a); i++) {
if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) {
cover_list("opt.opt_const.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1);
- new_y.extend(cell->parameters["\\Y_WIDTH"].as_int(), false);
+ new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y);
goto next_cell;
}
@@ -501,7 +504,7 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
if (new_a.size() == 0) {
cover_list("opt.opt_const.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0);
- new_y.extend(cell->parameters["\\Y_WIDTH"].as_int(), false);
+ new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "empty", "\\Y", new_y);
goto next_cell;
}
@@ -521,11 +524,11 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
- if (a.is_fully_const()) {
+ if (a.is_fully_const() && !b.is_fully_const()) {
cover_list("opt.opt_const.eqneq.swapconst", "$eq", "$ne", cell->type.str());
- RTLIL::SigSpec tmp = cell->getPort("\\A");
- cell->setPort("\\A", cell->getPort("\\B"));
- cell->setPort("\\B", tmp);
+ cell->setPort("\\A", b);
+ cell->setPort("\\B", a);
+ std::swap(a, b);
}
if (b.is_fully_const()) {
@@ -556,15 +559,15 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
RTLIL::SigSpec sig_y(cell->type == "$shiftx" ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam("\\Y_WIDTH").as_int());
- if (SIZE(sig_a) < SIZE(sig_y))
- sig_a.extend(SIZE(sig_y), cell->getParam("\\A_SIGNED").as_bool());
+ if (GetSize(sig_a) < GetSize(sig_y))
+ sig_a.extend_u0(GetSize(sig_y), cell->getParam("\\A_SIGNED").as_bool());
- for (int i = 0; i < SIZE(sig_y); i++) {
+ for (int i = 0; i < GetSize(sig_y); i++) {
int idx = i + shift_bits;
- if (0 <= idx && idx < SIZE(sig_a))
+ if (0 <= idx && idx < GetSize(sig_a))
sig_y[i] = sig_a[idx];
- else if (SIZE(sig_a) <= idx && sign_ext)
- sig_y[i] = sig_a[SIZE(sig_a)-1];
+ else if (GetSize(sig_a) <= idx && sign_ext)
+ sig_y[i] = sig_a[GetSize(sig_a)-1];
}
cover_list("opt.opt_const.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
@@ -666,8 +669,9 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
cell->unsetPort("\\B");
cell->unsetPort("\\S");
if (cell->type == "$mux") {
- cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\Y_WIDTH"] = cell->parameters["\\WIDTH"];
+ Const width = cell->parameters["\\WIDTH"];
+ cell->parameters["\\A_WIDTH"] = width;
+ cell->parameters["\\Y_WIDTH"] = width;
cell->parameters["\\A_SIGNED"] = 0;
cell->parameters.erase("\\WIDTH");
cell->type = "$not";
@@ -683,9 +687,10 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\S");
if (cell->type == "$mux") {
- cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\B_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\Y_WIDTH"] = cell->parameters["\\WIDTH"];
+ Const width = cell->parameters["\\WIDTH"];
+ cell->parameters["\\A_WIDTH"] = width;
+ cell->parameters["\\B_WIDTH"] = width;
+ cell->parameters["\\Y_WIDTH"] = width;
cell->parameters["\\A_SIGNED"] = 0;
cell->parameters["\\B_SIGNED"] = 0;
cell->parameters.erase("\\WIDTH");
@@ -702,9 +707,10 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
cell->setPort("\\B", cell->getPort("\\S"));
cell->unsetPort("\\S");
if (cell->type == "$mux") {
- cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\B_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\Y_WIDTH"] = cell->parameters["\\WIDTH"];
+ Const width = cell->parameters["\\WIDTH"];
+ cell->parameters["\\A_WIDTH"] = width;
+ cell->parameters["\\B_WIDTH"] = width;
+ cell->parameters["\\Y_WIDTH"] = width;
cell->parameters["\\A_SIGNED"] = 0;
cell->parameters["\\B_SIGNED"] = 0;
cell->parameters.erase("\\WIDTH");
@@ -751,7 +757,7 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
if (cell->getPort("\\S").size() != new_s.size()) {
cover_list("opt.opt_const.mux_reduce", "$mux", "$pmux", cell->type.str());
log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
- SIZE(cell->getPort("\\S")) - SIZE(new_s), log_id(cell->type), log_id(cell), log_id(module));
+ GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", new_a);
cell->setPort("\\B", new_b);
cell->setPort("\\S", new_s);
@@ -891,17 +897,17 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
if (!swapped_ab) {
cell->setPort("\\A", cell->getPort("\\B"));
- cell->parameters["\\A_WIDTH"] = cell->parameters["\\B_WIDTH"];
- cell->parameters["\\A_SIGNED"] = cell->parameters["\\B_SIGNED"];
+ cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH");
+ cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED");
}
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
- while (SIZE(new_b) > 1 && new_b.back() == RTLIL::State::S0)
+ while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
new_b.pop_back();
cell->type = "$shl";
- cell->parameters["\\B_WIDTH"] = SIZE(new_b);
+ cell->parameters["\\B_WIDTH"] = GetSize(new_b);
cell->parameters["\\B_SIGNED"] = false;
cell->setPort("\\B", new_b);
cell->check();
@@ -939,15 +945,18 @@ struct OptConstPass : public Pass {
log(" -undriven\n");
log(" replace undriven nets with undef (x) constants\n");
log("\n");
+ log(" -fine\n");
+ log(" perform fine-grain optimizations\n");
+ log("\n");
+ log(" -full\n");
+ log(" alias for -mux_undef -mux_bool -undriven -fine\n");
+ log("\n");
log(" -keepdc\n");
log(" some optimizations change the behavior of the circuit with respect to\n");
log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
log("\n");
- log(" -fine\n");
- log(" perform fine-grain optimizations\n");
- log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -978,6 +987,13 @@ struct OptConstPass : public Pass {
do_fine = true;
continue;
}
+ if (args[argidx] == "-full") {
+ mux_undef = true;
+ mux_bool = true;
+ undriven = true;
+ do_fine = true;
+ continue;
+ }
if (args[argidx] == "-keepdc") {
keepdc = true;
continue;
@@ -986,7 +1002,7 @@ struct OptConstPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto module : design->modules())
+ for (auto module : design->selected_modules())
{
if (undriven)
replace_undriven(design, module);
@@ -1006,3 +1022,4 @@ struct OptConstPass : public Pass {
}
} OptConstPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 2c5dcf66..98287074 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -25,6 +25,9 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
struct OptMuxtreeWorker
@@ -34,37 +37,33 @@ struct OptMuxtreeWorker
SigMap assign_map;
int removed_count;
- struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
- bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
- bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
- };
-
-
struct bitinfo_t {
- int num;
- bitDef_t bit;
bool seen_non_mux;
- std::vector<int> mux_users;
- std::vector<int> mux_drivers;
+ pool<int> mux_users;
+ pool<int> mux_drivers;
};
- std::map<bitDef_t, int> bit2num;
- std::vector<bitinfo_t> bit2info;
+ idict<SigBit> bit2num;
+ vector<bitinfo_t> bit2info;
struct portinfo_t {
- std::vector<int> ctrl_sigs;
- std::vector<int> input_sigs;
- std::vector<int> input_muxes;
+ int ctrl_sig;
+ pool<int> input_sigs;
+ pool<int> input_muxes;
bool const_activated;
+ bool const_deactivated;
bool enabled;
};
struct muxinfo_t {
RTLIL::Cell *cell;
- std::vector<portinfo_t> ports;
+ vector<portinfo_t> ports;
};
- std::vector<muxinfo_t> mux2info;
+ vector<muxinfo_t> mux2info;
+ vector<bool> root_muxes;
+ vector<bool> root_enable_muxes;
+ pool<int> root_mux_rerun;
OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) :
design(design), module(module), assign_map(module), removed_count(0)
@@ -78,9 +77,10 @@ struct OptMuxtreeWorker
// .mux_users
// .mux_drivers
// Populate mux2info[].ports[]:
- // .ctrl_sigs
+ // .ctrl_sig
// .input_sigs
// .const_activated
+ // .const_deactivated
for (auto cell : module->cells())
{
if (cell->type == "$mux" || cell->type == "$pmux")
@@ -93,32 +93,34 @@ struct OptMuxtreeWorker
muxinfo_t muxinfo;
muxinfo.cell = cell;
- for (int i = 0; i < sig_s.size(); i++) {
- RTLIL::SigSpec sig = sig_b.extract(i*sig_a.size(), sig_a.size());
+ for (int i = 0; i < GetSize(sig_s); i++) {
+ RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1));
portinfo_t portinfo;
+ portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front();
for (int idx : sig2bits(sig)) {
- add_to_list(bit2info[idx].mux_users, mux2info.size());
- add_to_list(portinfo.input_sigs, idx);
+ bit2info[idx].mux_users.insert(GetSize(mux2info));
+ portinfo.input_sigs.insert(idx);
}
- for (int idx : sig2bits(ctrl_sig))
- add_to_list(portinfo.ctrl_sigs, idx);
portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool();
+ portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool();
portinfo.enabled = false;
muxinfo.ports.push_back(portinfo);
}
portinfo_t portinfo;
for (int idx : sig2bits(sig_a)) {
- add_to_list(bit2info[idx].mux_users, mux2info.size());
- add_to_list(portinfo.input_sigs, idx);
+ bit2info[idx].mux_users.insert(GetSize(mux2info));
+ portinfo.input_sigs.insert(idx);
}
+ portinfo.ctrl_sig = -1;
portinfo.const_activated = false;
+ portinfo.const_deactivated = false;
portinfo.enabled = false;
muxinfo.ports.push_back(portinfo);
for (int idx : sig2bits(sig_y))
- add_to_list(bit2info[idx].mux_drivers, mux2info.size());
+ bit2info[idx].mux_drivers.insert(GetSize(mux2info));
for (int idx : sig2bits(sig_s))
bit2info[idx].seen_non_mux = true;
@@ -139,53 +141,78 @@ struct OptMuxtreeWorker
bit2info[idx].seen_non_mux = true;
}
- if (mux2info.size() == 0) {
+ if (mux2info.empty()) {
log(" No muxes found in this module.\n");
return;
}
// Populate mux2info[].ports[]:
// .input_muxes
- for (size_t i = 0; i < bit2info.size(); i++)
+ for (int i = 0; i < GetSize(bit2info); i++)
for (int j : bit2info[i].mux_users)
for (auto &p : mux2info[j].ports) {
- if (is_in_list(p.input_sigs, i))
+ if (p.input_sigs.count(i))
for (int k : bit2info[i].mux_drivers)
- add_to_list(p.input_muxes, k);
+ p.input_muxes.insert(k);
}
log(" Evaluating internal representation of mux trees.\n");
- std::set<int> root_muxes;
+ dict<int, pool<int>> mux_to_users;
+ root_muxes.resize(GetSize(mux2info));
+ root_enable_muxes.resize(GetSize(mux2info));
+
for (auto &bi : bit2info) {
+ for (int i : bi.mux_drivers)
+ for (int j : bi.mux_users)
+ mux_to_users[i].insert(j);
if (!bi.seen_non_mux)
continue;
- for (int mux_idx : bi.mux_drivers)
- root_muxes.insert(mux_idx);
+ for (int mux_idx : bi.mux_drivers) {
+ root_muxes.at(mux_idx) = true;
+ root_enable_muxes.at(mux_idx) = true;
+ }
}
- for (int mux_idx : root_muxes)
+
+ for (auto &it : mux_to_users)
+ if (GetSize(it.second) > 1)
+ root_muxes.at(it.first) = true;
+
+ for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++)
+ if (root_muxes.at(mux_idx)) {
+ log(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
+ root_mux_rerun.erase(mux_idx);
+ eval_root_mux(mux_idx);
+ }
+
+ while (!root_mux_rerun.empty()) {
+ int mux_idx = *root_mux_rerun.begin();
+ log(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell));
+ log_assert(root_enable_muxes.at(mux_idx));
+ root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
+ }
log(" Analyzing evaluation results.\n");
for (auto &mi : mux2info)
{
- std::vector<int> live_ports;
- for (size_t port_idx = 0; port_idx < mi.ports.size(); port_idx++) {
+ vector<int> live_ports;
+ for (int port_idx = 0; port_idx < GetSize(mi.ports); port_idx++) {
portinfo_t &pi = mi.ports[port_idx];
if (pi.enabled) {
live_ports.push_back(port_idx);
} else {
- log(" dead port %zd/%zd on %s %s.\n", port_idx+1, mi.ports.size(),
+ log(" dead port %d/%d on %s %s.\n", port_idx+1, GetSize(mi.ports),
mi.cell->type.c_str(), mi.cell->name.c_str());
removed_count++;
}
}
- if (live_ports.size() == mi.ports.size())
+ if (GetSize(live_ports) == GetSize(mi.ports))
continue;
- if (live_ports.size() == 0) {
+ if (live_ports.empty()) {
module->remove(mi.cell);
continue;
}
@@ -198,9 +225,9 @@ struct OptMuxtreeWorker
RTLIL::SigSpec sig_ports = sig_b;
sig_ports.append(sig_a);
- if (live_ports.size() == 1)
+ if (GetSize(live_ports) == 1)
{
- RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[0]*sig_a.size(), sig_a.size());
+ RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[0]*GetSize(sig_a), GetSize(sig_a));
module->connect(RTLIL::SigSig(sig_y, sig_in));
module->remove(mi.cell);
}
@@ -208,9 +235,9 @@ struct OptMuxtreeWorker
{
RTLIL::SigSpec new_sig_a, new_sig_b, new_sig_s;
- for (size_t i = 0; i < live_ports.size(); i++) {
- RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[i]*sig_a.size(), sig_a.size());
- if (i == live_ports.size()-1) {
+ for (int i = 0; i < GetSize(live_ports); i++) {
+ RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[i]*GetSize(sig_a), GetSize(sig_a));
+ if (i == GetSize(live_ports)-1) {
new_sig_a = sig_in;
} else {
new_sig_b.append(sig_in);
@@ -221,123 +248,162 @@ struct OptMuxtreeWorker
mi.cell->setPort("\\A", new_sig_a);
mi.cell->setPort("\\B", new_sig_b);
mi.cell->setPort("\\S", new_sig_s);
- if (new_sig_s.size() == 1) {
+ if (GetSize(new_sig_s) == 1) {
mi.cell->type = "$mux";
mi.cell->parameters.erase("\\S_WIDTH");
} else {
- mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.size());
+ mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(GetSize(new_sig_s));
}
}
}
}
- bool list_is_subset(const std::vector<int> &sub, const std::vector<int> &super)
+ vector<int> sig2bits(RTLIL::SigSpec sig, bool skip_non_wires = true)
{
- for (int v : sub)
- if (!is_in_list(super, v))
- return false;
- return true;
- }
-
- bool is_in_list(const std::vector<int> &list, int value)
- {
- for (int v : list)
- if (v == value)
- return true;
- return false;
- }
-
- void add_to_list(std::vector<int> &list, int value)
- {
- if (!is_in_list(list, value))
- list.push_back(value);
- }
-
- std::vector<int> sig2bits(RTLIL::SigSpec sig)
- {
- std::vector<int> results;
+ vector<int> results;
assign_map.apply(sig);
for (auto &bit : sig)
if (bit.wire != NULL) {
if (bit2num.count(bit) == 0) {
bitinfo_t info;
- info.num = bit2info.size();
- info.bit = bit;
info.seen_non_mux = false;
+ bit2num.expect(bit, GetSize(bit2info));
bit2info.push_back(info);
- bit2num[info.bit] = info.num;
}
- results.push_back(bit2num[bit]);
- }
+ results.push_back(bit2num.at(bit));
+ } else if (!skip_non_wires)
+ results.push_back(-1);
return results;
}
struct knowledge_t
{
// database of known inactive signals
- // the 2nd integer is a reference counter used to manage the
+ // the payload is a reference counter used to manage the
// list. when it is non-zero the signal in known to be inactive
- std::map<int, int> known_inactive;
+ vector<int> known_inactive;
// database of known active signals
- // the 2nd dimension is the list of or-ed signals. so we know that
- // for each i there is a j so that known_active[i][j] points to an
- // inactive control signal.
- std::vector<std::vector<int>> known_active;
+ vector<int> known_active;
// this is just used to keep track of visited muxes in order to prohibit
// endless recursion in mux loops
- std::set<int> visited_muxes;
+ vector<bool> visited_muxes;
};
- void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx)
+ void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
muxinfo_t &muxinfo = mux2info[mux_idx];
- muxinfo.ports[port_idx].enabled = true;
- for (size_t i = 0; i < muxinfo.ports.size(); i++) {
- if (int(i) == port_idx)
+ if (do_enable_ports)
+ muxinfo.ports[port_idx].enabled = true;
+
+ for (int i = 0; i < GetSize(muxinfo.ports); i++) {
+ if (i == port_idx)
continue;
- for (int b : muxinfo.ports[i].ctrl_sigs)
- knowledge.known_inactive[b]++;
+ if (muxinfo.ports[i].ctrl_sig >= 0)
+ knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)++;
}
- if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated)
- knowledge.known_active.push_back(muxinfo.ports[port_idx].ctrl_sigs);
+ if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
+ knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)++;
- std::vector<int> parent_muxes;
+ vector<int> parent_muxes;
for (int m : muxinfo.ports[port_idx].input_muxes) {
- if (knowledge.visited_muxes.count(m) > 0)
+ if (knowledge.visited_muxes[m])
continue;
- knowledge.visited_muxes.insert(m);
+ knowledge.visited_muxes[m] = true;
parent_muxes.push_back(m);
}
for (int m : parent_muxes)
- eval_mux(knowledge, m);
+ if (root_enable_muxes.at(m))
+ continue;
+ else if (root_muxes.at(m)) {
+ if (abort_count == 0) {
+ root_mux_rerun.insert(m);
+ root_enable_muxes.at(m) = true;
+ log(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell));
+ } else
+ eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1);
+ } else
+ eval_mux(knowledge, m, do_replace_known, do_enable_ports, abort_count);
for (int m : parent_muxes)
- knowledge.visited_muxes.erase(m);
+ knowledge.visited_muxes[m] = false;
+
+ if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
+ knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)--;
- if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated)
- knowledge.known_active.pop_back();
+ for (int i = 0; i < GetSize(muxinfo.ports); i++) {
+ if (i == port_idx)
+ continue;
+ if (muxinfo.ports[i].ctrl_sig >= 0)
+ knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)--;
+ }
+ }
- for (size_t i = 0; i < muxinfo.ports.size(); i++) {
- if (int(i) == port_idx)
+ void replace_known(knowledge_t &knowledge, muxinfo_t &muxinfo, IdString portname)
+ {
+ SigSpec sig = muxinfo.cell->getPort(portname);
+ bool did_something = false;
+
+ int width = 0;
+ idict<int> ctrl_bits;
+ if (portname == "\\B")
+ width = GetSize(muxinfo.cell->getPort("\\A"));
+ for (int bit : sig2bits(muxinfo.cell->getPort("\\S"), false))
+ ctrl_bits(bit);
+
+ int port_idx = 0, port_off = 0;
+ vector<int> bits = sig2bits(sig, false);
+ for (int i = 0; i < GetSize(bits); i++) {
+ if (bits[i] < 0)
continue;
- for (int b : muxinfo.ports[i].ctrl_sigs)
- knowledge.known_inactive[b]--;
+ if (knowledge.known_inactive.at(bits[i])) {
+ sig[i] = State::S0;
+ did_something = true;
+ } else
+ if (knowledge.known_active.at(bits[i])) {
+ sig[i] = State::S1;
+ did_something = true;
+ }
+ if (width) {
+ if (ctrl_bits.count(bits[i])) {
+ sig[i] = ctrl_bits.at(bits[i]) == port_idx ? State::S1 : State::S0;
+ did_something = true;
+ }
+ if (++port_off == width)
+ port_idx++, port_off=0;
+ } else {
+ if (ctrl_bits.count(bits[i])) {
+ sig[i] = State::S0;
+ did_something = true;
+ }
+ }
+ }
+
+ if (did_something) {
+ log(" Replacing known input bits on port %s of cell %s: %s -> %s\n", log_id(portname),
+ log_id(muxinfo.cell), log_signal(muxinfo.cell->getPort(portname)), log_signal(sig));
+ muxinfo.cell->setPort(portname, sig);
}
}
- void eval_mux(knowledge_t &knowledge, int mux_idx)
+ void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
muxinfo_t &muxinfo = mux2info[mux_idx];
+ // set input ports to constants if we find known active or inactive signals
+ if (do_replace_known) {
+ replace_known(knowledge, muxinfo, "\\A");
+ replace_known(knowledge, muxinfo, "\\B");
+ }
+
// if there is a constant activated port we just use it
- for (size_t port_idx = 0; port_idx < muxinfo.ports.size()-1; port_idx++)
+ for (int port_idx = 0; port_idx < GetSize(muxinfo.ports); port_idx++)
{
portinfo_t &portinfo = muxinfo.ports[port_idx];
if (portinfo.const_activated) {
- eval_mux_port(knowledge, mux_idx, port_idx);
+ eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
return;
}
}
@@ -345,56 +411,39 @@ struct OptMuxtreeWorker
// compare ports with known_active signals. if we find a match, only this
// port can be active. do not include the last port (its the default port
// that has no control signals).
- for (size_t port_idx = 0; port_idx < muxinfo.ports.size()-1; port_idx++)
+ for (int port_idx = 0; port_idx < GetSize(muxinfo.ports)-1; port_idx++)
{
portinfo_t &portinfo = muxinfo.ports[port_idx];
- for (size_t i = 0; i < knowledge.known_active.size(); i++) {
- if (list_is_subset(knowledge.known_active[i], portinfo.ctrl_sigs)) {
- eval_mux_port(knowledge, mux_idx, port_idx);
- return;
- }
+ if (portinfo.const_deactivated)
+ continue;
+ if (knowledge.known_active.at(portinfo.ctrl_sig)) {
+ eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
+ return;
}
}
- // compare ports with known_inactive and known_active signals. If all control
- // signals of the port are know_inactive or if the control signals of all other
- // ports are known_active this port can't be activated. this loop includes the
- // default port but no known_inactive match is performed on the default port.
- for (size_t port_idx = 0; port_idx < muxinfo.ports.size(); port_idx++)
+ // eval all ports that could be activated (control signal is not in
+ // known_inactive or const_deactivated).
+ for (int port_idx = 0; port_idx < GetSize(muxinfo.ports); port_idx++)
{
portinfo_t &portinfo = muxinfo.ports[port_idx];
-
- if (port_idx < muxinfo.ports.size()-1) {
- bool found_non_known_inactive = false;
- for (int i : portinfo.ctrl_sigs)
- if (knowledge.known_inactive[i] == 0)
- found_non_known_inactive = true;
- if (!found_non_known_inactive)
- continue;
- }
-
- bool port_active = true;
- std::vector<int> other_ctrl_sig;
- for (size_t i = 0; i < muxinfo.ports.size()-1; i++) {
- if (i == port_idx)
+ if (portinfo.const_deactivated)
+ continue;
+ if (port_idx < GetSize(muxinfo.ports)-1)
+ if (knowledge.known_inactive.at(portinfo.ctrl_sig))
continue;
- other_ctrl_sig.insert(other_ctrl_sig.end(),
- muxinfo.ports[i].ctrl_sigs.begin(), muxinfo.ports[i].ctrl_sigs.end());
- }
- for (size_t i = 0; i < knowledge.known_active.size(); i++) {
- if (list_is_subset(knowledge.known_active[i], other_ctrl_sig))
- port_active = false;
- }
- if (port_active)
- eval_mux_port(knowledge, mux_idx, port_idx);
+ eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
}
}
void eval_root_mux(int mux_idx)
{
knowledge_t knowledge;
- knowledge.visited_muxes.insert(mux_idx);
- eval_mux(knowledge, mux_idx);
+ knowledge.known_inactive.resize(GetSize(bit2info));
+ knowledge.known_active.resize(GetSize(bit2info));
+ knowledge.visited_muxes.resize(GetSize(mux2info));
+ knowledge.visited_muxes[mux_idx] = true;
+ eval_mux(knowledge, mux_idx, true, root_enable_muxes.at(mux_idx), 3);
}
};
@@ -413,24 +462,17 @@ struct OptMuxtreePass : public Pass {
log("This pass only operates on completely selected modules without processes.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
extra_args(args, 1, design);
int total_count = 0;
- for (auto mod : design->modules()) {
- if (!design->selected_whole_module(mod)) {
- if (design->selected(mod))
- log("Skipping module %s as it is only partially selected.\n", log_id(mod));
+ for (auto module : design->selected_whole_modules_warn()) {
+ if (module->has_processes_warn())
continue;
- }
- if (mod->processes.size() > 0) {
- log("Skipping module %s as it contains processes.\n", log_id(mod));
- } else {
- OptMuxtreeWorker worker(design, mod);
- total_count += worker.removed_count;
- }
+ OptMuxtreeWorker worker(design, module);
+ total_count += worker.removed_count;
}
if (total_count)
design->scratchpad_set_bool("opt.did_something", true);
@@ -438,3 +480,4 @@ struct OptMuxtreePass : public Pass {
}
} OptMuxtreePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index e9e2bb39..5c36eb26 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -25,6 +25,9 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct OptReduceWorker
{
RTLIL::Design *design;
@@ -34,14 +37,14 @@ struct OptReduceWorker
int total_count;
bool did_something;
- void opt_reduce(std::set<RTLIL::Cell*> &cells, SigSet<RTLIL::Cell*> &drivers, RTLIL::Cell *cell)
+ void opt_reduce(pool<RTLIL::Cell*> &cells, SigSet<RTLIL::Cell*> &drivers, RTLIL::Cell *cell)
{
if (cells.count(cell) == 0)
return;
cells.erase(cell);
RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
- std::set<RTLIL::SigBit> new_sig_a_bits;
+ pool<RTLIL::SigBit> new_sig_a_bits;
for (auto &bit : sig_a.to_sigbit_set())
{
@@ -71,7 +74,7 @@ struct OptReduceWorker
if (child_cell->type == cell->type) {
opt_reduce(cells, drivers, child_cell);
if (child_cell->getPort("\\Y")[0] == bit) {
- std::set<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort("\\A")).to_sigbit_set();
+ pool<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort("\\A")).to_sigbit_pool();
new_sig_a_bits.insert(child_sig_a_bits.begin(), child_sig_a_bits.end());
} else
new_sig_a_bits.insert(RTLIL::State::S0);
@@ -102,7 +105,7 @@ struct OptReduceWorker
RTLIL::SigSpec sig_s = assign_map(cell->getPort("\\S"));
RTLIL::SigSpec new_sig_b, new_sig_s;
- std::set<RTLIL::SigSpec> handled_sig;
+ pool<RTLIL::SigSpec> handled_sig;
handled_sig.insert(sig_a);
for (int i = 0; i < sig_s.size(); i++)
@@ -287,7 +290,7 @@ struct OptReduceWorker
for (auto type : type_list)
{
SigSet<RTLIL::Cell*> drivers;
- std::set<RTLIL::Cell*> cells;
+ pool<RTLIL::Cell*> cells;
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
@@ -343,6 +346,9 @@ struct OptReducePass : public Pass {
log(" -fine\n");
log(" perform fine-grain optimizations\n");
log("\n");
+ log(" -full\n");
+ log(" alias for -fine\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -356,21 +362,22 @@ struct OptReducePass : public Pass {
do_fine = true;
continue;
}
+ if (args[argidx] == "-full") {
+ do_fine = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
int total_count = 0;
- for (auto &mod_it : design->modules_) {
- if (!design->selected(mod_it.second))
- continue;
- do {
- OptReduceWorker worker(design, mod_it.second, do_fine);
+ for (auto module : design->selected_modules())
+ while (1) {
+ OptReduceWorker worker(design, module, do_fine);
total_count += worker.total_count;
if (worker.total_count == 0)
break;
- } while (1);
- }
+ }
if (total_count)
design->scratchpad_set_bool("opt.did_something", true);
@@ -378,3 +385,4 @@ struct OptReducePass : public Pass {
}
} OptReducePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index 48f406f6..5f52bb8d 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -23,10 +23,13 @@
#include <stdlib.h>
#include <stdio.h>
-static SigMap assign_map, dff_init_map;
-static SigSet<RTLIL::Cell*> mux_drivers;
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
-static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
+SigMap assign_map, dff_init_map;
+SigSet<RTLIL::Cell*> mux_drivers;
+
+bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
{
RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r;
RTLIL::Const val_cp, val_rp, val_rv;
@@ -80,7 +83,7 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
}
- if (dff->type == "$dff" && mux_drivers.has(sig_d)) {
+ if (dff->type == "$dff" && mux_drivers.has(sig_d) && !has_init) {
std::set<RTLIL::Cell*> muxes;
mux_drivers.find(sig_d, muxes);
for (auto mux : muxes) {
@@ -215,3 +218,4 @@ struct OptRmdffPass : public Pass {
}
} OptRmdffPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index 4b76a5a2..cce97d65 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -28,6 +28,9 @@
#define USE_CELL_HASH_CACHE
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct OptShareWorker
{
RTLIL::Design *design;
@@ -38,7 +41,7 @@ struct OptShareWorker
CellTypes ct;
int total_count;
#ifdef USE_CELL_HASH_CACHE
- std::map<const RTLIL::Cell*, std::string> cell_hash_cache;
+ dict<const RTLIL::Cell*, std::string> cell_hash_cache;
#endif
#ifdef USE_CELL_HASH_CACHE
@@ -64,8 +67,8 @@ struct OptShareWorker
for (auto &it : cell->parameters)
hash_string += "P " + it.first.str() + "=" + it.second.as_string() + "\n";
- const std::map<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections();
- std::map<RTLIL::IdString, RTLIL::SigSpec> alt_conn;
+ const dict<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections();
+ dict<RTLIL::IdString, RTLIL::SigSpec> alt_conn;
if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || cell->type == "$add" || cell->type == "$mul" ||
cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") {
@@ -124,12 +127,14 @@ struct OptShareWorker
#endif
if (cell1->parameters != cell2->parameters) {
- lt = cell1->parameters < cell2->parameters;
+ std::map<RTLIL::IdString, RTLIL::Const> p1(cell1->parameters.begin(), cell1->parameters.end());
+ std::map<RTLIL::IdString, RTLIL::Const> p2(cell2->parameters.begin(), cell2->parameters.end());
+ lt = p1 < p2;
return true;
}
- std::map<RTLIL::IdString, RTLIL::SigSpec> conn1 = cell1->connections();
- std::map<RTLIL::IdString, RTLIL::SigSpec> conn2 = cell2->connections();
+ dict<RTLIL::IdString, RTLIL::SigSpec> conn1 = cell1->connections();
+ dict<RTLIL::IdString, RTLIL::SigSpec> conn2 = cell2->connections();
for (auto &it : conn1) {
if (ct.cell_output(cell1->type, it.first))
@@ -168,7 +173,9 @@ struct OptShareWorker
}
if (conn1 != conn2) {
- lt = conn1 < conn2;
+ std::map<RTLIL::IdString, RTLIL::SigSpec> c1(conn1.begin(), conn1.end());
+ std::map<RTLIL::IdString, RTLIL::SigSpec> c2(conn2.begin(), conn2.end());
+ lt = c1 < c2;
return true;
}
@@ -193,7 +200,7 @@ struct OptShareWorker
if (!ct.cell_known(cell1->type))
return cell1 < cell2;
- if (cell1->get_bool_attribute("\\keep") || cell2->get_bool_attribute("\\keep"))
+ if (cell1->has_keep_attr() || cell2->has_keep_attr())
return cell1 < cell2;
bool lt;
@@ -263,6 +270,7 @@ struct OptShareWorker
}
}
log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
+ cell_hash_cache.erase(cell);
module->remove(cell);
total_count++;
} else {
@@ -306,10 +314,8 @@ struct OptSharePass : public Pass {
extra_args(args, argidx, design);
int total_count = 0;
- for (auto &mod_it : design->modules_) {
- if (!design->selected(mod_it.second))
- continue;
- OptShareWorker worker(design, mod_it.second, mode_nomux);
+ for (auto module : design->selected_modules()) {
+ OptShareWorker worker(design, module, mode_nomux);
total_count += worker.total_count;
}
@@ -319,3 +325,4 @@ struct OptSharePass : public Pass {
}
} OptSharePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 74b049bb..bf406bcd 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -22,22 +22,27 @@
#include "kernel/sigtools.h"
#include "kernel/modtools.h"
#include "kernel/utils.h"
+#include "kernel/macc.h"
+USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+typedef RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell> cell_ptr_cmp;
+typedef std::pair<RTLIL::SigSpec, RTLIL::Const> ssc_pair_t;
+
struct ShareWorkerConfig
{
int limit;
bool opt_force;
bool opt_aggressive;
bool opt_fast;
- std::set<RTLIL::IdString> generic_uni_ops, generic_bin_ops, generic_cbin_ops;
+ pool<RTLIL::IdString> generic_uni_ops, generic_bin_ops, generic_cbin_ops, generic_other_ops;
};
struct ShareWorker
{
ShareWorkerConfig config;
- std::set<RTLIL::IdString> generic_ops;
+ pool<RTLIL::IdString> generic_ops;
RTLIL::Design *design;
RTLIL::Module *module;
@@ -46,30 +51,32 @@ struct ShareWorker
ModWalker modwalker;
ModIndex mi;
- std::set<RTLIL::Cell*> cells_to_remove;
- std::set<RTLIL::Cell*> recursion_state;
+ pool<RTLIL::Cell*> cells_to_remove;
+ pool<RTLIL::Cell*> recursion_state;
SigMap topo_sigmap;
- std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> topo_cell_drivers;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> topo_bit_drivers;
+ std::map<RTLIL::Cell*, std::set<RTLIL::Cell*, cell_ptr_cmp>, cell_ptr_cmp> topo_cell_drivers;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*, cell_ptr_cmp>> topo_bit_drivers;
+
+ std::vector<std::pair<RTLIL::SigBit, RTLIL::SigBit>> exclusive_ctrls;
// ------------------------------------------------------------------------------
// Find terminal bits -- i.e. bits that do not (exclusively) feed into a mux tree
// ------------------------------------------------------------------------------
- std::set<RTLIL::SigBit> terminal_bits;
+ pool<RTLIL::SigBit> terminal_bits;
void find_terminal_bits()
{
- std::set<RTLIL::SigBit> queue_bits;
- std::set<RTLIL::Cell*> visited_cells;
+ pool<RTLIL::SigBit> queue_bits;
+ pool<RTLIL::Cell*> visited_cells;
queue_bits.insert(modwalker.signal_outputs.begin(), modwalker.signal_outputs.end());
for (auto &it : module->cells_)
if (!fwd_ct.cell_known(it.second->type)) {
- std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[it.second];
+ pool<RTLIL::SigBit> &bits = modwalker.cell_inputs[it.second];
queue_bits.insert(bits.begin(), bits.end());
}
@@ -77,19 +84,19 @@ struct ShareWorker
while (!queue_bits.empty())
{
- std::set<ModWalker::PortBit> portbits;
+ pool<ModWalker::PortBit> portbits;
modwalker.get_drivers(portbits, queue_bits);
queue_bits.clear();
for (auto &pbit : portbits) {
if (pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") {
- std::set<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->getPort("\\S")).to_sigbit_set();
+ pool<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->getPort("\\S")).to_sigbit_pool();
terminal_bits.insert(bits.begin(), bits.end());
queue_bits.insert(bits.begin(), bits.end());
visited_cells.insert(pbit.cell);
}
if (fwd_ct.cell_known(pbit.cell->type) && visited_cells.count(pbit.cell) == 0) {
- std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[pbit.cell];
+ pool<RTLIL::SigBit> &bits = modwalker.cell_inputs[pbit.cell];
terminal_bits.insert(bits.begin(), bits.end());
queue_bits.insert(bits.begin(), bits.end());
visited_cells.insert(pbit.cell);
@@ -100,17 +107,251 @@ struct ShareWorker
// ---------------------------------------------------
+ // Code for sharing and comparing MACC cells
+ // ---------------------------------------------------
+
+ static int bits_macc_port(const Macc::port_t &p, int width)
+ {
+ if (GetSize(p.in_a) == 0 || GetSize(p.in_b) == 0)
+ return std::min(std::max(GetSize(p.in_a), GetSize(p.in_b)), width);
+ return std::min(GetSize(p.in_a), width) * std::min(GetSize(p.in_b), width) / 2;
+ }
+
+ static int bits_macc(const Macc &m, int width)
+ {
+ int bits = GetSize(m.bit_ports);
+ for (auto &p : m.ports)
+ bits += bits_macc_port(p, width);
+ return bits;
+ }
+
+ static int bits_macc(RTLIL::Cell *c)
+ {
+ Macc m(c);
+ int width = GetSize(c->getPort("\\Y"));
+ return bits_macc(m, width);
+ }
+
+ static bool cmp_macc_ports(const Macc::port_t &p1, const Macc::port_t &p2)
+ {
+ bool mul1 = GetSize(p1.in_a) && GetSize(p1.in_b);
+ bool mul2 = GetSize(p2.in_a) && GetSize(p2.in_b);
+
+ int w1 = mul1 ? GetSize(p1.in_a) * GetSize(p1.in_b) : GetSize(p1.in_a) + GetSize(p1.in_b);
+ int w2 = mul2 ? GetSize(p2.in_a) * GetSize(p2.in_b) : GetSize(p2.in_a) + GetSize(p2.in_b);
+
+ if (mul1 != mul2)
+ return mul1;
+
+ if (w1 != w2)
+ return w1 > w2;
+
+ if (p1.is_signed != p2.is_signed)
+ return p1.is_signed < p2.is_signed;
+
+ if (p1.do_subtract != p2.do_subtract)
+ return p1.do_subtract < p2.do_subtract;
+
+ if (p1.in_a != p2.in_a)
+ return p1.in_a < p2.in_a;
+
+ if (p1.in_b != p2.in_b)
+ return p1.in_b < p2.in_b;
+
+ return false;
+ }
+
+ int share_macc_ports(Macc::port_t &p1, Macc::port_t &p2, int w1, int w2,
+ RTLIL::SigSpec act = RTLIL::SigSpec(), Macc *supermacc = nullptr, pool<RTLIL::Cell*> *supercell_aux = nullptr)
+ {
+ if (p1.do_subtract != p2.do_subtract)
+ return -1;
+
+ bool mul1 = GetSize(p1.in_a) && GetSize(p1.in_b);
+ bool mul2 = GetSize(p2.in_a) && GetSize(p2.in_b);
+
+ if (mul1 != mul2)
+ return -1;
+
+ bool force_signed = false, force_not_signed = false;
+
+ if ((GetSize(p1.in_a) && GetSize(p1.in_a) < w1) || (GetSize(p1.in_b) && GetSize(p1.in_b) < w1)) {
+ if (p1.is_signed)
+ force_signed = true;
+ else
+ force_not_signed = true;
+ }
+
+ if ((GetSize(p2.in_a) && GetSize(p2.in_a) < w2) || (GetSize(p2.in_b) && GetSize(p2.in_b) < w2)) {
+ if (p2.is_signed)
+ force_signed = true;
+ else
+ force_not_signed = true;
+ }
+
+ if (force_signed && force_not_signed)
+ return -1;
+
+ if (supermacc)
+ {
+ RTLIL::SigSpec sig_a1 = p1.in_a, sig_b1 = p1.in_b;
+ RTLIL::SigSpec sig_a2 = p2.in_a, sig_b2 = p2.in_b;
+
+ RTLIL::SigSpec sig_a = GetSize(sig_a1) > GetSize(sig_a2) ? sig_a1 : sig_a2;
+ RTLIL::SigSpec sig_b = GetSize(sig_b1) > GetSize(sig_b2) ? sig_b1 : sig_b2;
+
+ sig_a1.extend_u0(GetSize(sig_a), p1.is_signed);
+ sig_b1.extend_u0(GetSize(sig_b), p1.is_signed);
+
+ sig_a2.extend_u0(GetSize(sig_a), p2.is_signed);
+ sig_b2.extend_u0(GetSize(sig_b), p2.is_signed);
+
+ if (supercell_aux && GetSize(sig_a)) {
+ sig_a = module->addWire(NEW_ID, GetSize(sig_a));
+ supercell_aux->insert(module->addMux(NEW_ID, sig_a2, sig_a1, act, sig_a));
+ }
+
+ if (supercell_aux && GetSize(sig_b)) {
+ sig_b = module->addWire(NEW_ID, GetSize(sig_b));
+ supercell_aux->insert(module->addMux(NEW_ID, sig_b2, sig_b1, act, sig_b));
+ }
+
+ Macc::port_t p;
+ p.in_a = sig_a;
+ p.in_b = sig_b;
+ p.is_signed = force_signed;
+ p.do_subtract = p1.do_subtract;
+ supermacc->ports.push_back(p);
+ }
+
+ int score = 1000 + abs(GetSize(p1.in_a) - GetSize(p2.in_a)) * std::max(abs(GetSize(p1.in_b) - GetSize(p2.in_b)), 1);
+
+ for (int i = 0; i < std::min(GetSize(p1.in_a), GetSize(p2.in_a)); i++)
+ if (p1.in_a[i] == p2.in_a[i] && score > 0)
+ score--;
+
+ for (int i = 0; i < std::min(GetSize(p1.in_b), GetSize(p2.in_b)); i++)
+ if (p1.in_b[i] == p2.in_b[i] && score > 0)
+ score--;
+
+ return score;
+ }
+
+ int share_macc(RTLIL::Cell *c1, RTLIL::Cell *c2,
+ RTLIL::SigSpec act = RTLIL::SigSpec(), RTLIL::Cell *supercell = nullptr, pool<RTLIL::Cell*> *supercell_aux = nullptr)
+ {
+ Macc m1(c1), m2(c2), supermacc;
+
+ int w1 = GetSize(c1->getPort("\\Y")), w2 = GetSize(c2->getPort("\\Y"));
+ int width = std::max(w1, w2);
+
+ m1.optimize(w1);
+ m2.optimize(w2);
+
+ std::sort(m1.ports.begin(), m1.ports.end(), cmp_macc_ports);
+ std::sort(m2.ports.begin(), m2.ports.end(), cmp_macc_ports);
+
+ std::set<int> m1_unmapped, m2_unmapped;
+
+ for (int i = 0; i < GetSize(m1.ports); i++)
+ m1_unmapped.insert(i);
+
+ for (int i = 0; i < GetSize(m2.ports); i++)
+ m2_unmapped.insert(i);
+
+ while (1)
+ {
+ int best_i = -1, best_j = -1, best_score = 0;
+
+ for (int i : m1_unmapped)
+ for (int j : m2_unmapped) {
+ int score = share_macc_ports(m1.ports[i], m2.ports[j], w1, w2);
+ if (score >= 0 && (best_i < 0 || best_score > score))
+ best_i = i, best_j = j, best_score = score;
+ }
+
+ if (best_i >= 0) {
+ m1_unmapped.erase(best_i);
+ m2_unmapped.erase(best_j);
+ share_macc_ports(m1.ports[best_i], m2.ports[best_j], w1, w2, act, &supermacc, supercell_aux);
+ } else
+ break;
+ }
+
+ for (int i : m1_unmapped)
+ {
+ RTLIL::SigSpec sig_a = m1.ports[i].in_a;
+ RTLIL::SigSpec sig_b = m1.ports[i].in_b;
+
+ if (supercell_aux && GetSize(sig_a)) {
+ sig_a = module->addWire(NEW_ID, GetSize(sig_a));
+ supercell_aux->insert(module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(sig_a)), m1.ports[i].in_a, act, sig_a));
+ }
+
+ if (supercell_aux && GetSize(sig_b)) {
+ sig_b = module->addWire(NEW_ID, GetSize(sig_b));
+ supercell_aux->insert(module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(sig_b)), m1.ports[i].in_b, act, sig_b));
+ }
+
+ Macc::port_t p;
+ p.in_a = sig_a;
+ p.in_b = sig_b;
+ p.is_signed = m1.ports[i].is_signed;
+ p.do_subtract = m1.ports[i].do_subtract;
+ supermacc.ports.push_back(p);
+ }
+
+ for (int i : m2_unmapped)
+ {
+ RTLIL::SigSpec sig_a = m2.ports[i].in_a;
+ RTLIL::SigSpec sig_b = m2.ports[i].in_b;
+
+ if (supercell_aux && GetSize(sig_a)) {
+ sig_a = module->addWire(NEW_ID, GetSize(sig_a));
+ supercell_aux->insert(module->addMux(NEW_ID, m2.ports[i].in_a, RTLIL::SigSpec(0, GetSize(sig_a)), act, sig_a));
+ }
+
+ if (supercell_aux && GetSize(sig_b)) {
+ sig_b = module->addWire(NEW_ID, GetSize(sig_b));
+ supercell_aux->insert(module->addMux(NEW_ID, m2.ports[i].in_b, RTLIL::SigSpec(0, GetSize(sig_b)), act, sig_b));
+ }
+
+ Macc::port_t p;
+ p.in_a = sig_a;
+ p.in_b = sig_b;
+ p.is_signed = m2.ports[i].is_signed;
+ p.do_subtract = m2.ports[i].do_subtract;
+ supermacc.ports.push_back(p);
+ }
+
+ if (supercell)
+ {
+ RTLIL::SigSpec sig_y = module->addWire(NEW_ID, width);
+
+ supercell_aux->insert(module->addPos(NEW_ID, sig_y, c1->getPort("\\Y")));
+ supercell_aux->insert(module->addPos(NEW_ID, sig_y, c2->getPort("\\Y")));
+
+ supercell->setParam("\\Y_WIDTH", width);
+ supercell->setPort("\\Y", sig_y);
+
+ supermacc.optimize(width);
+ supermacc.to_cell(supercell);
+ }
+
+ return bits_macc(supermacc, width);
+ }
+
+
+ // ---------------------------------------------------
// Find shareable cells and compatible groups of cells
// ---------------------------------------------------
- std::set<RTLIL::Cell*, RTLIL::sort_by_name_str<RTLIL::Cell>> shareable_cells;
+ pool<RTLIL::Cell*> shareable_cells;
void find_shareable_cells()
{
- for (auto &it : module->cells_)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = it.second;
-
if (!design->selected(module, cell) || !modwalker.ct.cell_known(cell->type))
continue;
@@ -128,7 +369,9 @@ struct ShareWorker
}
if (cell->type == "$memrd") {
- if (!cell->parameters.at("\\CLK_ENABLE").as_bool())
+ if (cell->parameters.at("\\CLK_ENABLE").as_bool())
+ continue;
+ if (config.opt_aggressive || !modwalker.sigmap(cell->getPort("\\ADDR")).is_fully_const())
shareable_cells.insert(cell);
continue;
}
@@ -146,7 +389,7 @@ struct ShareWorker
}
if (generic_ops.count(cell->type)) {
- if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 10)
+ if (config.opt_aggressive)
shareable_cells.insert(cell);
continue;
}
@@ -183,7 +426,7 @@ struct ShareWorker
return true;
}
- if (config.generic_bin_ops.count(c1->type))
+ if (config.generic_bin_ops.count(c1->type) || c1->type == "$alu")
{
if (!config.opt_aggressive)
{
@@ -229,6 +472,14 @@ struct ShareWorker
return true;
}
+ if (c1->type == "$macc")
+ {
+ if (!config.opt_aggressive)
+ if (share_macc(c1, c2) > 2 * std::min(bits_macc(c1), bits_macc(c2))) return false;
+
+ return true;
+ }
+
for (auto &it : c1->parameters)
if (c2->parameters.count(it.first) == 0 || c2->parameters.at(it.first) != it.second)
return false;
@@ -253,7 +504,7 @@ struct ShareWorker
// Create replacement cell
// -----------------------
- RTLIL::Cell *make_supercell(RTLIL::Cell *c1, RTLIL::Cell *c2, RTLIL::SigSpec act, std::set<RTLIL::Cell*> &supercell_aux)
+ RTLIL::Cell *make_supercell(RTLIL::Cell *c1, RTLIL::Cell *c2, RTLIL::SigSpec act, pool<RTLIL::Cell*> &supercell_aux)
{
log_assert(c1->type == c2->type);
@@ -306,7 +557,7 @@ struct ShareWorker
return supercell;
}
- if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type))
+ if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type) || c1->type == "$alu")
{
bool modified_src_cells = false;
@@ -409,6 +660,8 @@ struct ShareWorker
supercell_aux.insert(module->addMux(NEW_ID, b2, b1, act, b));
RTLIL::Wire *y = module->addWire(NEW_ID, y_width);
+ RTLIL::Wire *x = c1->type == "$alu" ? module->addWire(NEW_ID, y_width) : nullptr;
+ RTLIL::Wire *co = c1->type == "$alu" ? module->addWire(NEW_ID, y_width) : nullptr;
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
supercell->parameters["\\A_SIGNED"] = a_signed;
@@ -419,15 +672,39 @@ struct ShareWorker
supercell->setPort("\\A", a);
supercell->setPort("\\B", b);
supercell->setPort("\\Y", y);
+ if (c1->type == "$alu") {
+ RTLIL::Wire *ci = module->addWire(NEW_ID), *bi = module->addWire(NEW_ID);
+ supercell_aux.insert(module->addMux(NEW_ID, c2->getPort("\\CI"), c1->getPort("\\CI"), act, ci));
+ supercell_aux.insert(module->addMux(NEW_ID, c2->getPort("\\BI"), c1->getPort("\\BI"), act, bi));
+ supercell->setPort("\\CI", ci);
+ supercell->setPort("\\BI", bi);
+ supercell->setPort("\\CO", co);
+ supercell->setPort("\\X", x);
+ }
supercell->check();
supercell_aux.insert(module->addPos(NEW_ID, y, y1));
supercell_aux.insert(module->addPos(NEW_ID, y, y2));
+ if (c1->type == "$alu") {
+ supercell_aux.insert(module->addPos(NEW_ID, co, c1->getPort("\\CO")));
+ supercell_aux.insert(module->addPos(NEW_ID, co, c2->getPort("\\CO")));
+ supercell_aux.insert(module->addPos(NEW_ID, x, c1->getPort("\\X")));
+ supercell_aux.insert(module->addPos(NEW_ID, x, c2->getPort("\\X")));
+ }
supercell_aux.insert(supercell);
return supercell;
}
+ if (c1->type == "$macc")
+ {
+ RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
+ supercell_aux.insert(supercell);
+ share_macc(c1, c2, act, supercell, &supercell_aux);
+ supercell->check();
+ return supercell;
+ }
+
if (c1->type == "$memrd")
{
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1);
@@ -444,20 +721,20 @@ struct ShareWorker
// Finding forbidden control inputs for a cell
// -------------------------------------------
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> forbidden_controls_cache;
+ std::map<RTLIL::Cell*, pool<RTLIL::SigBit>, cell_ptr_cmp> forbidden_controls_cache;
- const std::set<RTLIL::SigBit> &find_forbidden_controls(RTLIL::Cell *cell)
+ const pool<RTLIL::SigBit> &find_forbidden_controls(RTLIL::Cell *cell)
{
if (recursion_state.count(cell)) {
- static std::set<RTLIL::SigBit> empty_controls_set;
+ static pool<RTLIL::SigBit> empty_controls_set;
return empty_controls_set;
}
if (forbidden_controls_cache.count(cell))
return forbidden_controls_cache.at(cell);
- std::set<ModWalker::PortBit> pbits;
- std::set<RTLIL::Cell*> consumer_cells;
+ pool<ModWalker::PortBit> pbits;
+ pool<RTLIL::Cell*> consumer_cells;
modwalker.get_consumers(pbits, modwalker.cell_outputs[cell]);
@@ -471,11 +748,11 @@ struct ShareWorker
for (auto c : consumer_cells)
if (fwd_ct.cell_known(c->type)) {
- const std::set<RTLIL::SigBit> &bits = find_forbidden_controls(c);
+ const pool<RTLIL::SigBit> &bits = find_forbidden_controls(c);
forbidden_controls_cache[cell].insert(bits.begin(), bits.end());
}
- log_assert(recursion_state.count(cell));
+ log_assert(recursion_state.count(cell) != 0);
recursion_state.erase(cell);
return forbidden_controls_cache[cell];
@@ -486,14 +763,14 @@ struct ShareWorker
// Finding control inputs and activation pattern for a cell
// --------------------------------------------------------
- std::map<RTLIL::Cell*, std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>>> activation_patterns_cache;
+ std::map<RTLIL::Cell*, pool<ssc_pair_t>, cell_ptr_cmp> activation_patterns_cache;
- bool sort_check_activation_pattern(std::pair<RTLIL::SigSpec, RTLIL::Const> &p)
+ bool sort_check_activation_pattern(ssc_pair_t &p)
{
std::map<RTLIL::SigBit, RTLIL::State> p_bits;
std::vector<RTLIL::SigBit> p_first_bits = p.first;
- for (int i = 0; i < SIZE(p_first_bits); i++) {
+ for (int i = 0; i < GetSize(p_first_bits); i++) {
RTLIL::SigBit b = p_first_bits[i];
RTLIL::State v = p.second.bits[i];
if (p_bits.count(b) && p_bits.at(b) != v)
@@ -512,30 +789,30 @@ struct ShareWorker
return true;
}
- void optimize_activation_patterns(std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> & /* patterns */)
+ void optimize_activation_patterns(pool<ssc_pair_t> & /* patterns */)
{
// TODO: Remove patterns that are contained in other patterns
// TODO: Consolidate pairs of patterns that only differ in the value for one signal bit
}
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent)
+ const pool<ssc_pair_t> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent)
{
if (recursion_state.count(cell)) {
- static std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> empty_patterns_set;
+ static pool<ssc_pair_t> empty_patterns_set;
return empty_patterns_set;
}
if (activation_patterns_cache.count(cell))
return activation_patterns_cache.at(cell);
- const std::set<RTLIL::SigBit> &cell_out_bits = modwalker.cell_outputs[cell];
- std::set<RTLIL::Cell*> driven_cells, driven_data_muxes;
+ const pool<RTLIL::SigBit> &cell_out_bits = modwalker.cell_outputs[cell];
+ pool<RTLIL::Cell*> driven_cells, driven_data_muxes;
for (auto &bit : cell_out_bits)
{
if (terminal_bits.count(bit)) {
// Terminal cells are always active: unconditional activation pattern
- activation_patterns_cache[cell].insert(std::pair<RTLIL::SigSpec, RTLIL::Const>());
+ activation_patterns_cache[cell].insert(ssc_pair_t());
return activation_patterns_cache.at(cell);
}
for (auto &pbit : modwalker.signal_consumers[bit]) {
@@ -551,7 +828,7 @@ struct ShareWorker
for (auto c : driven_data_muxes)
{
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &c_patterns = find_cell_activation_patterns(c, indent);
+ const pool<ssc_pair_t> &c_patterns = find_cell_activation_patterns(c, indent);
bool used_in_a = false;
std::set<int> used_in_b_parts;
@@ -565,13 +842,13 @@ struct ShareWorker
if (cell_out_bits.count(bit))
used_in_a = true;
- for (int i = 0; i < SIZE(sig_b); i++)
+ for (int i = 0; i < GetSize(sig_b); i++)
if (cell_out_bits.count(sig_b[i]))
used_in_b_parts.insert(i / width);
if (used_in_a)
for (auto p : c_patterns) {
- for (int i = 0; i < SIZE(sig_s); i++)
+ for (int i = 0; i < GetSize(sig_s); i++)
p.first.append_bit(sig_s[i]), p.second.bits.push_back(RTLIL::State::S0);
if (sort_check_activation_pattern(p))
activation_patterns_cache[cell].insert(p);
@@ -586,11 +863,11 @@ struct ShareWorker
}
for (auto c : driven_cells) {
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &c_patterns = find_cell_activation_patterns(c, indent);
+ const pool<ssc_pair_t> &c_patterns = find_cell_activation_patterns(c, indent);
activation_patterns_cache[cell].insert(c_patterns.begin(), c_patterns.end());
}
- log_assert(recursion_state.count(cell));
+ log_assert(recursion_state.count(cell) != 0);
recursion_state.erase(cell);
optimize_activation_patterns(activation_patterns_cache[cell]);
@@ -604,7 +881,7 @@ struct ShareWorker
return activation_patterns_cache[cell];
}
- RTLIL::SigSpec bits_from_activation_patterns(const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &activation_patterns)
+ RTLIL::SigSpec bits_from_activation_patterns(const pool<ssc_pair_t> &activation_patterns)
{
std::set<RTLIL::SigBit> all_bits;
for (auto &it : activation_patterns) {
@@ -619,15 +896,15 @@ struct ShareWorker
return signal;
}
- void filter_activation_patterns(std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &out,
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &in, const std::set<RTLIL::SigBit> &filter_bits)
+ void filter_activation_patterns(pool<ssc_pair_t> &out,
+ const pool<ssc_pair_t> &in, const std::set<RTLIL::SigBit> &filter_bits)
{
for (auto &p : in)
{
std::vector<RTLIL::SigBit> p_first = p.first;
- std::pair<RTLIL::SigSpec, RTLIL::Const> new_p;
+ ssc_pair_t new_p;
- for (int i = 0; i < SIZE(p_first); i++)
+ for (int i = 0; i < GetSize(p_first); i++)
if (filter_bits.count(p_first[i]) == 0) {
new_p.first.append_bit(p_first[i]);
new_p.second.bits.push_back(p.second.bits.at(i));
@@ -637,7 +914,7 @@ struct ShareWorker
}
}
- RTLIL::SigSpec make_cell_activation_logic(const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &activation_patterns, std::set<RTLIL::Cell*> &supercell_aux)
+ RTLIL::SigSpec make_cell_activation_logic(const pool<ssc_pair_t> &activation_patterns, pool<RTLIL::Cell*> &supercell_aux)
{
RTLIL::Wire *all_cases_wire = module->addWire(NEW_ID, 0);
@@ -665,14 +942,14 @@ struct ShareWorker
ct.setup_internals();
ct.setup_stdcells();
- TopoSort<RTLIL::Cell*> toposort;
+ TopoSort<RTLIL::Cell*, cell_ptr_cmp> toposort;
toposort.analyze_loops = false;
topo_sigmap.set(module);
topo_bit_drivers.clear();
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bits;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cells;
+ dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_bits;
+ dict<RTLIL::SigBit, pool<RTLIL::Cell*>> bit_to_cells;
for (auto cell : module->cells())
if (ct.cell_known(cell->type))
@@ -709,7 +986,7 @@ struct ShareWorker
return found_scc;
}
- bool find_in_input_cone_worker(RTLIL::Cell *root, RTLIL::Cell *needle, std::set<RTLIL::Cell*> &stop)
+ bool find_in_input_cone_worker(RTLIL::Cell *root, RTLIL::Cell *needle, pool<RTLIL::Cell*> &stop)
{
if (root == needle)
return true;
@@ -727,7 +1004,7 @@ struct ShareWorker
bool find_in_input_cone(RTLIL::Cell *root, RTLIL::Cell *needle)
{
- std::set<RTLIL::Cell*> stop;
+ pool<RTLIL::Cell*> stop;
return find_in_input_cone_worker(root, needle, stop);
}
@@ -737,12 +1014,12 @@ struct ShareWorker
ct.setup_internals();
ct.setup_stdcells();
- std::set<RTLIL::Cell*> queue, covered;
+ pool<RTLIL::Cell*> queue, covered;
queue.insert(cell);
while (!queue.empty())
{
- std::set<RTLIL::Cell*> new_queue;
+ pool<RTLIL::Cell*> new_queue;
for (auto c : queue) {
if (!ct.cell_known(c->type))
@@ -775,14 +1052,25 @@ struct ShareWorker
// Setup and run
// -------------
+ void remove_cell(Cell *cell)
+ {
+ shareable_cells.erase(cell);
+ forbidden_controls_cache.erase(cell);
+ activation_patterns_cache.erase(cell);
+ module->remove(cell);
+ }
+
ShareWorker(ShareWorkerConfig config, RTLIL::Design *design, RTLIL::Module *module) :
config(config), design(design), module(module), mi(module)
{
+ #ifndef NDEBUG
bool before_scc = module_has_scc();
+ #endif
generic_ops.insert(config.generic_uni_ops.begin(), config.generic_uni_ops.end());
generic_ops.insert(config.generic_bin_ops.begin(), config.generic_bin_ops.end());
generic_ops.insert(config.generic_cbin_ops.begin(), config.generic_cbin_ops.end());
+ generic_ops.insert(config.generic_other_ops.begin(), config.generic_other_ops.end());
fwd_ct.setup_internals();
@@ -805,16 +1093,23 @@ struct ShareWorker
return;
log("Found %d cells in module %s that may be considered for resource sharing.\n",
- SIZE(shareable_cells), log_id(module));
+ GetSize(shareable_cells), log_id(module));
+
+ for (auto cell : module->cells())
+ if (cell->type == "$pmux")
+ for (auto bit : cell->getPort("\\S"))
+ for (auto other_bit : cell->getPort("\\S"))
+ if (bit < other_bit)
+ exclusive_ctrls.push_back(std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit, other_bit));
while (!shareable_cells.empty() && config.limit != 0)
{
RTLIL::Cell *cell = *shareable_cells.begin();
shareable_cells.erase(cell);
- log(" Analyzing resource sharing options for %s:\n", log_id(cell));
+ log(" Analyzing resource sharing options for %s (%s):\n", log_id(cell), log_id(cell->type));
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &cell_activation_patterns = find_cell_activation_patterns(cell, " ");
+ const pool<ssc_pair_t> &cell_activation_patterns = find_cell_activation_patterns(cell, " ");
RTLIL::SigSpec cell_activation_signals = bits_from_activation_patterns(cell_activation_patterns);
if (cell_activation_patterns.empty()) {
@@ -823,12 +1118,12 @@ struct ShareWorker
continue;
}
- if (cell_activation_patterns.count(std::pair<RTLIL::SigSpec, RTLIL::Const>())) {
+ if (cell_activation_patterns.count(ssc_pair_t())) {
log(" Cell is always active. Therefore no sharing is possible.\n");
continue;
}
- log(" Found %d activation_patterns using ctrl signal %s.\n", SIZE(cell_activation_patterns), log_signal(cell_activation_signals));
+ log(" Found %d activation_patterns using ctrl signal %s.\n", GetSize(cell_activation_patterns), log_signal(cell_activation_signals));
std::vector<RTLIL::Cell*> candidates;
find_shareable_partners(candidates, cell);
@@ -838,16 +1133,16 @@ struct ShareWorker
continue;
}
- log(" Found %d candidates:", SIZE(candidates));
+ log(" Found %d candidates:", GetSize(candidates));
for (auto c : candidates)
log(" %s", log_id(c));
log("\n");
for (auto other_cell : candidates)
{
- log(" Analyzing resource sharing with %s:\n", log_id(other_cell));
+ log(" Analyzing resource sharing with %s (%s):\n", log_id(other_cell), log_id(other_cell->type));
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &other_cell_activation_patterns = find_cell_activation_patterns(other_cell, " ");
+ const pool<ssc_pair_t> &other_cell_activation_patterns = find_cell_activation_patterns(other_cell, " ");
RTLIL::SigSpec other_cell_activation_signals = bits_from_activation_patterns(other_cell_activation_patterns);
if (other_cell_activation_patterns.empty()) {
@@ -857,17 +1152,17 @@ struct ShareWorker
continue;
}
- if (other_cell_activation_patterns.count(std::pair<RTLIL::SigSpec, RTLIL::Const>())) {
+ if (other_cell_activation_patterns.count(ssc_pair_t())) {
log(" Cell is always active. Therefore no sharing is possible.\n");
shareable_cells.erase(other_cell);
continue;
}
log(" Found %d activation_patterns using ctrl signal %s.\n",
- SIZE(other_cell_activation_patterns), log_signal(other_cell_activation_signals));
+ GetSize(other_cell_activation_patterns), log_signal(other_cell_activation_signals));
- const std::set<RTLIL::SigBit> &cell_forbidden_controls = find_forbidden_controls(cell);
- const std::set<RTLIL::SigBit> &other_cell_forbidden_controls = find_forbidden_controls(other_cell);
+ const pool<RTLIL::SigBit> &cell_forbidden_controls = find_forbidden_controls(cell);
+ const pool<RTLIL::SigBit> &other_cell_forbidden_controls = find_forbidden_controls(other_cell);
std::set<RTLIL::SigBit> union_forbidden_controls;
union_forbidden_controls.insert(cell_forbidden_controls.begin(), cell_forbidden_controls.end());
@@ -876,8 +1171,8 @@ struct ShareWorker
if (!union_forbidden_controls.empty())
log(" Forbidden control signals for this pair of cells: %s\n", log_signal(union_forbidden_controls));
- std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> filtered_cell_activation_patterns;
- std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> filtered_other_cell_activation_patterns;
+ pool<ssc_pair_t> filtered_cell_activation_patterns;
+ pool<ssc_pair_t> filtered_other_cell_activation_patterns;
filter_activation_patterns(filtered_cell_activation_patterns, cell_activation_patterns, union_forbidden_controls);
filter_activation_patterns(filtered_other_cell_activation_patterns, other_cell_activation_patterns, union_forbidden_controls);
@@ -885,10 +1180,10 @@ struct ShareWorker
optimize_activation_patterns(filtered_cell_activation_patterns);
optimize_activation_patterns(filtered_other_cell_activation_patterns);
- ezDefaultSAT ez;
- SatGen satgen(&ez, &modwalker.sigmap);
+ ezSatPtr ez;
+ SatGen satgen(ez.get(), &modwalker.sigmap);
- std::set<RTLIL::Cell*> sat_cells;
+ pool<RTLIL::Cell*> sat_cells;
std::set<RTLIL::SigBit> bits_queue;
std::vector<int> cell_active, other_cell_active;
@@ -896,13 +1191,13 @@ struct ShareWorker
for (auto &p : filtered_cell_activation_patterns) {
log(" Activation pattern for cell %s: %s = %s\n", log_id(cell), log_signal(p.first), log_signal(p.second));
- cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
+ cell_active.push_back(ez->vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
all_ctrl_signals.append(p.first);
}
for (auto &p : filtered_other_cell_activation_patterns) {
log(" Activation pattern for cell %s: %s = %s\n", log_id(other_cell), log_signal(p.first), log_signal(p.second));
- other_cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
+ other_cell_active.push_back(ez->vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
all_ctrl_signals.append(p.first);
}
@@ -914,7 +1209,7 @@ struct ShareWorker
while (!bits_queue.empty())
{
- std::set<ModWalker::PortBit> portbits;
+ pool<ModWalker::PortBit> portbits;
modwalker.get_drivers(portbits, bits_queue);
bits_queue.clear();
@@ -932,34 +1227,44 @@ struct ShareWorker
break;
}
- if (!ez.solve(ez.expression(ez.OpOr, cell_active))) {
+ for (auto it : exclusive_ctrls)
+ if (satgen.importedSigBit(it.first) && satgen.importedSigBit(it.second)) {
+ log(" Adding exclusive control bits: %s vs. %s\n", log_signal(it.first), log_signal(it.second));
+ int sub1 = satgen.importSigBit(it.first);
+ int sub2 = satgen.importSigBit(it.second);
+ ez->assume(ez->NOT(ez->AND(sub1, sub2)));
+ }
+
+ if (!ez->solve(ez->expression(ez->OpOr, cell_active))) {
log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(cell));
cells_to_remove.insert(cell);
break;
}
- if (!ez.solve(ez.expression(ez.OpOr, other_cell_active))) {
+ if (!ez->solve(ez->expression(ez->OpOr, other_cell_active))) {
log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(other_cell));
cells_to_remove.insert(other_cell);
shareable_cells.erase(other_cell);
continue;
}
- ez.non_incremental();
+ ez->non_incremental();
all_ctrl_signals.sort_and_unify();
std::vector<int> sat_model = satgen.importSigSpec(all_ctrl_signals);
std::vector<bool> sat_model_values;
- ez.assume(ez.AND(ez.expression(ez.OpOr, cell_active), ez.expression(ez.OpOr, other_cell_active)));
+ int sub1 = ez->expression(ez->OpOr, cell_active);
+ int sub2 = ez->expression(ez->OpOr, other_cell_active);
+ ez->assume(ez->AND(sub1, sub2));
log(" Size of SAT problem: %d cells, %d variables, %d clauses\n",
- SIZE(sat_cells), ez.numCnfVariables(), ez.numCnfClauses());
+ GetSize(sat_cells), ez->numCnfVariables(), ez->numCnfClauses());
- if (ez.solve(sat_model, sat_model_values)) {
+ if (ez->solve(sat_model, sat_model_values)) {
log(" According to the SAT solver this pair of cells can not be shared.\n");
- log(" Model from SAT solver: %s = %d'", log_signal(all_ctrl_signals), SIZE(sat_model_values));
- for (int i = SIZE(sat_model_values)-1; i >= 0; i--)
+ log(" Model from SAT solver: %s = %d'", log_signal(all_ctrl_signals), GetSize(sat_model_values));
+ for (int i = GetSize(sat_model_values)-1; i >= 0; i--)
log("%c", sat_model_values[i] ? '1' : '0');
log("\n");
continue;
@@ -989,7 +1294,7 @@ struct ShareWorker
other_cell_select_score += p.first.size();
RTLIL::Cell *supercell;
- std::set<RTLIL::Cell*> supercell_aux;
+ pool<RTLIL::Cell*> supercell_aux;
if (cell_select_score <= other_cell_select_score) {
RTLIL::SigSpec act = make_cell_activation_logic(filtered_cell_activation_patterns, supercell_aux);
supercell = make_supercell(cell, other_cell, act, supercell_aux);
@@ -1016,11 +1321,11 @@ struct ShareWorker
cells_to_remove.erase(other_cell);
shareable_cells.insert(other_cell);
for (auto cc : supercell_aux)
- module->remove(cc);
+ remove_cell(cc);
continue;
}
- std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> supercell_activation_patterns;
+ pool<ssc_pair_t> supercell_activation_patterns;
supercell_activation_patterns.insert(filtered_cell_activation_patterns.begin(), filtered_cell_activation_patterns.end());
supercell_activation_patterns.insert(filtered_other_cell_activation_patterns.begin(), filtered_other_cell_activation_patterns.end());
optimize_activation_patterns(supercell_activation_patterns);
@@ -1045,17 +1350,19 @@ struct ShareWorker
}
if (!cells_to_remove.empty()) {
- log("Removing %d cells in module %s:\n", SIZE(cells_to_remove), log_id(module));
+ log("Removing %d cells in module %s:\n", GetSize(cells_to_remove), log_id(module));
for (auto c : cells_to_remove) {
log(" Removing cell %s (%s).\n", log_id(c), log_id(c->type));
- module->remove(c);
+ remove_cell(c);
}
}
log_assert(recursion_state.empty());
+ #ifndef NDEBUG
bool after_scc = before_scc || module_has_scc();
log_assert(before_scc == after_scc);
+ #endif
}
};
@@ -1137,6 +1444,9 @@ struct SharePass : public Pass {
config.generic_cbin_ops.insert("$logic_and");
config.generic_cbin_ops.insert("$logic_or");
+ config.generic_other_ops.insert("$alu");
+ config.generic_other_ops.insert("$macc");
+
log_header("Executing SHARE pass (SAT-based resource sharing).\n");
size_t argidx;
@@ -1168,4 +1478,3 @@ struct SharePass : public Pass {
} SharePass;
PRIVATE_NAMESPACE_END
-
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 58a6d1b0..fc91f368 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -28,18 +28,18 @@ PRIVATE_NAMESPACE_BEGIN
struct WreduceConfig
{
- std::set<IdString> supported_cell_types;
+ pool<IdString> supported_cell_types;
WreduceConfig()
{
- supported_cell_types = {
+ supported_cell_types = pool<IdString>({
"$not", "$pos", "$neg",
"$and", "$or", "$xor", "$xnor",
"$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
"$add", "$sub", // "$mul", "$div", "$mod", "$pow",
"$mux", "$pmux"
- };
+ });
}
};
@@ -65,20 +65,20 @@ struct WreduceWorker
SigSpec sig_y = mi.sigmap(cell->getPort("\\Y"));
std::vector<SigBit> bits_removed;
- for (int i = SIZE(sig_y)-1; i >= 0; i--)
+ for (int i = GetSize(sig_y)-1; i >= 0; i--)
{
auto info = mi.query(sig_y[i]);
- if (!info->is_output && SIZE(info->ports) <= 1) {
+ if (!info->is_output && GetSize(info->ports) <= 1) {
bits_removed.push_back(Sx);
continue;
}
SigBit ref = sig_a[i];
- for (int k = 0; k < SIZE(sig_s); k++) {
- if (ref != Sx && sig_b[k*SIZE(sig_a) + i] != Sx && ref != sig_b[k*SIZE(sig_a) + i])
+ for (int k = 0; k < GetSize(sig_s); k++) {
+ if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i])
goto no_match_ab;
- if (sig_b[k*SIZE(sig_a) + i] != Sx)
- ref = sig_b[k*SIZE(sig_a) + i];
+ if (sig_b[k*GetSize(sig_a) + i] != Sx)
+ ref = sig_b[k*GetSize(sig_a) + i];
}
if (0)
no_match_ab:
@@ -90,10 +90,10 @@ struct WreduceWorker
return;
SigSpec sig_removed;
- for (int i = SIZE(bits_removed)-1; i >= 0; i--)
+ for (int i = GetSize(bits_removed)-1; i >= 0; i--)
sig_removed.append_bit(bits_removed[i]);
- if (SIZE(bits_removed) == SIZE(sig_y)) {
+ if (GetSize(bits_removed) == GetSize(sig_y)) {
log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
module->connect(sig_y, sig_removed);
module->remove(cell);
@@ -101,10 +101,10 @@ struct WreduceWorker
}
log("Removed top %d bits (of %d) from mux cell %s.%s (%s).\n",
- SIZE(sig_removed), SIZE(sig_y), log_id(module), log_id(cell), log_id(cell->type));
+ GetSize(sig_removed), GetSize(sig_y), log_id(module), log_id(cell), log_id(cell->type));
- int n_removed = SIZE(sig_removed);
- int n_kept = SIZE(sig_y) - SIZE(sig_removed);
+ int n_removed = GetSize(sig_removed);
+ int n_kept = GetSize(sig_y) - GetSize(sig_removed);
SigSpec new_work_queue_bits;
new_work_queue_bits.append(sig_a.extract(n_kept, n_removed));
@@ -114,9 +114,9 @@ struct WreduceWorker
SigSpec new_sig_y = sig_y.extract(0, n_kept);
SigSpec new_sig_b;
- for (int k = 0; k < SIZE(sig_s); k++) {
- new_sig_b.append(sig_b.extract(k*SIZE(sig_a), n_kept));
- new_work_queue_bits.append(sig_b.extract(k*SIZE(sig_a) + n_kept, n_removed));
+ for (int k = 0; k < GetSize(sig_s); k++) {
+ new_sig_b.append(sig_b.extract(k*GetSize(sig_a), n_kept));
+ new_work_queue_bits.append(sig_b.extract(k*GetSize(sig_a) + n_kept, n_removed));
}
for (auto bit : new_work_queue_bits)
@@ -139,24 +139,24 @@ struct WreduceWorker
port_signed = false;
int bits_removed = 0;
- if (SIZE(sig) > max_port_size) {
- bits_removed = SIZE(sig) - max_port_size;
+ if (GetSize(sig) > max_port_size) {
+ bits_removed = GetSize(sig) - max_port_size;
for (auto bit : sig.extract(max_port_size, bits_removed))
work_queue_bits.insert(bit);
sig = sig.extract(0, max_port_size);
}
if (port_signed) {
- while (SIZE(sig) > 1 && sig[SIZE(sig)-1] == sig[SIZE(sig)-2])
- work_queue_bits.insert(sig[SIZE(sig)-1]), sig.remove(SIZE(sig)-1), bits_removed++;
+ while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == sig[GetSize(sig)-2])
+ work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
} else {
- while (SIZE(sig) > 1 && sig[SIZE(sig)-1] == S0)
- work_queue_bits.insert(sig[SIZE(sig)-1]), sig.remove(SIZE(sig)-1), bits_removed++;
+ while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == S0)
+ work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
}
if (bits_removed) {
log("Removed top %d bits (of %d) from port %c of cell %s.%s (%s).\n",
- bits_removed, SIZE(sig) + bits_removed, port, log_id(module), log_id(cell), log_id(cell->type));
+ bits_removed, GetSize(sig) + bits_removed, port, log_id(module), log_id(cell), log_id(cell->type));
cell->setPort(stringf("\\%c", port), sig);
did_something = true;
}
@@ -175,12 +175,12 @@ struct WreduceWorker
// Reduce size of ports A and B based on constant input bits and size of output port
- int max_port_a_size = cell->hasPort("\\A") ? SIZE(cell->getPort("\\A")) : -1;
- int max_port_b_size = cell->hasPort("\\B") ? SIZE(cell->getPort("\\B")) : -1;
+ int max_port_a_size = cell->hasPort("\\A") ? GetSize(cell->getPort("\\A")) : -1;
+ int max_port_b_size = cell->hasPort("\\B") ? GetSize(cell->getPort("\\B")) : -1;
if (cell->type.in("$not", "$pos", "$neg", "$and", "$or", "$xor", "$add", "$sub")) {
- max_port_a_size = std::min(max_port_a_size, SIZE(cell->getPort("\\Y")));
- max_port_b_size = std::min(max_port_b_size, SIZE(cell->getPort("\\Y")));
+ max_port_a_size = std::min(max_port_a_size, GetSize(cell->getPort("\\Y")));
+ max_port_b_size = std::min(max_port_b_size, GetSize(cell->getPort("\\Y")));
}
bool port_a_signed = false;
@@ -201,14 +201,14 @@ struct WreduceWorker
if (port_a_signed && cell->type == "$shr") {
// do not reduce size of output on $shr cells with signed A inputs
} else {
- while (SIZE(sig) > 0)
+ while (GetSize(sig) > 0)
{
- auto info = mi.query(sig[SIZE(sig)-1]);
+ auto info = mi.query(sig[GetSize(sig)-1]);
- if (info->is_output || SIZE(info->ports) > 1)
+ if (info->is_output || GetSize(info->ports) > 1)
break;
- sig.remove(SIZE(sig)-1);
+ sig.remove(GetSize(sig)-1);
bits_removed++;
}
}
@@ -218,8 +218,8 @@ struct WreduceWorker
bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
int a_size = 0, b_size = 0;
- if (cell->hasPort("\\A")) a_size = SIZE(cell->getPort("\\A"));
- if (cell->hasPort("\\B")) b_size = SIZE(cell->getPort("\\B"));
+ if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A"));
+ if (cell->hasPort("\\B")) b_size = GetSize(cell->getPort("\\B"));
int max_y_size = std::max(a_size, b_size);
@@ -229,14 +229,14 @@ struct WreduceWorker
if (cell->type == "$mul")
max_y_size = a_size + b_size;
- while (SIZE(sig) > 1 && SIZE(sig) > max_y_size) {
- module->connect(sig[SIZE(sig)-1], is_signed ? sig[SIZE(sig)-2] : S0);
- sig.remove(SIZE(sig)-1);
+ while (GetSize(sig) > 1 && GetSize(sig) > max_y_size) {
+ module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : S0);
+ sig.remove(GetSize(sig)-1);
bits_removed++;
}
}
- if (SIZE(sig) == 0) {
+ if (GetSize(sig) == 0) {
log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
module->remove(cell);
return;
@@ -244,7 +244,7 @@ struct WreduceWorker
if (bits_removed) {
log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n",
- bits_removed, SIZE(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
+ bits_removed, GetSize(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
cell->setPort("\\Y", sig);
did_something = true;
}
@@ -281,6 +281,10 @@ struct WreduceWorker
work_queue_cells.insert(port.cell);
}
+ pool<SigSpec> complete_wires;
+ for (auto w : module->wires())
+ complete_wires.insert(mi.sigmap(w));
+
for (auto w : module->selected_wires())
{
int unused_top_bits = 0;
@@ -288,27 +292,30 @@ struct WreduceWorker
if (w->port_id > 0 || count_nontrivial_wire_attrs(w) > 0)
continue;
- for (int i = SIZE(w)-1; i >= 0; i--) {
+ for (int i = GetSize(w)-1; i >= 0; i--) {
SigBit bit(w, i);
auto info = mi.query(bit);
- if (info && (info->is_input || info->is_output || SIZE(info->ports) > 0))
+ if (info && (info->is_input || info->is_output || GetSize(info->ports) > 0))
break;
unused_top_bits++;
}
- if (0 < unused_top_bits && unused_top_bits < SIZE(w)) {
- log("Removed top %d bits (of %d) from wire %s.%s.\n", unused_top_bits, SIZE(w), log_id(module), log_id(w));
- Wire *nw = module->addWire(NEW_ID, w);
- nw->width = SIZE(w) - unused_top_bits;
- module->connect(nw, SigSpec(w).extract(0, SIZE(nw)));
- module->swap_names(w, nw);
- }
+ if (unused_top_bits == 0 || unused_top_bits == GetSize(w))
+ continue;
+
+ if (complete_wires[mi.sigmap(w).extract(0, GetSize(w) - unused_top_bits)])
+ continue;
+
+ log("Removed top %d bits (of %d) from wire %s.%s.\n", unused_top_bits, GetSize(w), log_id(module), log_id(w));
+ Wire *nw = module->addWire(NEW_ID, GetSize(w) - unused_top_bits);
+ module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
+ module->swap_names(w, nw);
}
}
};
struct WreducePass : public Pass {
- WreducePass() : Pass("wreduce", "reduce the word size of operations is possible") { }
+ WreducePass() : Pass("wreduce", "reduce the word size of operations if possible") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
diff --git a/passes/proc/Makefile.inc b/passes/proc/Makefile.inc
index dfbc78ea..397fe46a 100644
--- a/passes/proc/Makefile.inc
+++ b/passes/proc/Makefile.inc
@@ -5,5 +5,6 @@ OBJS += passes/proc/proc_rmdead.o
OBJS += passes/proc/proc_init.o
OBJS += passes/proc/proc_arst.o
OBJS += passes/proc/proc_mux.o
+OBJS += passes/proc/proc_dlatch.o
OBJS += passes/proc/proc_dff.o
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
index 36d4141b..40b2b30f 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -22,6 +22,9 @@
#include <stdlib.h>
#include <stdio.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct ProcPass : public Pass {
ProcPass() : Pass("proc", "translate processes to netlists") { }
virtual void help()
@@ -37,10 +40,12 @@ struct ProcPass : public Pass {
log(" proc_init\n");
log(" proc_arst\n");
log(" proc_mux\n");
+ log(" proc_dlatch\n");
log(" proc_dff\n");
log(" proc_clean\n");
log("\n");
- log("This replaces the processes in the design with multiplexers and flip-flops.\n");
+ log("This replaces the processes in the design with multiplexers,\n");
+ log("flip-flops and latches.\n");
log("\n");
log("The following options are supported:\n");
log("\n");
@@ -74,6 +79,7 @@ struct ProcPass : public Pass {
else
Pass::call(design, "proc_arst -global_arst " + global_arst);
Pass::call(design, "proc_mux");
+ Pass::call(design, "proc_dlatch");
Pass::call(design, "proc_dff");
Pass::call(design, "proc_clean");
@@ -81,3 +87,4 @@ struct ProcPass : public Pass {
}
} ProcPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index f11b328f..27c6b3bc 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -23,10 +23,14 @@
#include <stdlib.h>
#include <stdio.h>
-// defined in proc_clean.cc
+YOSYS_NAMESPACE_BEGIN
extern void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth);
+YOSYS_NAMESPACE_END
-static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, bool &polarity)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, bool &polarity)
{
if (signal.size() != 1)
return false;
@@ -81,7 +85,7 @@ static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSp
return false;
}
-static void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::SigSpec &rval, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity, bool unknown)
+void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::SigSpec &rval, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity, bool unknown)
{
for (auto &action : cs->actions) {
if (unknown)
@@ -114,7 +118,7 @@ static void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::S
}
}
-static void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity)
+void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity)
{
for (auto sw : cs->switches) {
bool this_polarity = polarity;
@@ -149,7 +153,7 @@ static void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigS
}
}
-static void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
+void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
{
restart_proc_arst:
if (proc->root_case.switches.size() != 1)
@@ -170,7 +174,7 @@ restart_proc_arst:
for (auto &action : sync->actions) {
RTLIL::SigSpec rspec = action.second;
RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
- for (int i = 0; i < SIZE(rspec); i++)
+ for (int i = 0; i < GetSize(rspec); i++)
if (rspec[i].wire == NULL)
rval[i] = rspec[i];
RTLIL::SigSpec last_rval;
@@ -258,7 +262,7 @@ struct ProcArstPass : public Pass {
for (auto &chunk : act.first.chunks())
if (chunk.wire && chunk.wire->attributes.count("\\init")) {
RTLIL::SigSpec value = chunk.wire->attributes.at("\\init");
- value.extend(chunk.wire->width, false);
+ value.extend_u0(chunk.wire->width, false);
arst_sig.append(chunk);
arst_val.append(value.extract(chunk.offset, chunk.width));
}
@@ -280,3 +284,4 @@ struct ProcArstPass : public Pass {
}
} ProcArstPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 1e3dd9ce..82716cd0 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -22,8 +22,12 @@
#include <stdlib.h>
#include <stdio.h>
-extern void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did_something, int &count, int max_depth);
+YOSYS_NAMESPACE_BEGIN
extern void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth);
+YOSYS_NAMESPACE_END
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did_something, int &count, int max_depth)
{
@@ -89,6 +93,9 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did
}
}
+PRIVATE_NAMESPACE_END
+YOSYS_NAMESPACE_BEGIN
+
void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth)
{
for (size_t i = 0; i < cs->actions.size(); i++) {
@@ -109,7 +116,10 @@ void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int m
}
}
-static void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)
+YOSYS_NAMESPACE_END
+PRIVATE_NAMESPACE_BEGIN
+
+void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)
{
int count = 0;
bool did_something = true;
@@ -174,3 +184,4 @@ struct ProcCleanPass : public Pass {
}
} ProcCleanPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index e69e8023..76842da6 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -25,7 +25,10 @@
#include <stdlib.h>
#include <stdio.h>
-static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
{
RTLIL::SigSpec lvalue;
@@ -50,7 +53,7 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
return lvalue;
}
-static void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, RTLIL::SigSpec clk, bool clk_polarity,
+void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, RTLIL::SigSpec clk, bool clk_polarity,
std::map<RTLIL::SigSpec, std::set<RTLIL::SyncRule*>> &async_rules, RTLIL::Process *proc)
{
RTLIL::SigSpec sig_sr_set = RTLIL::SigSpec(0, sig_d.size());
@@ -140,7 +143,7 @@ static void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::S
cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
}
-static void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_out,
+void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_out,
bool clk_polarity, bool set_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec set, RTLIL::Process *proc)
{
std::stringstream sstr;
@@ -187,7 +190,7 @@ static void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec
clk_polarity ? "positive" : "negative", set_polarity ? "positive" : "negative");
}
-static void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RTLIL::SigSpec sig_out,
+void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RTLIL::SigSpec sig_out,
bool clk_polarity, bool arst_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec *arst, RTLIL::Process *proc)
{
std::stringstream sstr;
@@ -215,7 +218,7 @@ static void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_
log(".\n");
}
-static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
+void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
{
while (1)
{
@@ -330,12 +333,12 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
if (many_async_rules.size() > 0)
{
- log("WARNING: Complex async reset for dff `%s'.\n", log_signal(sig));
+ log_warning("Complex async reset for dff `%s'.\n", log_signal(sig));
gen_dffsr_complex(mod, insig, sig, sync_edge->signal, sync_edge->type == RTLIL::SyncType::STp, many_async_rules, proc);
}
else if (!rstval.is_fully_const() && !ce.eval(rstval))
{
- log("WARNING: Async reset value `%s' is not constant!\n", log_signal(rstval));
+ log_warning("Async reset value `%s' is not constant!\n", log_signal(rstval));
gen_dffsr(mod, insig, rstval, sig,
sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
@@ -380,3 +383,4 @@ struct ProcDffPass : public Pass {
}
} ProcDffPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
new file mode 100644
index 00000000..e1bbab54
--- /dev/null
+++ b/passes/proc/proc_dlatch.cc
@@ -0,0 +1,308 @@
+/*
+ * 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/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/log.h"
+#include <sstream>
+#include <stdlib.h>
+#include <stdio.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct proc_dlatch_db_t
+{
+ Module *module;
+ SigMap sigmap;
+
+ dict<SigBit, pair<Cell*, int>> mux_drivers;
+ dict<SigBit, int> sigusers;
+
+ proc_dlatch_db_t(Module *module) : module(module), sigmap(module)
+ {
+ for (auto cell : module->cells())
+ {
+ if (cell->type.in("$mux", "$pmux")) {
+ auto sig_y = sigmap(cell->getPort("\\Y"));
+ for (int i = 0; i < GetSize(sig_y); i++)
+ mux_drivers[sig_y[i]] = pair<Cell*, int>(cell, i);
+ }
+
+ for (auto &conn : cell->connections())
+ if (!cell->known() || cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sigusers[bit]++;
+ }
+
+ for (auto wire : module->wires())
+ if (wire->port_input)
+ for (auto bit : sigmap(wire))
+ sigusers[bit]++;
+ }
+
+ struct rule_node_t
+ {
+ // a node is true if "signal" equals "match" and [any
+ // of the child nodes is true or "children" is empty]
+ SigBit signal, match;
+ vector<int> children;
+
+ bool operator==(const rule_node_t &other) const {
+ return signal == other.signal && match == other.match && children == other.children;
+ }
+
+ unsigned int hash() const {
+ unsigned int h = mkhash_init;
+ mkhash(h, signal.hash());
+ mkhash(h, match.hash());
+ for (auto i : children) mkhash(h, i);
+ return h;
+ }
+ };
+
+ enum tf_node_types_t : int {
+ true_node = 1,
+ false_node = 2
+ };
+
+ idict<rule_node_t, 3> rules_db;
+ dict<int, SigBit> rules_sig;
+
+ int make_leaf(SigBit signal, SigBit match)
+ {
+ rule_node_t node;
+ node.signal = signal;
+ node.match = match;
+ return rules_db(node);
+ }
+
+ int make_inner(SigBit signal, SigBit match, int child)
+ {
+ rule_node_t node;
+ node.signal = signal;
+ node.match = match;
+ node.children.push_back(child);
+ return rules_db(node);
+ }
+
+ int make_inner(const pool<int> &children)
+ {
+ rule_node_t node;
+ node.signal = State::S0;
+ node.match = State::S0;
+ node.children = vector<int>(children.begin(), children.end());
+ std::sort(node.children.begin(), node.children.end());
+ return rules_db(node);
+ }
+
+ int find_mux_feedback(SigBit haystack, SigBit needle, bool set_undef)
+ {
+ if (sigusers[haystack] > 1)
+ set_undef = false;
+
+ if (haystack == needle)
+ return true_node;
+
+ auto it = mux_drivers.find(haystack);
+ if (it == mux_drivers.end())
+ return false_node;
+
+ Cell *cell = it->second.first;
+ int index = it->second.second;
+
+ SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = sigmap(cell->getPort("\\B"));
+ SigSpec sig_s = sigmap(cell->getPort("\\S"));
+ int width = GetSize(sig_a);
+
+ pool<int> children;
+
+ int n = find_mux_feedback(sig_a[index], needle, set_undef);
+ if (n != false_node) {
+ if (set_undef && sig_a[index] == needle) {
+ SigSpec sig = cell->getPort("\\A");
+ sig[index] = State::Sx;
+ cell->setPort("\\A", sig);
+ }
+ for (int i = 0; i < GetSize(sig_s); i++)
+ n = make_inner(sig_s[i], State::S0, n);
+ children.insert(n);
+ }
+
+ for (int i = 0; i < GetSize(sig_s); i++) {
+ n = find_mux_feedback(sig_b[i*width + index], needle, set_undef);
+ if (n != false_node) {
+ if (set_undef && sig_b[i*width + index] == needle) {
+ SigSpec sig = cell->getPort("\\B");
+ sig[i*width + index] = State::Sx;
+ cell->setPort("\\B", sig);
+ }
+ children.insert(make_inner(sig_s[i], State::S1, n));
+ }
+ }
+
+ if (children.empty())
+ return false_node;
+
+ return make_inner(children);
+ }
+
+ SigBit make_hold(int n)
+ {
+ if (n == true_node)
+ return State::S1;
+
+ if (n == false_node)
+ return State::S0;
+
+ if (rules_sig.count(n))
+ return rules_sig.at(n);
+
+ const rule_node_t &rule = rules_db[n];
+ SigSpec and_bits;
+
+ if (rule.signal != rule.match) {
+ if (rule.match == State::S1)
+ and_bits.append(rule.signal);
+ else if (rule.match == State::S0)
+ and_bits.append(module->Not(NEW_ID, rule.signal));
+ else
+ and_bits.append(module->Eq(NEW_ID, rule.signal, rule.match));
+ }
+
+ if (!rule.children.empty()) {
+ SigSpec or_bits;
+ for (int k : rule.children)
+ or_bits.append(make_hold(k));
+ and_bits.append(module->ReduceOr(NEW_ID, or_bits));
+ }
+
+ if (GetSize(and_bits) == 2)
+ and_bits = module->And(NEW_ID, and_bits[0], and_bits[1]);
+ log_assert(GetSize(and_bits) == 1);
+
+ rules_sig[n] = and_bits[0];
+ return and_bits[0];
+ }
+};
+
+void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
+{
+ std::vector<RTLIL::SyncRule*> new_syncs;
+ RTLIL::SigSig latches_bits, nolatches_bits;
+ dict<SigBit, SigBit> latches_out_in;
+ dict<SigBit, int> latches_hold;
+
+ for (auto sr : proc->syncs)
+ {
+ if (sr->type != RTLIL::SyncType::STa) {
+ new_syncs.push_back(sr);
+ continue;
+ }
+
+ for (auto ss : sr->actions) {
+ db.sigmap.apply(ss.first);
+ db.sigmap.apply(ss.second);
+ for (int i = 0; i < GetSize(ss.first); i++)
+ latches_out_in[ss.first[i]] = ss.second[i];
+ }
+
+ delete sr;
+ }
+
+ latches_out_in.sort();
+ for (auto &it : latches_out_in) {
+ int n = db.find_mux_feedback(it.second, it.first, true);
+ if (n == db.false_node) {
+ nolatches_bits.first.append(it.first);
+ nolatches_bits.second.append(it.second);
+ } else {
+ latches_bits.first.append(it.first);
+ latches_bits.second.append(it.second);
+ latches_hold[it.first] = n;
+ }
+ }
+
+ int offset = 0;
+ for (auto chunk : nolatches_bits.first.chunks()) {
+ SigSpec lhs = chunk, rhs = nolatches_bits.second.extract(offset, chunk.width);
+ log("No latch inferred for signal `%s.%s' from process `%s.%s'.\n",
+ db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str());
+ db.module->connect(lhs, rhs);
+ offset += chunk.width;
+ }
+
+ offset = 0;
+ while (offset < GetSize(latches_bits.first))
+ {
+ int width = 1;
+ int n = latches_hold[latches_bits.first[offset]];
+ Wire *w = latches_bits.first[offset].wire;
+
+ if (w != nullptr)
+ {
+ while (offset+width < GetSize(latches_bits.first) &&
+ n == latches_hold[latches_bits.first[offset+width]] &&
+ w == latches_bits.first[offset+width].wire)
+ width++;
+
+ SigSpec lhs = latches_bits.first.extract(offset, width);
+ SigSpec rhs = latches_bits.second.extract(offset, width);
+
+ Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n)), rhs, lhs);
+ log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n",
+ db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), log_id(cell));
+ }
+
+ offset += width;
+ }
+
+ new_syncs.swap(proc->syncs);
+}
+
+struct ProcDlatchPass : public Pass {
+ ProcDlatchPass() : Pass("proc_dlatch", "extract latches from processes") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" proc_dlatch [selection]\n");
+ log("\n");
+ log("This pass identifies latches in the processes and converts them to\n");
+ log("d-type latches.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing PROC_DLATCH pass (convert process syncs to latches).\n");
+
+ extra_args(args, 1, design);
+
+ for (auto module : design->selected_modules()) {
+ proc_dlatch_db_t db(module);
+ for (auto &proc_it : module->processes)
+ if (design->selected(module, proc_it.second))
+ proc_dlatch(db, proc_it.second);
+ }
+ }
+} ProcDlatchPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index c72840c0..dff68159 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -23,7 +23,10 @@
#include <stdlib.h>
#include <stdio.h>
-static void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
{
log_assert(rule.compare.size() == 0);
@@ -37,7 +40,7 @@ static void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
}
}
-static void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
+void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
{
bool found_init = false;
@@ -109,3 +112,4 @@ struct ProcInitPass : public Pass {
}
} ProcInitPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index c00b00a2..4aa1aab5 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -24,7 +24,10 @@
#include <stdlib.h>
#include <stdio.h>
-static RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
{
for (auto &action : cs->actions) {
if (action.first.size())
@@ -41,7 +44,7 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
return RTLIL::SigSpec();
}
-static void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
+void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
{
for (auto &action : cs->actions) {
RTLIL::SigSpec lvalue = action.first.extract(sig);
@@ -54,7 +57,7 @@ static void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
extract_core_signal(cs2, sig);
}
-static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
+RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
{
std::stringstream sstr;
sstr << "$procmux$" << (autoidx++);
@@ -122,7 +125,7 @@ static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
return RTLIL::SigSpec(ctrl_wire);
}
-static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
+RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
{
log_assert(when_signal.size() == else_signal.size());
@@ -156,7 +159,7 @@ static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
return RTLIL::SigSpec(result_wire);
}
-static void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
+void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
{
log_assert(last_mux_cell != NULL);
log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size());
@@ -176,7 +179,7 @@ static void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const
last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size();
}
-static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
+RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
{
RTLIL::SigSpec result = defval;
@@ -233,7 +236,7 @@ static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs
return result;
}
-static void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
+void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
{
bool first = true;
while (1)
@@ -283,3 +286,4 @@ struct ProcMuxPass : public Pass {
}
} ProcMuxPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index fe3532da..427e0d56 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -25,13 +25,16 @@
#include <stdio.h>
#include <set>
-static void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
{
BitPatternPool pool(sw->signal);
for (size_t i = 0; i < sw->cases.size(); i++)
{
- bool is_default = SIZE(sw->cases[i]->compare) == 0 && (!pool.empty() || SIZE(sw->signal) == 0);
+ bool is_default = GetSize(sw->cases[i]->compare) == 0 && (!pool.empty() || GetSize(sw->signal) == 0);
for (size_t j = 0; j < sw->cases[i]->compare.size(); j++) {
RTLIL::SigSpec sig = sw->cases[i]->compare[j];
@@ -98,3 +101,4 @@ struct ProcRmdeadPass : public Pass {
}
} ProcRmdeadPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index f07ad943..01d0e031 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -31,7 +31,8 @@
#include <string.h>
#include <algorithm>
-namespace {
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
/* this should only be used for regression testing of ConstEval -- see vloghammer */
struct BruteForceEquivChecker
@@ -68,7 +69,7 @@ struct BruteForceEquivChecker
log_signal(undef2), log_signal(mod1_inputs), log_signal(inputs));
if (ignore_x_mod1) {
- for (int i = 0; i < SIZE(sig1); i++)
+ for (int i = 0; i < GetSize(sig1); i++)
if (sig1[i] == RTLIL::State::Sx)
sig2[i] = RTLIL::State::Sx;
}
@@ -142,16 +143,16 @@ struct VlogHammerReporter
{
log("Verifying SAT model (%s)..\n", model_undef ? "with undef" : "without undef");
- ezDefaultSAT ez;
+ ezSatPtr ez;
SigMap sigmap(module);
- SatGen satgen(&ez, &sigmap);
+ SatGen satgen(ez.get(), &sigmap);
satgen.model_undef = model_undef;
for (auto &c : module->cells_)
if (!satgen.importCell(c.second))
log_error("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(c.first), RTLIL::id2cstr(c.second->type));
- ez.assume(satgen.signals_eq(recorded_set_vars, recorded_set_vals));
+ ez->assume(satgen.signals_eq(recorded_set_vars, recorded_set_vals));
std::vector<int> y_vec = satgen.importDefSigSpec(module->wires_.at("\\y"));
std::vector<bool> y_values;
@@ -162,9 +163,9 @@ struct VlogHammerReporter
}
log(" Created SAT problem with %d variables and %d clauses.\n",
- ez.numCnfVariables(), ez.numCnfClauses());
+ ez->numCnfVariables(), ez->numCnfClauses());
- if (!ez.solve(y_vec, y_values))
+ if (!ez->solve(y_vec, y_values))
log_error("Failed to find solution to SAT problem.\n");
for (int i = 0; i < expected_y.size(); i++) {
@@ -203,7 +204,7 @@ struct VlogHammerReporter
if (y_undef.at(i))
{
log(" Toggling undef bit %d to test undef gating.\n", i);
- if (!ez.solve(y_vec, y_values, ez.IFF(y_vec.at(i), y_values.at(i) ? ez.FALSE : ez.TRUE)))
+ if (!ez->solve(y_vec, y_values, ez->IFF(y_vec.at(i), y_values.at(i) ? ez->CONST_FALSE : ez->CONST_TRUE)))
log_error("Failed to find solution with toggled bit!\n");
cmp_vars.push_back(y_vec.at(expected_y.size() + i));
@@ -219,15 +220,15 @@ struct VlogHammerReporter
}
log(" Testing if SAT solution is unique.\n");
- ez.assume(ez.vec_ne(cmp_vars, ez.vec_const(cmp_vals)));
- if (ez.solve(y_vec, y_values))
+ ez->assume(ez->vec_ne(cmp_vars, ez->vec_const(cmp_vals)));
+ if (ez->solve(y_vec, y_values))
log_error("Found two distinct solutions to SAT problem.\n");
}
else
{
log(" Testing if SAT solution is unique.\n");
- ez.assume(ez.vec_ne(y_vec, ez.vec_const(y_values)));
- if (ez.solve(y_vec, y_values))
+ ez->assume(ez->vec_ne(y_vec, ez->vec_const(y_values)));
+ if (ez->solve(y_vec, y_values))
log_error("Found two distinct solutions to SAT problem.\n");
}
@@ -276,7 +277,7 @@ struct VlogHammerReporter
while (!ce.eval(sig, undef)) {
// log_error("Evaluation of y in module %s failed: sig=%s, undef=%s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(undef));
- log("Warning: Setting signal %s in module %s to undef.\n", log_signal(undef), RTLIL::id2cstr(module->name));
+ log_warning("Setting signal %s in module %s to undef.\n", log_signal(undef), RTLIL::id2cstr(module->name));
ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.size()));
}
@@ -289,7 +290,7 @@ struct VlogHammerReporter
} else if (rtl_sig.size() > 0) {
if (rtl_sig.size() != sig.size())
log_error("Output (y) has a different width in module %s compared to rtl!\n", RTLIL::id2cstr(module->name));
- for (int i = 0; i < SIZE(sig); i++)
+ for (int i = 0; i < GetSize(sig); i++)
if (rtl_sig[i] == RTLIL::State::Sx)
sig[i] = RTLIL::State::Sx;
}
@@ -357,8 +358,6 @@ struct VlogHammerReporter
}
};
-} /* namespace */
-
struct EvalPass : public Pass {
EvalPass() : Pass("eval", "evaluate the circuit given an input") { }
virtual void help()
@@ -601,3 +600,4 @@ struct EvalPass : public Pass {
}
} EvalPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index e856fdf7..b012bc6a 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -23,6 +23,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct dff_map_info_t {
RTLIL::SigSpec sig_d, sig_clk, sig_arst;
bool clk_polarity, arst_polarity;
@@ -37,7 +40,7 @@ struct dff_map_bit_info_t {
RTLIL::Cell *cell;
};
-static bool consider_wire(RTLIL::Wire *wire, std::map<RTLIL::IdString, dff_map_info_t> &dff_dq_map)
+bool consider_wire(RTLIL::Wire *wire, std::map<RTLIL::IdString, dff_map_info_t> &dff_dq_map)
{
if (wire->name[0] == '$' || dff_dq_map.count(wire->name))
return false;
@@ -46,7 +49,7 @@ static bool consider_wire(RTLIL::Wire *wire, std::map<RTLIL::IdString, dff_map_i
return true;
}
-static bool consider_cell(RTLIL::Design *design, std::set<RTLIL::IdString> &dff_cells, RTLIL::Cell *cell)
+bool consider_cell(RTLIL::Design *design, std::set<RTLIL::IdString> &dff_cells, RTLIL::Cell *cell)
{
if (cell->name[0] == '$' || dff_cells.count(cell->name))
return false;
@@ -55,7 +58,7 @@ static bool consider_cell(RTLIL::Design *design, std::set<RTLIL::IdString> &dff_
return true;
}
-static bool compare_wires(RTLIL::Wire *wire1, RTLIL::Wire *wire2)
+bool compare_wires(RTLIL::Wire *wire1, RTLIL::Wire *wire2)
{
log_assert(wire1->name == wire2->name);
if (wire1->width != wire2->width)
@@ -63,7 +66,7 @@ static bool compare_wires(RTLIL::Wire *wire1, RTLIL::Wire *wire2)
return true;
}
-static bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2)
+bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2)
{
log_assert(cell1->name == cell2->name);
if (cell1->type != cell2->type)
@@ -73,7 +76,7 @@ static bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2)
return true;
}
-static void find_dff_wires(std::set<RTLIL::IdString> &dff_wires, RTLIL::Module *module)
+void find_dff_wires(std::set<RTLIL::IdString> &dff_wires, RTLIL::Module *module)
{
CellTypes ct;
ct.setup_internals_mem();
@@ -93,7 +96,7 @@ static void find_dff_wires(std::set<RTLIL::IdString> &dff_wires, RTLIL::Module *
}
}
-static void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::Design *design, RTLIL::Module *module)
+void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::Design *design, RTLIL::Module *module)
{
std::map<RTLIL::SigBit, dff_map_bit_info_t> bit_info;
SigMap sigmap(module);
@@ -208,7 +211,7 @@ static void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RT
}
}
-static RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width = 1)
+RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width = 1)
{
if (module->count_id(name))
log_error("Attempting to create wire %s, but a wire of this name exists already! Hint: Try another value for -sep.\n", log_id(name));
@@ -604,7 +607,7 @@ struct ExposePass : public Pass {
RTLIL::SigSpec sig;
if (cell->hasPort(p->name))
sig = cell->getPort(p->name);
- sig.extend(w->width);
+ sig.extend_u0(w->width);
if (w->port_input)
module->connect(RTLIL::SigSig(sig, w));
else
@@ -644,3 +647,4 @@ struct ExposePass : public Pass {
}
} ExposePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index bfed0005..8a5301ec 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -28,7 +28,8 @@
#include <string.h>
#include <algorithm>
-namespace {
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
bool inv_mode;
int verbose_level, reduce_counter, reduce_stop_at;
@@ -72,7 +73,7 @@ struct FindReducedInputs
SigMap &sigmap;
drivers_t &drivers;
- ezDefaultSAT ez;
+ ezSatPtr ez;
std::set<RTLIL::Cell*> ez_cells;
SatGen satgen;
@@ -80,7 +81,7 @@ struct FindReducedInputs
std::vector<int> sat_pi_uniq_bitvec;
FindReducedInputs(SigMap &sigmap, drivers_t &drivers) :
- sigmap(sigmap), drivers(drivers), satgen(&ez, &sigmap)
+ sigmap(sigmap), drivers(drivers), satgen(ez.get(), &sigmap)
{
satgen.model_undef = true;
}
@@ -103,30 +104,30 @@ struct FindReducedInputs
satgen.setContext(&sigmap, "A");
int sat_a = satgen.importSigSpec(bit).front();
- ez.assume(ez.NOT(satgen.importUndefSigSpec(bit).front()));
+ ez->assume(ez->NOT(satgen.importUndefSigSpec(bit).front()));
satgen.setContext(&sigmap, "B");
int sat_b = satgen.importSigSpec(bit).front();
- ez.assume(ez.NOT(satgen.importUndefSigSpec(bit).front()));
+ ez->assume(ez->NOT(satgen.importUndefSigSpec(bit).front()));
int idx = sat_pi.size();
size_t idx_bits = get_bits(idx);
if (sat_pi_uniq_bitvec.size() != idx_bits) {
- sat_pi_uniq_bitvec.push_back(ez.frozen_literal(stringf("uniq_%d", int(idx_bits)-1)));
+ sat_pi_uniq_bitvec.push_back(ez->frozen_literal(stringf("uniq_%d", int(idx_bits)-1)));
for (auto &it : sat_pi)
- ez.assume(ez.OR(ez.NOT(it.second), ez.NOT(sat_pi_uniq_bitvec.back())));
+ ez->assume(ez->OR(ez->NOT(it.second), ez->NOT(sat_pi_uniq_bitvec.back())));
}
log_assert(sat_pi_uniq_bitvec.size() == idx_bits);
- sat_pi[bit] = ez.frozen_literal(stringf("p, falsei_%s", log_signal(bit)));
- ez.assume(ez.IFF(ez.XOR(sat_a, sat_b), sat_pi[bit]));
+ sat_pi[bit] = ez->frozen_literal(stringf("p, falsei_%s", log_signal(bit)));
+ ez->assume(ez->IFF(ez->XOR(sat_a, sat_b), sat_pi[bit]));
for (size_t i = 0; i < idx_bits; i++)
if ((idx & (1 << i)) == 0)
- ez.assume(ez.OR(ez.NOT(sat_pi[bit]), ez.NOT(sat_pi_uniq_bitvec[i])));
+ ez->assume(ez->OR(ez->NOT(sat_pi[bit]), ez->NOT(sat_pi_uniq_bitvec[i])));
else
- ez.assume(ez.OR(ez.NOT(sat_pi[bit]), sat_pi_uniq_bitvec[i]));
+ ez->assume(ez->OR(ez->NOT(sat_pi[bit]), sat_pi_uniq_bitvec[i]));
}
void register_cone_worker(std::set<RTLIL::SigBit> &pi, std::set<RTLIL::SigBit> &sigdone, RTLIL::SigBit out)
@@ -200,7 +201,7 @@ struct FindReducedInputs
model_expr.push_back(sat_pi.at(pi[i]));
}
- if (!ez.solve(model_expr, model, ez.expression(ezSAT::OpOr, model_expr), ez.XOR(output_a, output_b), ez.NOT(output_undef_a), ez.NOT(output_undef_b)))
+ if (!ez->solve(model_expr, model, ez->expression(ezSAT::OpOr, model_expr), ez->XOR(output_a, output_b), ez->NOT(output_undef_a), ez->NOT(output_undef_b)))
break;
int found_count = 0;
@@ -229,7 +230,7 @@ struct PerformReduction
drivers_t &drivers;
std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> &inv_pairs;
- ezDefaultSAT ez;
+ ezSatPtr ez;
SatGen satgen;
std::vector<int> sat_pi, sat_out, sat_def;
@@ -259,7 +260,7 @@ struct PerformReduction
} else {
pi_bits.push_back(out);
sat_pi.push_back(satgen.importSigSpec(out).front());
- ez.assume(ez.NOT(satgen.importUndefSigSpec(out).front()));
+ ez->assume(ez->NOT(satgen.importUndefSigSpec(out).front()));
sigdepth[out] = 0;
}
@@ -267,7 +268,7 @@ struct PerformReduction
}
PerformReduction(SigMap &sigmap, drivers_t &drivers, std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> &inv_pairs, std::vector<RTLIL::SigBit> &bits, int cone_size) :
- sigmap(sigmap), drivers(drivers), inv_pairs(inv_pairs), satgen(&ez, &sigmap), out_bits(bits), cone_size(cone_size)
+ sigmap(sigmap), drivers(drivers), inv_pairs(inv_pairs), satgen(ez.get(), &sigmap), out_bits(bits), cone_size(cone_size)
{
satgen.model_undef = true;
@@ -277,15 +278,15 @@ struct PerformReduction
for (auto &bit : bits) {
out_depth.push_back(register_cone_worker(celldone, sigdepth, bit));
sat_out.push_back(satgen.importSigSpec(bit).front());
- sat_def.push_back(ez.NOT(satgen.importUndefSigSpec(bit).front()));
+ sat_def.push_back(ez->NOT(satgen.importUndefSigSpec(bit).front()));
}
if (inv_mode && cone_size > 0) {
- if (!ez.solve(sat_out, out_inverted, ez.expression(ezSAT::OpAnd, sat_def)))
+ if (!ez->solve(sat_out, out_inverted, ez->expression(ezSAT::OpAnd, sat_def)))
log_error("Solving for initial model failed!\n");
for (size_t i = 0; i < sat_out.size(); i++)
if (out_inverted.at(i))
- sat_out[i] = ez.NOT(sat_out[i]);
+ sat_out[i] = ez->NOT(sat_out[i]);
} else
out_inverted = std::vector<bool>(sat_out.size(), false);
}
@@ -295,8 +296,8 @@ struct PerformReduction
if (verbose_level == 1)
log(" Finding const value for %s.\n", log_signal(out_bits[idx]));
- bool can_be_set = ez.solve(ez.AND(sat_out[idx], sat_def[idx]));
- bool can_be_clr = ez.solve(ez.AND(ez.NOT(sat_out[idx]), sat_def[idx]));
+ bool can_be_set = ez->solve(ez->AND(sat_out[idx], sat_def[idx]));
+ bool can_be_clr = ez->solve(ez->AND(ez->NOT(sat_out[idx]), sat_def[idx]));
log_assert(!can_be_set || !can_be_clr);
RTLIL::SigBit value(RTLIL::State::Sx);
@@ -354,8 +355,8 @@ struct PerformReduction
std::vector<int> sat_set_list, sat_clr_list;
for (int idx : bucket) {
- sat_set_list.push_back(ez.AND(sat_out[idx], sat_def[idx]));
- sat_clr_list.push_back(ez.AND(ez.NOT(sat_out[idx]), sat_def[idx]));
+ sat_set_list.push_back(ez->AND(sat_out[idx], sat_def[idx]));
+ sat_clr_list.push_back(ez->AND(ez->NOT(sat_out[idx]), sat_def[idx]));
}
std::vector<int> modelVars = sat_out;
@@ -365,7 +366,7 @@ struct PerformReduction
if (verbose_level >= 2)
modelVars.insert(modelVars.end(), sat_pi.begin(), sat_pi.end());
- if (ez.solve(modelVars, model, ez.expression(ezSAT::OpOr, sat_set_list), ez.expression(ezSAT::OpOr, sat_clr_list)))
+ if (ez->solve(modelVars, model, ez->expression(ezSAT::OpOr, sat_set_list), ez->expression(ezSAT::OpOr, sat_clr_list)))
{
int iter_count = 1;
@@ -378,13 +379,13 @@ struct PerformReduction
for (int idx : bucket)
if (!model[sat_out.size() + idx]) {
- sat_set_list.push_back(ez.AND(sat_out[idx], sat_def[idx]));
- sat_clr_list.push_back(ez.AND(ez.NOT(sat_out[idx]), sat_def[idx]));
+ sat_set_list.push_back(ez->AND(sat_out[idx], sat_def[idx]));
+ sat_clr_list.push_back(ez->AND(ez->NOT(sat_out[idx]), sat_def[idx]));
} else {
sat_def_list.push_back(sat_def[idx]);
}
- if (!ez.solve(modelVars, model, ez.expression(ezSAT::OpOr, sat_set_list), ez.expression(ezSAT::OpOr, sat_clr_list), ez.expression(ezSAT::OpAnd, sat_def_list)))
+ if (!ez->solve(modelVars, model, ez->expression(ezSAT::OpOr, sat_set_list), ez->expression(ezSAT::OpOr, sat_clr_list), ez->expression(ezSAT::OpAnd, sat_def_list)))
break;
iter_count++;
}
@@ -430,7 +431,7 @@ struct PerformReduction
for (int idx2 : bucket)
if (idx != idx2)
sat_def_list.push_back(sat_def[idx2]);
- if (ez.solve(ez.NOT(sat_def[idx]), ez.expression(ezSAT::OpOr, sat_def_list)))
+ if (ez->solve(ez->NOT(sat_def[idx]), ez->expression(ezSAT::OpOr, sat_def_list)))
undef_slaves.push_back(idx);
}
@@ -504,7 +505,7 @@ struct PerformReduction
for (int idx2 : r)
if (idx != idx2)
sat_def_list.push_back(sat_def[idx2]);
- if (ez.solve(ez.NOT(sat_def[idx]), ez.expression(ezSAT::OpOr, sat_def_list)))
+ if (ez->solve(ez->NOT(sat_def[idx]), ez->expression(ezSAT::OpOr, sat_def_list)))
undef_slaves.push_back(idx);
}
@@ -745,8 +746,6 @@ struct FreduceWorker
}
};
-} /* namespace */
-
struct FreducePass : public Pass {
FreducePass() : Pass("freduce", "perform functional reduction") { }
virtual void help()
@@ -827,3 +826,4 @@ struct FreducePass : public Pass {
}
} FreducePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index b3adefb9..9853cd0c 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -21,7 +21,10 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-static void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL::Design *design)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL::Design *design)
{
bool flag_ignore_gold_x = false;
bool flag_make_outputs = false;
@@ -299,3 +302,4 @@ struct MiterPass : public Pass {
}
} MiterPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index fd0abf4a..9e5cc9e9 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -33,23 +33,25 @@
#include <errno.h>
#include <string.h>
-namespace {
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
struct SatHelper
{
RTLIL::Design *design;
RTLIL::Module *module;
- ezDefaultSAT ez;
SigMap sigmap;
CellTypes ct;
+
+ ezSatPtr ez;
SatGen satgen;
// additional constraints
std::vector<std::pair<std::string, std::string>> sets, prove, prove_x, sets_init;
std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at;
std::map<int, std::vector<std::string>> unsets_at;
- bool prove_asserts;
+ bool prove_asserts, set_assumes;
// undef constraints
bool enable_undef, set_init_def, set_init_undef, set_init_zero, ignore_unknown_cells;
@@ -64,7 +66,7 @@ struct SatHelper
bool gotTimeout;
SatHelper(RTLIL::Design *design, RTLIL::Module *module, bool enable_undef) :
- design(design), module(module), sigmap(module), ct(design), satgen(&ez, &sigmap)
+ design(design), module(module), sigmap(module), ct(design), satgen(ez.get(), &sigmap)
{
this->enable_undef = enable_undef;
satgen.model_undef = enable_undef;
@@ -115,7 +117,7 @@ struct SatHelper
}
if (removed_bits.size())
- log("Warning: ignoring initial value on non-register: %s\n", log_signal(removed_bits));
+ log_warning("ignoring initial value on non-register: %s\n", log_signal(removed_bits));
if (lhs.size()) {
log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs));
@@ -154,7 +156,7 @@ struct SatHelper
if (set_init_def) {
RTLIL::SigSpec rem = satgen.initial_state.export_all();
std::vector<int> undef_rem = satgen.importUndefSigSpec(rem, 1);
- ez.assume(ez.NOT(ez.expression(ezSAT::OpOr, undef_rem)));
+ ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_rem)));
}
if (set_init_undef) {
@@ -178,7 +180,7 @@ struct SatHelper
log("Final constraint equation: %s = %s\n\n", log_signal(big_lhs), log_signal(big_rhs));
check_undef_enabled(big_lhs), check_undef_enabled(big_rhs);
- ez.assume(satgen.signals_eq(big_lhs, big_rhs, 1));
+ ez->assume(satgen.signals_eq(big_lhs, big_rhs, 1));
}
void setup(int timestep = -1)
@@ -249,7 +251,7 @@ struct SatHelper
log("Final constraint equation: %s = %s\n", log_signal(big_lhs), log_signal(big_rhs));
check_undef_enabled(big_lhs), check_undef_enabled(big_rhs);
- ez.assume(satgen.signals_eq(big_lhs, big_rhs, timestep));
+ ez->assume(satgen.signals_eq(big_lhs, big_rhs, timestep));
// 0 = sets_def
// 1 = sets_any_undef
@@ -309,28 +311,36 @@ struct SatHelper
log("Import %s constraint for this timestep: %s\n", t == 0 ? "def" : t == 1 ? "any_undef" : "all_undef", log_signal(sig));
std::vector<int> undef_sig = satgen.importUndefSigSpec(sig, timestep);
if (t == 0)
- ez.assume(ez.NOT(ez.expression(ezSAT::OpOr, undef_sig)));
+ ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_sig)));
if (t == 1)
- ez.assume(ez.expression(ezSAT::OpOr, undef_sig));
+ ez->assume(ez->expression(ezSAT::OpOr, undef_sig));
if (t == 2)
- ez.assume(ez.expression(ezSAT::OpAnd, undef_sig));
+ ez->assume(ez->expression(ezSAT::OpAnd, undef_sig));
}
int import_cell_counter = 0;
- for (auto &c : module->cells_)
- if (design->selected(module, c.second)) {
- // log("Import cell: %s\n", RTLIL::id2cstr(c.first));
- if (satgen.importCell(c.second, timestep)) {
- for (auto &p : c.second->connections())
- if (ct.cell_output(c.second->type, p.first))
- show_drivers.insert(sigmap(p.second), c.second);
+ for (auto cell : module->cells())
+ if (design->selected(module, cell)) {
+ // log("Import cell: %s\n", RTLIL::id2cstr(cell->name));
+ if (satgen.importCell(cell, timestep)) {
+ for (auto &p : cell->connections())
+ if (ct.cell_output(cell->type, p.first))
+ show_drivers.insert(sigmap(p.second), cell);
import_cell_counter++;
} else if (ignore_unknown_cells)
- log("Warning: Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(c.first), RTLIL::id2cstr(c.second->type));
+ log_warning("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
else
- log_error("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(c.first), RTLIL::id2cstr(c.second->type));
+ log_error("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
}
log("Imported %d cells to SAT database.\n", import_cell_counter);
+
+ if (set_assumes) {
+ RTLIL::SigSpec assumes_a, assumes_en;
+ satgen.getAssumes(assumes_a, assumes_en, timestep);
+ for (int i = 0; i < GetSize(assumes_a); i++)
+ log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]));
+ ez->assume(satgen.importAssumes(timestep));
+ }
}
int setup_proof(int timestep = -1)
@@ -400,33 +410,33 @@ struct SatHelper
std::vector<int> undef_rhs = satgen.importUndefSigSpec(big_rhs, timestep);
for (size_t i = 0; i < value_lhs.size(); i++)
- prove_bits.push_back(ez.OR(undef_lhs.at(i), ez.AND(ez.NOT(undef_rhs.at(i)), ez.NOT(ez.XOR(value_lhs.at(i), value_rhs.at(i))))));
+ prove_bits.push_back(ez->OR(undef_lhs.at(i), ez->AND(ez->NOT(undef_rhs.at(i)), ez->NOT(ez->XOR(value_lhs.at(i), value_rhs.at(i))))));
}
if (prove_asserts) {
RTLIL::SigSpec asserts_a, asserts_en;
satgen.getAsserts(asserts_a, asserts_en, timestep);
- for (int i = 0; i < SIZE(asserts_a); i++)
+ for (int i = 0; i < GetSize(asserts_a); i++)
log("Import proof for assert: %s when %s.\n", log_signal(asserts_a[i]), log_signal(asserts_en[i]));
prove_bits.push_back(satgen.importAsserts(timestep));
}
- return ez.expression(ezSAT::OpAnd, prove_bits);
+ return ez->expression(ezSAT::OpAnd, prove_bits);
}
void force_unique_state(int timestep_from, int timestep_to)
{
RTLIL::SigSpec state_signals = satgen.initial_state.export_all();
for (int i = timestep_from; i < timestep_to; i++)
- ez.assume(ez.NOT(satgen.signals_eq(state_signals, state_signals, i, timestep_to)));
+ ez->assume(ez->NOT(satgen.signals_eq(state_signals, state_signals, i, timestep_to)));
}
bool solve(const std::vector<int> &assumptions)
{
log_assert(gotTimeout == false);
- ez.setSolverTimeout(timeout);
- bool success = ez.solve(modelExpressions, modelValues, assumptions);
- if (ez.getSolverTimoutStatus())
+ ez->setSolverTimeout(timeout);
+ bool success = ez->solve(modelExpressions, modelValues, assumptions);
+ if (ez->getSolverTimoutStatus())
gotTimeout = true;
return success;
}
@@ -434,9 +444,9 @@ struct SatHelper
bool solve(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0, int f = 0)
{
log_assert(gotTimeout == false);
- ez.setSolverTimeout(timeout);
- bool success = ez.solve(modelExpressions, modelValues, a, b, c, d, e, f);
- if (ez.getSolverTimoutStatus())
+ ez->setSolverTimeout(timeout);
+ bool success = ez->solve(modelExpressions, modelValues, a, b, c, d, e, f);
+ if (ez->getSolverTimoutStatus())
gotTimeout = true;
return success;
}
@@ -477,7 +487,7 @@ struct SatHelper
maybe_undef.push_back(modelExpressions.at(modelExpressions.size()/2 + i));
backupValues.swap(modelValues);
- if (!solve(ez.expression(ezSAT::OpAnd, must_undef), ez.expression(ezSAT::OpOr, maybe_undef)))
+ if (!solve(ez->expression(ezSAT::OpAnd, must_undef), ez->expression(ezSAT::OpOr, maybe_undef)))
break;
}
@@ -670,7 +680,7 @@ struct SatHelper
fprintf(f, " %s\n", stime);
fprintf(f, "$end\n");
fprintf(f, "$version\n");
- fprintf(f, " Generated by %s\n", yosys_version_str);
+ fprintf(f, " Generated by %s\n", yosys_version_str);
fprintf(f, "$end\n");
fprintf(f, "$comment\n");
fprintf(f, " Generated from SAT problem in module %s (declared at %s)\n",
@@ -749,6 +759,80 @@ struct SatHelper
fclose(f);
}
+ void dump_model_to_json(std::string json_file_name)
+ {
+ FILE *f = fopen(json_file_name.c_str(), "w");
+ if (!f)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", json_file_name.c_str(), strerror(errno));
+
+ log("Dumping SAT model to WaveJSON file '%s'.\n", json_file_name.c_str());
+
+ int mintime = 1, maxtime = 0, maxwidth = 0;;
+ dict<string, pair<int, dict<int, Const>>> wavedata;
+
+ for (auto &info : modelInfo)
+ {
+ Const value;
+ for (int i = 0; i < info.width; i++) {
+ value.bits.push_back(modelValues.at(info.offset+i) ? RTLIL::State::S1 : RTLIL::State::S0);
+ if (enable_undef && modelValues.at(modelExpressions.size()/2 + info.offset + i))
+ value.bits.back() = RTLIL::State::Sx;
+ }
+
+ wavedata[info.description].first = info.width;
+ wavedata[info.description].second[info.timestep] = value;
+ mintime = std::min(mintime, info.timestep);
+ maxtime = std::max(maxtime, info.timestep);
+ maxwidth = std::max(maxwidth, info.width);
+ }
+
+ fprintf(f, "{ \"signal\": [");
+ bool fist_wavedata = true;
+ for (auto &wd : wavedata)
+ {
+ fprintf(f, "%s", fist_wavedata ? "\n" : ",\n");
+ fist_wavedata = false;
+
+ vector<string> data;
+ string name = wd.first.c_str();
+ while (name.substr(0, 1) == "\\")
+ name = name.substr(1);
+
+ fprintf(f, " { \"name\": \"%s\", \"wave\": \"", name.c_str());
+ for (int i = mintime; i <= maxtime; i++) {
+ if (wd.second.second.count(i)) {
+ string this_data = wd.second.second[i].as_string();
+ char ch = '=';
+ if (wd.second.first == 1)
+ ch = this_data[0];
+ if (!data.empty() && data.back() == this_data) {
+ fprintf(f, ".");
+ } else {
+ data.push_back(this_data);
+ fprintf(f, "%c", ch);
+ }
+ } else {
+ data.push_back("");
+ fprintf(f, "4");
+ }
+ }
+ if (wd.second.first != 1) {
+ fprintf(f, "\", \"data\": [");
+ for (int i = 0; i < GetSize(data); i++)
+ fprintf(f, "%s\"%s\"", i ? ", " : "", data[i].c_str());
+ fprintf(f, "] }");
+ } else {
+ fprintf(f, "\" }");
+ }
+ }
+ fprintf(f, "\n ],\n");
+ fprintf(f, " \"config\": {\n");
+ fprintf(f, " \"hscale\": %.2f\n", maxwidth / 4.0);
+ fprintf(f, " }\n");
+ fprintf(f, "}\n");
+ fclose(f);
+ }
+
void invalidate_model(bool max_undef)
{
std::vector<int> clause;
@@ -757,18 +841,16 @@ struct SatHelper
int bit = modelExpressions.at(i), bit_undef = modelExpressions.at(modelExpressions.size()/2 + i);
bool val = modelValues.at(i), val_undef = modelValues.at(modelExpressions.size()/2 + i);
if (!max_undef || !val_undef)
- clause.push_back(val_undef ? ez.NOT(bit_undef) : val ? ez.NOT(bit) : bit);
+ clause.push_back(val_undef ? ez->NOT(bit_undef) : val ? ez->NOT(bit) : bit);
}
} else
for (size_t i = 0; i < modelExpressions.size(); i++)
- clause.push_back(modelValues.at(i) ? ez.NOT(modelExpressions.at(i)) : modelExpressions.at(i));
- ez.assume(ez.expression(ezSAT::OpOr, clause));
+ clause.push_back(modelValues.at(i) ? ez->NOT(modelExpressions.at(i)) : modelExpressions.at(i));
+ ez->assume(ez->expression(ezSAT::OpOr, clause));
}
};
-} /* namespace */
-
-static void print_proof_failed()
+void print_proof_failed()
{
log("\n");
log(" ______ ___ ___ _ _ _ _ \n");
@@ -780,7 +862,7 @@ static void print_proof_failed()
log("\n");
}
-static void print_timeout()
+void print_timeout()
{
log("\n");
log(" _____ _ _ _____ ____ _ _____\n");
@@ -791,7 +873,7 @@ static void print_timeout()
log("\n");
}
-static void print_qed()
+void print_qed()
{
log("\n");
log(" /$$$$$$ /$$$$$$$$ /$$$$$$$ \n");
@@ -851,8 +933,8 @@ struct SatPass : public Pass {
log(" show the model for the specified signal. if no -show option is\n");
log(" passed then a set of signals to be shown is automatically selected.\n");
log("\n");
- log(" -show-inputs, -show-outputs\n");
- log(" add all module input (output) ports to the list of shown signals\n");
+ log(" -show-inputs, -show-outputs, -show-ports\n");
+ log(" add all module (input/output) ports to the list of shown signals\n");
log("\n");
log(" -ignore_div_by_zero\n");
log(" ignore all solutions that involve a division by zero\n");
@@ -866,11 +948,17 @@ struct SatPass : public Pass {
log(" set up a sequential problem with <N> time steps. The steps will\n");
log(" be numbered from 1 to N.\n");
log("\n");
+ log(" note: for large <N> it can be significantly faster to use\n");
+ log(" -tempinduct-baseonly -maxsteps <N> instead of -seq <N>.\n");
+ log("\n");
log(" -set-at <N> <signal> <value>\n");
log(" -unset-at <N> <signal>\n");
log(" set or unset the specified signal to the specified value in the\n");
log(" given timestep. this has priority over a -set for the same signal.\n");
log("\n");
+ log(" -set-assumes\n");
+ log(" set all assumptions provided via $assume cells\n");
+ log("\n");
log(" -set-def-at <N> <signal>\n");
log(" -set-any-undef-at <N> <signal>\n");
log(" -set-all-undef-at <N> <signal>\n");
@@ -891,6 +979,9 @@ struct SatPass : public Pass {
log(" -dump_vcd <vcd-file-name>\n");
log(" dump SAT model (counter example in proof) to VCD file\n");
log("\n");
+ log(" -dump_json <json-file-name>\n");
+ log(" dump SAT model (counter example in proof) to a WaveJSON file.\n");
+ log("\n");
log(" -dump_cnf <cnf-file-name>\n");
log(" dump CNF of SAT problem (in DIMACS format). in temporal induction\n");
log(" proofs this is the CNF of the first induction step.\n");
@@ -907,6 +998,20 @@ struct SatPass : public Pass {
log(" Perform a temporal induction proof. Assume an initial state with all\n");
log(" registers set to defined values for the induction step.\n");
log("\n");
+ log(" -tempinduct-baseonly\n");
+ log(" Run only the basecase half of temporal induction (requires -maxsteps)\n");
+ log("\n");
+ log(" -tempinduct-inductonly\n");
+ log(" Run only the induction half of temporal induction\n");
+ log("\n");
+ log(" -tempinduct-skip <N>\n");
+ log(" Skip the first <N> steps of the induction proof.\n");
+ log("\n");
+ log(" note: this will assume that the base case holds for <N> steps.\n");
+ log(" this must be proven independently with \"-tempinduct-baseonly\n");
+ log(" -maxsteps <N>\". Use -initsteps if you just want to set a\n");
+ log(" minimal induction length.\n");
+ log("\n");
log(" -prove <signal> <value>\n");
log(" Attempt to proof that <signal> is always <value>.\n");
log("\n");
@@ -925,6 +1030,13 @@ struct SatPass : public Pass {
log("\n");
log(" -initsteps <N>\n");
log(" Set initial length for the induction.\n");
+ log(" This will speed up the search of the right induction length\n");
+ log(" for deep induction proofs.\n");
+ log("\n");
+ log(" -stepsize <N>\n");
+ log(" Increase the size of the induction proof in steps of <N>.\n");
+ log(" This will speed up the search of the right induction length\n");
+ log(" for deep induction proofs.\n");
log("\n");
log(" -timeout <N>\n");
log(" Maximum number of seconds a single SAT instance may take.\n");
@@ -953,7 +1065,9 @@ struct SatPass : public Pass {
bool ignore_div_by_zero = false, set_init_undef = false, set_init_zero = false, max_undef = false;
bool tempinduct = false, prove_asserts = false, show_inputs = false, show_outputs = false;
bool ignore_unknown_cells = false, falsify = false, tempinduct_def = false, set_init_def = false;
- std::string vcd_file_name, cnf_file_name;
+ bool tempinduct_baseonly = false, tempinduct_inductonly = false, set_assumes = false;
+ int tempinduct_skip = 0, stepsize = 1;
+ std::string vcd_file_name, json_file_name, cnf_file_name;
log_header("Executing SAT pass (solving SAT problems in the circuit).\n");
@@ -997,6 +1111,10 @@ struct SatPass : public Pass {
initsteps = atoi(args[++argidx].c_str());
continue;
}
+ if (args[argidx] == "-stepsize" && argidx+1 < args.size()) {
+ stepsize = std::max(1, atoi(args[++argidx].c_str()));
+ continue;
+ }
if (args[argidx] == "-ignore_div_by_zero") {
ignore_div_by_zero = true;
continue;
@@ -1036,6 +1154,10 @@ struct SatPass : public Pass {
enable_undef = true;
continue;
}
+ if (args[argidx] == "-set-assumes") {
+ set_assumes = true;
+ continue;
+ }
if (args[argidx] == "-tempinduct") {
tempinduct = true;
continue;
@@ -1045,6 +1167,20 @@ struct SatPass : public Pass {
tempinduct_def = true;
continue;
}
+ if (args[argidx] == "-tempinduct-baseonly") {
+ tempinduct = true;
+ tempinduct_baseonly = true;
+ continue;
+ }
+ if (args[argidx] == "-tempinduct-inductonly") {
+ tempinduct = true;
+ tempinduct_inductonly = true;
+ continue;
+ }
+ if (args[argidx] == "-tempinduct-skip" && argidx+1 < args.size()) {
+ tempinduct_skip = atoi(args[++argidx].c_str());
+ continue;
+ }
if (args[argidx] == "-prove" && argidx+2 < args.size()) {
std::string lhs = args[++argidx];
std::string rhs = args[++argidx];
@@ -1131,6 +1267,11 @@ struct SatPass : public Pass {
show_outputs = true;
continue;
}
+ if (args[argidx] == "-show-ports") {
+ show_inputs = true;
+ show_outputs = true;
+ continue;
+ }
if (args[argidx] == "-ignore_unknown_cells") {
ignore_unknown_cells = true;
continue;
@@ -1139,6 +1280,10 @@ struct SatPass : public Pass {
vcd_file_name = args[++argidx];
continue;
}
+ if (args[argidx] == "-dump_json" && argidx+1 < args.size()) {
+ json_file_name = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-dump_cnf" && argidx+1 < args.size()) {
cnf_file_name = args[++argidx];
continue;
@@ -1155,14 +1300,14 @@ struct SatPass : public Pass {
RTLIL::id2cstr(module->name), RTLIL::id2cstr(mod_it.first));
module = mod_it.second;
}
- if (module == NULL)
+ if (module == NULL)
log_cmd_error("Can't perform SAT on an empty selection!\n");
if (!prove.size() && !prove_x.size() && !prove_asserts && tempinduct)
log_cmd_error("Got -tempinduct but nothing to prove!\n");
if (prove_skip && tempinduct)
- log_cmd_error("Options -prove-skip and -tempinduct don't work with each other.\n");
+ log_cmd_error("Options -prove-skip and -tempinduct don't work with each other. Use -seq instead of -prove-skip.\n");
if (prove_skip >= seq_len && prove_skip > 0)
log_cmd_error("The value of -prove-skip must be smaller than the one of -seq.\n");
@@ -1195,8 +1340,10 @@ struct SatPass : public Pass {
SatHelper basecase(design, module, enable_undef);
SatHelper inductstep(design, module, enable_undef);
+ bool basecase_setup_init = true;
basecase.sets = sets;
+ basecase.set_assumes = set_assumes;
basecase.prove = prove;
basecase.prove_x = prove_x;
basecase.prove_asserts = prove_asserts;
@@ -1218,10 +1365,11 @@ struct SatPass : public Pass {
basecase.ignore_unknown_cells = ignore_unknown_cells;
for (int timestep = 1; timestep <= seq_len; timestep++)
- basecase.setup(timestep);
- basecase.setup_init();
+ if (!tempinduct_inductonly)
+ basecase.setup(timestep);
inductstep.sets = sets;
+ inductstep.set_assumes = set_assumes;
inductstep.prove = prove;
inductstep.prove_x = prove_x;
inductstep.prove_asserts = prove_asserts;
@@ -1233,12 +1381,14 @@ struct SatPass : public Pass {
inductstep.satgen.ignore_div_by_zero = ignore_div_by_zero;
inductstep.ignore_unknown_cells = ignore_unknown_cells;
- inductstep.setup(1);
- inductstep.ez.assume(inductstep.setup_proof(1));
+ if (!tempinduct_baseonly) {
+ inductstep.setup(1);
+ inductstep.ez->assume(inductstep.setup_proof(1));
+ }
if (tempinduct_def) {
std::vector<int> undef_state = inductstep.satgen.importUndefSigSpec(inductstep.satgen.initial_state.export_all(), 1);
- inductstep.ez.assume(inductstep.ez.NOT(inductstep.ez.expression(ezSAT::OpOr, undef_state)));
+ inductstep.ez->assume(inductstep.ez->NOT(inductstep.ez->expression(ezSAT::OpOr, undef_state)));
}
for (int inductlen = 1; inductlen <= maxsteps || maxsteps == 0; inductlen++)
@@ -1247,81 +1397,120 @@ struct SatPass : public Pass {
// phase 1: proving base case
- basecase.setup(seq_len + inductlen);
- int property = basecase.setup_proof(seq_len + inductlen);
- basecase.generate_model();
-
- if (inductlen > 1)
- basecase.force_unique_state(seq_len + 1, seq_len + inductlen);
+ if (!tempinduct_inductonly)
+ {
+ basecase.setup(seq_len + inductlen);
+ int property = basecase.setup_proof(seq_len + inductlen);
+ basecase.generate_model();
- log("\n[base case] Solving problem with %d variables and %d clauses..\n",
- basecase.ez.numCnfVariables(), basecase.ez.numCnfClauses());
+ if (basecase_setup_init) {
+ basecase.setup_init();
+ basecase_setup_init = false;
+ }
- if (basecase.solve(basecase.ez.NOT(property))) {
- log("SAT temporal induction proof finished - model found for base case: FAIL!\n");
- print_proof_failed();
- basecase.print_model();
- if(!vcd_file_name.empty())
- basecase.dump_model_to_vcd(vcd_file_name);
- goto tip_failed;
- }
+ if (inductlen > 1)
+ basecase.force_unique_state(seq_len + 1, seq_len + inductlen);
- if (basecase.gotTimeout)
- goto timeout;
+ if (tempinduct_skip < inductlen)
+ {
+ log("\n[base case %d] Solving problem with %d variables and %d clauses..\n",
+ inductlen, basecase.ez->numCnfVariables(), basecase.ez->numCnfClauses());
+
+ if (basecase.solve(basecase.ez->NOT(property))) {
+ log("SAT temporal induction proof finished - model found for base case: FAIL!\n");
+ print_proof_failed();
+ basecase.print_model();
+ if(!vcd_file_name.empty())
+ basecase.dump_model_to_vcd(vcd_file_name);
+ if(!json_file_name.empty())
+ basecase.dump_model_to_json(json_file_name);
+ goto tip_failed;
+ }
+
+ if (basecase.gotTimeout)
+ goto timeout;
- log("Base case for induction length %d proven.\n", inductlen);
- basecase.ez.assume(property);
+ log("Base case for induction length %d proven.\n", inductlen);
+ }
+ else
+ {
+ log("\n[base case %d] Skipping prove for this step (-tempinduct-skip %d).",
+ inductlen, tempinduct_skip);
+ log("\n[base case %d] Problem size so far: %d variables and %d clauses.\n",
+ inductlen, basecase.ez->numCnfVariables(), basecase.ez->numCnfClauses());
+ }
+ basecase.ez->assume(property);
+ }
// phase 2: proving induction step
- inductstep.setup(inductlen + 1);
- property = inductstep.setup_proof(inductlen + 1);
- inductstep.generate_model();
-
- if (inductlen > 1)
- inductstep.force_unique_state(1, inductlen + 1);
-
- if (inductlen < initsteps)
- {
- log("\n[induction step] Skipping problem with %d variables and %d clauses (below initsteps).\n",
- inductstep.ez.numCnfVariables(), inductstep.ez.numCnfClauses());
- inductstep.ez.assume(property);
- }
- else
+ if (!tempinduct_baseonly)
{
- if (!cnf_file_name.empty())
- {
- FILE *f = fopen(cnf_file_name.c_str(), "w");
- if (!f)
- log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
+ inductstep.setup(inductlen + 1);
+ int property = inductstep.setup_proof(inductlen + 1);
+ inductstep.generate_model();
- log("Dumping CNF to file `%s'.\n", cnf_file_name.c_str());
- cnf_file_name.clear();
+ if (inductlen > 1)
+ inductstep.force_unique_state(1, inductlen + 1);
- inductstep.ez.printDIMACS(f, false);
- fclose(f);
+ if (inductlen <= tempinduct_skip || inductlen <= initsteps || inductlen % stepsize != 0)
+ {
+ if (inductlen < tempinduct_skip)
+ log("\n[induction step %d] Skipping prove for this step (-tempinduct-skip %d).",
+ inductlen, tempinduct_skip);
+ if (inductlen < initsteps)
+ log("\n[induction step %d] Skipping prove for this step (-initsteps %d).",
+ inductlen, tempinduct_skip);
+ if (inductlen % stepsize != 0)
+ log("\n[induction step %d] Skipping prove for this step (-stepsize %d).",
+ inductlen, stepsize);
+ log("\n[induction step %d] Problem size so far: %d variables and %d clauses.\n",
+ inductlen, inductstep.ez->numCnfVariables(), inductstep.ez->numCnfClauses());
+ inductstep.ez->assume(property);
}
-
- log("\n[induction step] Solving problem with %d variables and %d clauses..\n",
- inductstep.ez.numCnfVariables(), inductstep.ez.numCnfClauses());
-
- if (!inductstep.solve(inductstep.ez.NOT(property))) {
- if (inductstep.gotTimeout)
- goto timeout;
- log("Induction step proven: SUCCESS!\n");
- print_qed();
- goto tip_success;
+ else
+ {
+ if (!cnf_file_name.empty())
+ {
+ FILE *f = fopen(cnf_file_name.c_str(), "w");
+ if (!f)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
+
+ log("Dumping CNF to file `%s'.\n", cnf_file_name.c_str());
+ cnf_file_name.clear();
+
+ inductstep.ez->printDIMACS(f, false);
+ fclose(f);
+ }
+
+ log("\n[induction step %d] Solving problem with %d variables and %d clauses..\n",
+ inductlen, inductstep.ez->numCnfVariables(), inductstep.ez->numCnfClauses());
+
+ if (!inductstep.solve(inductstep.ez->NOT(property))) {
+ if (inductstep.gotTimeout)
+ goto timeout;
+ log("Induction step proven: SUCCESS!\n");
+ print_qed();
+ goto tip_success;
+ }
+
+ log("Induction step failed. Incrementing induction length.\n");
+ inductstep.ez->assume(property);
+ inductstep.print_model();
}
-
- log("Induction step failed. Incrementing induction length.\n");
- inductstep.ez.assume(property);
- inductstep.print_model();
}
}
+ if (tempinduct_baseonly) {
+ log("\nReached maximum number of time steps -> proved base case for %d steps: SUCCESS!\n", maxsteps);
+ goto tip_success;
+ }
+
log("\nReached maximum number of time steps -> proof failed.\n");
if(!vcd_file_name.empty())
inductstep.dump_model_to_vcd(vcd_file_name);
+ if(!json_file_name.empty())
+ inductstep.dump_model_to_json(json_file_name);
print_proof_failed();
tip_failed:
@@ -1345,6 +1534,7 @@ struct SatPass : public Pass {
SatHelper sathelper(design, module, enable_undef);
sathelper.sets = sets;
+ sathelper.set_assumes = set_assumes;
sathelper.prove = prove;
sathelper.prove_x = prove_x;
sathelper.prove_asserts = prove_asserts;
@@ -1368,7 +1558,7 @@ struct SatPass : public Pass {
if (seq_len == 0) {
sathelper.setup();
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
- sathelper.ez.assume(sathelper.ez.NOT(sathelper.setup_proof()));
+ sathelper.ez->assume(sathelper.ez->NOT(sathelper.setup_proof()));
} else {
std::vector<int> prove_bits;
for (int timestep = 1; timestep <= seq_len; timestep++) {
@@ -1378,7 +1568,7 @@ struct SatPass : public Pass {
prove_bits.push_back(sathelper.setup_proof(timestep));
}
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
- sathelper.ez.assume(sathelper.ez.NOT(sathelper.ez.expression(ezSAT::OpAnd, prove_bits)));
+ sathelper.ez->assume(sathelper.ez->NOT(sathelper.ez->expression(ezSAT::OpAnd, prove_bits)));
sathelper.setup_init();
}
sathelper.generate_model();
@@ -1392,7 +1582,7 @@ struct SatPass : public Pass {
log("Dumping CNF to file `%s'.\n", cnf_file_name.c_str());
cnf_file_name.clear();
- sathelper.ez.printDIMACS(f, false);
+ sathelper.ez->printDIMACS(f, false);
fclose(f);
}
@@ -1400,7 +1590,7 @@ struct SatPass : public Pass {
rerun_solver:
log("\nSolving problem with %d variables and %d clauses..\n",
- sathelper.ez.numCnfVariables(), sathelper.ez.numCnfClauses());
+ sathelper.ez->numCnfVariables(), sathelper.ez->numCnfClauses());
if (sathelper.solve())
{
@@ -1420,6 +1610,8 @@ struct SatPass : public Pass {
if(!vcd_file_name.empty())
sathelper.dump_model_to_vcd(vcd_file_name);
+ if(!json_file_name.empty())
+ sathelper.dump_model_to_json(json_file_name);
if (loopcount != 0) {
loopcount--, rerun_counter++;
@@ -1483,4 +1675,5 @@ struct SatPass : public Pass {
}
}
} SatPass;
-
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 72998f87..6b6846e2 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -2,14 +2,15 @@
OBJS += passes/techmap/techmap.o
OBJS += passes/techmap/simplemap.o
OBJS += passes/techmap/dfflibmap.o
+OBJS += passes/techmap/maccmap.o
OBJS += passes/techmap/libparse.o
ifneq ($(SMALL),1)
OBJS += passes/techmap/iopadmap.o
OBJS += passes/techmap/hilomap.o
OBJS += passes/techmap/extract.o
-OBJS += passes/techmap/maccmap.o
OBJS += passes/techmap/alumacc.o
+OBJS += passes/techmap/dff2dffe.o
endif
GENFILES += passes/techmap/techmap.inc
@@ -23,9 +24,11 @@ passes/techmap/techmap.inc: techlibs/common/techmap.v
passes/techmap/techmap.o: passes/techmap/techmap.inc
-TARGETS += yosys-filterlib
-GENFILES += passes/techmap/filterlib.o
+ifneq ($(CONFIG),emcc)
+TARGETS += yosys-filterlib$(EXE)
+EXTRA_OBJS += passes/techmap/filterlib.o
-yosys-filterlib: passes/techmap/filterlib.o
- $(P) $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS)
+yosys-filterlib$(EXE): passes/techmap/filterlib.o
+ $(P) $(CXX) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS)
+endif
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index 1115eead..dcffed94 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -21,6 +21,9 @@
#include "kernel/sigtools.h"
#include "kernel/macc.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct AlumaccWorker
{
RTLIL::Module *module;
@@ -45,51 +48,51 @@ struct AlumaccWorker
RTLIL::SigSpec cached_cf, cached_of, cached_sf;
RTLIL::SigSpec get_lt() {
- if (SIZE(cached_lt) == 0)
+ if (GetSize(cached_lt) == 0)
cached_lt = is_signed ? alu_cell->module->Xor(NEW_ID, get_of(), get_sf()) : get_cf();
return cached_lt;
}
RTLIL::SigSpec get_gt() {
- if (SIZE(cached_gt) == 0)
+ if (GetSize(cached_gt) == 0)
cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()));
return cached_gt;
}
RTLIL::SigSpec get_eq() {
- if (SIZE(cached_eq) == 0)
+ if (GetSize(cached_eq) == 0)
cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"));
return cached_eq;
}
RTLIL::SigSpec get_ne() {
- if (SIZE(cached_ne) == 0)
+ if (GetSize(cached_ne) == 0)
cached_ne = alu_cell->module->Not(NEW_ID, get_eq());
return cached_ne;
}
RTLIL::SigSpec get_cf() {
- if (SIZE(cached_cf) == 0) {
+ if (GetSize(cached_cf) == 0) {
cached_cf = alu_cell->getPort("\\CO");
- log_assert(SIZE(cached_cf) >= 1);
- cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[SIZE(cached_cf)-1]);
+ log_assert(GetSize(cached_cf) >= 1);
+ cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1]);
}
return cached_cf;
}
RTLIL::SigSpec get_of() {
- if (SIZE(cached_of) == 0) {
+ if (GetSize(cached_of) == 0) {
cached_of = {alu_cell->getPort("\\CO"), alu_cell->getPort("\\CI")};
- log_assert(SIZE(cached_of) >= 2);
- cached_of = alu_cell->module->Xor(NEW_ID, cached_of[SIZE(cached_of)-1], cached_of[SIZE(cached_of)-2]);
+ log_assert(GetSize(cached_of) >= 2);
+ cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(cached_of)-1], cached_of[GetSize(cached_of)-2]);
}
return cached_of;
}
RTLIL::SigSpec get_sf() {
- if (SIZE(cached_sf) == 0) {
+ if (GetSize(cached_sf) == 0) {
cached_sf = alu_cell->getPort("\\Y");
- cached_sf = cached_sf[SIZE(cached_sf)-1];
+ cached_sf = cached_sf[GetSize(cached_sf)-1];
}
return cached_sf;
}
@@ -181,10 +184,10 @@ struct AlumaccWorker
return true;
if (!port.is_signed && port.do_subtract)
return true;
- if (SIZE(port.in_b))
- port_sizes.push_back(SIZE(port.in_a) + SIZE(port.in_b));
+ if (GetSize(port.in_b))
+ port_sizes.push_back(GetSize(port.in_a) + GetSize(port.in_b));
else
- port_sizes.push_back(SIZE(port.in_a));
+ port_sizes.push_back(GetSize(port.in_a));
}
std::sort(port_sizes.begin(), port_sizes.end());
@@ -221,11 +224,11 @@ struct AlumaccWorker
if (delete_nodes.count(n))
continue;
- for (int i = 0; i < SIZE(n->macc.ports); i++)
+ for (int i = 0; i < GetSize(n->macc.ports); i++)
{
auto &port = n->macc.ports[i];
- if (SIZE(port.in_b) > 0 || sig_macc.count(port.in_a) == 0)
+ if (GetSize(port.in_b) > 0 || sig_macc.count(port.in_a) == 0)
continue;
auto other_n = sig_macc.at(port.in_a);
@@ -233,13 +236,13 @@ struct AlumaccWorker
if (other_n->users > 1)
continue;
- if (SIZE(other_n->y) != SIZE(n->y) && macc_may_overflow(other_n->macc, SIZE(other_n->y), port.is_signed))
+ if (GetSize(other_n->y) != GetSize(n->y) && macc_may_overflow(other_n->macc, GetSize(other_n->y), port.is_signed))
continue;
log(" merging $macc model for %s into %s.\n", log_id(other_n->cell), log_id(n->cell));
bool do_subtract = port.do_subtract;
- for (int j = 0; j < SIZE(other_n->macc.ports); j++) {
+ for (int j = 0; j < GetSize(other_n->macc.ports); j++) {
if (do_subtract)
other_n->macc.ports[j].do_subtract = !other_n->macc.ports[j].do_subtract;
if (j == 0)
@@ -275,38 +278,38 @@ struct AlumaccWorker
alunode_t *alunode;
for (auto &port : n->macc.ports)
- if (SIZE(port.in_b) > 0) {
+ if (GetSize(port.in_b) > 0) {
goto next_macc;
- } else if (SIZE(port.in_a) == 1 && !port.is_signed && !port.do_subtract) {
+ } else if (GetSize(port.in_a) == 1 && !port.is_signed && !port.do_subtract) {
C.append(port.in_a);
- } else if (SIZE(A) || port.do_subtract) {
- if (SIZE(B))
+ } else if (GetSize(A) || port.do_subtract) {
+ if (GetSize(B))
goto next_macc;
B = port.in_a;
b_signed = port.is_signed;
subtract_b = port.do_subtract;
} else {
- if (SIZE(A))
+ if (GetSize(A))
goto next_macc;
A = port.in_a;
a_signed = port.is_signed;
}
if (!a_signed || !b_signed) {
- if (SIZE(A) == SIZE(n->y))
+ if (GetSize(A) == GetSize(n->y))
a_signed = false;
- if (SIZE(B) == SIZE(n->y))
+ if (GetSize(B) == GetSize(n->y))
b_signed = false;
if (a_signed != b_signed)
goto next_macc;
}
- if (SIZE(A) == 0 && SIZE(C) > 0) {
+ if (GetSize(A) == 0 && GetSize(C) > 0) {
A = C[0];
C.remove(0);
}
- if (SIZE(B) == 0 && SIZE(C) > 0) {
+ if (GetSize(B) == 0 && GetSize(C) > 0) {
B = C[0];
C.remove(0);
}
@@ -314,10 +317,10 @@ struct AlumaccWorker
if (subtract_b)
C.append(RTLIL::S1);
- if (SIZE(C) > 1)
+ if (GetSize(C) > 1)
goto next_macc;
- if (!subtract_b && B < A && SIZE(B))
+ if (!subtract_b && B < A && GetSize(B))
std::swap(A, B);
log(" creating $alu model for $macc %s.\n", log_id(n->cell));
@@ -353,7 +356,7 @@ struct AlumaccWorker
log(" creating $macc cell for %s: %s\n", log_id(n->cell), log_id(cell));
- n->macc.optimize(SIZE(n->y));
+ n->macc.optimize(GetSize(n->y));
n->macc.to_cell(cell);
cell->setPort("\\Y", n->y);
cell->fixup_parameters();
@@ -388,7 +391,7 @@ struct AlumaccWorker
RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
- if (B < A && SIZE(B)) {
+ if (B < A && GetSize(B)) {
cmp_less = !cmp_less;
std::swap(A, B);
}
@@ -406,7 +409,7 @@ struct AlumaccWorker
n->a = A;
n->b = B;
n->c = RTLIL::S1;
- n->y = module->addWire(NEW_ID, std::max(SIZE(A), SIZE(B)));
+ n->y = module->addWire(NEW_ID, std::max(GetSize(A), GetSize(B)));
n->is_signed = is_signed;
n->invert_b = true;
sig_alu[RTLIL::SigSig(A, B)].insert(n);
@@ -428,7 +431,7 @@ struct AlumaccWorker
RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
- if (B < A && SIZE(B))
+ if (B < A && GetSize(B))
std::swap(A, B);
alunode_t *n = nullptr;
@@ -452,12 +455,12 @@ struct AlumaccWorker
for (auto &it1 : sig_alu)
for (auto n : it1.second)
{
- if (SIZE(n->b) == 0 && SIZE(n->c) == 0 && SIZE(n->cmp) == 0)
+ if (GetSize(n->b) == 0 && GetSize(n->c) == 0 && GetSize(n->cmp) == 0)
{
n->alu_cell = module->addPos(NEW_ID, n->a, n->y, n->is_signed);
log(" creating $pos cell for ");
- for (int i = 0; i < SIZE(n->cells); i++)
+ for (int i = 0; i < GetSize(n->cells); i++)
log("%s%s", i ? ", ": "", log_id(n->cells[i]));
log(": %s\n", log_id(n->alu_cell));
@@ -468,17 +471,17 @@ struct AlumaccWorker
alu_counter++;
log(" creating $alu cell for ");
- for (int i = 0; i < SIZE(n->cells); i++)
+ for (int i = 0; i < GetSize(n->cells); i++)
log("%s%s", i ? ", ": "", log_id(n->cells[i]));
log(": %s\n", log_id(n->alu_cell));
n->alu_cell->setPort("\\A", n->a);
n->alu_cell->setPort("\\B", n->b);
- n->alu_cell->setPort("\\CI", SIZE(n->c) ? n->c : RTLIL::S0);
+ n->alu_cell->setPort("\\CI", GetSize(n->c) ? n->c : RTLIL::S0);
n->alu_cell->setPort("\\BI", n->invert_b ? RTLIL::S1 : RTLIL::S0);
n->alu_cell->setPort("\\Y", n->y);
- n->alu_cell->setPort("\\X", module->addWire(NEW_ID, SIZE(n->y)));
- n->alu_cell->setPort("\\CO", module->addWire(NEW_ID, SIZE(n->y)));
+ n->alu_cell->setPort("\\X", module->addWire(NEW_ID, GetSize(n->y)));
+ n->alu_cell->setPort("\\CO", module->addWire(NEW_ID, GetSize(n->y)));
n->alu_cell->fixup_parameters(n->is_signed, n->is_signed);
for (auto &it : n->cmp)
@@ -495,10 +498,10 @@ struct AlumaccWorker
if (cmp_eq) sig.append(n->get_eq());
if (cmp_ne) sig.append(n->get_ne());
- if (SIZE(sig) > 1)
+ if (GetSize(sig) > 1)
sig = module->ReduceOr(NEW_ID, sig);
- sig.extend(SIZE(cmp_y));
+ sig.extend_u0(GetSize(cmp_y));
module->connect(cmp_y, sig);
}
@@ -535,8 +538,8 @@ struct AlumaccPass : public Pass {
log("\n");
log(" alumacc [selection]\n");
log("\n");
- log("This pass translates arithmetic operations $add, $mul, $lt, etc. to $alu and\n");
- log("$macc cells.\n");
+ log("This pass translates arithmetic operations like $add, $mul, $lt, etc. to $alu\n");
+ log("and $macc cells.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
@@ -561,3 +564,4 @@ struct AlumaccPass : public Pass {
}
} AlumaccPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
new file mode 100644
index 00000000..17549bd0
--- /dev/null
+++ b/passes/techmap/dff2dffe.cc
@@ -0,0 +1,337 @@
+/*
+ * 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"
+#include "passes/techmap/simplemap.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Dff2dffeWorker
+{
+ RTLIL::Module *module;
+ SigMap sigmap;
+ CellTypes ct;
+
+ RTLIL::IdString direct_to;
+
+ typedef std::pair<RTLIL::Cell*, int> cell_int_t;
+ std::map<RTLIL::SigBit, cell_int_t> bit2mux;
+ std::vector<RTLIL::Cell*> dff_cells;
+ std::map<RTLIL::SigBit, int> bitusers;
+
+ typedef std::map<RTLIL::SigBit, bool> pattern_t;
+ typedef std::set<pattern_t> patterns_t;
+
+
+ Dff2dffeWorker(RTLIL::Module *module, RTLIL::IdString direct_from, RTLIL::IdString direct_to) :
+ module(module), sigmap(module), ct(module->design), direct_to(direct_to)
+ {
+ for (auto wire : module->wires()) {
+ if (wire->port_output)
+ for (auto bit : sigmap(wire))
+ bitusers[bit]++;
+ }
+
+ for (auto cell : module->cells()) {
+ if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") {
+ RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+ for (int i = 0; i < GetSize(sig_y); i++)
+ bit2mux[sig_y[i]] = cell_int_t(cell, i);
+ }
+ if (direct_to.empty()) {
+ if (cell->type == "$dff" || cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+ dff_cells.push_back(cell);
+ } else {
+ if (cell->type == direct_from)
+ dff_cells.push_back(cell);
+ }
+ for (auto conn : cell->connections()) {
+ if (ct.cell_output(cell->type, conn.first))
+ continue;
+ for (auto bit : sigmap(conn.second))
+ bitusers[bit]++;
+ }
+ }
+ }
+
+ patterns_t find_muxtree_feedback_patterns(RTLIL::SigBit d, RTLIL::SigBit q, pattern_t path)
+ {
+ patterns_t ret;
+
+ if (d == q) {
+ ret.insert(path);
+ return ret;
+ }
+
+ if (bit2mux.count(d) == 0 || bitusers[d] > 1)
+ return ret;
+
+ cell_int_t mux_cell_int = bit2mux.at(d);
+ RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort("\\A"));
+ RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort("\\B"));
+ RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort("\\S"));
+ int width = GetSize(sig_a), index = mux_cell_int.second;
+
+ for (int i = 0; i < GetSize(sig_s); i++)
+ if (path.count(sig_s[i]) && path.at(sig_s[i]))
+ {
+ ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path);
+
+ if (sig_b[i*width + index] == q) {
+ RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B");
+ s[i*width + index] = RTLIL::Sx;
+ mux_cell_int.first->setPort("\\B", s);
+ }
+
+ return ret;
+ }
+
+ pattern_t path_else = path;
+
+ for (int i = 0; i < GetSize(sig_s); i++)
+ {
+ if (path.count(sig_s[i]))
+ continue;
+
+ pattern_t path_this = path;
+ path_else[sig_s[i]] = false;
+ path_this[sig_s[i]] = true;
+
+ for (auto &pat : find_muxtree_feedback_patterns(sig_b[i*width + index], q, path_this))
+ ret.insert(pat);
+
+ if (sig_b[i*width + index] == q) {
+ RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B");
+ s[i*width + index] = RTLIL::Sx;
+ mux_cell_int.first->setPort("\\B", s);
+ }
+ }
+
+ for (auto &pat : find_muxtree_feedback_patterns(sig_a[index], q, path_else))
+ ret.insert(pat);
+
+ if (sig_a[index] == q) {
+ RTLIL::SigSpec s = mux_cell_int.first->getPort("\\A");
+ s[index] = RTLIL::Sx;
+ mux_cell_int.first->setPort("\\A", s);
+ }
+
+ return ret;
+ }
+
+ void simplify_patterns(patterns_t&)
+ {
+ // TBD
+ }
+
+ RTLIL::SigSpec make_patterns_logic(patterns_t patterns, bool make_gates)
+ {
+ RTLIL::SigSpec or_input;
+
+ for (auto pat : patterns)
+ {
+ RTLIL::SigSpec s1, s2;
+ for (auto it : pat) {
+ s1.append(it.first);
+ s2.append(it.second);
+ }
+
+ RTLIL::SigSpec y = module->addWire(NEW_ID);
+ RTLIL::Cell *c = module->addNe(NEW_ID, s1, s2, y);
+
+ if (make_gates) {
+ simplemap(module, c);
+ module->remove(c);
+ }
+
+ or_input.append(y);
+ }
+
+ if (GetSize(or_input) == 0)
+ return RTLIL::S1;
+
+ if (GetSize(or_input) == 1)
+ return or_input;
+
+ RTLIL::SigSpec y = module->addWire(NEW_ID);
+ RTLIL::Cell *c = module->addReduceAnd(NEW_ID, or_input, y);
+
+ if (make_gates) {
+ simplemap(module, c);
+ module->remove(c);
+ }
+
+ return y;
+ }
+
+ void handle_dff_cell(RTLIL::Cell *dff_cell)
+ {
+ RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort("\\D"));
+ RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort("\\Q"));
+
+ std::map<patterns_t, std::set<int>> grouped_patterns;
+ std::set<int> remaining_indices;
+
+ for (int i = 0 ; i < GetSize(sig_d); i++) {
+ patterns_t patterns = find_muxtree_feedback_patterns(sig_d[i], sig_q[i], pattern_t());
+ if (!patterns.empty()) {
+ simplify_patterns(patterns);
+ grouped_patterns[patterns].insert(i);
+ } else
+ remaining_indices.insert(i);
+ }
+
+ for (auto &it : grouped_patterns) {
+ RTLIL::SigSpec new_sig_d, new_sig_q;
+ for (int i : it.second) {
+ new_sig_d.append(sig_d[i]);
+ new_sig_q.append(sig_q[i]);
+ }
+ if (!direct_to.empty()) {
+ log(" converting %s cell %s to %s for %s -> %s.\n", log_id(dff_cell->type), log_id(dff_cell), log_id(direct_to), log_signal(new_sig_d), log_signal(new_sig_q));
+ dff_cell->setPort("\\E", make_patterns_logic(it.first, true));
+ dff_cell->type = direct_to;
+ } else
+ if (dff_cell->type == "$dff") {
+ RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort("\\CLK"), make_patterns_logic(it.first, false),
+ new_sig_d, new_sig_q, dff_cell->getParam("\\CLK_POLARITY").as_bool(), true);
+ log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
+ } else {
+ RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort("\\C"), make_patterns_logic(it.first, true),
+ new_sig_d, new_sig_q, dff_cell->type == "$_DFF_P_", true);
+ log(" created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
+ }
+ }
+
+ if (!direct_to.empty())
+ return;
+
+ if (remaining_indices.empty()) {
+ log(" removing now obsolete cell %s.\n", log_id(dff_cell));
+ module->remove(dff_cell);
+ } else if (GetSize(remaining_indices) != GetSize(sig_d)) {
+ log(" removing %d now obsolete bits from cell %s.\n", GetSize(sig_d) - GetSize(remaining_indices), log_id(dff_cell));
+ RTLIL::SigSpec new_sig_d, new_sig_q;
+ for (int i : remaining_indices) {
+ new_sig_d.append(sig_d[i]);
+ new_sig_q.append(sig_q[i]);
+ }
+ dff_cell->setPort("\\D", new_sig_d);
+ dff_cell->setPort("\\Q", new_sig_q);
+ dff_cell->setParam("\\WIDTH", GetSize(remaining_indices));
+ }
+ }
+
+ void run()
+ {
+ log("Transforming $dff to $dffe cells in module %s:\n", log_id(module));
+ for (auto dff_cell : dff_cells)
+ handle_dff_cell(dff_cell);
+ }
+};
+
+struct Dff2dffePass : public Pass {
+ Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" dff2dffe [selection]\n");
+ log("\n");
+ log("This pass transforms $dff cells driven by a tree of multiplexers with one or\n");
+ log("more feedback paths to $dffe cells. It also works on gate-level cells such as\n");
+ log("$_DFF_P_, $_DFF_N_ and $_MUX_.\n");
+ log("\n");
+ log(" -unmap\n");
+ log(" operate in the opposite direction: replace $dffe cells with combinations\n");
+ log(" of $dff and $mux cells. the options below are ignore in unmap mode.\n");
+ log("\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");
+ log(" <external_gate_type> is the cell type name for a cell with an\n");
+ log(" identical interface to the <internal_gate_type>, except it\n");
+ log(" also has an high-active enable port 'E'.\n");
+ log(" Usually <external_gate_type> is an intemediate cell type\n");
+ log(" that is then translated to the final type using 'techmap'.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
+
+ bool unmap_mode = false;
+ RTLIL::IdString direct_from, direct_to;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-unmap") {
+ unmap_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-direct" && argidx + 2 < args.size()) {
+ direct_from = RTLIL::escape_id(args[++argidx]);
+ direct_to = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules())
+ if (!mod->has_processes_warn())
+ {
+ if (unmap_mode) {
+ for (auto cell : mod->selected_cells()) {
+ if (cell->type == "$dffe") {
+ RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort("\\D")));
+ mod->addDff(NEW_ID, cell->getPort("\\CLK"), tmp, cell->getPort("\\Q"), cell->getParam("\\CLK_POLARITY").as_bool());
+ if (cell->getParam("\\EN_POLARITY").as_bool())
+ mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\EN"), tmp);
+ else
+ mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\EN"), tmp);
+ mod->remove(cell);
+ continue;
+ }
+ if (cell->type.substr(0, 7) == "$_DFFE_") {
+ 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);
+ mod->addDff(NEW_ID, cell->getPort("\\C"), tmp, cell->getPort("\\Q"), clk_pol);
+ if (en_pol)
+ mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\E"), tmp);
+ else
+ mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\E"), tmp);
+ mod->remove(cell);
+ continue;
+ }
+ }
+ continue;
+ }
+
+ Dff2dffeWorker worker(mod, direct_from, direct_to);
+ worker.run();
+ }
+ }
+} Dff2dffePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 07993b86..b0318a0b 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -23,7 +23,8 @@
#include <string.h>
#include <errno.h>
-using namespace PASS_DFFLIBMAP;
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
struct cell_mapping {
std::string cell_name;
@@ -102,12 +103,12 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name,
return false;
}
-static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval)
+static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode)
{
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
- float best_cell_area = 0;
+ double best_cell_area = 0;
if (ast->id != "library")
log_error("Format error in liberty file.\n");
@@ -143,7 +144,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
this_cell_ports[cell_rst_pin] = 'R';
this_cell_ports[cell_next_pin] = 'D';
- float area = 0;
+ double area = 0;
LibertyAst *ar = cell->find("area");
if (ar != NULL && !ar->value.empty())
area = atof(ar->value.c_str());
@@ -192,18 +193,27 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
}
if (best_cell != NULL) {
- log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.substr(1).c_str());
- cell_mappings[cell_type].cell_name = best_cell->args[0];
- cell_mappings[cell_type].ports = best_cell_ports;
+ log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str());
+ if (prepare_mode) {
+ cell_mappings[cell_type].cell_name = cell_type;
+ cell_mappings[cell_type].ports["C"] = 'C';
+ if (has_reset)
+ cell_mappings[cell_type].ports["R"] = 'R';
+ cell_mappings[cell_type].ports["D"] = 'D';
+ cell_mappings[cell_type].ports["Q"] = 'Q';
+ } else {
+ cell_mappings[cell_type].cell_name = best_cell->args[0];
+ cell_mappings[cell_type].ports = best_cell_ports;
+ }
}
}
-static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bool setpol, bool clrpol)
+static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode)
{
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
- float best_cell_area = 0;
+ double best_cell_area = 0;
if (ast->id != "library")
log_error("Format error in liberty file.\n");
@@ -235,7 +245,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
this_cell_ports[cell_clr_pin] = 'R';
this_cell_ports[cell_next_pin] = 'D';
- float area = 0;
+ double area = 0;
LibertyAst *ar = cell->find("area");
if (ar != NULL && !ar->value.empty())
area = atof(ar->value.c_str());
@@ -284,9 +294,18 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
}
if (best_cell != NULL) {
- log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.substr(1).c_str());
- cell_mappings[cell_type].cell_name = best_cell->args[0];
- cell_mappings[cell_type].ports = best_cell_ports;
+ log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str());
+ if (prepare_mode) {
+ cell_mappings[cell_type].cell_name = cell_type;
+ cell_mappings[cell_type].ports["C"] = 'C';
+ cell_mappings[cell_type].ports["S"] = 'S';
+ cell_mappings[cell_type].ports["R"] = 'R';
+ cell_mappings[cell_type].ports["D"] = 'D';
+ cell_mappings[cell_type].ports["Q"] = 'Q';
+ } else {
+ cell_mappings[cell_type].cell_name = best_cell->args[0];
+ cell_mappings[cell_type].ports = best_cell_ports;
+ }
}
}
@@ -346,8 +365,12 @@ static void map_sr_to_arst(const char *from, const char *to)
if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
return;
- char from_clk_pol = from[8], from_set_pol = from[9], from_clr_pol = from[10];
- char to_clk_pol = to[6], to_rst_pol = to[7], to_rst_val = to[8];
+ char from_clk_pol YS_ATTRIBUTE(unused) = from[8];
+ char from_set_pol = from[9];
+ char from_clr_pol = from[10];
+ char to_clk_pol YS_ATTRIBUTE(unused) = to[6];
+ char to_rst_pol YS_ATTRIBUTE(unused) = to[7];
+ char to_rst_val = to[8];
log_assert(from_clk_pol == to_clk_pol);
log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol);
@@ -383,7 +406,7 @@ static void map_sr_to_arst(const char *from, const char *to)
}
}
-static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module)
+static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode)
{
log("Mapping DFF cells in module `%s':\n", module->name.c_str());
@@ -402,7 +425,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module)
module->remove(cell);
cell_mapping &cm = cell_mappings[cell_type];
- RTLIL::Cell *new_cell = module->addCell(cell_name, "\\" + cm.cell_name);
+ RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : "\\" + cm.cell_name);
for (auto &port : cm.ports) {
RTLIL::SigSpec sig;
@@ -411,7 +434,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module)
} else
if (port.second == 'q') {
RTLIL::SigSpec old_sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))];
- sig = module->addWire(NEW_ID, SIZE(old_sig));
+ sig = module->addWire(NEW_ID, GetSize(old_sig));
module->addNotGate(NEW_ID, sig, old_sig);
} else
if ('a' <= port.second && port.second <= 'z') {
@@ -438,7 +461,7 @@ struct DfflibmapPass : public Pass {
virtual void help()
{
log("\n");
- log(" dfflibmap -liberty <file> [selection]\n");
+ log(" dfflibmap [-prepare] -liberty <file> [selection]\n");
log("\n");
log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
log("library specified in the given liberty file.\n");
@@ -446,12 +469,17 @@ struct DfflibmapPass : public Pass {
log("This pass may add inverters as needed. Therefore it is recommended to\n");
log("first run this pass and then map the logic paths to the target technology.\n");
log("\n");
+ log("When called with -prepare, this command will convert the internal FF cells\n");
+ log("to the internal cell types that best match the cells found in the given\n");
+ log("liberty file.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
std::string liberty_file;
+ bool prepare_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -461,6 +489,10 @@ struct DfflibmapPass : public Pass {
liberty_file = args[++argidx];
continue;
}
+ if (arg == "-prepare") {
+ prepare_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -475,26 +507,26 @@ struct DfflibmapPass : public Pass {
LibertyParser libparser(f);
f.close();
- find_cell(libparser.ast, "$_DFF_N_", false, false, false, false);
- find_cell(libparser.ast, "$_DFF_P_", true, false, false, false);
-
- find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false);
- find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true);
- find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false);
- find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true);
- find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false);
- find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true);
- find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false);
- find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true);
-
- find_cell_sr(libparser.ast, "$_DFFSR_NNN_", false, false, false);
- find_cell_sr(libparser.ast, "$_DFFSR_NNP_", false, false, true);
- find_cell_sr(libparser.ast, "$_DFFSR_NPN_", false, true, false);
- find_cell_sr(libparser.ast, "$_DFFSR_NPP_", false, true, true);
- find_cell_sr(libparser.ast, "$_DFFSR_PNN_", true, false, false);
- find_cell_sr(libparser.ast, "$_DFFSR_PNP_", true, false, true);
- find_cell_sr(libparser.ast, "$_DFFSR_PPN_", true, true, false);
- find_cell_sr(libparser.ast, "$_DFFSR_PPP_", true, true, true);
+ find_cell(libparser.ast, "$_DFF_N_", false, false, false, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_P_", true, false, false, false, prepare_mode);
+
+ find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true, prepare_mode);
+
+ find_cell_sr(libparser.ast, "$_DFFSR_NNN_", false, false, false, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_NNP_", false, false, true, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_NPN_", false, true, false, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_NPP_", false, true, true, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_PNN_", true, false, false, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_PNP_", true, false, true, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_PPN_", true, true, false, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_PPP_", true, true, true, prepare_mode);
// try to implement as many cells as possible just by inverting
// the SET and RESET pins. If necessary, implement cell types
@@ -532,9 +564,10 @@ struct DfflibmapPass : public Pass {
for (auto &it : design->modules_)
if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
- dfflibmap(design, it.second);
+ dfflibmap(design, it.second, prepare_mode);
cell_mappings.clear();
}
} DfflibmapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index 221e9e49..ff99040e 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -26,256 +26,240 @@
#include <stdio.h>
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
-namespace
+class SubCircuitSolver : public SubCircuit::Solver
{
- class SubCircuitSolver : public SubCircuit::Solver
- {
- public:
- bool ignore_parameters;
- std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> ignored_parameters;
- std::set<RTLIL::IdString> cell_attr, wire_attr;
+public:
+ bool ignore_parameters;
+ std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> ignored_parameters;
+ std::set<RTLIL::IdString> cell_attr, wire_attr;
- SubCircuitSolver() : ignore_parameters(false)
- {
- }
+ SubCircuitSolver() : ignore_parameters(false)
+ {
+ }
- bool compareAttributes(const std::set<RTLIL::IdString> &attr, const std::map<RTLIL::IdString, RTLIL::Const> &needleAttr, const std::map<RTLIL::IdString, RTLIL::Const> &haystackAttr)
- {
- for (auto &it : attr) {
- size_t nc = needleAttr.count(it), hc = haystackAttr.count(it);
- if (nc != hc || (nc > 0 && needleAttr.at(it) != haystackAttr.at(it)))
- return false;
- }
- return true;
+ bool compareAttributes(const std::set<RTLIL::IdString> &attr, const dict<RTLIL::IdString, RTLIL::Const> &needleAttr, const dict<RTLIL::IdString, RTLIL::Const> &haystackAttr)
+ {
+ for (auto &it : attr) {
+ size_t nc = needleAttr.count(it), hc = haystackAttr.count(it);
+ if (nc != hc || (nc > 0 && needleAttr.at(it) != haystackAttr.at(it)))
+ return false;
}
+ return true;
+ }
- RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value)
- {
- if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_")
- return value;
-
- #define param_bool(_n) if (param == _n) return value.as_bool();
- param_bool("\\ARST_POLARITY");
- param_bool("\\A_SIGNED");
- param_bool("\\B_SIGNED");
- param_bool("\\CLK_ENABLE");
- param_bool("\\CLK_POLARITY");
- param_bool("\\CLR_POLARITY");
- param_bool("\\EN_POLARITY");
- param_bool("\\SET_POLARITY");
- param_bool("\\TRANSPARENT");
- #undef param_bool
-
- #define param_int(_n) if (param == _n) return value.as_int();
- param_int("\\ABITS")
- param_int("\\A_WIDTH")
- param_int("\\B_WIDTH")
- param_int("\\CTRL_IN_WIDTH")
- param_int("\\CTRL_OUT_WIDTH")
- param_int("\\OFFSET")
- param_int("\\PRIORITY")
- param_int("\\RD_PORTS")
- param_int("\\SIZE")
- param_int("\\STATE_BITS")
- param_int("\\STATE_NUM")
- param_int("\\STATE_NUM_LOG2")
- param_int("\\STATE_RST")
- param_int("\\S_WIDTH")
- param_int("\\TRANS_NUM")
- param_int("\\WIDTH")
- param_int("\\WR_PORTS")
- param_int("\\Y_WIDTH")
- #undef param_int
-
+ RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value)
+ {
+ if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_")
return value;
- }
- virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData,
- const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping)
- {
- RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData;
- RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData;
+ #define param_bool(_n) if (param == _n) return value.as_bool();
+ param_bool("\\ARST_POLARITY");
+ param_bool("\\A_SIGNED");
+ param_bool("\\B_SIGNED");
+ param_bool("\\CLK_ENABLE");
+ param_bool("\\CLK_POLARITY");
+ param_bool("\\CLR_POLARITY");
+ param_bool("\\EN_POLARITY");
+ param_bool("\\SET_POLARITY");
+ param_bool("\\TRANSPARENT");
+ #undef param_bool
+
+ #define param_int(_n) if (param == _n) return value.as_int();
+ param_int("\\ABITS")
+ param_int("\\A_WIDTH")
+ param_int("\\B_WIDTH")
+ param_int("\\CTRL_IN_WIDTH")
+ param_int("\\CTRL_OUT_WIDTH")
+ param_int("\\OFFSET")
+ param_int("\\PRIORITY")
+ param_int("\\RD_PORTS")
+ param_int("\\SIZE")
+ param_int("\\STATE_BITS")
+ param_int("\\STATE_NUM")
+ param_int("\\STATE_NUM_LOG2")
+ param_int("\\STATE_RST")
+ param_int("\\S_WIDTH")
+ param_int("\\TRANS_NUM")
+ param_int("\\WIDTH")
+ param_int("\\WR_PORTS")
+ param_int("\\Y_WIDTH")
+ #undef param_int
+
+ return value;
+ }
- if (!needleCell || !haystackCell) {
- log_assert(!needleCell && !haystackCell);
- return true;
- }
+ virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData,
+ const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping)
+ {
+ RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData;
+ RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData;
- if (!ignore_parameters) {
- std::map<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param;
- for (auto &it : needleCell->parameters)
- if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(needleCell->type, it.first)))
- needle_param[it.first] = unified_param(needleCell->type, it.first, it.second);
- for (auto &it : haystackCell->parameters)
- if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(haystackCell->type, it.first)))
- haystack_param[it.first] = unified_param(haystackCell->type, it.first, it.second);
- if (needle_param != haystack_param)
- return false;
- }
+ if (!needleCell || !haystackCell) {
+ log_assert(!needleCell && !haystackCell);
+ return true;
+ }
- if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes))
+ if (!ignore_parameters) {
+ std::map<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param;
+ for (auto &it : needleCell->parameters)
+ if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(needleCell->type, it.first)))
+ needle_param[it.first] = unified_param(needleCell->type, it.first, it.second);
+ for (auto &it : haystackCell->parameters)
+ if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(haystackCell->type, it.first)))
+ haystack_param[it.first] = unified_param(haystackCell->type, it.first, it.second);
+ if (needle_param != haystack_param)
return false;
+ }
- if (wire_attr.size() > 0)
- {
- RTLIL::Wire *lastNeedleWire = NULL;
- RTLIL::Wire *lastHaystackWire = NULL;
- std::map<RTLIL::IdString, RTLIL::Const> emptyAttr;
+ if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes))
+ return false;
- for (auto &conn : needleCell->connections())
- {
- RTLIL::SigSpec needleSig = conn.second;
- RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str()));
-
- for (int i = 0; i < std::min(needleSig.size(), haystackSig.size()); i++) {
- RTLIL::Wire *needleWire = needleSig[i].wire, *haystackWire = haystackSig[i].wire;
- if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire)
- if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr))
- return false;
- lastNeedleWire = needleWire, lastHaystackWire = haystackWire;
- }
+ if (wire_attr.size() > 0)
+ {
+ RTLIL::Wire *lastNeedleWire = NULL;
+ RTLIL::Wire *lastHaystackWire = NULL;
+ dict<RTLIL::IdString, RTLIL::Const> emptyAttr;
+
+ for (auto &conn : needleCell->connections())
+ {
+ RTLIL::SigSpec needleSig = conn.second;
+ RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str()));
+
+ for (int i = 0; i < std::min(needleSig.size(), haystackSig.size()); i++) {
+ RTLIL::Wire *needleWire = needleSig[i].wire, *haystackWire = haystackSig[i].wire;
+ if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire)
+ if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr))
+ return false;
+ lastNeedleWire = needleWire, lastHaystackWire = haystackWire;
}
}
-
- return true;
}
- };
- struct bit_ref_t {
- std::string cell, port;
- int bit;
- };
+ return true;
+ }
+};
- bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL,
- int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
- {
- SigMap sigmap(mod);
- std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref;
+struct bit_ref_t {
+ std::string cell, port;
+ int bit;
+};
- if (sel && !sel->selected(mod)) {
- log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name));
- return false;
- }
+bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL,
+ int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
+{
+ SigMap sigmap(mod);
+ std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref;
- if (mod->processes.size() > 0) {
- log(" Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name));
- return false;
- }
+ if (sel && !sel->selected(mod)) {
+ log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name));
+ return false;
+ }
- if (constports) {
- graph.createNode("$const$0", "$const$0", NULL, true);
- graph.createNode("$const$1", "$const$1", NULL, true);
- graph.createNode("$const$x", "$const$x", NULL, true);
- graph.createNode("$const$z", "$const$z", NULL, true);
- graph.createPort("$const$0", "\\Y", 1);
- graph.createPort("$const$1", "\\Y", 1);
- graph.createPort("$const$x", "\\Y", 1);
- graph.createPort("$const$z", "\\Y", 1);
- graph.markExtern("$const$0", "\\Y", 0);
- graph.markExtern("$const$1", "\\Y", 0);
- graph.markExtern("$const$x", "\\Y", 0);
- graph.markExtern("$const$z", "\\Y", 0);
- }
+ if (mod->processes.size() > 0) {
+ log(" Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name));
+ return false;
+ }
- std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
- if (max_fanout > 0)
- for (auto &cell_it : mod->cells_)
- {
- RTLIL::Cell *cell = cell_it.second;
- if (!sel || sel->selected(mod, cell))
- for (auto &conn : cell->connections()) {
- RTLIL::SigSpec conn_sig = conn.second;
- sigmap.apply(conn_sig);
- for (auto &bit : conn_sig)
- if (bit.wire != NULL)
- sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++;
- }
- }
+ if (constports) {
+ graph.createNode("$const$0", "$const$0", NULL, true);
+ graph.createNode("$const$1", "$const$1", NULL, true);
+ graph.createNode("$const$x", "$const$x", NULL, true);
+ graph.createNode("$const$z", "$const$z", NULL, true);
+ graph.createPort("$const$0", "\\Y", 1);
+ graph.createPort("$const$1", "\\Y", 1);
+ graph.createPort("$const$x", "\\Y", 1);
+ graph.createPort("$const$z", "\\Y", 1);
+ graph.markExtern("$const$0", "\\Y", 0);
+ graph.markExtern("$const$1", "\\Y", 0);
+ graph.markExtern("$const$x", "\\Y", 0);
+ graph.markExtern("$const$z", "\\Y", 0);
+ }
- // create graph nodes from cells
+ std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
+ if (max_fanout > 0)
for (auto &cell_it : mod->cells_)
{
RTLIL::Cell *cell = cell_it.second;
- if (sel && !sel->selected(mod, cell))
- continue;
+ if (!sel || sel->selected(mod, cell))
+ for (auto &conn : cell->connections()) {
+ RTLIL::SigSpec conn_sig = conn.second;
+ sigmap.apply(conn_sig);
+ for (auto &bit : conn_sig)
+ if (bit.wire != NULL)
+ sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++;
+ }
+ }
- std::string type = cell->type.str();
- if (sel == NULL && type.substr(0, 2) == "\\$")
- type = type.substr(1);
- graph.createNode(cell->name.str(), type, (void*)cell);
+ // create graph nodes from cells
+ for (auto &cell_it : mod->cells_)
+ {
+ RTLIL::Cell *cell = cell_it.second;
+ if (sel && !sel->selected(mod, cell))
+ continue;
- for (auto &conn : cell->connections())
- {
- graph.createPort(cell->name.str(), conn.first.str(), conn.second.size());
+ std::string type = cell->type.str();
+ if (sel == NULL && type.substr(0, 2) == "\\$")
+ type = type.substr(1);
+ graph.createNode(cell->name.str(), type, (void*)cell);
- if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
- continue;
+ for (auto &conn : cell->connections())
+ {
+ graph.createPort(cell->name.str(), conn.first.str(), conn.second.size());
- RTLIL::SigSpec conn_sig = conn.second;
- sigmap.apply(conn_sig);
+ if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
+ continue;
- for (int i = 0; i < conn_sig.size(); i++)
- {
- auto &bit = conn_sig[i];
-
- if (bit.wire == NULL) {
- if (constports) {
- std::string node = "$const$x";
- if (bit == RTLIL::State::S0) node = "$const$0";
- if (bit == RTLIL::State::S1) node = "$const$1";
- if (bit == RTLIL::State::Sz) node = "$const$z";
- graph.createConnection(cell->name.str(), conn.first.str(), i, node, "\\Y", 0);
- } else
- graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data));
- continue;
- }
+ RTLIL::SigSpec conn_sig = conn.second;
+ sigmap.apply(conn_sig);
- if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout)
- continue;
+ for (int i = 0; i < conn_sig.size(); i++)
+ {
+ auto &bit = conn_sig[i];
+
+ if (bit.wire == NULL) {
+ if (constports) {
+ std::string node = "$const$x";
+ if (bit == RTLIL::State::S0) node = "$const$0";
+ if (bit == RTLIL::State::S1) node = "$const$1";
+ if (bit == RTLIL::State::Sz) node = "$const$z";
+ graph.createConnection(cell->name.str(), conn.first.str(), i, node, "\\Y", 0);
+ } else
+ graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data));
+ continue;
+ }
- if (sel && !sel->selected(mod, bit.wire))
- continue;
+ if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout)
+ continue;
- if (sig_bit_ref.count(bit) == 0) {
- bit_ref_t &bit_ref = sig_bit_ref[bit];
- bit_ref.cell = cell->name.str();
- bit_ref.port = conn.first.str();
- bit_ref.bit = i;
- }
+ if (sel && !sel->selected(mod, bit.wire))
+ continue;
+ if (sig_bit_ref.count(bit) == 0) {
bit_ref_t &bit_ref = sig_bit_ref[bit];
- graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name.str(), conn.first.str(), i);
+ bit_ref.cell = cell->name.str();
+ bit_ref.port = conn.first.str();
+ bit_ref.bit = i;
}
- }
- }
-
- // mark external signals (used in non-selected cells)
- for (auto &cell_it : mod->cells_)
- {
- RTLIL::Cell *cell = cell_it.second;
- if (sel && !sel->selected(mod, cell))
- for (auto &conn : cell->connections())
- {
- RTLIL::SigSpec conn_sig = conn.second;
- sigmap.apply(conn_sig);
- for (auto &bit : conn_sig)
- if (sig_bit_ref.count(bit) != 0) {
- bit_ref_t &bit_ref = sig_bit_ref[bit];
- graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
- }
- }
+ bit_ref_t &bit_ref = sig_bit_ref[bit];
+ graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name.str(), conn.first.str(), i);
+ }
}
+ }
- // mark external signals (used in module ports)
- for (auto &wire_it : mod->wires_)
- {
- RTLIL::Wire *wire = wire_it.second;
- if (wire->port_id > 0)
+ // mark external signals (used in non-selected cells)
+ for (auto &cell_it : mod->cells_)
+ {
+ RTLIL::Cell *cell = cell_it.second;
+ if (sel && !sel->selected(mod, cell))
+ for (auto &conn : cell->connections())
{
- RTLIL::SigSpec conn_sig(wire);
+ RTLIL::SigSpec conn_sig = conn.second;
sigmap.apply(conn_sig);
for (auto &bit : conn_sig)
@@ -284,70 +268,86 @@ namespace
graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
}
}
- }
-
- // graph.print();
- return true;
}
- RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match)
+ // mark external signals (used in module ports)
+ for (auto &wire_it : mod->wires_)
{
- SigMap sigmap(needle);
- SigSet<std::pair<RTLIL::IdString, int>> sig2port;
-
- // create new cell
- RTLIL::Cell *cell = haystack->addCell(stringf("$extract$%s$%d", needle->name.c_str(), autoidx++), needle->name);
-
- // create cell ports
- for (auto &it : needle->wires_) {
- RTLIL::Wire *wire = it.second;
- if (wire->port_id > 0) {
- for (int i = 0; i < wire->width; i++)
- sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<RTLIL::IdString, int>(wire->name, i));
- cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width));
- }
+ RTLIL::Wire *wire = wire_it.second;
+ if (wire->port_id > 0)
+ {
+ RTLIL::SigSpec conn_sig(wire);
+ sigmap.apply(conn_sig);
+
+ for (auto &bit : conn_sig)
+ if (sig_bit_ref.count(bit) != 0) {
+ bit_ref_t &bit_ref = sig_bit_ref[bit];
+ graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
+ }
}
+ }
- // delete replaced cells and connect new ports
- for (auto &it : match.mappings)
- {
- auto &mapping = it.second;
- RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData;
- RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData;
+ // graph.print();
+ return true;
+}
- if (needle_cell == NULL)
- continue;
+RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match)
+{
+ SigMap sigmap(needle);
+ SigSet<std::pair<RTLIL::IdString, int>> sig2port;
+
+ // create new cell
+ RTLIL::Cell *cell = haystack->addCell(stringf("$extract$%s$%d", needle->name.c_str(), autoidx++), needle->name);
+
+ // create cell ports
+ for (auto &it : needle->wires_) {
+ RTLIL::Wire *wire = it.second;
+ if (wire->port_id > 0) {
+ for (int i = 0; i < wire->width; i++)
+ sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<RTLIL::IdString, int>(wire->name, i));
+ cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width));
+ }
+ }
- for (auto &conn : needle_cell->connections()) {
- RTLIL::SigSpec sig = sigmap(conn.second);
- if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(sig))) {
- for (int i = 0; i < sig.size(); i++)
- for (auto &port : sig2port.find(sig[i])) {
- RTLIL::SigSpec bitsig = haystack_cell->getPort(mapping.portMapping[conn.first.str()]).extract(i, 1);
- RTLIL::SigSpec new_sig = cell->getPort(port.first);
- new_sig.replace(port.second, bitsig);
- cell->setPort(port.first, new_sig);
- }
+ // delete replaced cells and connect new ports
+ for (auto &it : match.mappings)
+ {
+ auto &mapping = it.second;
+ RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData;
+ RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData;
+
+ if (needle_cell == NULL)
+ continue;
+
+ for (auto &conn : needle_cell->connections()) {
+ RTLIL::SigSpec sig = sigmap(conn.second);
+ if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(sig))) {
+ for (int i = 0; i < sig.size(); i++)
+ for (auto &port : sig2port.find(sig[i])) {
+ RTLIL::SigSpec bitsig = haystack_cell->getPort(mapping.portMapping[conn.first.str()]).extract(i, 1);
+ RTLIL::SigSpec new_sig = cell->getPort(port.first);
+ new_sig.replace(port.second, bitsig);
+ cell->setPort(port.first, new_sig);
}
}
-
- haystack->remove(haystack_cell);
}
- return cell;
+ haystack->remove(haystack_cell);
}
- bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
- {
- int left_idx = 0, right_idx = 0;
- if (left->attributes.count("\\extract_order") > 0)
- left_idx = left->attributes.at("\\extract_order").as_int();
- if (right->attributes.count("\\extract_order") > 0)
- right_idx = right->attributes.at("\\extract_order").as_int();
- if (left_idx != right_idx)
- return left_idx < right_idx;
- return left->name < right->name;
- }
+ return cell;
+}
+
+bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
+{
+ int left_idx = 0, right_idx = 0;
+ if (left->attributes.count("\\extract_order") > 0)
+ left_idx = left->attributes.at("\\extract_order").as_int();
+ if (right->attributes.count("\\extract_order") > 0)
+ right_idx = right->attributes.at("\\extract_order").as_int();
+ if (left_idx != right_idx)
+ return left_idx < right_idx;
+ return left->name < right->name;
}
struct ExtractPass : public Pass {
@@ -518,24 +518,21 @@ struct ExtractPass : public Pass {
if (args[argidx] == "-swap" && argidx+2 < args.size()) {
std::string type = RTLIL::escape_id(args[++argidx]);
std::set<std::string> ports;
- char *ports_str = strdup(args[++argidx].c_str());
- for (char *sptr, *p = strtok_r(ports_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
+ std::string ports_str = args[++argidx], p;
+ while (!(p = next_token(ports_str, ",\t\r\n ")).empty())
ports.insert(RTLIL::escape_id(p));
- free(ports_str);
solver.addSwappablePorts(type, ports);
continue;
}
if (args[argidx] == "-perm" && argidx+3 < args.size()) {
std::string type = RTLIL::escape_id(args[++argidx]);
std::vector<std::string> map_left, map_right;
- char *left_str = strdup(args[++argidx].c_str());
- char *right_str = strdup(args[++argidx].c_str());
- for (char *sptr, *p = strtok_r(left_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
+ std::string left_str = args[++argidx];
+ std::string right_str = args[++argidx], p;
+ while (!(p = next_token(left_str, ",\t\r\n ")).empty())
map_left.push_back(RTLIL::escape_id(p));
- for (char *sptr, *p = strtok_r(right_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
+ while (!(p = next_token(right_str, ",\t\r\n ")).empty())
map_right.push_back(RTLIL::escape_id(p));
- free(left_str);
- free(right_str);
if (map_left.size() != map_right.size())
log_cmd_error("Arguments to -perm are not a valid permutation!\n");
std::map<std::string, std::string> map;
@@ -665,7 +662,7 @@ struct ExtractPass : public Pass {
log("Solving for %s in %s.\n", ("needle_" + RTLIL::unescape_id(needle->name)).c_str(), haystack_it.first.c_str());
solver.solve(results, "needle_" + RTLIL::unescape_id(needle->name), haystack_it.first, false);
}
- log("Found %zd matches.\n", results.size());
+ log("Found %d matches.\n", GetSize(results));
if (results.size() > 0)
{
@@ -761,3 +758,4 @@ struct ExtractPass : public Pass {
}
} ExtractPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index 784c4cf3..9a14ffa3 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -21,6 +21,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static std::string hicell_celltype, hicell_portname;
static std::string locell_celltype, locell_portname;
static bool singleton_mode;
@@ -57,9 +60,7 @@ struct HilomapPass : public Pass {
log("\n");
log(" hilomap [options] [selection]\n");
log("\n");
- log("Map module inputs/outputs to PAD cells from a library. This pass\n");
- log("can only map to very simple PAD cells. Use 'techmap' to further map\n");
- log("the resulting cells to more sophisticated PAD cells.\n");
+ log("Map constants to 'tielo' and 'tiehi' driver cells.\n");
log("\n");
log(" -hicell <celltype> <portname>\n");
log(" Replace constant hi bits with this cell.\n");
@@ -75,7 +76,7 @@ struct HilomapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing HILOPAD pass (mapping to constant drivers).\n");
+ log_header("Executing HILOMAP pass (mapping to constant drivers).\n");
hicell_celltype = std::string();
hicell_portname = std::string();
@@ -119,3 +120,4 @@ struct HilomapPass : public Pass {
}
} HilomapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 9cd23ce6..3fba0e61 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -21,7 +21,10 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-static void split_portname_pair(std::string &port1, std::string &port2)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void split_portname_pair(std::string &port1, std::string &port2)
{
size_t pos = port1.find_first_of(':');
if (pos != std::string::npos) {
@@ -59,8 +62,8 @@ struct IopadmapPass : public Pass {
log("\n");
log(" -bits\n");
log(" create individual bit-wide buffers even for ports that\n");
- log(" are wider. (the default behavio is to create word-wide\n");
- log(" buffers use -widthparam to set the word size on the cell.)\n");
+ log(" are wider. (the default behavior is to create word-wide\n");
+ log(" buffers using -widthparam to set the word size on the cell.)\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
@@ -111,18 +114,11 @@ struct IopadmapPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &it : design->modules_)
+ for (auto module : design->selected_modules())
{
- RTLIL::Module *module = it.second;
-
- if (!design->selected(module) || module->get_bool_attribute("\\blackbox"))
- continue;
-
- for (auto &it2 : module->wires_)
+ for (auto wire : module->selected_wires())
{
- RTLIL::Wire *wire = it2.second;
-
- if (!wire->port_id || !design->selected(module, wire))
+ if (!wire->port_id)
continue;
std::string celltype, portname, portname2;
@@ -207,3 +203,4 @@ struct IopadmapPass : public Pass {
}
} IopadmapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 612fa111..def48039 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -29,7 +29,7 @@
#include "kernel/log.h"
#endif
-using namespace PASS_DFFLIBMAP;
+using namespace Yosys;
std::set<std::string> LibertyAst::blacklist;
std::set<std::string> LibertyAst::whitelist;
@@ -43,8 +43,6 @@ LibertyAst::~LibertyAst()
LibertyAst *LibertyAst::find(std::string name)
{
- if (this == NULL)
- return NULL;
for (auto child : children)
if (child->id == name)
return child;
@@ -107,14 +105,14 @@ int LibertyParser::lexer(std::string &str)
}
if (c == '"') {
- str = c;
+ str = "";
while (1) {
c = f.get();
if (c == '\n')
line++;
- str += c;
if (c == '"')
break;
+ str += c;
}
// fprintf(stderr, "LEX: string >>%s<<\n", str.c_str());
return 'v';
@@ -244,21 +242,6 @@ void LibertyParser::error()
/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
-// This is to not confuse the VIM syntax highlighting
-#define CHECK_VAL_OPEN (
-#define CHECK_VAL_CLOSE )
-
-#define CHECK(result, check) \
- CHECK_VAL_OPEN{ \
- 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(); \
- } \
- _R; \
- }CHECK_VAL_CLOSE
-
#define CHECK_NV(result, check) \
do { \
auto _R = (result); \
@@ -280,6 +263,14 @@ void LibertyParser::error()
/**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
+LibertyAst *find_non_null(LibertyAst *node, const char *name)
+{
+ LibertyAst *ret = node->find(name);
+ if (ret == NULL)
+ fprintf(stderr, "Error: expected to find `%s' node.\n", name);
+ return ret;
+}
+
std::string func2vl(std::string str)
{
for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) {
@@ -388,7 +379,7 @@ void gen_verilogsim_cell(LibertyAst *ast)
if (child->id != "pin")
continue;
CHECK_NV(child->args.size(), == 1);
- LibertyAst *dir = CHECK(child->find("direction"), != NULL);
+ LibertyAst *dir = find_non_null(child, "direction");
LibertyAst *func = child->find("function");
printf(" %s %s;\n", dir->value.c_str(), child->args[0].c_str());
if (func != NULL)
@@ -428,8 +419,8 @@ void gen_verilogsim_cell(LibertyAst *ast)
const char *else_prefix = "";
if (!clear_expr.empty() && !preset_expr.empty()) {
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
- clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value);
- clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value);
+ clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
+ clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
printf(" end\n");
else_prefix = "else ";
}
@@ -449,7 +440,7 @@ void gen_verilogsim_cell(LibertyAst *ast)
}
if (*else_prefix)
printf(" %sbegin\n", else_prefix);
- std::string expr = CHECK(child->find("next_state"), != NULL)->value;
+ std::string expr = find_non_null(child, "next_state")->value;
printf(" // %s\n", expr.c_str());
printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
@@ -481,8 +472,8 @@ void gen_verilogsim_cell(LibertyAst *ast)
const char *else_prefix = "";
if (!clear_expr.empty() && !preset_expr.empty()) {
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
- clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value);
- clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value);
+ clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
+ clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
printf(" end\n");
else_prefix = "else ";
}
@@ -502,7 +493,7 @@ void gen_verilogsim_cell(LibertyAst *ast)
}
if (!enable_expr.empty()) {
printf(" %sif (%s) begin\n", else_prefix, enable_expr.c_str());
- std::string expr = CHECK(child->find("data_in"), != NULL)->value;
+ std::string expr = find_non_null(child, "data_in")->value;
printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
printf(" end\n");
diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h
index 24748742..e947bd8c 100644
--- a/passes/techmap/libparse.h
+++ b/passes/techmap/libparse.h
@@ -25,7 +25,7 @@
#include <vector>
#include <set>
-namespace PASS_DFFLIBMAP
+namespace Yosys
{
struct LibertyAst
{
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index 2d625eef..ffbd6289 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -20,7 +20,8 @@
#include "kernel/yosys.h"
#include "kernel/macc.h"
-extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false);
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
struct MaccmapWorker
{
@@ -48,7 +49,7 @@ struct MaccmapWorker
void add(RTLIL::SigSpec a, bool is_signed, bool do_subtract)
{
- a.extend(width, is_signed);
+ a.extend_u0(width, is_signed);
if (do_subtract) {
a = module->Not(NEW_ID, a);
@@ -61,16 +62,16 @@ struct MaccmapWorker
void add(RTLIL::SigSpec a, RTLIL::SigSpec b, bool is_signed, bool do_subtract)
{
- if (SIZE(a) < SIZE(b))
+ if (GetSize(a) < GetSize(b))
std::swap(a, b);
- a.extend(width, is_signed);
+ a.extend_u0(width, is_signed);
- if (SIZE(b) > width)
- b.extend(width, is_signed);
+ if (GetSize(b) > width)
+ b.extend_u0(width, is_signed);
- for (int i = 0; i < SIZE(b); i++)
- if (is_signed && i+1 == SIZE(b))
+ for (int i = 0; i < GetSize(b); i++)
+ if (is_signed && i+1 == GetSize(b))
{
a = {module->Not(NEW_ID, a.extract(i, width-i)), RTLIL::SigSpec(0, i)};
add(module->And(NEW_ID, a, RTLIL::SigSpec(b[i], width)), false, do_subtract);
@@ -85,7 +86,7 @@ struct MaccmapWorker
void fulladd(RTLIL::SigSpec &in1, RTLIL::SigSpec &in2, RTLIL::SigSpec &in3, RTLIL::SigSpec &out1, RTLIL::SigSpec &out2)
{
- int start_index = 0, stop_index = SIZE(in1);
+ int start_index = 0, stop_index = GetSize(in1);
while (start_index < stop_index && in1[start_index] == RTLIL::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0)
start_index++;
@@ -95,18 +96,18 @@ struct MaccmapWorker
if (start_index == stop_index)
{
- out1 = RTLIL::SigSpec(0, SIZE(in1));
- out2 = RTLIL::SigSpec(0, SIZE(in1));
+ out1 = RTLIL::SigSpec(0, GetSize(in1));
+ out2 = RTLIL::SigSpec(0, GetSize(in1));
}
else
{
- RTLIL::SigSpec out_zeros_lsb(0, start_index), out_zeros_msb(0, SIZE(in1)-stop_index);
+ RTLIL::SigSpec out_zeros_lsb(0, start_index), out_zeros_msb(0, GetSize(in1)-stop_index);
in1 = in1.extract(start_index, stop_index-start_index);
in2 = in2.extract(start_index, stop_index-start_index);
in3 = in3.extract(start_index, stop_index-start_index);
- int width = SIZE(in1);
+ int width = GetSize(in1);
RTLIL::Wire *w1 = module->addWire(NEW_ID, width);
RTLIL::Wire *w2 = module->addWire(NEW_ID, width);
@@ -164,12 +165,12 @@ struct MaccmapWorker
while (1)
{
- int free_bit_slots = tree_bit_slots(SIZE(summands)) - SIZE(tree_sum_bits);
+ int free_bit_slots = tree_bit_slots(GetSize(summands)) - GetSize(tree_sum_bits);
int max_depth = 0, max_position = 0;
for (int i = 0; i < width; i++)
- if (max_depth <= SIZE(bits.at(i))) {
- max_depth = SIZE(bits.at(i));
+ if (max_depth <= GetSize(bits.at(i))) {
+ max_depth = GetSize(bits.at(i));
max_position = i;
}
@@ -178,14 +179,14 @@ struct MaccmapWorker
int required_bits = 0;
for (int i = 0; i <= max_position; i++)
- if (SIZE(bits.at(i)) == max_depth)
+ if (GetSize(bits.at(i)) == max_depth)
required_bits += 1 << i;
if (required_bits > free_bit_slots)
break;
for (int i = 0; i <= max_position; i++)
- if (SIZE(bits.at(i)) == max_depth) {
+ if (GetSize(bits.at(i)) == max_depth) {
auto it = bits.at(i).begin();
RTLIL::SigBit bit = *it;
for (int k = 0; k < (1 << i); k++, free_bit_slots--)
@@ -199,23 +200,23 @@ struct MaccmapWorker
}
if (!tree_sum_bits.empty())
- log(" packed %d (%d) bits / %d words into adder tree\n", SIZE(tree_sum_bits), unique_tree_bits, count_tree_words);
+ log(" packed %d (%d) bits / %d words into adder tree\n", GetSize(tree_sum_bits), unique_tree_bits, count_tree_words);
- if (SIZE(summands) == 0) {
+ if (GetSize(summands) == 0) {
log_assert(tree_sum_bits.empty());
return RTLIL::SigSpec(0, width);
}
- if (SIZE(summands) == 1) {
+ if (GetSize(summands) == 1) {
log_assert(tree_sum_bits.empty());
return summands.front();
}
- while (SIZE(summands) > 2)
+ while (GetSize(summands) > 2)
{
std::vector<RTLIL::SigSpec> new_summands;
- for (int i = 0; i < SIZE(summands); i += 3)
- if (i+2 < SIZE(summands)) {
+ for (int i = 0; i < GetSize(summands); i += 3)
+ if (i+2 < GetSize(summands)) {
RTLIL::SigSpec in1 = summands[i];
RTLIL::SigSpec in2 = summands[i+1];
RTLIL::SigSpec in3 = summands[i+2];
@@ -256,9 +257,14 @@ struct MaccmapWorker
}
};
+PRIVATE_NAMESPACE_END
+YOSYS_NAMESPACE_BEGIN
+
+extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false);
+
void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
{
- int width = SIZE(cell->getPort("\\Y"));
+ int width = GetSize(cell->getPort("\\Y"));
Macc macc;
macc.from_cell(cell);
@@ -273,15 +279,15 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
}
for (auto &port : macc.ports)
- if (SIZE(port.in_b) == 0)
+ if (GetSize(port.in_b) == 0)
log(" %s %s (%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a),
- SIZE(port.in_a), port.is_signed ? "signed" : "unsigned");
+ GetSize(port.in_a), port.is_signed ? "signed" : "unsigned");
else
log(" %s %s * %s (%dx%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a), log_signal(port.in_b),
- SIZE(port.in_a), SIZE(port.in_b), port.is_signed ? "signed" : "unsigned");
+ GetSize(port.in_a), GetSize(port.in_b), port.is_signed ? "signed" : "unsigned");
- if (SIZE(macc.bit_ports) != 0)
- log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), SIZE(macc.bit_ports));
+ if (GetSize(macc.bit_ports) != 0)
+ log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), GetSize(macc.bit_ports));
if (unmap)
{
@@ -290,10 +296,10 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
for (auto &port : macc.ports) {
summand_t this_summand;
- if (SIZE(port.in_b)) {
+ if (GetSize(port.in_b)) {
this_summand.first = module->addWire(NEW_ID, width);
module->addMul(NEW_ID, port.in_a, port.in_b, this_summand.first, port.is_signed);
- } else if (SIZE(port.in_a) != width) {
+ } else if (GetSize(port.in_a) != width) {
this_summand.first = module->addWire(NEW_ID, width);
module->addPos(NEW_ID, port.in_a, this_summand.first, port.is_signed);
} else {
@@ -306,14 +312,14 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
for (auto &bit : macc.bit_ports)
summands.push_back(summand_t(bit, false));
- if (SIZE(summands) == 0)
+ if (GetSize(summands) == 0)
summands.push_back(summand_t(RTLIL::SigSpec(0, width), false));
- while (SIZE(summands) > 1)
+ while (GetSize(summands) > 1)
{
std::vector<summand_t> new_summands;
- for (int i = 0; i < SIZE(summands); i += 2) {
- if (i+1 < SIZE(summands)) {
+ for (int i = 0; i < GetSize(summands); i += 2) {
+ if (i+1 < GetSize(summands)) {
summand_t this_summand;
this_summand.first = module->addWire(NEW_ID, width);
this_summand.second = summands[i].second && summands[i+1].second;
@@ -342,7 +348,7 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
MaccmapWorker worker(module, width);
for (auto &port : macc.ports)
- if (SIZE(port.in_b) == 0)
+ if (GetSize(port.in_b) == 0)
worker.add(port.in_a, port.is_signed, port.do_subtract);
else
worker.add(port.in_a, port.in_b, port.is_signed, port.do_subtract);
@@ -354,6 +360,9 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
}
}
+YOSYS_NAMESPACE_END
+PRIVATE_NAMESPACE_BEGIN
+
struct MaccmapPass : public Pass {
MaccmapPass() : Pass("maccmap", "mapping macc cells") { }
virtual void help()
@@ -392,3 +401,4 @@ struct MaccmapPass : public Pass {
}
} MaccmapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index f8d5d458..9cea5f45 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -17,53 +17,53 @@
*
*/
-#include "kernel/register.h"
+#include "simplemap.h"
#include "kernel/sigtools.h"
-#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+USING_YOSYS_NAMESPACE
+YOSYS_NAMESPACE_BEGIN
-static void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- sig_a.extend(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
- for (int i = 0; i < SIZE(sig_y); i++) {
+ for (int i = 0; i < GetSize(sig_y); i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
gate->setPort("\\A", sig_a[i]);
gate->setPort("\\Y", sig_y[i]);
}
}
-static void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
module->connect(RTLIL::SigSig(sig_y, sig_a));
}
-static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_b = cell->getPort("\\B");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
- sig_b.extend_u0(SIZE(sig_y), cell->parameters.at("\\B_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
+ sig_b.extend_u0(GetSize(sig_y), cell->parameters.at("\\B_SIGNED").as_bool());
if (cell->type == "$xnor")
{
- RTLIL::SigSpec sig_t = module->addWire(NEW_ID, SIZE(sig_y));
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID, GetSize(sig_y));
- for (int i = 0; i < SIZE(sig_y); i++) {
+ for (int i = 0; i < GetSize(sig_y); i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
gate->setPort("\\A", sig_t[i]);
gate->setPort("\\Y", sig_y[i]);
@@ -79,7 +79,7 @@ static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
if (cell->type == "$xnor") gate_type = "$_XOR_";
log_assert(!gate_type.empty());
- for (int i = 0; i < SIZE(sig_y); i++) {
+ for (int i = 0; i < GetSize(sig_y); i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
gate->setPort("\\A", sig_a[i]);
gate->setPort("\\B", sig_b[i]);
@@ -87,7 +87,7 @@ static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
@@ -182,7 +182,7 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig)
sig = RTLIL::SigSpec(0, 1);
}
-static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
logic_reduce(module, sig_a);
@@ -202,7 +202,7 @@ static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
gate->setPort("\\Y", sig_y);
}
-static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
logic_reduce(module, sig_a);
@@ -231,13 +231,38 @@ static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
gate->setPort("\\Y", sig_y);
}
-static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_b = cell->getPort("\\B");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
+ bool is_ne = cell->type == "$ne" || cell->type == "$nex";
+
+ RTLIL::SigSpec xor_out = module->addWire(NEW_ID, std::max(GetSize(sig_a), GetSize(sig_b)));
+ RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed);
+ simplemap_bitop(module, xor_cell);
+ module->remove(xor_cell);
+
+ RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID);
+ RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out);
+ simplemap_reduce(module, reduce_cell);
+ module->remove(reduce_cell);
+
+ if (!is_ne) {
+ RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y);
+ simplemap_lognot(module, not_cell);
+ module->remove(not_cell);
+ }
+}
- for (int i = 0; i < SIZE(sig_y); i++) {
+void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+
+ for (int i = 0; i < GetSize(sig_y); i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_");
gate->setPort("\\A", sig_a[i]);
gate->setPort("\\B", sig_b[i]);
@@ -246,7 +271,7 @@ static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
{
int offset = cell->parameters.at("\\OFFSET").as_int();
RTLIL::SigSpec sig_a = cell->getPort("\\A");
@@ -254,7 +279,7 @@ static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
module->connect(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.size())));
}
-static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_ab = cell->getPort("\\A");
sig_ab.append(cell->getPort("\\B"));
@@ -262,7 +287,7 @@ static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
module->connect(RTLIL::SigSig(sig_y, sig_ab));
}
-static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
@@ -282,7 +307,7 @@ static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
@@ -301,7 +326,29 @@ static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ int width = cell->parameters.at("\\WIDTH").as_int();
+ char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
+ char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
+
+ RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
+ RTLIL::SigSpec sig_en = cell->getPort("\\EN");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+
+ std::string gate_type = stringf("$_DFFE_%c%c_", clk_pol, en_pol);
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\C", sig_clk);
+ gate->setPort("\\E", sig_en);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
+ }
+}
+
+void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
@@ -326,7 +373,7 @@ static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
@@ -353,7 +400,7 @@ static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
@@ -388,16 +435,37 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL
mappers["$logic_not"] = simplemap_lognot;
mappers["$logic_and"] = simplemap_logbin;
mappers["$logic_or"] = simplemap_logbin;
+ mappers["$eq"] = simplemap_eqne;
+ mappers["$eqx"] = simplemap_eqne;
+ mappers["$ne"] = simplemap_eqne;
+ mappers["$nex"] = simplemap_eqne;
mappers["$mux"] = simplemap_mux;
mappers["$slice"] = simplemap_slice;
mappers["$concat"] = simplemap_concat;
mappers["$sr"] = simplemap_sr;
mappers["$dff"] = simplemap_dff;
+ mappers["$dffe"] = simplemap_dffe;
mappers["$dffsr"] = simplemap_dffsr;
mappers["$adff"] = simplemap_adff;
mappers["$dlatch"] = simplemap_dlatch;
}
+void simplemap(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ static std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
+ static bool initialized_mappers = false;
+
+ if (!initialized_mappers) {
+ simplemap_get_mappers(mappers);
+ initialized_mappers = true;
+ }
+
+ mappers.at(cell->type)(module, cell);
+}
+
+YOSYS_NAMESPACE_END
+PRIVATE_NAMESPACE_BEGIN
+
struct SimplemapPass : public Pass {
SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { }
virtual void help()
@@ -440,3 +508,4 @@ struct SimplemapPass : public Pass {
}
} SimplemapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/simplemap.h b/passes/techmap/simplemap.h
new file mode 100644
index 00000000..dc2a395d
--- /dev/null
+++ b/passes/techmap/simplemap.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SIMPLEMAP_H
+#define SIMPLEMAP_H
+
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+extern void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell);
+
+extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index ed466faa..ab748ed7 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -26,15 +26,20 @@
#include <stdio.h>
#include <string.h>
+#include "simplemap.h"
#include "passes/techmap/techmap.inc"
-// see simplemap.cc
-extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+YOSYS_NAMESPACE_BEGIN
// see maccmap.cc
extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false);
-static void apply_prefix(std::string prefix, std::string &id)
+YOSYS_NAMESPACE_END
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void apply_prefix(std::string prefix, std::string &id)
{
if (id[0] == '\\')
id = prefix + "." + id.substr(1);
@@ -42,7 +47,7 @@ static void apply_prefix(std::string prefix, std::string &id)
id = "$techmap" + prefix + "." + id;
}
-static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
+void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{
std::vector<RTLIL::SigChunk> chunks = sig;
for (auto &chunk : chunks)
@@ -61,6 +66,11 @@ struct TechmapWorker
std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
std::map<RTLIL::Module*, bool> techmap_do_cache;
std::set<RTLIL::Module*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Module>> module_queue;
+ dict<Module*, SigMap> sigmaps;
+
+ pool<IdString> flatten_do_list;
+ pool<IdString> flatten_done_list;
+ pool<Cell*> flatten_keep_list;
struct TechmapWireData {
RTLIL::Wire *wire;
@@ -90,7 +100,7 @@ struct TechmapWorker
std::map<RTLIL::SigBit, std::pair<RTLIL::IdString, int>> connbits_map;
for (auto conn : cell->connections())
- for (int i = 0; i < SIZE(conn.second); i++) {
+ for (int i = 0; i < GetSize(conn.second); i++) {
RTLIL::SigBit bit = sigmap(conn.second[i]);
if (bit.wire == nullptr) {
if (verbose)
@@ -102,8 +112,10 @@ struct TechmapWorker
connbits_map.at(bit).second, log_id(connbits_map.at(bit).first));
constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i,
log_id(connbits_map.at(bit).first), connbits_map.at(bit).second);
- } else
- connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i);stringf("%s %d", log_id(conn.first), i, bit.data);
+ } else {
+ connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i);
+ constmap_info += stringf("|%s %d", log_id(conn.first), i);
+ }
}
return stringf("$paramod$constmap:%s%s", sha1(constmap_info).c_str(), tpl->name.c_str());
@@ -122,7 +134,7 @@ struct TechmapWorker
continue;
const char *q = strrchr(p+1, '.');
- p = q ? q : p+1;
+ p = q ? q+1 : p+1;
if (!strncmp(p, "_TECHMAP_", 9)) {
TechmapWireData record;
@@ -146,16 +158,13 @@ struct TechmapWorker
void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl)
{
- if (tpl->memories.size() != 0)
- log_error("Technology map yielded memories -> this is not supported.\n");
-
if (tpl->processes.size() != 0) {
log("Technology map yielded processes:\n");
for (auto &it : tpl->processes)
log(" %s",RTLIL::id2cstr(it.first));
if (autoproc_mode) {
Pass::call_on_module(tpl->design, tpl, "proc");
- log_assert(SIZE(tpl->processes) == 0);
+ log_assert(GetSize(tpl->processes) == 0);
} else
log_error("Technology map yielded processes -> this is not supported (use -autoproc to run 'proc' automatically).\n");
}
@@ -169,6 +178,22 @@ struct TechmapWorker
break;
}
+ dict<IdString, IdString> memory_renames;
+
+ for (auto &it : tpl->memories) {
+ std::string m_name = it.first.str();
+ apply_prefix(cell->name.str(), m_name);
+ RTLIL::Memory *m = new RTLIL::Memory;
+ m->name = m_name;
+ m->width = it.second->width;
+ m->start_offset = it.second->start_offset;
+ m->size = it.second->size;
+ m->attributes = it.second->attributes;
+ module->memories[m->name] = m;
+ memory_renames[it.first] = m->name;
+ design->select(module, m);
+ }
+
std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
for (auto &it : tpl->wires_) {
@@ -215,6 +240,11 @@ struct TechmapWorker
if (flatten_mode) {
// more conservative approach:
// connect internal and external wires
+ if (sigmaps.count(module) == 0)
+ sigmaps[module].set(module);
+ if (sigmaps.at(module)(c.first).has_const())
+ log_error("Mismatch in directionality for cell port %s.%s.%s: %s <= %s\n",
+ log_id(module), log_id(cell), log_id(it.first), log_signal(c.first), log_signal(c.second));
module->connect(c);
} else {
// approach that yields nicer outputs:
@@ -245,6 +275,12 @@ struct TechmapWorker
apply_prefix(cell->name.str(), it2.second, module);
port_signal_map.apply(it2.second);
}
+
+ if (c->type == "$memrd" || c->type == "$memwr") {
+ IdString memid = c->getParam("\\MEMID").decode_string();
+ log_assert(memory_renames.count(memid));
+ c->setParam("\\MEMID", Const(memory_renames[memid].str()));
+ }
}
for (auto &it : tpl->connections()) {
@@ -272,7 +308,7 @@ struct TechmapWorker
SigMap sigmap(module);
- TopoSort<RTLIL::Cell*> cells;
+ TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
@@ -291,12 +327,28 @@ struct TechmapWorker
continue;
}
+ if (flatten_mode) {
+ bool keepit = cell->get_bool_attribute("\\keep_hierarchy");
+ for (auto &tpl_name : celltypeMap.at(cell_type))
+ if (map->modules_[tpl_name]->get_bool_attribute("\\keep_hierarchy"))
+ keepit = true;
+ if (keepit) {
+ if (!flatten_keep_list[cell]) {
+ log("Keeping %s.%s (found keep_hierarchy property).\n", log_id(module), log_id(cell));
+ flatten_keep_list.insert(cell);
+ }
+ if (!flatten_done_list[cell->type])
+ flatten_do_list.insert(cell->type);
+ continue;
+ }
+ }
+
for (auto &conn : cell->connections())
{
RTLIL::SigSpec sig = sigmap(conn.second);
sig.remove_const();
- if (SIZE(sig) == 0)
+ if (GetSize(sig) == 0)
continue;
for (auto &tpl_name : celltypeMap.at(cell_type)) {
@@ -334,7 +386,7 @@ struct TechmapWorker
{
RTLIL::IdString derived_name = tpl_name;
RTLIL::Module *tpl = map->modules_[tpl_name];
- std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters;
+ std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end());
if (tpl->get_bool_attribute("\\blackbox"))
continue;
@@ -376,7 +428,7 @@ struct TechmapWorker
int port_counter = 1;
for (auto &c : extmapper_cell->connections_) {
- RTLIL::Wire *w = extmapper_module->addWire(c.first, SIZE(c.second));
+ RTLIL::Wire *w = extmapper_module->addWire(c.first, GetSize(c.second));
if (w->name == "\\Y" || w->name == "\\Q")
w->port_output = true;
else
@@ -522,7 +574,7 @@ struct TechmapWorker
tpl = techmap_cache[key];
} else {
if (cell->parameters.size() != 0) {
- derived_name = tpl->derive(map, parameters);
+ derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end()));
tpl = map->module(derived_name);
log_continue = true;
}
@@ -623,7 +675,7 @@ struct TechmapWorker
}
for (auto conn : cell->connections())
- for (int i = 0; i < SIZE(conn.second); i++)
+ for (int i = 0; i < GetSize(conn.second); i++)
{
RTLIL::SigBit bit = sigmap(conn.second[i]);
RTLIL::SigBit tplbit(tpl->wire(conn.first), i);
@@ -968,7 +1020,7 @@ struct TechmapPass : public Pass {
Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
}
- std::map<RTLIL::IdString, RTLIL::Module*> modules_new;
+ dict<RTLIL::IdString, RTLIL::Module*> modules_new;
for (auto &it : map->modules_) {
if (it.first.substr(0, 2) == "\\$")
it.second->name = it.first.substr(1);
@@ -1027,6 +1079,9 @@ struct FlattenPass : public Pass {
log("pass is very simmilar to the 'techmap' pass. The only difference is that this\n");
log("pass is using the current design as mapping library.\n");
log("\n");
+ log("Cells and/or modules with the 'keep_hiearchy' attribute set will not be\n");
+ log("flattened by this command.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -1039,8 +1094,8 @@ struct FlattenPass : public Pass {
worker.flatten_mode = true;
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
- for (auto &it : design->modules_)
- celltypeMap[it.first].insert(it.first);
+ for (auto module : design->modules())
+ celltypeMap[module->name].insert(module->name);
RTLIL::Module *top_mod = NULL;
if (design->full_selection())
@@ -1048,26 +1103,40 @@ struct FlattenPass : public Pass {
if (mod->get_bool_attribute("\\top"))
top_mod = mod;
- bool did_something = true;
std::set<RTLIL::Cell*> handled_cells;
- while (did_something) {
- did_something = false;
- if (top_mod != NULL) {
- if (worker.techmap_module(design, top_mod, design, handled_cells, celltypeMap, false))
- did_something = true;
- } else {
- for (auto mod : design->modules())
- if (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false))
- did_something = true;
+ if (top_mod != NULL) {
+ worker.flatten_do_list.insert(top_mod->name);
+ while (!worker.flatten_do_list.empty()) {
+ auto mod = design->module(*worker.flatten_do_list.begin());
+ while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { }
+ worker.flatten_done_list.insert(mod->name);
+ worker.flatten_do_list.erase(mod->name);
}
+ } else {
+ for (auto mod : vector<Module*>(design->modules()))
+ while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { }
}
log("No more expansions possible.\n");
- if (top_mod != NULL) {
- std::map<RTLIL::IdString, RTLIL::Module*> new_modules;
- for (auto mod : design->modules())
- if (mod == top_mod || mod->get_bool_attribute("\\blackbox")) {
+ if (top_mod != NULL)
+ {
+ pool<RTLIL::IdString> used_modules, new_used_modules;
+ new_used_modules.insert(top_mod->name);
+ while (!new_used_modules.empty()) {
+ pool<RTLIL::IdString> queue;
+ queue.swap(new_used_modules);
+ for (auto modname : queue)
+ used_modules.insert(modname);
+ for (auto modname : queue)
+ for (auto cell : design->module(modname)->cells())
+ if (design->module(cell->type) && !used_modules[cell->type])
+ new_used_modules.insert(cell->type);
+ }
+
+ dict<RTLIL::IdString, RTLIL::Module*> new_modules;
+ for (auto mod : vector<Module*>(design->modules()))
+ if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) {
new_modules[mod->name] = mod;
} else {
log("Deleting now unused module %s.\n", log_id(mod));
@@ -1080,3 +1149,4 @@ struct FlattenPass : public Pass {
}
} FlattenPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/tests/test_abcloop.cc b/passes/tests/test_abcloop.cc
index 0a0ceb1d..09cb4195 100644
--- a/passes/tests/test_abcloop.cc
+++ b/passes/tests/test_abcloop.cc
@@ -21,6 +21,9 @@
#include "kernel/yosys.h"
#include "kernel/satgen.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static uint32_t xorshift32_state = 123456789;
static uint32_t xorshift32(uint32_t limit) {
@@ -33,7 +36,7 @@ static uint32_t xorshift32(uint32_t limit) {
static RTLIL::Wire *getw(std::vector<RTLIL::Wire*> &wires, RTLIL::Wire *w)
{
while (1) {
- int idx = xorshift32(SIZE(wires));
+ int idx = xorshift32(GetSize(wires));
if (wires[idx] != w && !wires[idx]->port_output)
return wires[idx];
}
@@ -124,28 +127,28 @@ static void test_abcloop()
module->fixup_ports();
Pass::call(design, "clean");
- ezDefaultSAT ez;
+ ezSatPtr ez;
SigMap sigmap(module);
- SatGen satgen(&ez, &sigmap);
+ SatGen satgen(ez.get(), &sigmap);
for (auto c : module->cells()) {
- bool ok = satgen.importCell(c);
+ bool ok YS_ATTRIBUTE(unused) = satgen.importCell(c);
log_assert(ok);
}
std::vector<int> in_vec = satgen.importSigSpec(in_sig);
- std::vector<int> inverse_in_vec = ez.vec_not(in_vec);
+ std::vector<int> inverse_in_vec = ez->vec_not(in_vec);
std::vector<int> out_vec = satgen.importSigSpec(out_sig);
for (int i = 0; i < 16; i++)
{
std::vector<int> assumptions;
- for (int j = 0; j < SIZE(in_vec); j++)
+ for (int j = 0; j < GetSize(in_vec); j++)
assumptions.push_back((i & (1 << j)) ? in_vec.at(j) : inverse_in_vec.at(j));
std::vector<bool> results;
- if (!ez.solve(out_vec, results, assumptions)) {
+ if (!ez->solve(out_vec, results, assumptions)) {
log("No stable solution for input %d found -> recreate module.\n", i);
goto recreate_module;
}
@@ -153,10 +156,10 @@ static void test_abcloop()
for (int j = 0; j < 4; j++)
truthtab[i][j] = results[j];
- assumptions.push_back(ez.vec_ne(out_vec, ez.vec_const(results)));
+ assumptions.push_back(ez->vec_ne(out_vec, ez->vec_const(results)));
std::vector<bool> results2;
- if (ez.solve(out_vec, results2, assumptions)) {
+ if (ez->solve(out_vec, results2, assumptions)) {
log("Two stable solutions for input %d found -> recreate module.\n", i);
goto recreate_module;
}
@@ -174,17 +177,17 @@ static void test_abcloop()
log("\n");
log("Pre- and post-abc truth table:\n");
- ezDefaultSAT ez;
+ ezSatPtr ez;
SigMap sigmap(module);
- SatGen satgen(&ez, &sigmap);
+ SatGen satgen(ez.get(), &sigmap);
for (auto c : module->cells()) {
- bool ok = satgen.importCell(c);
+ bool ok YS_ATTRIBUTE(unused) = satgen.importCell(c);
log_assert(ok);
}
std::vector<int> in_vec = satgen.importSigSpec(in_sig);
- std::vector<int> inverse_in_vec = ez.vec_not(in_vec);
+ std::vector<int> inverse_in_vec = ez->vec_not(in_vec);
std::vector<int> out_vec = satgen.importSigSpec(out_sig);
@@ -194,14 +197,14 @@ static void test_abcloop()
for (int i = 0; i < 16; i++)
{
std::vector<int> assumptions;
- for (int j = 0; j < SIZE(in_vec); j++)
+ for (int j = 0; j < GetSize(in_vec); j++)
assumptions.push_back((i & (1 << j)) ? in_vec.at(j) : inverse_in_vec.at(j));
for (int j = 0; j < 4; j++)
truthtab2[i][j] = truthtab[i][j];
std::vector<bool> results;
- if (!ez.solve(out_vec, results, assumptions)) {
+ if (!ez->solve(out_vec, results, assumptions)) {
log("No stable solution for input %d found.\n", i);
found_error = true;
continue;
@@ -210,10 +213,10 @@ static void test_abcloop()
for (int j = 0; j < 4; j++)
truthtab2[i][j] = results[j];
- assumptions.push_back(ez.vec_ne(out_vec, ez.vec_const(results)));
+ assumptions.push_back(ez->vec_ne(out_vec, ez->vec_const(results)));
std::vector<bool> results2;
- if (ez.solve(out_vec, results2, assumptions)) {
+ if (ez->solve(out_vec, results2, assumptions)) {
log("Two stable solutions for input %d found -> recreate module.\n", i);
found_error = true;
}
@@ -262,13 +265,13 @@ struct TestAbcloopPass : public Pass {
xorshift32_state = 0;
int argidx;
- for (argidx = 1; argidx < SIZE(args); argidx++)
+ for (argidx = 1; argidx < GetSize(args); argidx++)
{
- if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-n" && argidx+1 < GetSize(args)) {
num_iter = atoi(args[++argidx].c_str());
continue;
}
- if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-s" && argidx+1 < GetSize(args)) {
xorshift32_state = atoi(args[++argidx].c_str());
continue;
}
@@ -283,3 +286,4 @@ struct TestAbcloopPass : public Pass {
}
} TestAbcloopPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
index eed0f75f..7c1b671c 100644
--- a/passes/tests/test_autotb.cc
+++ b/passes/tests/test_autotb.cc
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <time.h>
+USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static std::string id(std::string internal_id)
@@ -91,7 +92,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("end\n");
f << stringf("endtask\n\n");
- for (auto it = design->modules_.begin(); it != design->modules_.end(); it++)
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it)
{
std::map<std::string, int> signal_in;
std::map<std::string, std::string> signal_const;
@@ -105,7 +106,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
int count_ports = 0;
log("Generating test bench for module `%s'.\n", it->first.c_str());
- for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); it2++) {
+ for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); ++it2) {
RTLIL::Wire *wire = it2->second;
if (wire->port_output) {
count_ports++;
@@ -114,8 +115,8 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
} else if (wire->port_input) {
count_ports++;
bool is_clksignal = wire->get_bool_attribute("\\gentb_clock");
- for (auto it3 = mod->processes.begin(); it3 != mod->processes.end(); it3++)
- for (auto it4 = it3->second->syncs.begin(); it4 != it3->second->syncs.end(); it4++) {
+ for (auto it3 = mod->processes.begin(); it3 != mod->processes.end(); ++it3)
+ for (auto it4 = it3->second->syncs.begin(); it4 != it3->second->syncs.end(); ++it4) {
if ((*it4)->type == RTLIL::ST0 || (*it4)->type == RTLIL::ST1)
continue;
RTLIL::SigSpec &signal = (*it4)->signal;
@@ -134,7 +135,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
}
}
f << stringf("%s %s(\n", id(mod->name.str()).c_str(), idy("uut", mod->name.str()).c_str());
- for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); it2++) {
+ for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); ++it2) {
RTLIL::Wire *wire = it2->second;
if (wire->port_output || wire->port_input)
f << stringf("\t.%s(%s)%s\n", id(wire->name.str()).c_str(),
@@ -145,23 +146,23 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("task %s;\n", idy(mod->name.str(), "reset").c_str());
f << stringf("begin\n");
int delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++)
+ for (auto it = signal_in.begin(); it != signal_in.end(); ++it)
f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it)
f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
}
delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++)
+ for (auto it = signal_in.begin(); it != signal_in.end(); ++it)
f << stringf("\t%s <= #%d ~0;\n", it->first.c_str(), ++delay_counter*2);
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
}
delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
+ for (auto it = signal_in.begin(); it != signal_in.end(); ++it) {
if (signal_const.count(it->first) == 0)
continue;
f << stringf("\t%s <= #%d 'b%s;\n", it->first.c_str(), ++delay_counter*2, signal_const[it->first].c_str());
@@ -194,7 +195,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf(" } = {");
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
- f << stringf(" } ^ (%d'b1 << (xorshift128_w %% %d));\n", total_clock_bits, total_clock_bits);
+ f << stringf(" } ^ (%d'b1 << (xorshift128_w %% %d));\n", total_clock_bits, total_clock_bits + 1);
}
f << stringf("end\n");
f << stringf("endtask\n\n");
@@ -292,7 +293,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("initial begin\n");
f << stringf("\t// $dumpfile(\"testbench.vcd\");\n");
f << stringf("\t// $dumpvars(0, testbench);\n");
- for (auto it = design->modules_.begin(); it != design->modules_.end(); it++)
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it)
if (!it->second->get_bool_attribute("\\gentb_skip"))
f << stringf("\t%s;\n", idy(it->first.str(), "test").c_str());
f << stringf("\t$finish;\n");
@@ -335,9 +336,9 @@ struct TestAutotbBackend : public Backend {
log_header("Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n");
int argidx;
- for (argidx = 1; argidx < SIZE(args); argidx++)
+ for (argidx = 1; argidx < GetSize(args); argidx++)
{
- if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-n" && argidx+1 < GetSize(args)) {
num_iter = atoi(args[++argidx].c_str());
continue;
}
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index 1fa90b54..268f2559 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -24,6 +24,9 @@
#include "kernel/macc.h"
#include <algorithm>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static uint32_t xorshift32_state = 123456789;
static uint32_t xorshift32(uint32_t limit) {
@@ -33,7 +36,7 @@ static uint32_t xorshift32(uint32_t limit) {
return xorshift32_state % limit;
}
-static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode)
+static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode, bool muxdiv)
{
RTLIL::Module *module = design->addModule("\\gold");
RTLIL::Cell *cell = module->addCell("\\UUT", cell_type);
@@ -199,6 +202,13 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->setPort("\\Y", wire);
}
+ if (muxdiv && (cell_type == "$div" || cell_type == "$mod")) {
+ auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort("\\B"));
+ auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort("\\Y")));
+ module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(div_out)), div_out, b_not_zero, cell->getPort("\\Y"));
+ cell->setPort("\\Y", div_out);
+ }
+
if (cell_type == "$alu")
{
wire = module->addWire("\\CI");
@@ -210,12 +220,12 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->setPort("\\BI", wire);
wire = module->addWire("\\X");
- wire->width = SIZE(cell->getPort("\\Y"));
+ wire->width = GetSize(cell->getPort("\\Y"));
wire->port_output = true;
cell->setPort("\\X", wire);
wire = module->addWire("\\CO");
- wire->width = SIZE(cell->getPort("\\Y"));
+ wire->width = GetSize(cell->getPort("\\Y"));
wire->port_output = true;
cell->setPort("\\CO", wire);
}
@@ -227,25 +237,25 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
{
RTLIL::SigSpec sig = conn.second;
- if (SIZE(sig) == 0 || sig[0].wire == nullptr || sig[0].wire->port_output)
+ if (GetSize(sig) == 0 || sig[0].wire == nullptr || sig[0].wire->port_output)
continue;
int n, m;
switch (xorshift32(5))
{
case 0:
- n = xorshift32(SIZE(sig) + 1);
+ n = xorshift32(GetSize(sig) + 1);
for (int i = 0; i < n; i++)
sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
break;
case 1:
- n = xorshift32(SIZE(sig) + 1);
- for (int i = n; i < SIZE(sig); i++)
+ n = xorshift32(GetSize(sig) + 1);
+ for (int i = n; i < GetSize(sig); i++)
sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
break;
case 2:
- n = xorshift32(SIZE(sig));
- m = xorshift32(SIZE(sig));
+ n = xorshift32(GetSize(sig));
+ m = xorshift32(GetSize(sig));
for (int i = std::min(n, m); i < std::max(n, m); i++)
sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
break;
@@ -268,10 +278,10 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
RTLIL::Module *gate_mod = design->module("\\gate");
ConstEval gold_ce(gold_mod), gate_ce(gate_mod);
- ezDefaultSAT ez1, ez2;
+ ezSatPtr ez1, ez2;
SigMap sigmap(gold_mod);
- SatGen satgen1(&ez1, &sigmap);
- SatGen satgen2(&ez2, &sigmap);
+ SatGen satgen1(ez1.get(), &sigmap);
+ SatGen satgen2(ez2.get(), &sigmap);
satgen2.model_undef = true;
if (!nosat)
@@ -287,19 +297,19 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
for (auto port : gold_mod->ports) {
RTLIL::Wire *wire = gold_mod->wire(port);
if (wire->port_input)
- vlog_file << stringf(" reg [%d:0] %s;\n", SIZE(wire)-1, log_id(wire));
+ vlog_file << stringf(" reg [%d:0] %s;\n", GetSize(wire)-1, log_id(wire));
else
- vlog_file << stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", SIZE(wire)-1, log_id(wire), log_id(wire));
+ vlog_file << stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", GetSize(wire)-1, log_id(wire), log_id(wire));
}
vlog_file << stringf(" %s_expr uut_expr(", uut_name.c_str());
- for (int i = 0; i < SIZE(gold_mod->ports); i++)
+ for (int i = 0; i < GetSize(gold_mod->ports); i++)
vlog_file << stringf("%s.%s(%s%s)", i ? ", " : "", log_id(gold_mod->ports[i]), log_id(gold_mod->ports[i]),
gold_mod->wire(gold_mod->ports[i])->port_input ? "" : "_expr");
vlog_file << stringf(");\n");
vlog_file << stringf(" %s_expr uut_noexpr(", uut_name.c_str());
- for (int i = 0; i < SIZE(gold_mod->ports); i++)
+ for (int i = 0; i < GetSize(gold_mod->ports); i++)
vlog_file << stringf("%s.%s(%s%s)", i ? ", " : "", log_id(gold_mod->ports[i]), log_id(gold_mod->ports[i]),
gold_mod->wire(gold_mod->ports[i])->port_input ? "" : "_noexpr");
vlog_file << stringf(");\n");
@@ -327,18 +337,18 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
log_assert(gold_wire != nullptr);
log_assert(gate_wire != nullptr);
log_assert(gold_wire->port_input == gate_wire->port_input);
- log_assert(SIZE(gold_wire) == SIZE(gate_wire));
+ log_assert(GetSize(gold_wire) == GetSize(gate_wire));
if (!gold_wire->port_input)
continue;
RTLIL::Const in_value;
- for (int i = 0; i < SIZE(gold_wire); i++)
+ for (int i = 0; i < GetSize(gold_wire); i++)
in_value.bits.push_back(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
if (xorshift32(4) == 0) {
int inv_chance = 1 + xorshift32(8);
- for (int i = 0; i < SIZE(gold_wire); i++)
+ for (int i = 0; i < GetSize(gold_wire); i++)
if (xorshift32(inv_chance) == 0)
in_value.bits[i] = RTLIL::Sx;
}
@@ -352,7 +362,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
gold_ce.set(gold_wire, in_value);
gate_ce.set(gate_wire, in_value);
- if (vlog_file.is_open() && SIZE(in_value) > 0) {
+ if (vlog_file.is_open() && GetSize(in_value) > 0) {
vlog_file << stringf(" %s = 'b%s;\n", log_id(gold_wire), in_value.as_string().c_str());
if (!vlog_pattern_info.empty())
vlog_pattern_info += " ";
@@ -371,7 +381,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
log_assert(gold_wire != nullptr);
log_assert(gate_wire != nullptr);
log_assert(gold_wire->port_output == gate_wire->port_output);
- log_assert(SIZE(gold_wire) == SIZE(gate_wire));
+ log_assert(GetSize(gold_wire) == GetSize(gate_wire));
if (!gold_wire->port_output)
continue;
@@ -386,7 +396,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
log_error("Failed to eval %s in gate module.\n", log_id(gate_wire));
bool gold_gate_mismatch = false;
- for (int i = 0; i < SIZE(gold_wire); i++) {
+ for (int i = 0; i < GetSize(gold_wire); i++) {
if (gold_outval[i] == RTLIL::Sx)
continue;
if (gold_outval[i] == gate_outval[i])
@@ -406,9 +416,9 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
if (vlog_file.is_open()) {
vlog_file << stringf(" $display(\"[%s] %s expected: %%b, expr: %%b, noexpr: %%b\", %d'b%s, %s_expr, %s_noexpr);\n",
- vlog_pattern_info.c_str(), log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str(), log_id(gold_wire), log_id(gold_wire));
- vlog_file << stringf(" if (%s_expr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str());
- vlog_file << stringf(" if (%s_noexpr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str());
+ vlog_pattern_info.c_str(), log_id(gold_wire), GetSize(gold_outval), gold_outval.as_string().c_str(), log_id(gold_wire), log_id(gold_wire));
+ vlog_file << stringf(" if (%s_expr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), GetSize(gold_outval), gold_outval.as_string().c_str());
+ vlog_file << stringf(" if (%s_noexpr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), GetSize(gold_outval), gold_outval.as_string().c_str());
}
}
@@ -423,17 +433,17 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
std::vector<int> sat1_model = satgen1.importSigSpec(out_sig);
std::vector<bool> sat1_model_value;
- if (!ez1.solve(sat1_model, sat1_model_value, ez1.vec_eq(sat1_in_sig, sat1_in_val)))
+ if (!ez1->solve(sat1_model, sat1_model_value, ez1->vec_eq(sat1_in_sig, sat1_in_val)))
log_error("Evaluating sat model 1 (no undef modeling) failed!\n");
if (verbose) {
log("SAT 1: ");
- for (int i = SIZE(out_sig)-1; i >= 0; i--)
+ for (int i = GetSize(out_sig)-1; i >= 0; i--)
log("%c", sat1_model_value.at(i) ? '1' : '0');
log("\n");
}
- for (int i = 0; i < SIZE(out_sig); i++) {
+ for (int i = 0; i < GetSize(out_sig); i++) {
if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
continue;
if (out_val[i] == RTLIL::S0 && sat1_model_value.at(i) == false)
@@ -458,18 +468,18 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
std::vector<bool> sat2_model_value;
- if (!ez2.solve(sat2_model, sat2_model_value, ez2.vec_eq(sat2_in_def_sig, sat2_in_def_val), ez2.vec_eq(sat2_in_undef_sig, sat2_in_undef_val)))
+ if (!ez2->solve(sat2_model, sat2_model_value, ez2->vec_eq(sat2_in_def_sig, sat2_in_def_val), ez2->vec_eq(sat2_in_undef_sig, sat2_in_undef_val)))
log_error("Evaluating sat model 2 (undef modeling) failed!\n");
if (verbose) {
log("SAT 2: ");
- for (int i = SIZE(out_sig)-1; i >= 0; i--)
- log("%c", sat2_model_value.at(SIZE(out_sig) + i) ? 'x' : sat2_model_value.at(i) ? '1' : '0');
+ for (int i = GetSize(out_sig)-1; i >= 0; i--)
+ log("%c", sat2_model_value.at(GetSize(out_sig) + i) ? 'x' : sat2_model_value.at(i) ? '1' : '0');
log("\n");
}
- for (int i = 0; i < SIZE(out_sig); i++) {
- if (sat2_model_value.at(SIZE(out_sig) + i)) {
+ for (int i = 0; i < GetSize(out_sig); i++) {
+ if (sat2_model_value.at(GetSize(out_sig) + i)) {
if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
continue;
} else {
@@ -505,7 +515,7 @@ struct TestCellPass : public Pass {
log("by comparing SAT solver, EVAL and TECHMAP implementations of the cell types..\n");
log("\n");
log("Run with 'all' instead of a cell type to run the test on all supported\n");
- log("cell types.\n");
+ log("cell types. Use for example 'all /$add' for all cell types except $add.\n");
log("\n");
log(" -n {integer}\n");
log(" create this number of cell instances and test them (default = 100).\n");
@@ -516,12 +526,20 @@ struct TestCellPass : public Pass {
log(" -f {ilang_file}\n");
log(" don't generate circuits. instead load the specified ilang file.\n");
log("\n");
+ log(" -w {filename_prefix}\n");
+ log(" don't test anything. just generate the circuits and write them\n");
+ log(" to ilang files with the specified prefix\n");
+ log("\n");
log(" -map {filename}\n");
log(" pass this option to techmap.\n");
log("\n");
- log(" -simplib\n");
+ log(" -simlib\n");
log(" use \"techmap -map +/simlib.v -max_iter 2 -autoproc\"\n");
log("\n");
+ log(" -muxdiv\n");
+ log(" when creating test benches with dividers, create an additional mux\n");
+ log(" to mask out the division-by-zero case\n");
+ log("\n");
log(" -script {script_file}\n");
log(" instead of calling \"techmap\", call \"script {script_file}\".\n");
log("\n");
@@ -542,34 +560,39 @@ struct TestCellPass : public Pass {
{
int num_iter = 100;
std::string techmap_cmd = "techmap -assert";
- std::string ilang_file;
+ std::string ilang_file, write_prefix;
xorshift32_state = 0;
std::ofstream vlog_file;
+ bool muxdiv = false;
bool verbose = false;
bool constmode = false;
bool nosat = false;
int argidx;
- for (argidx = 1; argidx < SIZE(args); argidx++)
+ for (argidx = 1; argidx < GetSize(args); argidx++)
{
- if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-n" && argidx+1 < GetSize(args)) {
num_iter = atoi(args[++argidx].c_str());
continue;
}
- if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-s" && argidx+1 < GetSize(args)) {
xorshift32_state = atoi(args[++argidx].c_str());
continue;
}
- if (args[argidx] == "-map" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-map" && argidx+1 < GetSize(args)) {
techmap_cmd += " -map " + args[++argidx];
continue;
}
- if (args[argidx] == "-f" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-f" && argidx+1 < GetSize(args)) {
ilang_file = args[++argidx];
num_iter = 1;
continue;
}
- if (args[argidx] == "-script" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-w" && argidx+1 < GetSize(args)) {
+ write_prefix = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-script" && argidx+1 < GetSize(args)) {
techmap_cmd = "script " + args[++argidx];
continue;
}
@@ -577,6 +600,10 @@ struct TestCellPass : public Pass {
techmap_cmd = "techmap -map +/simlib.v -max_iter 2 -autoproc";
continue;
}
+ if (args[argidx] == "-muxdiv") {
+ muxdiv = true;
+ continue;
+ }
if (args[argidx] == "-const") {
constmode = true;
continue;
@@ -589,7 +616,7 @@ struct TestCellPass : public Pass {
verbose = true;
continue;
}
- if (args[argidx] == "-vlog" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-vlog" && argidx+1 < GetSize(args)) {
vlog_file.open(args[++argidx], std::ios_base::trunc);
if (!vlog_file.is_open())
log_cmd_error("Failed to open output file `%s'.\n", args[argidx].c_str());
@@ -660,7 +687,7 @@ struct TestCellPass : public Pass {
cell_types["$macc"] = "*";
cell_types["$fa"] = "*";
- for (; argidx < SIZE(args); argidx++)
+ for (; argidx < GetSize(args); argidx++)
{
if (args[argidx].rfind("-", 0) == 0)
log_cmd_error("Unexpected option: %s\n", args[argidx].c_str());
@@ -672,6 +699,15 @@ struct TestCellPass : public Pass {
continue;
}
+ if (args[argidx].substr(0, 1) == "/") {
+ std::vector<std::string> new_selected_cell_types;
+ for (auto it : selected_cell_types)
+ if (it != args[argidx].substr(1))
+ new_selected_cell_types.push_back(it);
+ new_selected_cell_types.swap(selected_cell_types);
+ continue;
+ }
+
if (cell_types.count(args[argidx]) == 0) {
std::string cell_type_list;
int charcount = 100;
@@ -681,7 +717,7 @@ struct TestCellPass : public Pass {
charcount = 0;
} else
cell_type_list += " " + it.first;
- charcount += SIZE(it.first);
+ charcount += GetSize(it.first);
}
log_cmd_error("The cell type `%s' is currently not supported. Try one of these:%s\n",
args[argidx].c_str(), cell_type_list.c_str());
@@ -709,24 +745,28 @@ struct TestCellPass : public Pass {
if (cell_type == "ilang")
Frontend::frontend_call(design, NULL, std::string(), "ilang " + ilang_file);
else
- create_gold_module(design, cell_type, cell_types.at(cell_type), constmode);
- Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
- if (!nosat)
- Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
- if (verbose)
- Pass::call(design, "dump gate");
- Pass::call(design, "dump gold");
- if (!nosat)
- Pass::call(design, "sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter");
- std::string uut_name = stringf("uut_%s_%d", cell_type.substr(1).c_str(), i);
- if (vlog_file.is_open()) {
- Pass::call(design, stringf("copy gold %s_expr; select %s_expr", uut_name.c_str(), uut_name.c_str()));
- Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected");
- Pass::call(design, stringf("copy gold %s_noexpr; select %s_noexpr", uut_name.c_str(), uut_name.c_str()));
- Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected -noexpr");
- uut_names.push_back(uut_name);
+ create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv);
+ if (!write_prefix.empty()) {
+ Pass::call(design, stringf("write_ilang %s_%s_%05d.il", write_prefix.c_str(), cell_type.c_str()+1, i));
+ } else {
+ Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
+ if (!nosat)
+ Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
+ if (verbose)
+ Pass::call(design, "dump gate");
+ Pass::call(design, "dump gold");
+ if (!nosat)
+ Pass::call(design, "sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter");
+ std::string uut_name = stringf("uut_%s_%d", cell_type.substr(1).c_str(), i);
+ if (vlog_file.is_open()) {
+ Pass::call(design, stringf("copy gold %s_expr; select %s_expr", uut_name.c_str(), uut_name.c_str()));
+ Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected");
+ Pass::call(design, stringf("copy gold %s_noexpr; select %s_noexpr", uut_name.c_str(), uut_name.c_str()));
+ Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected -noexpr");
+ uut_names.push_back(uut_name);
+ }
+ run_eval_test(design, verbose, nosat, uut_name, vlog_file);
}
- run_eval_test(design, verbose, nosat, uut_name, vlog_file);
delete design;
}
@@ -743,3 +783,4 @@ struct TestCellPass : public Pass {
}
} TestCellPass;
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/cmos/cmos_cells.v b/techlibs/cmos/cmos_cells.v
index da75270c..27278fac 100644
--- a/techlibs/cmos/cmos_cells.v
+++ b/techlibs/cmos/cmos_cells.v
@@ -1,17 +1,26 @@
+module BUF(A, Y);
+input A;
+output Y;
+assign Y = A;
+endmodule
+
module NOT(A, Y);
input A;
-output Y = ~A;
+output Y;
+assign Y = ~A;
endmodule
module NAND(A, B, Y);
input A, B;
-output Y = ~(A & B);
+output Y;
+assign Y = ~(A & B);
endmodule
module NOR(A, B, Y);
input A, B;
-output Y = ~(A | B);
+output Y;
+assign Y = ~(A | B);
endmodule
module DFF(C, D, Q);
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc
index 7c8cc2f6..d2ce61cf 100644
--- a/techlibs/common/Makefile.inc
+++ b/techlibs/common/Makefile.inc
@@ -1,5 +1,7 @@
+ifneq ($(SMALL),1)
OBJS += techlibs/common/synth.o
+endif
EXTRA_TARGETS += techlibs/common/blackbox.v
@@ -7,29 +9,11 @@ techlibs/common/blackbox.v: techlibs/common/blackbox.sed techlibs/common/simlib.
$(P) cat techlibs/common/simlib.v techlibs/common/simcells.v | $(SED) -rf techlibs/common/blackbox.sed > techlibs/common/blackbox.v.new
$(Q) mv techlibs/common/blackbox.v.new techlibs/common/blackbox.v
-EXTRA_TARGETS += share/simlib.v share/simcells.v share/techmap.v share/blackbox.v share/pmux2mux.v share/adff2dff.v
-
-share/simlib.v: techlibs/common/simlib.v
- $(P) mkdir -p share
- $(Q) cp techlibs/common/simlib.v share/simlib.v
-
-share/simcells.v: techlibs/common/simcells.v
- $(P) mkdir -p share
- $(Q) cp techlibs/common/simcells.v share/simcells.v
-
-share/techmap.v: techlibs/common/techmap.v
- $(P) mkdir -p share
- $(Q) cp techlibs/common/techmap.v share/techmap.v
-
-share/blackbox.v: techlibs/common/blackbox.v
- $(P) mkdir -p share
- $(Q) cp techlibs/common/blackbox.v share/blackbox.v
-
-share/pmux2mux.v: techlibs/common/pmux2mux.v
- $(P) mkdir -p share
- $(Q) cp techlibs/common/pmux2mux.v share/pmux2mux.v
-
-share/adff2dff.v: techlibs/common/adff2dff.v
- $(P) mkdir -p share
- $(Q) cp techlibs/common/adff2dff.v share/adff2dff.v
+$(eval $(call add_share_file,share,techlibs/common/simlib.v))
+$(eval $(call add_share_file,share,techlibs/common/simcells.v))
+$(eval $(call add_share_file,share,techlibs/common/techmap.v))
+$(eval $(call add_share_file,share,techlibs/common/blackbox.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/cells.lib))
diff --git a/techlibs/common/cells.lib b/techlibs/common/cells.lib
new file mode 100644
index 00000000..eb89036d
--- /dev/null
+++ b/techlibs/common/cells.lib
@@ -0,0 +1,108 @@
+library(yosys_cells) {
+ cell(DFF_N) {
+ ff(IQ, IQN) {
+ clocked_on: "!C";
+ next_state: "D";
+ }
+ pin(D) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+ cell(DFF_P) {
+ ff(IQ, IQN) {
+ clocked_on: "C";
+ next_state: "D";
+ }
+ pin(D) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+ cell(DFF_NN0) {
+ ff(IQ, IQN) {
+ clocked_on: "!C";
+ next_state: "D";
+ clear: "!R";
+ }
+ pin(D) { direction: input; }
+ pin(R) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+ cell(DFF_NN1) {
+ ff(IQ, IQN) {
+ clocked_on: "!C";
+ next_state: "D";
+ preset: "!R";
+ }
+ pin(D) { direction: input; }
+ pin(R) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+ cell(DFF_NP0) {
+ ff(IQ, IQN) {
+ clocked_on: "!C";
+ next_state: "D";
+ clear: "R";
+ }
+ pin(D) { direction: input; }
+ pin(R) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+ cell(DFF_NP1) {
+ ff(IQ, IQN) {
+ clocked_on: "!C";
+ next_state: "D";
+ preset: "R";
+ }
+ pin(D) { direction: input; }
+ pin(R) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+ cell(DFF_PN0) {
+ ff(IQ, IQN) {
+ clocked_on: "C";
+ next_state: "D";
+ clear: "!R";
+ }
+ pin(D) { direction: input; }
+ pin(R) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+ cell(DFF_PN1) {
+ ff(IQ, IQN) {
+ clocked_on: "C";
+ next_state: "D";
+ preset: "!R";
+ }
+ pin(D) { direction: input; }
+ pin(R) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+ cell(DFF_PP0) {
+ ff(IQ, IQN) {
+ clocked_on: "C";
+ next_state: "D";
+ clear: "R";
+ }
+ pin(D) { direction: input; }
+ pin(R) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+ cell(DFF_PP1) {
+ ff(IQ, IQN) {
+ clocked_on: "C";
+ next_state: "D";
+ preset: "R";
+ }
+ pin(D) { direction: input; }
+ pin(R) { direction: input; }
+ pin(C) { direction: input; clock: true; }
+ pin(Q) { direction: output; function: "IQ"; }
+ }
+}
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index a2a37735..eb62d783 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -25,6 +25,12 @@
*
*/
+module \$_BUF_ (A, Y);
+input A;
+output Y;
+assign Y = A;
+endmodule
+
module \$_NOT_ (A, Y);
input A;
output Y;
@@ -157,6 +163,38 @@ always @(posedge C) begin
end
endmodule
+module \$_DFFE_NN_ (D, Q, C, E);
+input D, C, E;
+output reg Q;
+always @(negedge C) begin
+ if (!E) Q <= D;
+end
+endmodule
+
+module \$_DFFE_NP_ (D, Q, C, E);
+input D, C, E;
+output reg Q;
+always @(negedge C) begin
+ if (E) Q <= D;
+end
+endmodule
+
+module \$_DFFE_PN_ (D, Q, C, E);
+input D, C, E;
+output reg Q;
+always @(posedge C) begin
+ if (!E) Q <= D;
+end
+endmodule
+
+module \$_DFFE_PP_ (D, Q, C, E);
+input D, C, E;
+output reg Q;
+always @(posedge C) begin
+ if (E) Q <= D;
+end
+endmodule
+
module \$_DFF_NN0_ (D, Q, C, R);
input D, C, R;
output reg Q;
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 2d8088ad..abd2af52 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -1160,12 +1160,51 @@ module \$assert (A, EN);
input A, EN;
+`ifndef SIMLIB_NOCHECKS
always @* begin
if (A !== 1'b1 && EN === 1'b1) begin
- $display("Assertation failed!");
- $finish;
+ $display("Assertation %m failed!");
+ $stop;
+ end
+end
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$assume (A, EN);
+
+input A, EN;
+
+`ifndef SIMLIB_NOCHECKS
+always @* begin
+ if (A !== 1'b1 && EN === 1'b1) begin
+ $display("Assumption %m failed!");
+ $stop;
+ end
+end
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$equiv (A, B, Y);
+
+input A, B;
+output Y;
+
+assign Y = (A !== 1'bx && A !== B) ? 1'bx : A;
+
+`ifndef SIMLIB_NOCHECKS
+always @* begin
+ if (A !== 1'bx && A !== B) begin
+ $display("Equivalence failed!");
+ $stop;
end
end
+`endif
endmodule
@@ -1217,6 +1256,25 @@ end
endmodule
// --------------------------------------------------------
+
+module \$dffe (CLK, EN, D, Q);
+
+parameter WIDTH = 0;
+parameter CLK_POLARITY = 1'b1;
+parameter EN_POLARITY = 1'b1;
+
+input CLK, EN;
+input [WIDTH-1:0] D;
+output reg [WIDTH-1:0] Q;
+wire pos_clk = CLK == CLK_POLARITY;
+
+always @(posedge pos_clk) begin
+ if (EN == EN_POLARITY) Q <= D;
+end
+
+endmodule
+
+// --------------------------------------------------------
`ifndef SIMLIB_NOSR
module \$dffsr (CLK, SET, CLR, D, Q);
@@ -1287,7 +1345,7 @@ output reg [WIDTH-1:0] Q;
always @* begin
if (EN == EN_POLARITY)
- Q <= D;
+ Q = D;
end
endmodule
@@ -1315,11 +1373,11 @@ generate
for (i = 0; i < WIDTH; i = i+1) begin:bit
always @*
if (pos_clr[i])
- Q[i] <= 0;
+ Q[i] = 0;
else if (pos_set[i])
- Q[i] <= 1;
+ Q[i] = 1;
else if (pos_en)
- Q[i] <= D[i];
+ Q[i] = D[i];
end
endgenerate
@@ -1430,6 +1488,7 @@ parameter WIDTH = 8;
parameter CLK_ENABLE = 0;
parameter CLK_POLARITY = 0;
+parameter TRANSPARENT = 0;
input CLK;
input [ABITS-1:0] ADDR;
@@ -1454,6 +1513,7 @@ parameter WIDTH = 8;
parameter CLK_ENABLE = 0;
parameter CLK_POLARITY = 0;
+parameter PRIORITY = 0;
input CLK;
input [WIDTH-1:0] EN;
@@ -1471,13 +1531,36 @@ endmodule
// --------------------------------------------------------
+module \$meminit (ADDR, DATA);
+
+parameter MEMID = "";
+parameter ABITS = 8;
+parameter WIDTH = 8;
+
+parameter PRIORITY = 0;
+
+input [ABITS-1:0] ADDR;
+input [WIDTH-1:0] DATA;
+
+initial begin
+ if (MEMID != "") begin
+ $display("ERROR: Found non-simulatable instance of $meminit!");
+ $finish;
+ end
+end
+
+endmodule
+
+// --------------------------------------------------------
+
module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
parameter MEMID = "";
-parameter SIZE = 256;
+parameter SIZE = 4;
parameter OFFSET = 0;
-parameter ABITS = 8;
+parameter ABITS = 2;
parameter WIDTH = 8;
+parameter signed INIT = 1'bx;
parameter RD_PORTS = 1;
parameter RD_CLK_ENABLE = 1'b1;
@@ -1497,107 +1580,62 @@ input [WR_PORTS*WIDTH-1:0] WR_EN;
input [WR_PORTS*ABITS-1:0] WR_ADDR;
input [WR_PORTS*WIDTH-1:0] WR_DATA;
-reg [WIDTH-1:0] data [SIZE-1:0];
-reg update_async_rd;
+reg [WIDTH-1:0] memory [SIZE-1:0];
-genvar i;
-generate
+integer i, j;
+reg [WR_PORTS-1:0] LAST_WR_CLK;
+reg [RD_PORTS-1:0] LAST_RD_CLK;
+
+function port_active;
+ input clk_enable;
+ input clk_polarity;
+ input last_clk;
+ input this_clk;
+ begin
+ casez ({clk_enable, clk_polarity, last_clk, this_clk})
+ 4'b0???: port_active = 1;
+ 4'b1101: port_active = 1;
+ 4'b1010: port_active = 1;
+ default: port_active = 0;
+ endcase
+ end
+endfunction
- for (i = 0; i < RD_PORTS; i = i+1) begin:rd
- if (RD_CLK_ENABLE[i] == 0) begin:rd_noclk
- always @(RD_ADDR or update_async_rd)
- RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
- end else
- if (RD_TRANSPARENT[i] == 1) begin:rd_transparent
- reg [ABITS-1:0] addr_buf;
- if (RD_CLK_POLARITY[i] == 1) begin:rd_trans_posclk
- always @(posedge RD_CLK[i])
- addr_buf <= RD_ADDR[i*ABITS +: ABITS];
- end else begin:rd_trans_negclk
- always @(negedge RD_CLK[i])
- addr_buf <= RD_ADDR[i*ABITS +: ABITS];
- end
- always @(addr_buf or update_async_rd)
- RD_DATA[i*WIDTH +: WIDTH] <= data[addr_buf - OFFSET];
- end else begin:rd_notransparent
- if (RD_CLK_POLARITY[i] == 1) begin:rd_notrans_posclk
- always @(posedge RD_CLK[i])
- RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
- end else begin:rd_notrans_negclk
- always @(negedge RD_CLK[i])
- RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
- end
+initial begin
+ for (i = 0; i < SIZE; i = i+1)
+ memory[i] = INIT >>> (i*WIDTH);
+end
+
+always @(RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA) begin
+`ifdef SIMLIB_MEMDELAY
+ #`SIMLIB_MEMDELAY;
+`endif
+ for (i = 0; i < RD_PORTS; i = i+1) begin
+ if ((!RD_TRANSPARENT[i] && RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin
+ // $display("Read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]);
+ RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
end
end
- for (i = 0; i < WR_PORTS; i = i+1) begin:wr
- integer k, n;
- reg found_collision, run_update;
- if (WR_CLK_ENABLE[i] == 0) begin:wr_noclk
- always @(WR_ADDR or WR_DATA or WR_EN) begin
- run_update = 0;
- for (n = 0; n < WIDTH; n = n+1) begin
- if (WR_EN[i*WIDTH + n]) begin
- found_collision = 0;
- for (k = i+1; k < WR_PORTS; k = k+1)
- if (WR_EN[k*WIDTH + n] && WR_ADDR[i*ABITS +: ABITS] == WR_ADDR[k*ABITS +: ABITS])
- found_collision = 1;
- if (!found_collision) begin
- data[WR_ADDR[i*ABITS +: ABITS] - OFFSET][n] <= WR_DATA[i*WIDTH + n];
- run_update = 1;
- end
- end
- end
- if (run_update) begin
- update_async_rd <= 1;
- update_async_rd <= 0;
+ for (i = 0; i < WR_PORTS; i = i+1) begin
+ if (port_active(WR_CLK_ENABLE[i], WR_CLK_POLARITY[i], LAST_WR_CLK[i], WR_CLK[i]))
+ for (j = 0; j < WIDTH; j = j+1)
+ if (WR_EN[i*WIDTH+j]) begin
+ // $display("Write to %s: addr=%b data=%b", MEMID, WR_ADDR[i*ABITS +: ABITS], WR_DATA[i*WIDTH+j]);
+ memory[WR_ADDR[i*ABITS +: ABITS] - OFFSET][j] = WR_DATA[i*WIDTH+j];
end
- end
- end else
- if (WR_CLK_POLARITY[i] == 1) begin:rd_posclk
- always @(posedge WR_CLK[i]) begin
- run_update = 0;
- for (n = 0; n < WIDTH; n = n+1) begin
- if (WR_EN[i*WIDTH + n]) begin
- found_collision = 0;
- for (k = i+1; k < WR_PORTS; k = k+1)
- if (WR_EN[k*WIDTH + n] && WR_ADDR[i*ABITS +: ABITS] == WR_ADDR[k*ABITS +: ABITS])
- found_collision = 1;
- if (!found_collision) begin
- data[WR_ADDR[i*ABITS +: ABITS] - OFFSET][n] <= WR_DATA[i*WIDTH + n];
- run_update = 1;
- end
- end
- end
- if (run_update) begin
- update_async_rd <= 1;
- update_async_rd <= 0;
- end
- end
- end else begin:rd_negclk
- always @(negedge WR_CLK[i]) begin
- run_update = 0;
- for (n = 0; n < WIDTH; n = n+1) begin
- if (WR_EN[i*WIDTH + n]) begin
- found_collision = 0;
- for (k = i+1; k < WR_PORTS; k = k+1)
- if (WR_EN[k*WIDTH + n] && WR_ADDR[i*ABITS +: ABITS] == WR_ADDR[k*ABITS +: ABITS])
- found_collision = 1;
- if (!found_collision) begin
- data[WR_ADDR[i*ABITS +: ABITS] - OFFSET][n] <= WR_DATA[i*WIDTH + n];
- run_update = 1;
- end
- end
- end
- if (run_update) begin
- update_async_rd <= 1;
- update_async_rd <= 0;
- end
- end
+ end
+
+ for (i = 0; i < RD_PORTS; i = i+1) begin
+ if ((RD_TRANSPARENT[i] || !RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin
+ // $display("Transparent read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]);
+ RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
end
end
-endgenerate
+ LAST_RD_CLK <= RD_CLK;
+ LAST_WR_CLK <= WR_CLK;
+end
endmodule
diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc
index 4ccacd30..c3e7288d 100644
--- a/techlibs/common/synth.cc
+++ b/techlibs/common/synth.cc
@@ -22,7 +22,10 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-static bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
{
if (!run_from.empty() && run_from == run_to) {
active = (label == run_from);
@@ -49,6 +52,12 @@ struct SynthPass : public Pass {
log(" -top <module>\n");
log(" use the specified module as top module (default='top')\n");
log("\n");
+ log(" -encfile <file>\n");
+ log(" passed to 'fsm_recode' via 'fsm'\n");
+ log("\n");
+ log(" -noabc\n");
+ log(" do not run abc (as if yosys was compiled without ABC support)\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");
@@ -62,6 +71,8 @@ struct SynthPass : public Pass {
log("\n");
log(" coarse:\n");
log(" proc\n");
+ log(" opt_clean\n");
+ log(" check\n");
log(" opt\n");
log(" wreduce\n");
log(" alumacc\n");
@@ -73,19 +84,27 @@ struct SynthPass : public Pass {
log(" opt_clean\n");
log("\n");
log(" fine:\n");
+ log(" opt -fast -full\n");
log(" memory_map\n");
+ log(" opt -full\n");
log(" techmap\n");
log(" opt -fast\n");
#ifdef YOSYS_ENABLE_ABC
log(" abc -fast\n");
- log(" opt_clean\n");
+ log(" opt -fast\n");
#endif
log("\n");
+ log(" check:\n");
+ log(" hierarchy -check\n");
+ log(" stat\n");
+ log(" check\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- std::string top_module;
+ std::string top_module, fsm_opts;
std::string run_from, run_to;
+ bool noabc = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -94,6 +113,10 @@ struct SynthPass : public Pass {
top_module = args[++argidx];
continue;
}
+ if (args[argidx] == "-encfile" && argidx+1 < args.size()) {
+ fsm_opts = " -encfile " + args[++argidx];
+ continue;
+ }
if (args[argidx] == "-run" && argidx+1 < args.size()) {
size_t pos = args[argidx+1].find(':');
if (pos == std::string::npos) {
@@ -105,6 +128,10 @@ struct SynthPass : public Pass {
}
continue;
}
+ if (args[argidx] == "-noabc") {
+ noabc = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -128,12 +155,14 @@ struct SynthPass : public Pass {
if (check_label(active, run_from, run_to, "coarse"))
{
Pass::call(design, "proc");
+ Pass::call(design, "opt_clean");
+ Pass::call(design, "check");
Pass::call(design, "opt");
Pass::call(design, "wreduce");
Pass::call(design, "alumacc");
Pass::call(design, "share");
Pass::call(design, "opt");
- Pass::call(design, "fsm");
+ Pass::call(design, "fsm" + fsm_opts);
Pass::call(design, "opt -fast");
Pass::call(design, "memory -nomap");
Pass::call(design, "opt_clean");
@@ -141,16 +170,29 @@ struct SynthPass : public Pass {
if (check_label(active, run_from, run_to, "fine"))
{
+ Pass::call(design, "opt -fast -full");
Pass::call(design, "memory_map");
+ Pass::call(design, "opt -full");
Pass::call(design, "techmap");
Pass::call(design, "opt -fast");
+
+ if (!noabc) {
#ifdef YOSYS_ENABLE_ABC
- Pass::call(design, "abc -fast");
- Pass::call(design, "opt_clean");
+ Pass::call(design, "abc -fast");
+ Pass::call(design, "opt -fast");
#endif
+ }
+ }
+
+ if (check_label(active, run_from, run_to, "check"))
+ {
+ Pass::call(design, "hierarchy -check");
+ Pass::call(design, "stat");
+ Pass::call(design, "check");
}
log_pop();
}
} SynthPass;
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v
index b6c075b6..e0ecf0c4 100644
--- a/techlibs/common/techmap.v
+++ b/techlibs/common/techmap.v
@@ -54,12 +54,17 @@ module _90_simplemap_logic_ops;
endmodule
(* techmap_simplemap *)
+(* techmap_celltype = "$eq $eqx $ne $nex" *)
+module _90_simplemap_compare_ops;
+endmodule
+
+(* techmap_simplemap *)
(* techmap_celltype = "$pos $slice $concat $mux" *)
module _90_simplemap_various;
endmodule
(* techmap_simplemap *)
-(* techmap_celltype = "$sr $dff $adff $dffsr $dlatch" *)
+(* techmap_celltype = "$sr $dff $dffe $adff $dffsr $dlatch" *)
module _90_simplemap_registers;
endmodule
@@ -207,7 +212,7 @@ module _90_lcu (P, G, CI, CO);
g[0] = g[0] | (p[0] & CI);
// [[CITE]] Brent Kung Adder
- // R. P. Brent and H. T. Kung, “A Regular Layout for Parallel Adders”,
+ // R. P. Brent and H. T. Kung, "A Regular Layout for Parallel Adders",
// IEEE Transaction on Computers, Vol. C-31, No. 3, p. 260-264, March, 1982
// Main tree
@@ -407,55 +412,6 @@ endmodule
// --------------------------------------------------------
-// Equal and Not-Equal
-// --------------------------------------------------------
-
-(* techmap_celltype = "$eq $eqx" *)
-module _90_eq_eqx (A, B, Y);
- parameter A_SIGNED = 0;
- parameter B_SIGNED = 0;
- parameter A_WIDTH = 1;
- parameter B_WIDTH = 1;
- parameter Y_WIDTH = 1;
-
- localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
-
- input [A_WIDTH-1:0] A;
- input [B_WIDTH-1:0] B;
- output [Y_WIDTH-1:0] Y;
-
- wire carry, carry_sign;
- wire [WIDTH-1:0] A_buf, B_buf;
- \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
- \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
-
- assign Y = ~|(A_buf ^ B_buf);
-endmodule
-
-(* techmap_celltype = "$ne $nex" *)
-module _90_ne_nex (A, B, Y);
- parameter A_SIGNED = 0;
- parameter B_SIGNED = 0;
- parameter A_WIDTH = 1;
- parameter B_WIDTH = 1;
- parameter Y_WIDTH = 1;
-
- localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
-
- input [A_WIDTH-1:0] A;
- input [B_WIDTH-1:0] B;
- output [Y_WIDTH-1:0] Y;
-
- wire carry, carry_sign;
- wire [WIDTH-1:0] A_buf, B_buf;
- \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
- \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
-
- assign Y = |(A_buf ^ B_buf);
-endmodule
-
-
-// --------------------------------------------------------
// Parallel Multiplexers
// --------------------------------------------------------
diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc
new file mode 100644
index 00000000..08a24d92
--- /dev/null
+++ b/techlibs/ice40/Makefile.inc
@@ -0,0 +1,6 @@
+
+OBJS += techlibs/ice40/synth_ice40.o
+
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v))
+
diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v
new file mode 100644
index 00000000..f7008a57
--- /dev/null
+++ b/techlibs/ice40/cells_map.v
@@ -0,0 +1,32 @@
+module \$_DFF_P_ (input D, C, output Q);
+ SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C));
+endmodule
+
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+
+ input [WIDTH-1:0] A;
+ output Y;
+
+ generate
+ if (WIDTH == 1) begin
+ SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0));
+ end else
+ if (WIDTH == 2) begin
+ SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0));
+ end else
+ if (WIDTH == 3) begin
+ SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0));
+ end else
+ if (WIDTH == 4) begin
+ SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
+ end else begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ endgenerate
+endmodule
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
new file mode 100644
index 00000000..a1d9b0ca
--- /dev/null
+++ b/techlibs/ice40/cells_sim.v
@@ -0,0 +1,12 @@
+module SB_LUT4(output O, input I0, I1, I2, I3);
+ parameter [15:0] INIT = 0;
+ wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0];
+ wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
+ wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
+ assign O = I0 ? s1[1] : s1[0];
+endmodule
+
+module SB_DFF (output reg Q, input C, D);
+ always @(posedge C)
+ Q <= D;
+endmodule
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
new file mode 100644
index 00000000..8c98c4b2
--- /dev/null
+++ b/techlibs/ice40/synth_ice40.cc
@@ -0,0 +1,161 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
+{
+ if (label == run_from)
+ active = true;
+ if (label == run_to)
+ active = false;
+ return active;
+}
+
+struct SynthIce40Pass : public Pass {
+ SynthIce40Pass() : Pass("synth_ice40", "synthesis for iCE40 FPGAs") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_ice40 [options]\n");
+ log("\n");
+ log("This command runs synthesis for iCE40 FPGAs. This work is experimental.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module (default='top')\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ log("\n");
+ log(" begin:\n");
+ log(" read_verilog -lib +/ice40/cells_sim.v\n");
+ log(" hierarchy -check -top <top>\n");
+ log("\n");
+ log(" coarse:\n");
+ log(" synth -run coarse\n");
+ log("\n");
+ log(" fine:\n");
+ log(" opt -fast -full\n");
+ log(" memory_map\n");
+ log(" opt -full\n");
+ log(" techmap\n");
+ log(" opt -fast\n");
+ log("\n");
+ log(" map_luts:\n");
+ log(" abc -lut 4\n");
+ log(" clean\n");
+ log("\n");
+ log(" map_cells:\n");
+ log(" techmap -map +/ice40/cells_map.v\n");
+ log(" clean\n");
+ log("\n");
+ log(" check:\n");
+ log(" hierarchy -check\n");
+ log(" stat\n");
+ log(" check -noinit\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::string top_module = "top";
+ std::string run_from, run_to;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_module = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This comannd only operates on fully selected designs!\n");
+
+ bool active = run_from.empty();
+
+ log_header("Executing SYNTH_ICE40 pass.\n");
+ log_push();
+
+ if (check_label(active, run_from, run_to, "begin"))
+ {
+ Pass::call(design, "read_verilog -lib +/ice40/cells_sim.v");
+ Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str()));
+ }
+
+ if (check_label(active, run_from, run_to, "coarse"))
+ {
+ Pass::call(design, "synth -run coarse");
+ }
+
+ if (check_label(active, run_from, run_to, "fine"))
+ {
+ Pass::call(design, "opt -fast -full");
+ Pass::call(design, "memory_map");
+ Pass::call(design, "opt -full");
+ Pass::call(design, "techmap");
+ Pass::call(design, "opt -fast");
+ }
+
+ if (check_label(active, run_from, run_to, "map_luts"))
+ {
+ Pass::call(design, "abc -lut 4");
+ Pass::call(design, "clean");
+ }
+
+ if (check_label(active, run_from, run_to, "map_cells"))
+ {
+ Pass::call(design, "techmap -map +/ice40/cells_map.v");
+ Pass::call(design, "clean");
+ }
+
+ if (check_label(active, run_from, run_to, "check"))
+ {
+ Pass::call(design, "hierarchy -check");
+ Pass::call(design, "stat");
+ Pass::call(design, "check -noinit");
+ }
+
+ log_pop();
+ }
+} SynthIce40Pass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index cd19f10e..9af7b58f 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -1,9 +1,9 @@
OBJS += techlibs/xilinx/synth_xilinx.o
-EXTRA_TARGETS += share/xilinx/cells.v
-
-share/xilinx/cells.v: techlibs/xilinx/cells.v
- $(P) mkdir -p share/xilinx
- $(Q) cp techlibs/xilinx/cells.v share/xilinx/cells.v
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v
new file mode 100644
index 00000000..a154f774
--- /dev/null
+++ b/techlibs/xilinx/arith_map.v
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ *
+ */
+
+(* techmap_celltype = "$lcu" *)
+module _80_xilinx_lcu (P, G, CI, CO);
+ parameter WIDTH = 2;
+
+ input [WIDTH-1:0] P, G;
+ input CI;
+
+ output [WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = WIDTH <= 2;
+
+ 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]),
+ .DI(G[i]),
+ .S(S[i]),
+ .O(CO[i])
+ );
+ end endgenerate
+endmodule
+
+(* techmap_celltype = "$alu" *)
+module _80_xilinx_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] 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;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
+ MUXCY muxcy (
+ .CI(C[i]),
+ .DI(G[i]),
+ .S(S[i]),
+ .O(CO[i])
+ );
+ XORCY xorcy (
+ .CI(C[i]),
+ .LI(S[i]),
+ .O(Y[i])
+ );
+ end endgenerate
+
+ assign X = P;
+endmodule
+
diff --git a/techlibs/xilinx/brams.txt b/techlibs/xilinx/brams.txt
new file mode 100644
index 00000000..84c11457
--- /dev/null
+++ b/techlibs/xilinx/brams.txt
@@ -0,0 +1,101 @@
+
+bram $__XILINX_RAMB36_SDP
+ abits 9
+ dbits 72
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 8
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+bram $__XILINX_RAMB18_SDP
+ abits 9
+ dbits 36
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 4
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+bram $__XILINX_RAMB36_TDP
+ abits 10 @a10d36
+ dbits 36 @a10d36
+ abits 11 @a11d18
+ dbits 18 @a11d18
+ abits 12 @a12d9
+ dbits 9 @a12d9
+ abits 13 @a13d4
+ dbits 4 @a13d4
+ abits 14 @a14d2
+ dbits 2 @a14d2
+ abits 15 @a15d1
+ dbits 1 @a15d1
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 4 @a10d36
+ enable 0 2 @a11d18
+ enable 0 1 @a12d9 @a13d4 @a14d2 @a15d1
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+bram $__XILINX_RAMB18_TDP
+ abits 10 @a10d18
+ dbits 18 @a10d18
+ abits 11 @a11d9
+ dbits 9 @a11d9
+ abits 12 @a12d4
+ dbits 4 @a12d4
+ abits 13 @a13d2
+ dbits 2 @a13d2
+ abits 14 @a14d1
+ dbits 1 @a14d1
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 2 @a10d18
+ enable 0 1 @a11d9 @a12d4 @a13d2 @a14d1
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+match $__XILINX_RAMB36_SDP
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__XILINX_RAMB18_SDP
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__XILINX_RAMB36_TDP
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__XILINX_RAMB18_TDP
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+endmatch
+
diff --git a/techlibs/xilinx/brams_map.v b/techlibs/xilinx/brams_map.v
new file mode 100644
index 00000000..2e9bba9a
--- /dev/null
+++ b/techlibs/xilinx/brams_map.v
@@ -0,0 +1,267 @@
+module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+
+ input CLK2;
+ input CLK3;
+
+ input [8:0] A1ADDR;
+ output [71:0] A1DATA;
+
+ input [8:0] B1ADDR;
+ input [71:0] B1DATA;
+ input [7:0] B1EN;
+
+ wire [15:0] A1ADDR_16 = {A1ADDR, 6'b0};
+ wire [15:0] B1ADDR_16 = {B1ADDR, 6'b0};
+
+ wire [7:0] DIP, DOP;
+ wire [63:0] DI, DO;
+
+ assign A1DATA = { DOP[7], DO[63:56], DOP[6], DO[55:48], DOP[5], DO[47:40], DOP[4], DO[39:32],
+ DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
+
+ assign { DIP[7], DI[63:56], DIP[6], DI[55:48], DIP[5], DI[47:40], DIP[4], DI[39:32],
+ DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
+
+ RAMB36E1 #(
+ .RAM_MODE("SDP"),
+ .READ_WIDTH_A(72),
+ .WRITE_WIDTH_B(72),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ .IS_CLKARDCLK_INVERTED(!CLKPOL2),
+ .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
+ .SIM_DEVICE("7SERIES")
+ ) _TECHMAP_REPLACE_ (
+ .DOBDO(DO[63:32]),
+ .DOADO(DO[31:0]),
+ .DOPBDOP(DOP[7:4]),
+ .DOPADOP(DOP[3:0]),
+ .DIBDI(DI[63:32]),
+ .DIADI(DI[31:0]),
+ .DIPBDIP(DIP[7:4]),
+ .DIPADIP(DIP[3:0]),
+
+ .ADDRARDADDR(A1ADDR_16),
+ .CLKARDCLK(CLK2),
+ .ENARDEN(|1),
+ .REGCEAREGCE(|1),
+ .RSTRAMARSTRAM(|0),
+ .RSTREGARSTREG(|0),
+ .WEA(4'b0),
+
+ .ADDRBWRADDR(B1ADDR_16),
+ .CLKBWRCLK(CLK3),
+ .ENBWREN(|1),
+ .REGCEB(|0),
+ .RSTRAMB(|0),
+ .RSTREGB(|0),
+ .WEBWE(B1EN)
+ );
+endmodule
+
+// ------------------------------------------------------------------------
+
+module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+
+ input CLK2;
+ input CLK3;
+
+ input [8:0] A1ADDR;
+ output [35:0] A1DATA;
+
+ input [8:0] B1ADDR;
+ input [35:0] B1DATA;
+ input [3:0] B1EN;
+
+ wire [13:0] A1ADDR_14 = {A1ADDR, 5'b0};
+ wire [13:0] B1ADDR_14 = {B1ADDR, 5'b0};
+
+ wire [3:0] DIP, DOP;
+ wire [31:0] DI, DO;
+
+ assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
+ assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
+
+ RAMB18E1 #(
+ .RAM_MODE("SDP"),
+ .READ_WIDTH_A(36),
+ .WRITE_WIDTH_B(36),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ .IS_CLKARDCLK_INVERTED(!CLKPOL2),
+ .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
+ .SIM_DEVICE("7SERIES")
+ ) _TECHMAP_REPLACE_ (
+ .DOBDO(DO[31:16]),
+ .DOADO(DO[15:0]),
+ .DOPBDOP(DOP[3:2]),
+ .DOPADOP(DOP[1:0]),
+ .DIBDI(DI[31:16]),
+ .DIADI(DI[15:0]),
+ .DIPBDIP(DIP[3:2]),
+ .DIPADIP(DIP[1:0]),
+
+ .ADDRARDADDR(A1ADDR_14),
+ .CLKARDCLK(CLK2),
+ .ENARDEN(|1),
+ .REGCEAREGCE(|1),
+ .RSTRAMARSTRAM(|0),
+ .RSTREGARSTREG(|0),
+ .WEA(2'b0),
+
+ .ADDRBWRADDR(B1ADDR_14),
+ .CLKBWRCLK(CLK3),
+ .ENBWREN(|1),
+ .REGCEB(|0),
+ .RSTRAMB(|0),
+ .RSTREGB(|0),
+ .WEBWE(B1EN)
+ );
+endmodule
+
+// ------------------------------------------------------------------------
+
+module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 10;
+ parameter CFG_DBITS = 36;
+ parameter CFG_ENABLE_B = 4;
+
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+
+ input CLK2;
+ input CLK3;
+
+ input [CFG_ABITS-1:0] A1ADDR;
+ output [CFG_DBITS-1:0] A1DATA;
+
+ input [CFG_ABITS-1:0] B1ADDR;
+ input [CFG_DBITS-1:0] B1DATA;
+ input [CFG_ENABLE_B-1:0] B1EN;
+
+ wire [15:0] A1ADDR_16 = A1ADDR << (15 - CFG_ABITS);
+ wire [15:0] B1ADDR_16 = B1ADDR << (15 - CFG_ABITS);
+ wire [7:0] B1EN_8 = B1EN;
+
+ wire [3:0] DIP, DOP;
+ wire [31:0] DI, DO;
+
+ wire [31:0] DOBDO;
+ wire [3:0] DOPBDOP;
+
+ assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
+ assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
+
+ RAMB36E1 #(
+ .RAM_MODE("TDP"),
+ .READ_WIDTH_A(CFG_DBITS),
+ .READ_WIDTH_B(CFG_DBITS),
+ .WRITE_WIDTH_A(CFG_DBITS),
+ .WRITE_WIDTH_B(CFG_DBITS),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ .IS_CLKARDCLK_INVERTED(!CLKPOL2),
+ .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
+ .SIM_DEVICE("7SERIES")
+ ) _TECHMAP_REPLACE_ (
+ .DIADI(32'd0),
+ .DIPADIP(4'd0),
+ .DOADO(DO[31:0]),
+ .DOPADOP(DOP[3:0]),
+ .ADDRARDADDR(A1ADDR_16),
+ .CLKARDCLK(CLK2),
+ .ENARDEN(|1),
+ .REGCEAREGCE(|1),
+ .RSTRAMARSTRAM(|0),
+ .RSTREGARSTREG(|0),
+ .WEA(4'b0),
+
+ .DIBDI(DI),
+ .DIPBDIP(DIP),
+ .DOBDO(DOBDO),
+ .DOPBDOP(DOPBDOP),
+ .ADDRBWRADDR(B1ADDR_16),
+ .CLKBWRCLK(CLK3),
+ .ENBWREN(|1),
+ .REGCEB(|0),
+ .RSTRAMB(|0),
+ .RSTREGB(|0),
+ .WEBWE(B1EN_8)
+ );
+endmodule
+
+// ------------------------------------------------------------------------
+
+module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 10;
+ parameter CFG_DBITS = 18;
+ parameter CFG_ENABLE_B = 2;
+
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+
+ input CLK2;
+ input CLK3;
+
+ input [CFG_ABITS-1:0] A1ADDR;
+ output [CFG_DBITS-1:0] A1DATA;
+
+ input [CFG_ABITS-1:0] B1ADDR;
+ input [CFG_DBITS-1:0] B1DATA;
+ input [CFG_ENABLE_B-1:0] B1EN;
+
+ wire [13:0] A1ADDR_14 = A1ADDR << (14 - CFG_ABITS);
+ wire [13:0] B1ADDR_14 = B1ADDR << (14 - CFG_ABITS);
+ wire [3:0] B1EN_4 = B1EN;
+
+ wire [1:0] DIP, DOP;
+ wire [15:0] DI, DO;
+
+ wire [15:0] DOBDO;
+ wire [1:0] DOPBDOP;
+
+ assign A1DATA = { DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
+ assign { DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
+
+ RAMB18E1 #(
+ .RAM_MODE("TDP"),
+ .READ_WIDTH_A(CFG_DBITS),
+ .READ_WIDTH_B(CFG_DBITS),
+ .WRITE_WIDTH_A(CFG_DBITS),
+ .WRITE_WIDTH_B(CFG_DBITS),
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ .IS_CLKARDCLK_INVERTED(!CLKPOL2),
+ .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
+ .SIM_DEVICE("7SERIES")
+ ) _TECHMAP_REPLACE_ (
+ .DIADI(16'b0),
+ .DIPADIP(2'b0),
+ .DOADO(DO),
+ .DOPADOP(DOP),
+ .ADDRARDADDR(A1ADDR_14),
+ .CLKARDCLK(CLK2),
+ .ENARDEN(|1),
+ .REGCEAREGCE(|1),
+ .RSTRAMARSTRAM(|0),
+ .RSTREGARSTREG(|0),
+ .WEA(2'b0),
+
+ .DIBDI(DI),
+ .DIPBDIP(DIP),
+ .DOBDO(DOBDO),
+ .DOPBDOP(DOPBDOP),
+ .ADDRBWRADDR(B1ADDR_14),
+ .CLKBWRCLK(CLK3),
+ .ENBWREN(|1),
+ .REGCEB(|0),
+ .RSTRAMB(|0),
+ .RSTREGB(|0),
+ .WEBWE(B1EN_4)
+ );
+endmodule
+
diff --git a/techlibs/xilinx/cells.v b/techlibs/xilinx/cells.v
deleted file mode 100644
index d19be0db..00000000
--- a/techlibs/xilinx/cells.v
+++ /dev/null
@@ -1,53 +0,0 @@
-module \$_DFF_P_ (D, C, Q);
-
- input D, C;
- output Q;
-
- FDRE fpga_dff (
- .D(D), .Q(Q), .C(C),
- .CE(1'b1), .R(1'b0)
- );
-
-endmodule
-
-module \$lut (A, Y);
-
- parameter WIDTH = 0;
- parameter LUT = 0;
-
- input [WIDTH-1:0] A;
- output Y;
-
- generate
- if (WIDTH == 1) begin:lut1
- LUT1 #(.INIT(LUT)) fpga_lut (.O(Y),
- .I0(A[0]));
- end else
- if (WIDTH == 2) begin:lut2
- LUT2 #(.INIT(LUT)) fpga_lut (.O(Y),
- .I0(A[0]), .I1(A[1]));
- end else
- if (WIDTH == 3) begin:lut3
- LUT3 #(.INIT(LUT)) fpga_lut (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]));
- end else
- if (WIDTH == 4) begin:lut4
- LUT4 #(.INIT(LUT)) fpga_lut (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]));
- end else
- if (WIDTH == 5) begin:lut5
- LUT5 #(.INIT(LUT)) fpga_lut (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]));
- end else
- if (WIDTH == 6) begin:lut6
- LUT6 #(.INIT(LUT)) fpga_lut (.O(Y),
- .I0(A[0]), .I1(A[1]), .I2(A[2]),
- .I3(A[3]), .I4(A[4]), .I5(A[5]));
- end else begin:error
- wire _TECHMAP_FAIL_ = 1;
- end
- endgenerate
-
-endmodule
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
new file mode 100644
index 00000000..8e5a83ce
--- /dev/null
+++ b/techlibs/xilinx/cells_map.v
@@ -0,0 +1,84 @@
+
+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
+
+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
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
new file mode 100644
index 00000000..1f114a22
--- /dev/null
+++ b/techlibs/xilinx/cells_sim.v
@@ -0,0 +1,158 @@
+
+// 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
+// http://www.xilinx.com/support/documentation/sw_manuals/xilinx2014_4/ug953-vivado-7series-libraries.pdf
+
+module VCC(output P);
+ assign P = 1;
+endmodule
+
+module GND(output G);
+ assign G = 0;
+endmodule
+
+module IBUF(output O, input I);
+ assign O = I;
+endmodule
+
+module OBUF(output O, input I);
+ assign O = I;
+endmodule
+
+module BUFG(output O, input I);
+ assign O = I;
+endmodule
+
+// module OBUFT(output O, input I, T);
+// assign O = T ? 1'bz : I;
+// endmodule
+
+// module IOBUF(inout IO, output O, input I, T);
+// assign O = IO, IO = T ? 1'bz : I;
+// endmodule
+
+module INV(output O, input I);
+ assign O = !I;
+endmodule
+
+module LUT1(output O, input I0);
+ parameter [1:0] INIT = 0;
+ assign O = I0 ? INIT[1] : INIT[0];
+endmodule
+
+module LUT2(output O, input I0, I1);
+ parameter [3:0] INIT = 0;
+ wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0];
+ assign O = I0 ? s1[1] : s1[0];
+endmodule
+
+module LUT3(output O, input I0, I1, I2);
+ parameter [7:0] INIT = 0;
+ wire [ 3: 0] s2 = I2 ? INIT[ 7: 4] : INIT[ 3: 0];
+ wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
+ assign O = I0 ? s1[1] : s1[0];
+endmodule
+
+module LUT4(output O, input I0, I1, I2, I3);
+ parameter [15:0] INIT = 0;
+ wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0];
+ wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
+ wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
+ assign O = I0 ? s1[1] : s1[0];
+endmodule
+
+module LUT5(output O, input I0, I1, I2, I3, I4);
+ parameter [31:0] INIT = 0;
+ wire [15: 0] s4 = I4 ? INIT[31:16] : INIT[15: 0];
+ wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
+ wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
+ wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
+ assign O = I0 ? s1[1] : s1[0];
+endmodule
+
+module LUT6(output O, input I0, I1, I2, I3, I4, I5);
+ parameter [63:0] INIT = 0;
+ wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0];
+ wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0];
+ wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
+ wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
+ wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
+ assign O = I0 ? s1[1] : s1[0];
+endmodule
+
+module MUXCY(output O, input CI, DI, S);
+ assign O = S ? CI : DI;
+endmodule
+
+module MUXF7(output O, input I0, I1, S);
+ assign O = S ? I1 : I0;
+endmodule
+
+module MUXF8(output O, input I0, I1, S);
+ assign O = S ? I1 : I0;
+endmodule
+
+module XORCY(output O, input CI, LI);
+ assign O = CI ^ LI;
+endmodule
+
+module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
+ assign O = S ^ {CO[2:0], CI | CYINIT};
+ assign CO[0] = S[0] ? CI | CYINIT : DI[0];
+ assign CO[1] = S[1] ? CO[0] : DI[1];
+ assign CO[2] = S[2] ? CO[1] : DI[2];
+ assign CO[3] = S[3] ? CO[2] : DI[3];
+endmodule
+
+module FDRE (output reg Q, input C, CE, D, R);
+ parameter [0:0] INIT = 1'b0;
+ parameter [0:0] IS_C_INVERTED = 1'b0;
+ parameter [0:0] IS_D_INVERTED = 1'b0;
+ parameter [0:0] IS_R_INVERTED = 1'b0;
+ initial Q <= INIT;
+ generate case (|IS_C_INVERTED)
+ 1'b0: always @(posedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
+ 1'b1: always @(negedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
+ endcase endgenerate
+endmodule
+
+module FDSE (output reg Q, input C, CE, D, S);
+ parameter [0:0] INIT = 1'b0;
+ parameter [0:0] IS_C_INVERTED = 1'b0;
+ parameter [0:0] IS_D_INVERTED = 1'b0;
+ parameter [0:0] IS_S_INVERTED = 1'b0;
+ initial Q <= INIT;
+ generate case (|IS_C_INVERTED)
+ 1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+ 1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+ endcase endgenerate
+endmodule
+
+module FDCE (output reg Q, input C, CE, D, CLR);
+ parameter [0:0] INIT = 1'b0;
+ parameter [0:0] IS_C_INVERTED = 1'b0;
+ parameter [0:0] IS_D_INVERTED = 1'b0;
+ parameter [0:0] IS_CLR_INVERTED = 1'b0;
+ initial Q <= INIT;
+ generate case ({|IS_C_INVERTED, |IS_CLR_INVERTED})
+ 2'b00: always @(posedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
+ 2'b01: always @(posedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
+ 2'b10: always @(negedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
+ 2'b11: always @(negedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
+ endcase endgenerate
+endmodule
+
+module FDPE (output reg Q, input C, CE, D, PRE);
+ parameter [0:0] INIT = 1'b0;
+ parameter [0:0] IS_C_INVERTED = 1'b0;
+ parameter [0:0] IS_D_INVERTED = 1'b0;
+ parameter [0:0] IS_PRE_INVERTED = 1'b0;
+ initial Q <= INIT;
+ generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED})
+ 2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+ 2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+ 2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+ 2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+ endcase endgenerate
+endmodule
+
diff --git a/techlibs/xilinx/example_basys3/README b/techlibs/xilinx/example_basys3/README
new file mode 100644
index 00000000..85b6eab1
--- /dev/null
+++ b/techlibs/xilinx/example_basys3/README
@@ -0,0 +1,16 @@
+
+A simple example design, based on the Digilent BASYS3 board
+===========================================================
+
+Running Yosys:
+ yosys run_yosys.ys
+
+Running Vivado:
+ vivado -nolog -nojournal -mode batch -source run_vivado.tcl
+
+Programming board:
+ vivado -nolog -nojournal -mode batch -source run_prog.tcl
+
+All of the above:
+ bash run.sh
+
diff --git a/techlibs/xilinx/example_basys3/example.v b/techlibs/xilinx/example_basys3/example.v
new file mode 100644
index 00000000..2b01a22a
--- /dev/null
+++ b/techlibs/xilinx/example_basys3/example.v
@@ -0,0 +1,21 @@
+module example(CLK, LD);
+ input CLK;
+ output [15:0] LD;
+
+ wire clock;
+ reg [15:0] leds;
+
+ BUFG CLK_BUF (.I(CLK), .O(clock));
+ OBUF LD_BUF[15:0] (.I(leds), .O(LD));
+
+ parameter COUNTBITS = 26;
+ reg [COUNTBITS-1:0] counter;
+
+ always @(posedge CLK) begin
+ counter <= counter + 1;
+ if (counter[COUNTBITS-1])
+ leds <= 16'h8000 >> counter[COUNTBITS-2:COUNTBITS-5];
+ else
+ leds <= 16'h0001 << counter[COUNTBITS-2:COUNTBITS-5];
+ end
+endmodule
diff --git a/techlibs/xilinx/example_basys3/example.xdc b/techlibs/xilinx/example_basys3/example.xdc
new file mode 100644
index 00000000..c1fd0e92
--- /dev/null
+++ b/techlibs/xilinx/example_basys3/example.xdc
@@ -0,0 +1,21 @@
+
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W5 } [get_ports CLK]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U16 } [get_ports {LD[0]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN E19 } [get_ports {LD[1]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U19 } [get_ports {LD[2]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V19 } [get_ports {LD[3]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W18 } [get_ports {LD[4]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U15 } [get_ports {LD[5]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U14 } [get_ports {LD[6]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V14 } [get_ports {LD[7]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V13 } [get_ports {LD[8]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V3 } [get_ports {LD[9]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W3 } [get_ports {LD[10]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U3 } [get_ports {LD[11]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN P3 } [get_ports {LD[12]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN N3 } [get_ports {LD[13]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN P1 } [get_ports {LD[14]}]
+set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN L1 } [get_ports {LD[15]}]
+
+create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports CLK]
+
diff --git a/techlibs/xilinx/example_basys3/run.sh b/techlibs/xilinx/example_basys3/run.sh
new file mode 100644
index 00000000..10f05910
--- /dev/null
+++ b/techlibs/xilinx/example_basys3/run.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+yosys run_yosys.ys
+vivado -nolog -nojournal -mode batch -source run_vivado.tcl
+vivado -nolog -nojournal -mode batch -source run_prog.tcl
diff --git a/techlibs/xilinx/example_basys3/run_prog.tcl b/techlibs/xilinx/example_basys3/run_prog.tcl
new file mode 100644
index 00000000..d711af84
--- /dev/null
+++ b/techlibs/xilinx/example_basys3/run_prog.tcl
@@ -0,0 +1,4 @@
+connect_hw_server
+open_hw_target [lindex [get_hw_targets] 0]
+set_property PROGRAM.FILE example.bit [lindex [get_hw_devices] 0]
+program_hw_devices [lindex [get_hw_devices] 0]
diff --git a/techlibs/xilinx/example_basys3/run_vivado.tcl b/techlibs/xilinx/example_basys3/run_vivado.tcl
new file mode 100644
index 00000000..c3b6a610
--- /dev/null
+++ b/techlibs/xilinx/example_basys3/run_vivado.tcl
@@ -0,0 +1,9 @@
+read_xdc example.xdc
+read_edif example.edif
+link_design -part xc7a35tcpg236-1 -top example
+opt_design
+place_design
+route_design
+report_utilization
+report_timing
+write_bitstream -force example.bit
diff --git a/techlibs/xilinx/example_basys3/run_yosys.ys b/techlibs/xilinx/example_basys3/run_yosys.ys
new file mode 100644
index 00000000..4541826d
--- /dev/null
+++ b/techlibs/xilinx/example_basys3/run_yosys.ys
@@ -0,0 +1,2 @@
+read_verilog example.v
+synth_xilinx -edif example.edif -top example
diff --git a/techlibs/xilinx/example_mojo_counter/README b/techlibs/xilinx/example_mojo_counter/README
deleted file mode 100644
index 690a9d84..00000000
--- a/techlibs/xilinx/example_mojo_counter/README
+++ /dev/null
@@ -1,10 +0,0 @@
-
-This is a simple example for Yosys synthesis targeting the Mojo FPGA
-development board [1, 2]. Simple script for xst-based synthesis (incl.
-generation of reference edif files) and uploading to the board can be
-found here [3].
-
-[1] http://embeddedmicro.com/tutorials/mojo
-[2] https://www.sparkfun.com/products/11953
-[3] http://svn.clifford.at/handicraft/2013/mojo/
-
diff --git a/techlibs/xilinx/example_mojo_counter/example.sh b/techlibs/xilinx/example_mojo_counter/example.sh
deleted file mode 100644
index 74a0c117..00000000
--- a/techlibs/xilinx/example_mojo_counter/example.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-XILINX_DIR=/opt/Xilinx/14.5/ISE_DS/ISE
-XILINX_PART=xc6slx9-2-tqg144
-
-../../../yosys - <<- EOT
- read_verilog example.v
- synth_xilinx -edif synth.edif
-EOT
-
-$XILINX_DIR/bin/lin64/edif2ngd -a synth.edif synth.ngo
-$XILINX_DIR/bin/lin64/ngdbuild -p $XILINX_PART -uc example.ucf synth.ngo synth.ngd
-$XILINX_DIR/bin/lin64/map -p $XILINX_PART -w -o mapped.ncd synth.ngd constraints.pcf
-$XILINX_DIR/bin/lin64/par -w mapped.ncd placed.ncd constraints.pcf
-$XILINX_DIR/bin/lin64/bitgen -w placed.ncd example.bit constraints.pcf
-
diff --git a/techlibs/xilinx/example_mojo_counter/example.ucf b/techlibs/xilinx/example_mojo_counter/example.ucf
deleted file mode 100644
index 93d97b4d..00000000
--- a/techlibs/xilinx/example_mojo_counter/example.ucf
+++ /dev/null
@@ -1,14 +0,0 @@
-NET "clk" TNM_NET = clk;
-TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;
-
-NET "clk" LOC = P56;
-NET "ctrl" LOC = P1;
-
-NET "led_0" LOC = P134;
-NET "led_1" LOC = P133;
-NET "led_2" LOC = P132;
-NET "led_3" LOC = P131;
-NET "led_4" LOC = P127;
-NET "led_5" LOC = P126;
-NET "led_6" LOC = P124;
-NET "led_7" LOC = P123;
diff --git a/techlibs/xilinx/example_mojo_counter/example.v b/techlibs/xilinx/example_mojo_counter/example.v
deleted file mode 100644
index cb98cc1b..00000000
--- a/techlibs/xilinx/example_mojo_counter/example.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module top(clk, ctrl, led_7, led_6, led_5, led_4, led_3, led_2, led_1, led_0);
-
-input clk, ctrl;
-output led_7, led_6, led_5, led_4;
-output led_3, led_2, led_1, led_0;
-
-reg [31:0] counter;
-
-always @(posedge clk)
- counter <= counter + (ctrl ? 4 : 1);
-
-assign {led_7, led_6, led_5, led_4, led_3, led_2, led_1, led_0} = counter >> 24;
-
-endmodule
diff --git a/techlibs/xilinx/example_sim_counter/counter.v b/techlibs/xilinx/example_sim_counter/counter.v
deleted file mode 100644
index 72208bd8..00000000
--- a/techlibs/xilinx/example_sim_counter/counter.v
+++ /dev/null
@@ -1,12 +0,0 @@
-module counter (clk, rst, en, count);
-
- input clk, rst, en;
- output reg [3:0] count;
-
- always @(posedge clk)
- if (rst)
- count <= 4'd0;
- else if (en)
- count <= count + 4'd1;
-
-endmodule
diff --git a/techlibs/xilinx/example_sim_counter/counter_tb.v b/techlibs/xilinx/example_sim_counter/counter_tb.v
deleted file mode 100644
index b6b64269..00000000
--- a/techlibs/xilinx/example_sim_counter/counter_tb.v
+++ /dev/null
@@ -1,61 +0,0 @@
-`timescale 1 ns / 1 ps
-
-module testbench;
-
-reg clk, en, rst;
-wire [3:0] count;
-
-counter uut_counter(
- .clk(clk),
- .count(count),
- .en(en),
- .rst(rst)
-);
-
-initial begin
- clk <= 0;
- forever begin
- #50;
- clk <= ~clk;
- end
-end
-
-initial begin
- @(posedge clk);
- forever begin
- @(posedge clk);
- $display("%d", count);
- end
-end
-
-initial begin
- rst <= 1; en <= 0; @(posedge clk);
- rst <= 1; en <= 0; @(posedge clk);
- rst <= 0; en <= 0; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 0; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 1; en <= 1; @(posedge clk);
- rst <= 0; en <= 0; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 0; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 0; @(posedge clk);
- rst <= 1; en <= 0; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 0; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 0; @(posedge clk);
- rst <= 0; en <= 1; @(posedge clk);
- rst <= 0; en <= 0; @(posedge clk);
- $finish;
-end
-
-endmodule
diff --git a/techlibs/xilinx/example_sim_counter/run_sim.sh b/techlibs/xilinx/example_sim_counter/run_sim.sh
deleted file mode 100644
index b8354c00..00000000
--- a/techlibs/xilinx/example_sim_counter/run_sim.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-XILINX_DIR=/opt/Xilinx/14.5/ISE_DS/ISE
-
-../../../yosys -p 'synth_xilinx -top counter; write_verilog -noattr testbench_synth.v' counter.v
-
-iverilog -o testbench_gold counter_tb.v counter.v
-iverilog -o testbench_gate counter_tb.v testbench_synth.v \
- $XILINX_DIR/verilog/src/{glbl,unisims/{FDRE,LUT1,LUT2,LUT3,LUT4,LUT5,LUT6,BUFGP,IBUF}}.v
-
-./testbench_gold > testbench_gold.txt
-./testbench_gate > testbench_gate.txt
-
-if diff -u testbench_gold.txt testbench_gate.txt; then
- set +x; echo; echo; banner " PASS "
-else
- exit 1
-fi
-
-rm -f testbench_{synth,gold,gate,mapped}*
-
diff --git a/techlibs/xilinx/example_zed_counter/README b/techlibs/xilinx/example_zed_counter/README
deleted file mode 100644
index 539f24e7..00000000
--- a/techlibs/xilinx/example_zed_counter/README
+++ /dev/null
@@ -1,10 +0,0 @@
-
-This is a simple example for Yosys synthesis targeting the ZED FPGA
-development board [1, 2]. Simple script for xst-based synthesis (incl.
-generation of reference edif files) and uploading to the board can be
-found here [3].
-
-[1] http://www.zedboard.org/
-[2] https://www.xilinx.com/zynq/
-[3] http://verilog.james.walms.co.uk/
-
diff --git a/techlibs/xilinx/example_zed_counter/example.sh b/techlibs/xilinx/example_zed_counter/example.sh
deleted file mode 100644
index d0fcd832..00000000
--- a/techlibs/xilinx/example_zed_counter/example.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-XILINX_DIR=/opt/Xilinx/14.7/ISE_DS/ISE
-XILINX_PART=xc7z020clg484-1
-
-yosys - <<- EOT
- read_verilog example.v
- synth_xilinx -edif synth.edif
-EOT
-
-$XILINX_DIR/bin/lin64/edif2ngd -a synth.edif synth.ngo
-$XILINX_DIR/bin/lin64/ngdbuild -p $XILINX_PART -uc example.ucf synth.ngo synth.ngd
-$XILINX_DIR/bin/lin64/map -p $XILINX_PART -w -o mapped.ncd synth.ngd constraints.pcf
-$XILINX_DIR/bin/lin64/par -w mapped.ncd placed.ncd constraints.pcf
-$XILINX_DIR/bin/lin64/bitgen -w placed.ncd example.bit constraints.pcf
-$XILINX_DIR/bin/lin64/promgen -w -b -p bin -o example.bin -u 0 example.bit -data_width 32
diff --git a/techlibs/xilinx/example_zed_counter/example.ucf b/techlibs/xilinx/example_zed_counter/example.ucf
deleted file mode 100644
index dadc8373..00000000
--- a/techlibs/xilinx/example_zed_counter/example.ucf
+++ /dev/null
@@ -1,14 +0,0 @@
-NET "clk" TNM_NET = clk;
-TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;
-
-NET "clk" LOC = Y9 | IOSTANDARD=LVCMOS33; # "GCLK"
-NET "ctrl" LOC = P16 | IOSTANDARD=LVCMOS18; # "BTNC"
-
-NET "led_0" LOC = T22 | IOSTANDARD=LVCMOS33; # "LD0"
-NET "led_1" LOC = T21 | IOSTANDARD=LVCMOS33; # "LD0"
-NET "led_2" LOC = U22 | IOSTANDARD=LVCMOS33; # "LD0"
-NET "led_3" LOC = U21 | IOSTANDARD=LVCMOS33; # "LD0"
-NET "led_4" LOC = V22 | IOSTANDARD=LVCMOS33; # "LD0"
-NET "led_5" LOC = W22 | IOSTANDARD=LVCMOS33; # "LD0"
-NET "led_6" LOC = U19 | IOSTANDARD=LVCMOS33; # "LD0"
-NET "led_7" LOC = U14 | IOSTANDARD=LVCMOS33; # "LD0"
diff --git a/techlibs/xilinx/example_zed_counter/example.v b/techlibs/xilinx/example_zed_counter/example.v
deleted file mode 100644
index cb98cc1b..00000000
--- a/techlibs/xilinx/example_zed_counter/example.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module top(clk, ctrl, led_7, led_6, led_5, led_4, led_3, led_2, led_1, led_0);
-
-input clk, ctrl;
-output led_7, led_6, led_5, led_4;
-output led_3, led_2, led_1, led_0;
-
-reg [31:0] counter;
-
-always @(posedge clk)
- counter <= counter + (ctrl ? 4 : 1);
-
-assign {led_7, led_6, led_5, led_4, led_3, led_2, led_1, led_0} = counter >> 24;
-
-endmodule
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index ff906db8..836ba9ad 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -22,7 +22,10 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-static bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
{
if (label == run_from)
active = true;
@@ -40,16 +43,12 @@ struct SynthXilinxPass : public Pass {
log(" synth_xilinx [options]\n");
log("\n");
log("This command runs synthesis for Xilinx FPGAs. This command does not operate on\n");
- log("partly selected designs.\n");
+ log("partly selected designs. At the moment this command creates netlists that are\n");
+ log("compatible with 7-Series Xilinx devices.\n");
log("\n");
log(" -top <module>\n");
log(" use the specified module as top module (default='top')\n");
log("\n");
- log(" -arch <arch>\n");
- log(" select architecture. the following architectures are supported:\n");
- log(" spartan6 (default), artix7, kintex7, virtex7, zynq7000\n");
- log(" (this parameter is not used by the command at the moment)\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");
@@ -59,39 +58,50 @@ struct SynthXilinxPass : public Pass {
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(" -flatten\n");
+ log(" 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");
log("\n");
log(" begin:\n");
+ log(" read_verilog -lib +/xilinx/cells_sim.v\n");
log(" hierarchy -check -top <top>\n");
log("\n");
- log(" coarse:\n");
+ log(" flatten: (only if -flatten)\n");
log(" proc\n");
- log(" opt\n");
- log(" memory\n");
- log(" clean\n");
- log(" fsm\n");
- log(" opt\n");
+ log(" flatten\n");
+ log("\n");
+ log(" coarse:\n");
+ log(" synth -run coarse\n");
+ log(" dff2dffe\n");
+ log("\n");
+ log(" bram:\n");
+ log(" memory_bram -rules +/xilinx/brams.txt\n");
+ log(" techmap -map +/xilinx/brams_map.v\n");
log("\n");
log(" fine:\n");
- log(" techmap\n");
- log(" opt\n");
+ log(" opt -fast -full\n");
+ log(" memory_map\n");
+ log(" opt -full\n");
+ log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n");
+ log(" opt -fast\n");
log("\n");
log(" map_luts:\n");
- log(" abc -lut 6\n");
+ log(" abc -lut 5:8 [-dff]\n");
log(" clean\n");
log("\n");
log(" map_cells:\n");
- log(" techmap -share_map xilinx/cells.v\n");
+ log(" techmap -map +/xilinx/cells_map.v\n");
log(" clean\n");
log("\n");
- log(" clkbuf:\n");
- log(" select -set xilinx_clocks <top>/t:FDRE %%x:+FDRE[C] <top>/t:FDRE %%d\n");
- log(" iopadmap -inpad BUFGP O:I @xilinx_clocks\n");
- log("\n");
- log(" iobuf:\n");
- log(" select -set xilinx_nonclocks <top>/w:* <top>/t:BUFGP %%x:+BUFGP[I] %%d\n");
- log(" iopadmap -outpad OBUF I:O -inpad IBUF O:I @xilinx_nonclocks\n");
+ log(" check:\n");
+ log(" hierarchy -check\n");
+ log(" stat\n");
+ log(" check -noinit\n");
log("\n");
log(" edif:\n");
log(" write_edif synth.edif\n");
@@ -103,6 +113,8 @@ struct SynthXilinxPass : public Pass {
std::string arch_name = "spartan6";
std::string edif_file;
std::string run_from, run_to;
+ bool flatten = false;
+ bool retime = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -111,10 +123,6 @@ struct SynthXilinxPass : public Pass {
top_module = args[++argidx];
continue;
}
- if (args[argidx] == "-arch" && argidx+1 < args.size()) {
- arch_name = args[++argidx];
- continue;
- }
if (args[argidx] == "-edif" && argidx+1 < args.size()) {
edif_file = args[++argidx];
continue;
@@ -127,6 +135,14 @@ struct SynthXilinxPass : public Pass {
run_to = args[argidx].substr(pos+1);
continue;
}
+ if (args[argidx] == "-flatten") {
+ flatten = true;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -134,20 +150,6 @@ struct SynthXilinxPass : public Pass {
if (!design->full_selection())
log_cmd_error("This comannd only operates on fully selected designs!\n");
- if (arch_name == "spartan6") {
- /* set flags */
- } else
- if (arch_name == "artix7") {
- /* set flags */
- } else
- if (arch_name == "kintex7") {
- /* set flags */
- } else
- if (arch_name == "zynq7000") {
- /* set flags */
- } else
- log_cmd_error("Architecture '%s' is not supported!\n", arch_name.c_str());
-
bool active = run_from.empty();
log_header("Executing SYNTH_XILINX pass.\n");
@@ -155,47 +157,54 @@ struct SynthXilinxPass : public Pass {
if (check_label(active, run_from, run_to, "begin"))
{
+ Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v");
Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str()));
}
- if (check_label(active, run_from, run_to, "coarse"))
+ if (flatten && check_label(active, run_from, run_to, "flatten"))
{
Pass::call(design, "proc");
- Pass::call(design, "opt");
- Pass::call(design, "memory");
- Pass::call(design, "clean");
- Pass::call(design, "fsm");
- Pass::call(design, "opt");
+ Pass::call(design, "flatten");
+ }
+
+ if (check_label(active, run_from, run_to, "coarse"))
+ {
+ Pass::call(design, "synth -run coarse");
+ Pass::call(design, "dff2dffe");
+ }
+
+ 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 (check_label(active, run_from, run_to, "fine"))
{
- Pass::call(design, "techmap");
- Pass::call(design, "opt");
+ Pass::call(design, "opt -fast -full");
+ Pass::call(design, "memory_map");
+ Pass::call(design, "opt -full");
+ Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v");
+ Pass::call(design, "opt -fast");
}
if (check_label(active, run_from, run_to, "map_luts"))
{
- Pass::call(design, "abc -lut 6");
+ Pass::call(design, "abc -lut 5:8" + string(retime ? " -dff" : ""));
Pass::call(design, "clean");
}
if (check_label(active, run_from, run_to, "map_cells"))
{
- Pass::call(design, "techmap -share_map xilinx/cells.v");
+ Pass::call(design, "techmap -map +/xilinx/cells_map.v");
Pass::call(design, "clean");
}
- if (check_label(active, run_from, run_to, "clkbuf"))
- {
- Pass::call(design, stringf("select -set xilinx_clocks %s/t:FDRE %%x:+FDRE[C] %s/t:FDRE %%d", top_module.c_str(), top_module.c_str()));
- Pass::call(design, "iopadmap -inpad BUFGP O:I @xilinx_clocks");
- }
-
- if (check_label(active, run_from, run_to, "iobuf"))
+ if (check_label(active, run_from, run_to, "check"))
{
- Pass::call(design, stringf("select -set xilinx_nonclocks %s/w:* %s/t:BUFGP %%x:+BUFGP[I] %%d", top_module.c_str(), top_module.c_str()));
- Pass::call(design, "iopadmap -outpad OBUF I:O -inpad IBUF O:I @xilinx_nonclocks");
+ Pass::call(design, "hierarchy -check");
+ Pass::call(design, "stat");
+ Pass::call(design, "check -noinit");
}
if (check_label(active, run_from, run_to, "edif"))
@@ -208,3 +217,4 @@ struct SynthXilinxPass : public Pass {
}
} SynthXilinxPass;
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/xilinx/tests/.gitignore b/techlibs/xilinx/tests/.gitignore
new file mode 100644
index 00000000..bc2f8bab
--- /dev/null
+++ b/techlibs/xilinx/tests/.gitignore
@@ -0,0 +1,3 @@
+bram1_cmp
+bram1.mk
+bram1_[0-9]*/
diff --git a/techlibs/xilinx/tests/bram1.sh b/techlibs/xilinx/tests/bram1.sh
new file mode 100644
index 00000000..1f0359ac
--- /dev/null
+++ b/techlibs/xilinx/tests/bram1.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+set -e
+
+transp_list="0 1"
+abits_list="1 2 4 8 10 16 20"
+dbits_list="1 2 4 8 10 16 20 24 30 32 40 48 50 56 60 64 70 72 80"
+
+use_xsim=false
+unisims=/opt/Xilinx/Vivado/2014.4/data/verilog/src/unisims
+
+echo "all: all_list" > bram1.mk
+all_list=""
+
+for transp in $transp_list; do
+for abits in $abits_list; do
+for dbits in $dbits_list; do
+ if [ $(( (1 << $abits) * $dbits )) -gt 1000000 ]; then continue; fi
+ id=`printf "%d%02d%02d" $transp $abits $dbits`
+ echo "Creating bram1_$id.."
+ rm -rf bram1_$id
+ mkdir -p bram1_$id
+ cp bram1.v bram1_tb.v bram1_$id/
+ sed -i "/parameter/ s,ABITS *= *[0-9]*,ABITS = $abits," bram1_$id/*.v
+ sed -i "/parameter/ s,DBITS *= *[0-9]*,DBITS = $dbits," bram1_$id/*.v
+ sed -i "/parameter/ s,TRANSP *= *[0-9]*,TRANSP = $transp," bram1_$id/*.v
+ {
+ echo "set -e"
+ echo "../../../../yosys -q -lsynth.log -p 'synth_xilinx -top bram1; write_verilog synth.v' bram1.v"
+ if $use_xsim; then
+ echo "xvlog --work gold bram1_tb.v bram1.v > gold.txt"
+ echo "xvlog --work gate bram1_tb.v synth.v > gate.txt"
+ echo "xelab -R gold.bram1_tb >> gold.txt"
+ echo "xelab -L unisim -R gate.bram1_tb >> gate.txt"
+ else
+ echo "iverilog -o bram1_tb_gold bram1_tb.v bram1.v > gold.txt 2>&1"
+ echo "iverilog -o bram1_tb_gate bram1_tb.v synth.v -y $unisims $unisims/../glbl.v > gate.txt 2>&1"
+ echo "./bram1_tb_gold >> gold.txt"
+ echo "./bram1_tb_gate >> gate.txt"
+ fi
+ echo "../bram1_cmp <( grep '#OUT#' gold.txt; ) <( grep '#OUT#' gate.txt; )"
+ } > bram1_$id/run.sh
+ {
+ echo "bram1_$id/ok:"
+ echo " @cd bram1_$id && bash run.sh"
+ echo " @echo -n '[$id]'"
+ echo " @touch \$@"
+ } >> bram1.mk
+ all_list="$all_list bram1_$id/ok"
+done; done; done
+
+cc -o bram1_cmp ../../../tests/tools/cmp_tbdata.c
+echo all_list: $(echo $all_list | tr ' ' '\n' | sort -R) >> bram1.mk
+
+echo "Testing..."
+${MAKE:-make} -f bram1.mk
+echo
+
+echo "Used rules:" $(grep -h 'Selected rule.*with efficiency' bram1_*/synth.log | gawk '{ print $3; }' | sort -u)
+
+echo "Cleaning up..."
+rm -rf bram1_cmp bram1.mk bram1_[0-9]*/
+
diff --git a/techlibs/xilinx/tests/bram1.v b/techlibs/xilinx/tests/bram1.v
new file mode 100644
index 00000000..034cc18e
--- /dev/null
+++ b/techlibs/xilinx/tests/bram1.v
@@ -0,0 +1,24 @@
+module bram1 #(
+ parameter ABITS = 8, DBITS = 8, TRANSP = 0
+) (
+ input clk,
+
+ input [ABITS-1:0] WR_ADDR,
+ input [DBITS-1:0] WR_DATA,
+ input WR_EN,
+
+ input [ABITS-1:0] RD_ADDR,
+ output [DBITS-1:0] RD_DATA
+);
+ reg [DBITS-1:0] memory [0:2**ABITS-1];
+ reg [ABITS-1:0] RD_ADDR_BUF;
+ reg [DBITS-1:0] RD_DATA_BUF;
+
+ always @(posedge clk) begin
+ if (WR_EN) memory[WR_ADDR] <= WR_DATA;
+ RD_ADDR_BUF <= RD_ADDR;
+ RD_DATA_BUF <= memory[RD_ADDR];
+ end
+
+ assign RD_DATA = TRANSP ? memory[RD_ADDR_BUF] : RD_DATA_BUF;
+endmodule
diff --git a/techlibs/xilinx/tests/bram1_tb.v b/techlibs/xilinx/tests/bram1_tb.v
new file mode 100644
index 00000000..8f854b74
--- /dev/null
+++ b/techlibs/xilinx/tests/bram1_tb.v
@@ -0,0 +1,116 @@
+module bram1_tb #(
+ parameter ABITS = 8, DBITS = 8, TRANSP = 0
+);
+ reg clk;
+ reg [ABITS-1:0] WR_ADDR;
+ reg [DBITS-1:0] WR_DATA;
+ reg WR_EN;
+ reg [ABITS-1:0] RD_ADDR;
+ wire [DBITS-1:0] RD_DATA;
+
+ bram1 #(
+ // .ABITS(ABITS),
+ // .DBITS(DBITS),
+ // .TRANSP(TRANSP)
+ ) uut (
+ .clk (clk ),
+ .WR_ADDR(WR_ADDR),
+ .WR_DATA(WR_DATA),
+ .WR_EN (WR_EN ),
+ .RD_ADDR(RD_ADDR),
+ .RD_DATA(RD_DATA)
+ );
+
+ reg [63:0] xorshift64_state = 64'd88172645463325252 ^ (ABITS << 24) ^ (DBITS << 16) ^ (TRANSP << 8);
+
+ task xorshift64_next;
+ begin
+ // see page 4 of Marsaglia, George (July 2003). "Xorshift RNGs". Journal of Statistical Software 8 (14).
+ xorshift64_state = xorshift64_state ^ (xorshift64_state << 13);
+ xorshift64_state = xorshift64_state ^ (xorshift64_state >> 7);
+ xorshift64_state = xorshift64_state ^ (xorshift64_state << 17);
+ end
+ endtask
+
+ reg [ABITS-1:0] randaddr1;
+ reg [ABITS-1:0] randaddr2;
+ reg [ABITS-1:0] randaddr3;
+
+ function [31:0] getaddr(input [3:0] n);
+ begin
+ case (n)
+ 0: getaddr = 0;
+ 1: getaddr = 2**ABITS-1;
+ 2: getaddr = 'b101 << (ABITS / 3);
+ 3: getaddr = 'b101 << (2*ABITS / 3);
+ 4: getaddr = 'b11011 << (ABITS / 4);
+ 5: getaddr = 'b11011 << (2*ABITS / 4);
+ 6: getaddr = 'b11011 << (3*ABITS / 4);
+ 7: getaddr = randaddr1;
+ 8: getaddr = randaddr2;
+ 9: getaddr = randaddr3;
+ default: begin
+ getaddr = 1 << (2*n-16);
+ if (!getaddr) getaddr = xorshift64_state;
+ end
+ endcase
+ end
+ endfunction
+
+ reg [DBITS-1:0] memory [0:2**ABITS-1];
+ reg [DBITS-1:0] expected_rd, expected_rd_masked;
+
+ event error;
+ reg error_ind = 0;
+
+ integer i, j;
+ initial begin
+ // $dumpfile("testbench.vcd");
+ // $dumpvars(0, bram1_tb);
+
+ xorshift64_next;
+ xorshift64_next;
+ xorshift64_next;
+ xorshift64_next;
+
+ randaddr1 = xorshift64_state;
+ xorshift64_next;
+
+ randaddr2 = xorshift64_state;
+ xorshift64_next;
+
+ randaddr3 = xorshift64_state;
+ xorshift64_next;
+
+ clk <= 0;
+ for (i = 0; i < 512; i = i+1) begin
+ if (DBITS > 64)
+ WR_DATA <= (xorshift64_state << (DBITS-64)) ^ xorshift64_state;
+ else
+ WR_DATA <= xorshift64_state;
+ xorshift64_next;
+ WR_ADDR <= getaddr(i < 256 ? i[7:4] : xorshift64_state[63:60]);
+ xorshift64_next;
+ RD_ADDR <= getaddr(i < 256 ? i[3:0] : xorshift64_state[59:56]);
+ WR_EN <= xorshift64_state[55];
+ xorshift64_next;
+
+ #1; clk <= 1;
+ #1; clk <= 0;
+
+ if (TRANSP) begin
+ if (WR_EN) memory[WR_ADDR] = WR_DATA;
+ expected_rd = memory[RD_ADDR];
+ end else begin
+ expected_rd = memory[RD_ADDR];
+ if (WR_EN) memory[WR_ADDR] = WR_DATA;
+ end
+
+ for (j = 0; j < DBITS; j = j+1)
+ expected_rd_masked[j] = expected_rd[j] !== 1'bx ? expected_rd[j] : RD_DATA[j];
+
+ $display("#OUT# %3d | WA=%x WD=%x WE=%x | RA=%x RD=%x (%x) | %s", i, WR_ADDR, WR_DATA, WR_EN, RD_ADDR, RD_DATA, expected_rd, expected_rd_masked === RD_DATA ? "ok" : "ERROR");
+ if (expected_rd_masked !== RD_DATA) begin -> error; error_ind = ~error_ind; end
+ end
+ end
+endmodule
diff --git a/tests/asicworld/code_hdl_models_dlatch_reset.v b/tests/asicworld/code_hdl_models_dlatch_reset.v
deleted file mode 100644
index 2cfc6fbd..00000000
--- a/tests/asicworld/code_hdl_models_dlatch_reset.v
+++ /dev/null
@@ -1,30 +0,0 @@
-//-----------------------------------------------------
-// Design Name : dlatch_reset
-// File Name : dlatch_reset.v
-// Function : DLATCH async reset
-// Coder : Deepak Kumar Tala
-//-----------------------------------------------------
-module dlatch_reset (
-data , // Data Input
-en , // LatchInput
-reset , // Reset input
-q // Q output
-);
-//-----------Input Ports---------------
-input data, en, reset ;
-
-//-----------Output Ports---------------
-output q;
-
-//------------Internal Variables--------
-reg q;
-
-//-------------Code Starts Here---------
-always @ ( en or reset or data)
-if (~reset) begin
- q <= 1'b0;
-end else if (en) begin
- q <= data;
-end
-
-endmodule //End Of Module dlatch_reset
diff --git a/tests/asicworld/code_hdl_models_ram_sp_ar_sw.v b/tests/asicworld/code_hdl_models_ram_sp_ar_sw.v
deleted file mode 100644
index d3338f74..00000000
--- a/tests/asicworld/code_hdl_models_ram_sp_ar_sw.v
+++ /dev/null
@@ -1,58 +0,0 @@
-//-----------------------------------------------------
-// Design Name : ram_sp_ar_sw
-// File Name : ram_sp_ar_sw.v
-// Function : Asynchronous read write RAM
-// Coder : Deepak Kumar Tala
-//-----------------------------------------------------
-module ram_sp_ar_sw (
-clk , // Clock Input
-address , // Address Input
-data , // Data bi-directional
-cs , // Chip Select
-we , // Write Enable/Read Enable
-oe // Output Enable
-);
-
-parameter DATA_WIDTH = 8 ;
-parameter ADDR_WIDTH = 8 ;
-parameter RAM_DEPTH = 1 << ADDR_WIDTH;
-
-//--------------Input Ports-----------------------
-input clk ;
-input [ADDR_WIDTH-1:0] address ;
-input cs ;
-input we ;
-input oe ;
-
-//--------------Inout Ports-----------------------
-inout [DATA_WIDTH-1:0] data ;
-
-//--------------Internal variables----------------
-reg [DATA_WIDTH-1:0] data_out ;
-reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
-
-//--------------Code Starts Here------------------
-
-// Tri-State Buffer control
-// output : When we = 0, oe = 1, cs = 1
-assign data = (cs && oe && !we) ? data_out : 8'bz;
-
-// Memory Write Block
-// Write Operation : When we = 1, cs = 1
-always @ (posedge clk)
-begin : MEM_WRITE
- if ( cs && we ) begin
- mem[address] = data;
- end
-end
-
-// Memory Read Block
-// Read Operation : When we = 0, oe = 1, cs = 1
-always @ (address or cs or we or oe)
-begin : MEM_READ
- if (cs && !we && oe) begin
- data_out = mem[address];
- end
-end
-
-endmodule // End of Module ram_sp_ar_sw
diff --git a/tests/asicworld/code_hdl_models_ram_sp_sr_sw.v b/tests/asicworld/code_hdl_models_ram_sp_sr_sw.v
deleted file mode 100644
index c7fd9554..00000000
--- a/tests/asicworld/code_hdl_models_ram_sp_sr_sw.v
+++ /dev/null
@@ -1,62 +0,0 @@
-//-----------------------------------------------------
-// Design Name : ram_sp_sr_sw
-// File Name : ram_sp_sr_sw.v
-// Function : Synchronous read write RAM
-// Coder : Deepak Kumar Tala
-//-----------------------------------------------------
-module ram_sp_sr_sw (
-clk , // Clock Input
-address , // Address Input
-data , // Data bi-directional
-cs , // Chip Select
-we , // Write Enable/Read Enable
-oe // Output Enable
-);
-
-parameter DATA_WIDTH = 8 ;
-parameter ADDR_WIDTH = 8 ;
-parameter RAM_DEPTH = 1 << ADDR_WIDTH;
-
-//--------------Input Ports-----------------------
-input clk ;
-input [ADDR_WIDTH-1:0] address ;
-input cs ;
-input we ;
-input oe ;
-
-//--------------Inout Ports-----------------------
-inout [DATA_WIDTH-1:0] data ;
-
-//--------------Internal variables----------------
-reg [DATA_WIDTH-1:0] data_out ;
-reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
-reg oe_r;
-
-//--------------Code Starts Here------------------
-
-// Tri-State Buffer control
-// output : When we = 0, oe = 1, cs = 1
-assign data = (cs && oe && !we) ? data_out : 8'bz;
-
-// Memory Write Block
-// Write Operation : When we = 1, cs = 1
-always @ (posedge clk)
-begin : MEM_WRITE
- if ( cs && we ) begin
- mem[address] = data;
- end
-end
-
-// Memory Read Block
-// Read Operation : When we = 0, oe = 1, cs = 1
-always @ (posedge clk)
-begin : MEM_READ
- if (cs && !we && oe) begin
- data_out = mem[address];
- oe_r = 1;
- end else begin
- oe_r = 0;
- end
-end
-
-endmodule // End of Module ram_sp_sr_sw
diff --git a/tests/bram/.gitignore b/tests/bram/.gitignore
new file mode 100644
index 00000000..9c595a6f
--- /dev/null
+++ b/tests/bram/.gitignore
@@ -0,0 +1 @@
+temp
diff --git a/tests/bram/generate.py b/tests/bram/generate.py
new file mode 100644
index 00000000..2adfdcfb
--- /dev/null
+++ b/tests/bram/generate.py
@@ -0,0 +1,264 @@
+#!/usr/bin/python
+
+from __future__ import division
+from __future__ import print_function
+
+import os
+import sys
+import random
+
+debug_mode = False
+seed = (int(os.times()[4]*100) + os.getpid()) % 900000 + 100000
+
+def create_bram(dsc_f, sim_f, ref_f, tb_f, k1, k2, or_next):
+ while True:
+ init = 0 # random.randrange(2)
+ abits = random.randrange(1, 8)
+ dbits = random.randrange(1, 8)
+ groups = random.randrange(2, 5)
+
+ if random.randrange(2):
+ abits = 2 ** random.randrange(1, 4)
+ if random.randrange(2):
+ dbits = 2 ** random.randrange(1, 4)
+
+ while True:
+ wrmode = [ random.randrange(0, 2) for i in range(groups) ]
+ if wrmode.count(1) == 0: continue
+ if wrmode.count(0) == 0: continue
+ break
+
+ if random.randrange(2) or True:
+ maxpol = 4
+ maxtransp = 1
+ else:
+ maxpol = 2
+ maxtransp = 2
+
+ def generate_enable(i):
+ if wrmode[i]:
+ v = 2 ** random.randrange(0, 4)
+ while dbits < v or dbits % v != 0:
+ v //= 2
+ return v
+ return 0
+
+ def generate_transp(i):
+ if wrmode[i] == 0:
+ return random.randrange(maxtransp)
+ return 0
+
+ ports = [ random.randrange(1, 3) for i in range(groups) ]
+ enable = [ generate_enable(i) for i in range(groups) ]
+ transp = [ generate_transp(i) for i in range(groups) ]
+ clocks = [ random.randrange(1, 4) for i in range(groups) ]
+ clkpol = [ random.randrange(maxpol) for i in range(groups) ]
+ break
+
+ print("bram bram_%02d_%02d" % (k1, k2), file=dsc_f)
+ print(" init %d" % init, file=dsc_f)
+ print(" abits %d" % abits, file=dsc_f)
+ print(" dbits %d" % dbits, file=dsc_f)
+ print(" groups %d" % groups, file=dsc_f)
+ print(" ports %s" % " ".join(["%d" % i for i in ports]), file=dsc_f)
+ print(" wrmode %s" % " ".join(["%d" % i for i in wrmode]), file=dsc_f)
+ print(" enable %s" % " ".join(["%d" % i for i in enable]), file=dsc_f)
+ print(" transp %s" % " ".join(["%d" % i for i in transp]), file=dsc_f)
+ print(" clocks %s" % " ".join(["%d" % i for i in clocks]), file=dsc_f)
+ print(" clkpol %s" % " ".join(["%d" % i for i in clkpol]), file=dsc_f)
+ print("endbram", file=dsc_f)
+ print("match bram_%02d_%02d" % (k1, k2), file=dsc_f)
+ if random.randrange(2):
+ non_zero_enables = [chr(ord('A') + i) for i in range(len(enable)) if enable[i]]
+ if len(non_zero_enables):
+ print(" shuffle_enable %c" % random.choice(non_zero_enables), file=dsc_f)
+ if or_next:
+ print(" or_next_if_better", file=dsc_f)
+ print("endmatch", file=dsc_f)
+
+ states = set()
+ v_ports = set()
+ v_stmts = list()
+ v_always = dict()
+
+ tb_decls = list()
+ tb_clocks = list()
+ tb_addr = list()
+ tb_din = list()
+ tb_dout = list()
+ tb_addrlist = list()
+
+ for i in range(10):
+ tb_addrlist.append(random.randrange(1048576))
+
+ t = random.randrange(1048576)
+ for i in range(10):
+ tb_addrlist.append(t ^ (1 << i))
+
+ v_stmts.append("(* nomem2reg *) reg [%d:0] memory [0:%d];" % (dbits-1, 2**abits-1))
+
+ portindex = 0
+ last_always_hdr = (-1, "")
+
+ for p1 in range(groups):
+ for p2 in range(ports[p1]):
+ pf = "%c%d" % (chr(ord("A") + p1), p2 + 1)
+ portindex += 1
+
+ v_stmts.append("`ifndef SYNTHESIS")
+ v_stmts.append(" event UPDATE_%s;" % pf)
+ v_stmts.append("`endif")
+
+ if clocks[p1] and not ("CLK%d" % clocks[p1]) in v_ports:
+ v_ports.add("CLK%d" % clocks[p1])
+ v_stmts.append("input CLK%d;" % clocks[p1])
+ tb_decls.append("reg CLK%d;" % clocks[p1])
+ tb_clocks.append("CLK%d" % clocks[p1])
+
+ v_ports.add("%sADDR" % pf)
+ v_stmts.append("input [%d:0] %sADDR;" % (abits-1, pf))
+ tb_decls.append("reg [%d:0] %sADDR;" % (abits-1, pf))
+ tb_addr.append("%sADDR" % pf)
+
+ v_ports.add("%sDATA" % pf)
+ v_stmts.append("%s [%d:0] %sDATA;" % ("input" if wrmode[p1] else "output reg", dbits-1, pf))
+
+ if wrmode[p1]:
+ tb_decls.append("reg [%d:0] %sDATA;" % (dbits-1, pf))
+ tb_din.append("%sDATA" % pf)
+ else:
+ tb_decls.append("wire [%d:0] %sDATA;" % (dbits-1, pf))
+ tb_decls.append("wire [%d:0] %sDATA_R;" % (dbits-1, pf))
+ tb_dout.append("%sDATA" % pf)
+
+ if wrmode[p1] and enable[p1]:
+ v_ports.add("%sEN" % pf)
+ v_stmts.append("input [%d:0] %sEN;" % (enable[p1]-1, pf))
+ tb_decls.append("reg [%d:0] %sEN;" % (enable[p1]-1, pf))
+ tb_din.append("%sEN" % pf)
+
+ assign_op = "<="
+ if clocks[p1] == 0:
+ always_hdr = "always @* begin"
+ assign_op = "="
+ elif clkpol[p1] == 0:
+ always_hdr = "always @(negedge CLK%d) begin" % clocks[p1]
+ elif clkpol[p1] == 1:
+ always_hdr = "always @(posedge CLK%d) begin" % clocks[p1]
+ else:
+ if not ("CP", clkpol[p1]) in states:
+ v_stmts.append("parameter CLKPOL%d = 0;" % clkpol[p1])
+ states.add(("CP", clkpol[p1]))
+ if not ("CPW", clocks[p1], clkpol[p1]) in states:
+ v_stmts.append("wire CLK%d_CLKPOL%d = CLK%d == CLKPOL%d;" % (clocks[p1], clkpol[p1], clocks[p1], clkpol[p1]))
+ states.add(("CPW", clocks[p1], clkpol[p1]))
+ always_hdr = "always @(posedge CLK%d_CLKPOL%d) begin" % (clocks[p1], clkpol[p1])
+
+ if last_always_hdr[1] != always_hdr:
+ last_always_hdr = (portindex, always_hdr)
+ v_always[last_always_hdr] = list()
+
+ if wrmode[p1]:
+ for i in range(enable[p1]):
+ enrange = "[%d:%d]" % ((i+1)*dbits/enable[p1]-1, i*dbits/enable[p1])
+ v_always[last_always_hdr].append((portindex, pf, "if (%sEN[%d]) memory[%sADDR]%s = %sDATA%s;" % (pf, i, pf, enrange, pf, enrange)))
+ else:
+ v_always[last_always_hdr].append((sum(ports)+1 if transp[p1] else 0, pf, "%sDATA %s memory[%sADDR];" % (pf, assign_op, pf)))
+
+ for always_hdr in sorted(v_always):
+ v_stmts.append(always_hdr[1])
+ triggered_events = set()
+ time_cursor = 0
+ v_always[always_hdr].sort()
+ for t, p, s in v_always[always_hdr]:
+ if time_cursor != t or not p in triggered_events:
+ v_stmts.append(" `ifndef SYNTHESIS")
+ stmt = ""
+ if time_cursor != t:
+ stmt += " #%d;" % (t-time_cursor)
+ time_cursor = t
+ if not p in triggered_events:
+ stmt += (" -> UPDATE_%s;" % p)
+ triggered_events.add(p)
+ v_stmts.append(" %s" % stmt)
+ v_stmts.append(" `endif")
+ v_stmts.append(" %s" % s)
+ v_stmts.append("end")
+
+ print("module bram_%02d_%02d(%s);" % (k1, k2, ", ".join(v_ports)), file=sim_f)
+ for stmt in v_stmts:
+ print(" %s" % stmt, file=sim_f)
+ print("endmodule", file=sim_f)
+
+ print("module bram_%02d_%02d_ref(%s);" % (k1, k2, ", ".join(v_ports)), file=ref_f)
+ for stmt in v_stmts:
+ print(" %s" % stmt, file=ref_f)
+ print("endmodule", file=ref_f)
+
+ print("module bram_%02d_%02d_tb;" % (k1, k2), file=tb_f)
+ for stmt in tb_decls:
+ print(" %s" % stmt, file=tb_f)
+ print(" bram_%02d_%02d uut (" % (k1, k2), file=tb_f)
+ print(" " + ",\n ".join([".%s(%s)" % (p, p) for p in (tb_clocks + tb_addr + tb_din + tb_dout)]), file=tb_f)
+ print(" );", file=tb_f)
+ print(" bram_%02d_%02d_ref ref (" % (k1, k2), file=tb_f)
+ print(" " + ",\n ".join([".%s(%s)" % (p, p) for p in (tb_clocks + tb_addr + tb_din)]) + ",", file=tb_f)
+ print(" " + ",\n ".join([".%s(%s_R)" % (p, p) for p in tb_dout]), file=tb_f)
+ print(" );", file=tb_f)
+
+ expr_dout = "{%s}" % ", ".join(tb_dout)
+ expr_dout_ref = "{%s}" % ", ".join(i + "_R" for i in tb_dout)
+
+ print(" wire error = %s !== %s;" % (expr_dout, expr_dout_ref), file=tb_f)
+
+ print(" initial begin", file=tb_f)
+
+ if debug_mode:
+ print(" $dumpfile(`vcd_file);", file=tb_f)
+ print(" $dumpvars(0, bram_%02d_%02d_tb);" % (k1, k2), file=tb_f)
+ print(" #%d;" % (1000 + k2), file=tb_f)
+
+ for p in (tb_clocks + tb_addr + tb_din):
+ if p[-2:] == "EN":
+ print(" %s <= ~0;" % p, file=tb_f)
+ else:
+ print(" %s <= 0;" % p, file=tb_f)
+ print(" #1000;", file=tb_f)
+
+ for v in [1, 0, 1, 0]:
+ for p in tb_clocks:
+ print(" %s = %d;" % (p, v), file=tb_f)
+ print(" #1000;", file=tb_f)
+
+ for i in range(20 if debug_mode else 100):
+ if len(tb_clocks):
+ c = random.choice(tb_clocks)
+ print(" %s = !%s;" % (c, c), file=tb_f)
+ print(" #100;", file=tb_f)
+ print(" $display(\"bram_%02d_%02d %3d: %%b %%b %%s\", %s, %s, error ? \"ERROR\" : \"OK\");" %
+ (k1, k2, i, expr_dout, expr_dout_ref), file=tb_f)
+ for p in tb_din:
+ print(" %s <= %d;" % (p, random.randrange(1048576)), file=tb_f)
+ for p in tb_addr:
+ print(" %s <= %d;" % (p, random.choice(tb_addrlist)), file=tb_f)
+ print(" #900;", file=tb_f)
+
+ print(" end", file=tb_f)
+ print("endmodule", file=tb_f)
+
+print("Rng seed: %d" % seed)
+random.seed(seed)
+
+for k1 in range(5):
+ dsc_f = file("temp/brams_%02d.txt" % k1, "w")
+ sim_f = file("temp/brams_%02d.v" % k1, "w")
+ ref_f = file("temp/brams_%02d_ref.v" % k1, "w")
+ tb_f = file("temp/brams_%02d_tb.v" % k1, "w")
+
+ for f in [sim_f, ref_f, tb_f]:
+ print("`timescale 1 ns / 1 ns", file=f)
+
+ lenk2 = 1 if debug_mode else 10
+ for k2 in range(lenk2):
+ create_bram(dsc_f, sim_f, ref_f, tb_f, k1, k2, random.randrange(2 if k2+1 < lenk2 else 1))
+
diff --git a/tests/bram/run-single.sh b/tests/bram/run-single.sh
new file mode 100644
index 00000000..19a235c7
--- /dev/null
+++ b/tests/bram/run-single.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+set -e
+../../yosys -qq -p "proc; opt; memory -nomap -bram temp/brams_${2}.txt; opt -fast -full" \
+ -l temp/synth_${1}_${2}.log -o temp/synth_${1}_${2}.v temp/brams_${1}.v
+iverilog -Dvcd_file=\"temp/tb_${1}_${2}.vcd\" -DSIMLIB_MEMDELAY=1ns -o temp/tb_${1}_${2}.tb temp/brams_${1}_tb.v \
+ temp/brams_${1}_ref.v temp/synth_${1}_${2}.v temp/brams_${2}.v ../../techlibs/common/simlib.v
+temp/tb_${1}_${2}.tb > temp/tb_${1}_${2}.txt
+if grep -q ERROR temp/tb_${1}_${2}.txt; then
+ grep -HC2 ERROR temp/tb_${1}_${2}.txt | head
+ exit 1
+fi
+exit 0
diff --git a/tests/bram/run-test.sh b/tests/bram/run-test.sh
new file mode 100755
index 00000000..d617187e
--- /dev/null
+++ b/tests/bram/run-test.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+# run this test many times:
+# MAKE="make -j8" time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done'
+
+set -e
+rm -rf temp
+mkdir -p temp
+
+echo "generating tests.."
+python generate.py
+
+{
+ echo -n "all:"
+ for i in $( ls temp/brams_*.txt | sed 's,.*_,,; s,\..*,,;' ); do
+ for j in $( ls temp/brams_*.txt | sed 's,.*_,,; s,\..*,,;' | grep -v $i ); do
+ echo -n " temp/job_${i}_${j}.ok"
+ done; done
+ echo
+ for i in $( ls temp/brams_*.txt | sed 's,.*_,,; s,\..*,,;' ); do
+ for j in $( ls temp/brams_*.txt | sed 's,.*_,,; s,\..*,,;' | grep -v $i ); do
+ echo "temp/job_${i}_${j}.ok:"
+ echo " @bash run-single.sh ${i} ${j}"
+ echo " @echo 'Passed memory_bram test ${i}_${j}.'"
+ echo " @touch \$@"
+ done; done
+} > temp/makefile
+
+echo "running tests.."
+${MAKE:-make} -f temp/makefile
+
+exit 0
diff --git a/tests/fsm/generate.py b/tests/fsm/generate.py
index b5b4626d..fc67543f 100644
--- a/tests/fsm/generate.py
+++ b/tests/fsm/generate.py
@@ -34,76 +34,78 @@ def random_expr(variables):
raise AssertionError
for idx in range(50):
- with file('temp/uut_%05d.v' % idx, 'w') as f, redirect_stdout(f):
- rst2 = random.choice([False, True])
- if rst2:
- print('module uut_%05d(clk, rst1, rst2, rst, a, b, c, x, y, z);' % (idx))
- print(' input clk, rst1, rst2;')
- print(' output rst;')
- print(' assign rst = rst1 || rst2;')
- else:
- print('module uut_%05d(clk, rst, a, b, c, x, y, z);' % (idx))
- print(' input clk, rst;')
- variables=['a', 'b', 'c', 'x', 'y', 'z']
- print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), random.randint(0, 31)))
- print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), random.randint(0, 31)))
- print(' input%s [%d:0] c;' % (random.choice(['', ' signed']), random.randint(0, 31)))
- print(' output reg%s [%d:0] x;' % (random.choice(['', ' signed']), random.randint(0, 31)))
- print(' output reg%s [%d:0] y;' % (random.choice(['', ' signed']), random.randint(0, 31)))
- print(' output reg%s [%d:0] z;' % (random.choice(['', ' signed']), random.randint(0, 31)))
- state_bits = random.randint(5, 16);
- print(' %sreg [%d:0] state;' % (random.choice(['', '(* fsm_encoding = "one-hot" *)',
- '(* fsm_encoding = "binary" *)']), state_bits-1))
- states=[]
- for i in range(random.randint(2, 10)):
- n = random.randint(0, 2**state_bits-1)
- if n not in states:
- states.append(n)
- print(' always @(posedge clk) begin')
- print(' if (%s) begin' % ('rst1' if rst2 else 'rst'))
- print(' x <= %d;' % random.randint(0, 2**31-1))
- print(' y <= %d;' % random.randint(0, 2**31-1))
- print(' z <= %d;' % random.randint(0, 2**31-1))
- print(' state <= %d;' % random.choice(states))
- print(' end else begin')
- print(' case (state)')
- for state in states:
- print(' %d: begin' % state)
- for var in ('x', 'y', 'z'):
- print(' %s <= %s;' % (var, random_expr(variables)))
- next_states = states[:]
- for i in range(random.randint(0, len(states))):
- next_state = random.choice(next_states)
- next_states.remove(next_state)
- print(' if ((%s) %s (%s)) state <= %s;' % (random_expr(variables),
- random.choice(['<', '<=', '>=', '>']), random_expr(variables), next_state))
- print(' end')
- print(' endcase')
- if rst2:
- print(' if (rst2) begin')
- print(' x <= a;')
- print(' y <= b;')
- print(' z <= c;')
- print(' state <= %d;' % random.choice(states))
- print(' end')
- print(' end')
- print(' end')
- print('endmodule')
- with file('temp/uut_%05d.ys' % idx, 'w') as f, redirect_stdout(f):
- if test_verific:
- print('read_verilog temp/uut_%05d.v' % idx)
- print('proc;; rename uut_%05d gold' % idx)
- print('verific -vlog2k temp/uut_%05d.v' % idx)
- print('verific -import uut_%05d' % idx)
- print('rename uut_%05d gate' % idx)
- else:
- print('read_verilog temp/uut_%05d.v' % idx)
- print('proc;;')
- print('copy uut_%05d gold' % idx)
- print('rename uut_%05d gate' % idx)
- print('cd gate')
- print('opt; wreduce; share%s; opt; fsm;;' % random.choice(['', ' -aggressive']))
- print('cd ..')
- print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter')
- print('sat -verify-no-timeout -timeout 20 -seq 5 -set-at 1 %s_rst 1 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter' % ('gold' if rst2 else 'in'))
+ with file('temp/uut_%05d.v' % idx, 'w') as f:
+ with redirect_stdout(f):
+ rst2 = random.choice([False, True])
+ if rst2:
+ print('module uut_%05d(clk, rst1, rst2, rst, a, b, c, x, y, z);' % (idx))
+ print(' input clk, rst1, rst2;')
+ print(' output rst;')
+ print(' assign rst = rst1 || rst2;')
+ else:
+ print('module uut_%05d(clk, rst, a, b, c, x, y, z);' % (idx))
+ print(' input clk, rst;')
+ variables=['a', 'b', 'c', 'x', 'y', 'z']
+ print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' input%s [%d:0] c;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' output reg%s [%d:0] x;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' output reg%s [%d:0] y;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ print(' output reg%s [%d:0] z;' % (random.choice(['', ' signed']), random.randint(0, 31)))
+ state_bits = random.randint(5, 16);
+ print(' %sreg [%d:0] state;' % (random.choice(['', '(* fsm_encoding = "one-hot" *)',
+ '(* fsm_encoding = "binary" *)']), state_bits-1))
+ states=[]
+ for i in range(random.randint(2, 10)):
+ n = random.randint(0, 2**state_bits-1)
+ if n not in states:
+ states.append(n)
+ print(' always @(posedge clk) begin')
+ print(' if (%s) begin' % ('rst1' if rst2 else 'rst'))
+ print(' x <= %d;' % random.randint(0, 2**31-1))
+ print(' y <= %d;' % random.randint(0, 2**31-1))
+ print(' z <= %d;' % random.randint(0, 2**31-1))
+ print(' state <= %d;' % random.choice(states))
+ print(' end else begin')
+ print(' case (state)')
+ for state in states:
+ print(' %d: begin' % state)
+ for var in ('x', 'y', 'z'):
+ print(' %s <= %s;' % (var, random_expr(variables)))
+ next_states = states[:]
+ for i in range(random.randint(0, len(states))):
+ next_state = random.choice(next_states)
+ next_states.remove(next_state)
+ print(' if ((%s) %s (%s)) state <= %s;' % (random_expr(variables),
+ random.choice(['<', '<=', '>=', '>']), random_expr(variables), next_state))
+ print(' end')
+ print(' endcase')
+ if rst2:
+ print(' if (rst2) begin')
+ print(' x <= a;')
+ print(' y <= b;')
+ print(' z <= c;')
+ print(' state <= %d;' % random.choice(states))
+ print(' end')
+ print(' end')
+ print(' end')
+ print('endmodule')
+ with file('temp/uut_%05d.ys' % idx, 'w') as f:
+ with redirect_stdout(f):
+ if test_verific:
+ print('read_verilog temp/uut_%05d.v' % idx)
+ print('proc;; rename uut_%05d gold' % idx)
+ print('verific -vlog2k temp/uut_%05d.v' % idx)
+ print('verific -import uut_%05d' % idx)
+ print('rename uut_%05d gate' % idx)
+ else:
+ print('read_verilog temp/uut_%05d.v' % idx)
+ print('proc;;')
+ print('copy uut_%05d gold' % idx)
+ print('rename uut_%05d gate' % idx)
+ print('cd gate')
+ print('opt; wreduce; share%s; opt; fsm;;' % random.choice(['', ' -aggressive']))
+ print('cd ..')
+ print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter')
+ print('sat -verify-no-timeout -timeout 20 -seq 5 -set-at 1 %s_rst 1 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter' % ('gold' if rst2 else 'in'))
diff --git a/tests/realmath/generate.py b/tests/realmath/generate.py
index 972021dc..24d13561 100644
--- a/tests/realmath/generate.py
+++ b/tests/realmath/generate.py
@@ -40,52 +40,55 @@ def random_expression(depth = 3, maxparam = 0):
raise
for idx in range(100):
- with file('temp/uut_%05d.v' % idx, 'w') as f, redirect_stdout(f):
- print('module uut_%05d(output [63:0] %s);\n' % (idx, ', '.join(['y%02d' % i for i in range(100)])))
- for i in range(30):
- if idx < 10:
- print('localparam p%02d = %s;' % (i, random_expression()))
- else:
- print('localparam%s p%02d = %s;' % (random.choice(['', ' real', ' integer']), i, random_expression()))
- for i in range(30, 60):
- if idx < 10:
- print('localparam p%02d = %s;' % (i, random_expression(maxparam = 30)))
- else:
- print('localparam%s p%02d = %s;' % (random.choice(['', ' real', ' integer']), i, random_expression(maxparam = 30)))
- for i in range(100):
- print('assign y%02d = 65536 * (%s);' % (i, random_expression(maxparam = 60)))
- print('endmodule')
- with file('temp/uut_%05d.ys' % idx, 'w') as f, redirect_stdout(f):
- print('read_verilog uut_%05d.v' % idx)
- print('rename uut_%05d uut_%05d_syn' % (idx, idx))
- print('write_verilog uut_%05d_syn.v' % idx)
- with file('temp/uut_%05d_tb.v' % idx, 'w') as f, redirect_stdout(f):
- print('module uut_%05d_tb;\n' % idx)
- print('wire [63:0] %s;' % (', '.join(['r%02d' % i for i in range(100)])))
- print('wire [63:0] %s;' % (', '.join(['s%02d' % i for i in range(100)])))
- print('uut_%05d ref(%s);' % (idx, ', '.join(['r%02d' % i for i in range(100)])))
- print('uut_%05d_syn syn(%s);' % (idx, ', '.join(['s%02d' % i for i in range(100)])))
- print('task compare_ref_syn;')
- print(' input [7:0] i;')
- print(' input [63:0] r, s;')
- print(' reg [64*8-1:0] buffer;')
- print(' integer j;')
- print(' begin')
- print(' if (-1 <= $signed(r-s) && $signed(r-s) <= +1) begin')
- print(' // $display("%d: %b %b", i, r, s);')
- print(' end else if (r === s) begin ')
- print(' // $display("%d: %b %b", i, r, s);')
- print(' end else begin ')
- print(' for (j = 0; j < 64; j = j+1)')
- print(' buffer[j*8 +: 8] = r[j] !== s[j] ? "^" : " ";')
- print(' $display("\\n%3d: %b %b", i, r, s);')
- print(' $display(" %s %s", buffer, buffer);')
- print(' end')
- print(' end')
- print('endtask')
- print('initial begin #1;')
- for i in range(100):
- print(' compare_ref_syn(%2d, r%02d, s%02d);' % (i, i, i))
- print('end')
- print('endmodule')
+ with file('temp/uut_%05d.v' % idx, 'w') as f:
+ with redirect_stdout(f):
+ print('module uut_%05d(output [63:0] %s);\n' % (idx, ', '.join(['y%02d' % i for i in range(100)])))
+ for i in range(30):
+ if idx < 10:
+ print('localparam p%02d = %s;' % (i, random_expression()))
+ else:
+ print('localparam%s p%02d = %s;' % (random.choice(['', ' real', ' integer']), i, random_expression()))
+ for i in range(30, 60):
+ if idx < 10:
+ print('localparam p%02d = %s;' % (i, random_expression(maxparam = 30)))
+ else:
+ print('localparam%s p%02d = %s;' % (random.choice(['', ' real', ' integer']), i, random_expression(maxparam = 30)))
+ for i in range(100):
+ print('assign y%02d = 65536 * (%s);' % (i, random_expression(maxparam = 60)))
+ print('endmodule')
+ with file('temp/uut_%05d.ys' % idx, 'w') as f:
+ with redirect_stdout(f):
+ print('read_verilog uut_%05d.v' % idx)
+ print('rename uut_%05d uut_%05d_syn' % (idx, idx))
+ print('write_verilog uut_%05d_syn.v' % idx)
+ with file('temp/uut_%05d_tb.v' % idx, 'w') as f:
+ with redirect_stdout(f):
+ print('module uut_%05d_tb;\n' % idx)
+ print('wire [63:0] %s;' % (', '.join(['r%02d' % i for i in range(100)])))
+ print('wire [63:0] %s;' % (', '.join(['s%02d' % i for i in range(100)])))
+ print('uut_%05d ref(%s);' % (idx, ', '.join(['r%02d' % i for i in range(100)])))
+ print('uut_%05d_syn syn(%s);' % (idx, ', '.join(['s%02d' % i for i in range(100)])))
+ print('task compare_ref_syn;')
+ print(' input [7:0] i;')
+ print(' input [63:0] r, s;')
+ print(' reg [64*8-1:0] buffer;')
+ print(' integer j;')
+ print(' begin')
+ print(' if (-1 <= $signed(r-s) && $signed(r-s) <= +1) begin')
+ print(' // $display("%d: %b %b", i, r, s);')
+ print(' end else if (r === s) begin ')
+ print(' // $display("%d: %b %b", i, r, s);')
+ print(' end else begin ')
+ print(' for (j = 0; j < 64; j = j+1)')
+ print(' buffer[j*8 +: 8] = r[j] !== s[j] ? "^" : " ";')
+ print(' $display("\\n%3d: %b %b", i, r, s);')
+ print(' $display(" %s %s", buffer, buffer);')
+ print(' end')
+ print(' end')
+ print('endtask')
+ print('initial begin #1;')
+ for i in range(100):
+ print(' compare_ref_syn(%2d, r%02d, s%02d);' % (i, i, i))
+ print('end')
+ print('endmodule')
diff --git a/tests/realmath/run-test.sh b/tests/realmath/run-test.sh
index b8e222ad..0997ccb5 100755
--- a/tests/realmath/run-test.sh
+++ b/tests/realmath/run-test.sh
@@ -11,7 +11,7 @@ echo "running tests.."
for ((i = 0; i < 100; i++)); do
echo -n "[$i]"
idx=$( printf "%05d" $i )
- ../../../yosys -q uut_${idx}.ys
+ ../../../yosys -qq uut_${idx}.ys
iverilog -o uut_${idx}_tb uut_${idx}_tb.v uut_${idx}.v uut_${idx}_syn.v
./uut_${idx}_tb | tee uut_${idx}.err
if test -s uut_${idx}.err; then
diff --git a/tests/share/generate.py b/tests/share/generate.py
index a06a642d..bb96fec6 100644
--- a/tests/share/generate.py
+++ b/tests/share/generate.py
@@ -25,49 +25,51 @@ def maybe_plus_x(expr):
return expr
for idx in range(100):
- with file('temp/uut_%05d.v' % idx, 'w') as f, redirect_stdout(f):
- if random.choice(['bin', 'uni']) == 'bin':
- print('module uut_%05d(a, b, c, d, x, s, y);' % (idx))
- op = random.choice([
- random.choice(['+', '-', '*', '/', '%']),
- random.choice(['<', '<=', '==', '!=', '===', '!==', '>=', '>' ]),
- random.choice(['<<', '>>', '<<<', '>>>']),
- random.choice(['|', '&', '^', '~^', '||', '&&']),
- ])
- print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), random.randint(0, 8)))
- print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), random.randint(0, 8)))
- print(' input%s [%d:0] c;' % (random.choice(['', ' signed']), random.randint(0, 8)))
- print(' input%s [%d:0] d;' % (random.choice(['', ' signed']), random.randint(0, 8)))
- print(' input%s [%d:0] x;' % (random.choice(['', ' signed']), random.randint(0, 8)))
- print(' input s;')
- print(' output [%d:0] y;' % random.randint(0, 8))
- print(' assign y = (s ? %s(%s %s %s) : %s(%s %s %s))%s;' %
- (random.choice(['', '$signed', '$unsigned']), maybe_plus_x('a'), op, maybe_plus_x('b'),
- random.choice(['', '$signed', '$unsigned']), maybe_plus_x('c'), op, maybe_plus_x('d'),
- random_plus_x() if random.randint(0, 4) == 0 else ''))
- print('endmodule')
- else:
- print('module uut_%05d(a, b, x, s, y);' % (idx))
- op = random.choice(['~', '-', '!'])
- print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), random.randint(0, 8)))
- print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), random.randint(0, 8)))
- print(' input%s [%d:0] x;' % (random.choice(['', ' signed']), random.randint(0, 8)))
- print(' input s;')
- print(' output [%d:0] y;' % random.randint(0, 8))
- print(' assign y = (s ? %s(%s%s) : %s(%s%s))%s;' %
- (random.choice(['', '$signed', '$unsigned']), op, maybe_plus_x('a'),
- random.choice(['', '$signed', '$unsigned']), op, maybe_plus_x('b'),
- random_plus_x() if random.randint(0, 4) == 0 else ''))
- print('endmodule')
- with file('temp/uut_%05d.ys' % idx, 'w') as f, redirect_stdout(f):
- print('read_verilog temp/uut_%05d.v' % idx)
- print('proc;;')
- print('copy uut_%05d gold' % idx)
- print('rename uut_%05d gate' % idx)
- print('tee -a temp/all_share_log.txt log')
- print('tee -a temp/all_share_log.txt log #job# uut_%05d' % idx)
- print('tee -a temp/all_share_log.txt wreduce')
- print('tee -a temp/all_share_log.txt share -aggressive gate')
- print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter')
- print('sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter')
+ with file('temp/uut_%05d.v' % idx, 'w') as f:
+ with redirect_stdout(f):
+ if random.choice(['bin', 'uni']) == 'bin':
+ print('module uut_%05d(a, b, c, d, x, s, y);' % (idx))
+ op = random.choice([
+ random.choice(['+', '-', '*', '/', '%']),
+ random.choice(['<', '<=', '==', '!=', '===', '!==', '>=', '>' ]),
+ random.choice(['<<', '>>', '<<<', '>>>']),
+ random.choice(['|', '&', '^', '~^', '||', '&&']),
+ ])
+ print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] c;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] d;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] x;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input s;')
+ print(' output [%d:0] y;' % random.randint(0, 8))
+ print(' assign y = (s ? %s(%s %s %s) : %s(%s %s %s))%s;' %
+ (random.choice(['', '$signed', '$unsigned']), maybe_plus_x('a'), op, maybe_plus_x('b'),
+ random.choice(['', '$signed', '$unsigned']), maybe_plus_x('c'), op, maybe_plus_x('d'),
+ random_plus_x() if random.randint(0, 4) == 0 else ''))
+ print('endmodule')
+ else:
+ print('module uut_%05d(a, b, x, s, y);' % (idx))
+ op = random.choice(['~', '-', '!'])
+ print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input%s [%d:0] x;' % (random.choice(['', ' signed']), random.randint(0, 8)))
+ print(' input s;')
+ print(' output [%d:0] y;' % random.randint(0, 8))
+ print(' assign y = (s ? %s(%s%s) : %s(%s%s))%s;' %
+ (random.choice(['', '$signed', '$unsigned']), op, maybe_plus_x('a'),
+ random.choice(['', '$signed', '$unsigned']), op, maybe_plus_x('b'),
+ random_plus_x() if random.randint(0, 4) == 0 else ''))
+ print('endmodule')
+ with file('temp/uut_%05d.ys' % idx, 'w') as f:
+ with redirect_stdout(f):
+ print('read_verilog temp/uut_%05d.v' % idx)
+ print('proc;;')
+ print('copy uut_%05d gold' % idx)
+ print('rename uut_%05d gate' % idx)
+ print('tee -a temp/all_share_log.txt log')
+ print('tee -a temp/all_share_log.txt log #job# uut_%05d' % idx)
+ print('tee -a temp/all_share_log.txt wreduce')
+ print('tee -a temp/all_share_log.txt share -aggressive gate')
+ print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter')
+ print('sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter')
diff --git a/tests/share/run-test.sh b/tests/share/run-test.sh
index 203d6fcd..6e880677 100755
--- a/tests/share/run-test.sh
+++ b/tests/share/run-test.sh
@@ -18,7 +18,7 @@ for i in $( ls temp/*.ys | sed 's,[^0-9],,g; s,^0*\(.\),\1,g;' ); do
done
echo
-failed_share=$( echo $( gawk '/^#job#/ { j=$2; db[j]=0; } /^Removing [24] cells/ { delete db[j]; } END { for (j in db) print(j); }' temp/all_share_log.txt ) )
+failed_share=$( echo $( gawk '/^#job#/ { j=$2; db[j]=0; } /^Removing [246] cells/ { delete db[j]; } END { for (j in db) print(j); }' temp/all_share_log.txt ) )
if [ -n "$failed_share" ]; then
echo "Resource sharing failed for the following test cases: $failed_share"
false
diff --git a/tests/simple/memory.v b/tests/simple/memory.v
index db06c56d..67f89cd7 100644
--- a/tests/simple/memory.v
+++ b/tests/simple/memory.v
@@ -205,3 +205,26 @@ module memtest08(input clk, input [3:0] a, b, c, output reg [3:0] y);
end
endmodule
+// ----------------------------------------------------------
+
+module memtest09 (
+ input clk,
+ input [3:0] a_addr, a_din, b_addr, b_din,
+ input a_wen, b_wen,
+ output reg [3:0] a_dout, b_dout
+);
+ reg [3:0] memory [10:35];
+
+ always @(posedge clk) begin
+ if (a_wen)
+ memory[10 + a_addr] <= a_din;
+ a_dout <= memory[10 + a_addr];
+ end
+
+ always @(posedge clk) begin
+ if (b_wen && (10 + a_addr != 20 + b_addr || !a_wen))
+ memory[20 + b_addr] <= b_din;
+ b_dout <= memory[20 + b_addr];
+ end
+endmodule
+
diff --git a/tests/simple/muxtree.v b/tests/simple/muxtree.v
index c5060eae..1fb1cea5 100644
--- a/tests/simple/muxtree.v
+++ b/tests/simple/muxtree.v
@@ -70,3 +70,14 @@ end
endmodule
+
+// test case for muxtree with select on leaves
+
+module select_leaves(input R, C, D, output reg Q);
+ always @(posedge C)
+ if (!R)
+ Q <= R;
+ else
+ Q <= Q ? Q : D ? D : Q;
+endmodule
+
diff --git a/tests/simple/task_func.v b/tests/simple/task_func.v
index 51e31015..9b8e26e5 100644
--- a/tests/simple/task_func.v
+++ b/tests/simple/task_func.v
@@ -33,8 +33,42 @@ end
endmodule
+// -------------------------------------------------------------------
-module task_func_test02( input [7:0] din_a, input [7:0] din_b, output [7:0] dout_a);
+module task_func_test02(clk, a, b, c, x, y, z, w);
+
+input clk;
+input [7:0] a, b, c;
+output reg [7:0] x, y, z, w;
+
+function [7:0] sum_shift(input [3:0] s1, s2, s3);
+sum_shift = s1 + (s2 << 2) + (s3 << 4);
+endfunction
+
+task reset_w;
+w = 0;
+endtask
+
+task add_to(output [7:0] out, input [7:0] in);
+out = out + in;
+endtask
+
+always @(posedge clk) begin
+ x = sum_shift(a, b, c);
+ y = sum_shift(a[7:4], b[5:2], c[3:0]);
+ z = sum_shift(a[0], b[5:4], c >> 5) ^ sum_shift(1, 2, 3);
+
+ reset_w;
+ add_to(w, x);
+ add_to(w, y);
+ add_to(w, z);
+end
+
+endmodule
+
+// -------------------------------------------------------------------
+
+module task_func_test03( input [7:0] din_a, input [7:0] din_b, output [7:0] dout_a);
assign dout_a = test(din_a,din_b);
function [7:0] test;
input [7:0] a;
diff --git a/tests/techmap/mem_simple_4x1_map.v b/tests/techmap/mem_simple_4x1_map.v
index 820f89de..868f5d00 100644
--- a/tests/techmap/mem_simple_4x1_map.v
+++ b/tests/techmap/mem_simple_4x1_map.v
@@ -5,6 +5,7 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
parameter OFFSET = 0;
parameter ABITS = 8;
parameter WIDTH = 8;
+ parameter signed INIT = 1'bx;
parameter RD_PORTS = 1;
parameter RD_CLK_ENABLE = 1'b1;
@@ -37,6 +38,10 @@ module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
initial begin
_TECHMAP_FAIL_ <= 0;
+ // no initialized memories
+ if (INIT !== 1'bx)
+ _TECHMAP_FAIL_ <= 1;
+
// only map cells with only one read and one write port
if (RD_PORTS > 1 || WR_PORTS > 1)
_TECHMAP_FAIL_ <= 1;
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index 50f5cb58..6fdc2792 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -145,7 +145,7 @@ do
elif [ "$frontend" = "verific_gates" ]; then
test_passes -p "verific -vlog2k $fn; verific -import -gates -all; opt; memory;;"
else
- test_passes -f "$frontend" -p "hierarchy; proc; opt; memory; opt; fsm; opt -fine" $fn
+ test_passes -f "$frontend" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" $fn
test_passes -f "$frontend" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" $fn
fi
touch ../${bn}.log
diff --git a/tests/tools/cmp_tbdata.c b/tests/tools/cmp_tbdata.c
index 86485efd..b81ae1ca 100644
--- a/tests/tools/cmp_tbdata.c
+++ b/tests/tools/cmp_tbdata.c
@@ -53,6 +53,8 @@ int main(int argc, char **argv)
// here means we don't care about the result.
if (buffer1[i] == 'z' || buffer1[i] == 'x')
continue;
+ if (buffer1[i] == 'Z' || buffer1[i] == 'X')
+ continue;
check(buffer1[i] == buffer2[i]);
}
diff --git a/tests/tools/vcdcd.pl b/tests/tools/vcdcd.pl
index 2abfb7a2..6f497e99 100755
--- a/tests/tools/vcdcd.pl
+++ b/tests/tools/vcdcd.pl
@@ -80,8 +80,8 @@ for my $net (sort keys %gold_signals_hash) {
for my $fullname (keys $gate_signals_hash{$net}) {
$orig_net_names{$fullname} = 1;
}
- for my $_ (sort keys %orig_net_names) {
- push @signals, $_;
+ for my $net (sort keys %orig_net_names) {
+ push @signals, $net;
print " $1" if /(\[([0-9]+|[0-9]+:[0-9]+)\])$/;
}
print "\n";