summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2018-08-30 20:46:20 +0200
committerRuben Undheim <ruben.undheim@gmail.com>2018-08-30 20:46:20 +0200
commit5033b51947a6ef02cb785b5622e993335efa750a (patch)
tree7bed18c526bd94917fa2f08e3df12209863698a1
parentfefe0fc0430f4f173a25e674708aa0f4f0854b31 (diff)
New upstream version 0.7+20180830git0b7a184
-rw-r--r--.github/issue_template.md16
-rw-r--r--.gitignore8
-rw-r--r--.travis.yml176
-rwxr-xr-x.travis/build-and-test.sh49
-rw-r--r--.travis/common.sh15
-rwxr-xr-x.travis/deploy-after-success.sh6
-rwxr-xr-x.travis/setup.sh97
-rw-r--r--Brewfile8
-rw-r--r--CHANGELOG13
-rw-r--r--COPYING13
-rw-r--r--CodingReadme98
-rw-r--r--Makefile313
-rw-r--r--README.md (renamed from README)240
-rw-r--r--backends/aiger/Makefile.inc3
-rw-r--r--backends/aiger/aiger.cc754
-rw-r--r--backends/blif/blif.cc82
-rw-r--r--backends/btor/README23
-rw-r--r--backends/btor/btor.cc1876
-rw-r--r--backends/btor/test_cells.sh30
-rwxr-xr-xbackends/btor/verilog2btor.sh37
-rw-r--r--backends/edif/edif.cc181
-rw-r--r--backends/edif/runtest.py121
-rw-r--r--backends/firrtl/.gitignore2
-rw-r--r--backends/firrtl/Makefile.inc3
-rw-r--r--backends/firrtl/firrtl.cc677
-rw-r--r--backends/firrtl/test.sh25
-rw-r--r--backends/firrtl/test.v63
-rw-r--r--backends/ilang/ilang_backend.cc10
-rw-r--r--backends/intersynth/intersynth.cc4
-rw-r--r--backends/json/json.cc18
-rw-r--r--backends/protobuf/.gitignore2
-rw-r--r--backends/protobuf/Makefile.inc8
-rw-r--r--backends/protobuf/protobuf.cc370
-rw-r--r--backends/simplec/.gitignore2
-rw-r--r--backends/simplec/Makefile.inc3
-rw-r--r--backends/simplec/simplec.cc810
-rw-r--r--backends/simplec/test00.sh5
-rw-r--r--backends/simplec/test00_tb.c93
-rw-r--r--backends/simplec/test00_uut.v14
-rw-r--r--backends/smt2/Makefile.inc2
-rw-r--r--backends/smt2/smt2.cc728
-rw-r--r--backends/smt2/smtbmc.py944
-rw-r--r--backends/smt2/smtio.py458
-rw-r--r--backends/smv/smv.cc14
-rw-r--r--backends/spice/spice.cc4
-rw-r--r--backends/table/Makefile.inc3
-rw-r--r--backends/table/table.cc120
-rw-r--r--backends/verilog/verilog_backend.cc223
-rw-r--r--examples/aiger/.gitignore5
-rw-r--r--examples/aiger/README22
-rw-r--r--examples/aiger/demo.sh14
-rw-r--r--examples/aiger/demo.v12
-rw-r--r--examples/basys3/example.xdc3
-rw-r--r--examples/basys3/run_prog.tcl1
-rw-r--r--examples/cmos/counter.ys10
-rw-r--r--examples/cmos/counter_tb.v4
-rw-r--r--examples/cmos/testbench_digital.sh2
-rw-r--r--examples/cxx-api/evaldemo.cc2
-rw-r--r--examples/gowin/.gitignore8
-rw-r--r--examples/gowin/README17
-rw-r--r--examples/gowin/demo.cst41
-rw-r--r--examples/gowin/demo.sdc1
-rw-r--r--examples/gowin/demo.v12
-rw-r--r--examples/gowin/run.sh12
-rw-r--r--examples/gowin/testbench.v40
-rw-r--r--examples/intel/DE2i-150/quartus_compile/de2i.qpf4
-rw-r--r--examples/intel/DE2i-150/quartus_compile/de2i.qsf1099
-rw-r--r--examples/intel/DE2i-150/quartus_compile/runme_quartus7
-rw-r--r--examples/intel/DE2i-150/run_cycloneiv2
-rw-r--r--examples/intel/DE2i-150/sevenseg.v25
-rw-r--r--examples/intel/DE2i-150/top.v15
-rw-r--r--examples/intel/MAX10/run_max101
-rw-r--r--examples/intel/MAX10/runme_postsynth5
-rw-r--r--examples/intel/MAX10/sevenseg.v25
-rw-r--r--examples/intel/MAX10/top.v15
-rw-r--r--examples/intel/asicworld_lfsr/README6
-rw-r--r--examples/intel/asicworld_lfsr/lfsr_updown.v35
-rw-r--r--examples/intel/asicworld_lfsr/lfsr_updown_tb.v34
-rwxr-xr-xexamples/intel/asicworld_lfsr/run_cycloneiv2
-rwxr-xr-xexamples/intel/asicworld_lfsr/run_max102
-rwxr-xr-xexamples/intel/asicworld_lfsr/runme_postsynth5
-rwxr-xr-xexamples/intel/asicworld_lfsr/runme_presynth5
-rw-r--r--examples/osu035/.gitignore3
-rw-r--r--examples/osu035/Makefile13
-rw-r--r--examples/osu035/example.constr2
-rw-r--r--examples/osu035/example.v3
-rw-r--r--examples/osu035/example.ys11
-rw-r--r--examples/smtbmc/.gitignore2
-rw-r--r--examples/smtbmc/Makefile11
-rw-r--r--examples/smtbmc/demo2.v2
-rw-r--r--examples/smtbmc/demo8.v12
-rw-r--r--frontends/ast/ast.cc94
-rw-r--r--frontends/ast/ast.h33
-rw-r--r--frontends/ast/genrtlil.cc209
-rw-r--r--frontends/ast/simplify.cc482
-rw-r--r--frontends/blif/blifparse.cc159
-rw-r--r--frontends/blif/blifparse.h3
-rw-r--r--frontends/ilang/.gitignore2
-rw-r--r--frontends/ilang/Makefile.inc7
-rw-r--r--frontends/ilang/ilang_frontend.cc4
-rw-r--r--frontends/ilang/ilang_lexer.l2
-rw-r--r--frontends/json/Makefile.inc3
-rw-r--r--frontends/json/jsonparse.cc541
-rw-r--r--frontends/liberty/liberty.cc73
-rw-r--r--frontends/verific/Makefile.inc3
-rw-r--r--frontends/verific/README62
-rw-r--r--frontends/verific/build_amd64.txt30
-rw-r--r--frontends/verific/example.sby16
-rw-r--r--frontends/verific/example.sv18
-rw-r--r--frontends/verific/test_navre.ys18
-rw-r--r--frontends/verific/verific.cc1870
-rw-r--r--frontends/verific/verific.h106
-rw-r--r--frontends/verific/verificsva.cc1814
-rw-r--r--frontends/verilog/.gitignore2
-rw-r--r--frontends/verilog/Makefile.inc7
-rw-r--r--frontends/verilog/const2ast.cc8
-rw-r--r--frontends/verilog/preproc.cc189
-rw-r--r--frontends/verilog/verilog_frontend.cc121
-rw-r--r--frontends/verilog/verilog_frontend.h3
-rw-r--r--frontends/verilog/verilog_lexer.l55
-rw-r--r--frontends/verilog/verilog_parser.y440
-rw-r--r--frontends/vhdl2verilog/Makefile.inc1
-rw-r--r--frontends/vhdl2verilog/vhdl2verilog.cc183
-rw-r--r--kernel/calc.cc4
-rw-r--r--kernel/cellaigs.cc16
-rw-r--r--kernel/celledges.h6
-rw-r--r--kernel/celltypes.h15
-rw-r--r--kernel/consteval.h9
-rw-r--r--kernel/cost.h30
-rw-r--r--kernel/driver.cc175
-rw-r--r--kernel/hashlib.h9
-rw-r--r--kernel/log.cc149
-rw-r--r--kernel/log.h17
-rw-r--r--kernel/modtools.h10
-rw-r--r--kernel/register.cc15
-rw-r--r--kernel/register.h14
-rw-r--r--kernel/rtlil.cc339
-rw-r--r--kernel/rtlil.h342
-rw-r--r--kernel/satgen.h39
-rw-r--r--kernel/yosys.cc97
-rw-r--r--kernel/yosys.h16
-rw-r--r--libs/ezsat/ezminisat.cc6
-rw-r--r--libs/minisat/00_PATCH_no_fpu_control.patch43
-rw-r--r--libs/minisat/00_PATCH_remove_zlib.patch17
-rw-r--r--libs/minisat/00_PATCH_typofixes.patch20
-rwxr-xr-x[-rw-r--r--]libs/minisat/00_UPDATE.sh6
-rw-r--r--libs/minisat/Dimacs.h8
-rw-r--r--libs/minisat/Options.cc4
-rw-r--r--libs/minisat/SimpSolver.cc4
-rw-r--r--libs/minisat/Solver.cc4
-rw-r--r--libs/minisat/System.cc15
-rw-r--r--libs/minisat/System.h7
-rw-r--r--libs/subcircuit/subcircuit.h2
-rw-r--r--manual/CHAPTER_CellLib.tex6
-rw-r--r--manual/CHAPTER_Prog/stubnets.cc2
-rw-r--r--manual/PRESENTATION_Prog/my_cmd.cc6
-rwxr-xr-xmanual/clean.sh2
-rw-r--r--misc/yosys.proto175
-rw-r--r--passes/cmds/Makefile.inc4
-rw-r--r--passes/cmds/add.cc4
-rw-r--r--passes/cmds/blackbox.cc81
-rw-r--r--passes/cmds/check.cc89
-rw-r--r--passes/cmds/chformal.cc282
-rw-r--r--passes/cmds/chtype.cc83
-rw-r--r--passes/cmds/connect.cc4
-rw-r--r--passes/cmds/connwrappers.cc6
-rw-r--r--passes/cmds/copy.cc4
-rw-r--r--passes/cmds/cover.cc6
-rw-r--r--passes/cmds/delete.cc4
-rw-r--r--passes/cmds/design.cc142
-rw-r--r--passes/cmds/edgetypes.cc4
-rw-r--r--passes/cmds/logcmd.cc4
-rw-r--r--passes/cmds/ltp.cc185
-rw-r--r--passes/cmds/plugin.cc4
-rw-r--r--passes/cmds/qwp.cc5
-rw-r--r--passes/cmds/rename.cc4
-rw-r--r--passes/cmds/scatter.cc4
-rw-r--r--passes/cmds/scc.cc78
-rw-r--r--passes/cmds/select.cc59
-rw-r--r--passes/cmds/setattr.cc12
-rw-r--r--passes/cmds/setundef.cc263
-rw-r--r--passes/cmds/show.cc36
-rw-r--r--passes/cmds/splice.cc4
-rw-r--r--passes/cmds/splitnets.cc14
-rw-r--r--passes/cmds/stat.cc15
-rw-r--r--passes/cmds/tee.cc5
-rw-r--r--passes/cmds/torder.cc4
-rw-r--r--passes/cmds/trace.cc17
-rw-r--r--passes/cmds/write_file.cc5
-rw-r--r--passes/equiv/equiv_add.cc4
-rw-r--r--passes/equiv/equiv_induct.cc4
-rw-r--r--passes/equiv/equiv_make.cc8
-rw-r--r--passes/equiv/equiv_mark.cc4
-rw-r--r--passes/equiv/equiv_miter.cc4
-rw-r--r--passes/equiv/equiv_purge.cc8
-rw-r--r--passes/equiv/equiv_remove.cc4
-rw-r--r--passes/equiv/equiv_simple.cc59
-rw-r--r--passes/equiv/equiv_status.cc4
-rw-r--r--passes/equiv/equiv_struct.cc4
-rw-r--r--passes/fsm/fsm.cc4
-rw-r--r--passes/fsm/fsm_detect.cc8
-rw-r--r--passes/fsm/fsm_expand.cc34
-rw-r--r--passes/fsm/fsm_export.cc4
-rw-r--r--passes/fsm/fsm_extract.cc4
-rw-r--r--passes/fsm/fsm_info.cc4
-rw-r--r--passes/fsm/fsm_map.cc7
-rw-r--r--passes/fsm/fsm_opt.cc4
-rw-r--r--passes/fsm/fsm_recode.cc4
-rw-r--r--passes/hierarchy/Makefile.inc2
-rw-r--r--passes/hierarchy/hierarchy.cc164
-rw-r--r--passes/hierarchy/submod.cc5
-rw-r--r--passes/hierarchy/uniquify.cc (renamed from passes/hierarchy/singleton.cc)43
-rw-r--r--passes/memory/Makefile.inc1
-rw-r--r--passes/memory/memory.cc4
-rw-r--r--passes/memory/memory_bram.cc4
-rw-r--r--passes/memory/memory_collect.cc4
-rw-r--r--passes/memory/memory_dff.cc24
-rw-r--r--passes/memory/memory_map.cc4
-rw-r--r--passes/memory/memory_memx.cc4
-rw-r--r--passes/memory/memory_nordff.cc121
-rw-r--r--passes/memory/memory_share.cc4
-rw-r--r--passes/memory/memory_unpack.cc4
-rw-r--r--passes/opt/Makefile.inc2
-rw-r--r--passes/opt/opt.cc4
-rw-r--r--passes/opt/opt_clean.cc107
-rw-r--r--passes/opt/opt_demorgan.cc202
-rw-r--r--passes/opt/opt_expr.cc315
-rw-r--r--passes/opt/opt_merge.cc19
-rw-r--r--passes/opt/opt_muxtree.cc4
-rw-r--r--passes/opt/opt_reduce.cc4
-rw-r--r--passes/opt/opt_rmdff.cc246
-rw-r--r--passes/opt/rmports.cc187
-rw-r--r--passes/opt/share.cc4
-rw-r--r--passes/opt/wreduce.cc4
-rw-r--r--passes/proc/proc.cc4
-rw-r--r--passes/proc/proc_arst.cc4
-rw-r--r--passes/proc/proc_clean.cc4
-rw-r--r--passes/proc/proc_dff.cc9
-rw-r--r--passes/proc/proc_dlatch.cc20
-rw-r--r--passes/proc/proc_init.cc4
-rw-r--r--passes/proc/proc_mux.cc4
-rw-r--r--passes/proc/proc_rmdead.cc4
-rw-r--r--passes/sat/Makefile.inc2
-rw-r--r--passes/sat/assertpmux.cc4
-rw-r--r--passes/sat/async2sync.cc147
-rw-r--r--passes/sat/clk2fflogic.cc114
-rw-r--r--passes/sat/eval.cc4
-rw-r--r--passes/sat/expose.cc55
-rw-r--r--passes/sat/freduce.cc7
-rw-r--r--passes/sat/miter.cc4
-rw-r--r--passes/sat/sat.cc5
-rw-r--r--passes/sat/sim.cc862
-rw-r--r--passes/techmap/Makefile.inc5
-rw-r--r--passes/techmap/abc.cc612
-rw-r--r--passes/techmap/aigmap.cc4
-rw-r--r--passes/techmap/alumacc.cc19
-rw-r--r--passes/techmap/attrmap.cc12
-rw-r--r--passes/techmap/attrmvcp.cc4
-rw-r--r--passes/techmap/deminout.cc36
-rw-r--r--passes/techmap/dff2dffe.cc18
-rw-r--r--passes/techmap/dff2dffs.cc142
-rw-r--r--passes/techmap/dffinit.cc24
-rw-r--r--passes/techmap/dfflibmap.cc12
-rw-r--r--passes/techmap/dffsr2dff.cc4
-rw-r--r--passes/techmap/extract.cc4
-rw-r--r--passes/techmap/extract_counter.cc (renamed from techlibs/greenpak4/greenpak4_counters.cc)425
-rw-r--r--passes/techmap/extract_fa.cc605
-rw-r--r--passes/techmap/extract_reduce.cc324
-rw-r--r--passes/techmap/hilomap.cc4
-rw-r--r--passes/techmap/insbuf.cc4
-rw-r--r--passes/techmap/iopadmap.cc61
-rw-r--r--passes/techmap/libparse.cc24
-rw-r--r--passes/techmap/lut2mux.cc4
-rw-r--r--passes/techmap/maccmap.cc4
-rw-r--r--passes/techmap/muxcover.cc4
-rw-r--r--passes/techmap/nlutmap.cc6
-rw-r--r--passes/techmap/pmuxtree.cc4
-rw-r--r--passes/techmap/shregmap.cc4
-rw-r--r--passes/techmap/simplemap.cc4
-rw-r--r--passes/techmap/techmap.cc45
-rw-r--r--passes/techmap/tribuf.cc4
-rw-r--r--passes/techmap/zinit.cc4
-rw-r--r--passes/tests/test_abcloop.cc4
-rw-r--r--passes/tests/test_autotb.cc4
-rw-r--r--passes/tests/test_cell.cc6
-rwxr-xr-xtechlibs/achronix/Makefile.inc6
-rwxr-xr-xtechlibs/achronix/speedster22i/cells_arith.v65
-rwxr-xr-xtechlibs/achronix/speedster22i/cells_map.v72
-rwxr-xr-xtechlibs/achronix/speedster22i/cells_sim.v80
-rwxr-xr-xtechlibs/achronix/synth_achronix.cc188
-rw-r--r--techlibs/common/Makefile.inc1
-rw-r--r--techlibs/common/dff2ff.v14
-rw-r--r--techlibs/common/prep.cc32
-rw-r--r--techlibs/common/simcells.v38
-rw-r--r--techlibs/common/simlib.v48
-rw-r--r--techlibs/common/synth.cc21
-rw-r--r--techlibs/coolrunner2/Makefile.inc8
-rw-r--r--techlibs/coolrunner2/cells_latch.v19
-rw-r--r--techlibs/coolrunner2/cells_sim.v310
-rw-r--r--techlibs/coolrunner2/coolrunner2_sop.cc320
-rw-r--r--techlibs/coolrunner2/synth_coolrunner2.cc202
-rw-r--r--techlibs/coolrunner2/tff_extract.v41
-rw-r--r--techlibs/coolrunner2/xc2_dff.lib31
-rw-r--r--techlibs/easic/Makefile.inc3
-rw-r--r--techlibs/easic/synth_easic.cc188
-rw-r--r--techlibs/ecp5/Makefile.inc8
-rw-r--r--techlibs/ecp5/arith_map.v79
-rw-r--r--techlibs/ecp5/cells_map.v135
-rw-r--r--techlibs/ecp5/cells_sim.v448
-rw-r--r--techlibs/ecp5/dram.txt16
-rw-r--r--techlibs/ecp5/drams_map.v28
-rw-r--r--techlibs/ecp5/synth_ecp5.cc331
-rw-r--r--techlibs/gowin/cells_sim.v48
-rw-r--r--techlibs/gowin/synth_gowin.cc10
-rw-r--r--techlibs/greenpak4/Makefile.inc6
-rw-r--r--techlibs/greenpak4/cells_blackbox.v18
-rw-r--r--techlibs/greenpak4/cells_latch.v15
-rw-r--r--techlibs/greenpak4/cells_map.v165
-rw-r--r--techlibs/greenpak4/cells_sim.v462
-rw-r--r--techlibs/greenpak4/cells_sim_ams.v110
-rw-r--r--techlibs/greenpak4/cells_sim_digital.v794
-rw-r--r--techlibs/greenpak4/cells_sim_wip.v136
-rw-r--r--techlibs/greenpak4/greenpak4_dffinv.cc25
-rw-r--r--techlibs/greenpak4/synth_greenpak4.cc15
-rw-r--r--techlibs/ice40/cells_map.v2
-rw-r--r--techlibs/ice40/cells_sim.v436
-rw-r--r--techlibs/ice40/ice40_ffinit.cc4
-rw-r--r--techlibs/ice40/ice40_ffssr.cc4
-rw-r--r--techlibs/ice40/ice40_opt.cc38
-rw-r--r--techlibs/ice40/synth_ice40.cc74
-rw-r--r--techlibs/intel/Makefile.inc24
-rw-r--r--techlibs/intel/a10gx/cells_arith.v65
-rw-r--r--techlibs/intel/a10gx/cells_map.v53
-rw-r--r--techlibs/intel/a10gx/cells_sim.v59
-rw-r--r--techlibs/intel/common/altpll_bb.v366
-rw-r--r--techlibs/intel/common/brams.txt33
-rw-r--r--techlibs/intel/common/brams_map.v93
-rw-r--r--techlibs/intel/common/m9k_bb.v70
-rw-r--r--techlibs/intel/cyclone10/cells_arith.v65
-rw-r--r--techlibs/intel/cyclone10/cells_map.v109
-rw-r--r--techlibs/intel/cyclone10/cells_sim.v137
-rw-r--r--techlibs/intel/cycloneiv/cells_arith.v97
-rw-r--r--techlibs/intel/cycloneiv/cells_map.v93
-rw-r--r--techlibs/intel/cycloneiv/cells_sim.v299
-rw-r--r--techlibs/intel/cycloneive/arith_map.v99
-rw-r--r--techlibs/intel/cycloneive/cells_map.v109
-rw-r--r--techlibs/intel/cycloneive/cells_sim.v292
-rw-r--r--techlibs/intel/cyclonev/cells_arith.v65
-rw-r--r--techlibs/intel/cyclonev/cells_map.v162
-rw-r--r--techlibs/intel/cyclonev/cells_sim.v144
-rw-r--r--techlibs/intel/max10/cells_arith.v65
-rw-r--r--techlibs/intel/max10/cells_map.v93
-rw-r--r--techlibs/intel/max10/cells_sim.v292
-rw-r--r--techlibs/intel/synth_intel.cc270
-rw-r--r--techlibs/xilinx/Makefile.inc2
-rw-r--r--techlibs/xilinx/brams_init.py16
-rw-r--r--techlibs/xilinx/cells_map.v2
-rw-r--r--techlibs/xilinx/cells_sim.v30
-rw-r--r--techlibs/xilinx/drams_bb.v20
-rw-r--r--techlibs/xilinx/lut2lut.v65
-rw-r--r--techlibs/xilinx/synth_xilinx.cc43
-rw-r--r--tests/sat/sizebits.sv32
-rw-r--r--tests/sat/sizebits.ys2
-rw-r--r--tests/simple/arraycells.v2
-rw-r--r--tests/simple/graphtest.v2
-rw-r--r--tests/simple/hierdefparam.v23
-rw-r--r--tests/simple/specify.v31
-rw-r--r--tests/sva/.gitignore7
-rw-r--r--tests/sva/Makefile13
-rw-r--r--tests/sva/basic00.sv12
-rw-r--r--tests/sva/basic01.sv16
-rw-r--r--tests/sva/basic02.sv20
-rw-r--r--tests/sva/basic03.sv12
-rw-r--r--tests/sva/basic04.sv10
-rw-r--r--tests/sva/basic04.vhd26
-rw-r--r--tests/sva/basic05.sv19
-rw-r--r--tests/sva/basic05.vhd26
-rw-r--r--tests/sva/counter.sv30
-rw-r--r--tests/sva/runtest.sh72
-rw-r--r--tests/sva/sva_not.sv34
-rw-r--r--tests/sva/sva_range.sv19
-rw-r--r--tests/sva/sva_throughout.sv19
-rwxr-xr-xtests/tools/autotest.sh4
-rw-r--r--tests/unit/Makefile35
-rw-r--r--tests/unit/kernel/logTest.cc14
-rw-r--r--tests/unit/kernel/rtlilTest.cc14
-rw-r--r--tests/various/reg_wire_error.sv74
-rw-r--r--tests/various/reg_wire_error.ys1
388 files changed, 29857 insertions, 4431 deletions
diff --git a/.github/issue_template.md b/.github/issue_template.md
new file mode 100644
index 00000000..24e91a4e
--- /dev/null
+++ b/.github/issue_template.md
@@ -0,0 +1,16 @@
+## Steps to reproduce the issue
+
+*Provide instructions for reproducing the issue. Make sure to include
+all neccessary source files. (You can simply drag&drop a .zip file into
+the issue editor.)*
+
+## Expected behavior
+
+*Please describe the behavior you would have expected from the tool.*
+
+## Actual behavior
+
+*Please describe how the behavior you see differs from the expected behavior.*
+
+**Important Note:** Nobody will be able to help you and/or fix the issue if you
+do not provide sufficient information for reproducing the problem.
diff --git a/.gitignore b/.gitignore
index 93e28cd6..48ce458c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,9 @@
*.o
*.d
.*.swp
+*.gch
+*.gcda
+*.gcno
/.cproject
/.project
/.settings
@@ -9,6 +12,8 @@
/qtcreator.config
/qtcreator.creator
/qtcreator.creator.user
+/coverage.info
+/coverage_html
/Makefile.conf
/abc
/viz.js
@@ -27,3 +32,6 @@
/yosys-win32-vcxsrc-*
/yosysjs-*
/libyosys.so
+/tests/unit/bintest/
+/tests/unit/objtest/
+/tests/ystests
diff --git a/.travis.yml b/.travis.yml
index 9f0cc06e..321c3325 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,34 +1,148 @@
sudo: false
-script: make && make test
language: cpp
-addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - gperf
- - build-essential
- - clang
- - bison
- - flex
- - libreadline-dev
- - gawk
- - tcl-dev
- - libffi-dev
- - git
- - mercurial
- - graphviz
- - xdot
- - pkg-config
- - python
- - g++-4.8
+
+cache:
+ ccache: true
+ directories:
+ - ~/.local-bin
+
+
+env:
+ global:
+ - MAKEFLAGS="-j 2"
+
+matrix:
+ include:
+ # Latest gcc-4.8, earliest version supported by Travis
+ - os: linux
+ addons:
+ apt:
+ packages:
+ - g++-4.8
+ - gperf
+ - build-essential
+ - bison
+ - flex
+ - libreadline-dev
+ - gawk
+ - tcl-dev
+ - libffi-dev
+ - git
+ - graphviz
+ - xdot
+ - pkg-config
+ - python
+ env:
+ - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8"
+
+ # Latest gcc-6 on Travis Linux
+ - os: linux
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - g++-6
+ - gperf
+ - build-essential
+ - bison
+ - flex
+ - libreadline-dev
+ - gawk
+ - tcl-dev
+ - libffi-dev
+ - git
+ - graphviz
+ - xdot
+ - pkg-config
+ - python
+ env:
+ - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6"
+
+ # Latest gcc supported on Travis Linux
+ - os: linux
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - g++-7
+ - gperf
+ - build-essential
+ - bison
+ - flex
+ - libreadline-dev
+ - gawk
+ - tcl-dev
+ - libffi-dev
+ - git
+ - graphviz
+ - xdot
+ - pkg-config
+ - python
+ env:
+ - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
+
+ # Clang which ships on Trusty Linux
+ - os: linux
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.8
+ packages:
+ - clang-3.8
+ - gperf
+ - build-essential
+ - bison
+ - flex
+ - libreadline-dev
+ - gawk
+ - tcl-dev
+ - libffi-dev
+ - git
+ - graphviz
+ - xdot
+ - pkg-config
+ - python
+ env:
+ - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8"
+
+ # Latest clang supported by Travis Linux
+ - os: linux
+ addons:
+ apt:
+ sources:
+ - llvm-toolchain-trusty-5.0
+ packages:
+ - clang-5.0
+ - gperf
+ - build-essential
+ - bison
+ - flex
+ - libreadline-dev
+ - gawk
+ - tcl-dev
+ - libffi-dev
+ - git
+ - graphviz
+ - xdot
+ - pkg-config
+ - python
+ env:
+ - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"
+
+ # Latest clang on Mac OS X
+ - os: osx
+ osx_image: xcode8
+ env:
+ - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
+
before_install:
- - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
- - git clone git://github.com/steveicarus/iverilog.git
- - (cd iverilog && autoconf && ./configure --prefix=$HOME/iverilog && make && make install)
- - export PATH=$PATH:$HOME/iverilog/bin
-compiler:
-# - clang
- - gcc
-os:
- - linux
+ - ./.travis/setup.sh
+
+script:
+ - ./.travis/build-and-test.sh
+
+after_success:
+ - ./.travis/deploy-after-success.sh
diff --git a/.travis/build-and-test.sh b/.travis/build-and-test.sh
new file mode 100755
index 00000000..096dde64
--- /dev/null
+++ b/.travis/build-and-test.sh
@@ -0,0 +1,49 @@
+#! /bin/bash
+
+set -e
+
+source .travis/common.sh
+
+##########################################################################
+
+echo
+echo 'Configuring...' && echo -en 'travis_fold:start:script.configure\\r'
+echo
+
+if [ "$CONFIG" = "gcc" ]; then
+ echo "Configuring for gcc."
+ make config-gcc
+elif [ "$CONFIG" = "clang" ]; then
+ echo "Configuring for clang."
+ make config-clang
+fi
+
+echo
+echo -en 'travis_fold:end:script.configure\\r'
+echo
+
+##########################################################################
+
+echo
+echo 'Building...' && echo -en 'travis_fold:start:script.build\\r'
+echo
+
+make
+
+echo
+echo -en 'travis_fold:end:script.build\\r'
+echo
+
+##########################################################################
+
+echo
+echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r'
+echo
+
+make test
+
+echo
+echo -en 'travis_fold:end:script.test\\r'
+echo
+
+##########################################################################
diff --git a/.travis/common.sh b/.travis/common.sh
new file mode 100644
index 00000000..8eecc4c0
--- /dev/null
+++ b/.travis/common.sh
@@ -0,0 +1,15 @@
+#! /bin/bash
+
+# Setup the CC / CXX from the matrix config
+eval "${MATRIX_EVAL}"
+
+# Look for location binaries first
+export PATH="$HOME/.local-bin/bin:$PATH"
+
+# OS X specific common setup
+if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+ export PATH="/usr/local/opt/ccache/libexec:$PATH"
+fi
+
+# Parallel builds!
+MAKEFLAGS="-j 2"
diff --git a/.travis/deploy-after-success.sh b/.travis/deploy-after-success.sh
new file mode 100755
index 00000000..d64e9524
--- /dev/null
+++ b/.travis/deploy-after-success.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+set -x
+set -e
+
+# FIXME: Upload the build results somewhere...
diff --git a/.travis/setup.sh b/.travis/setup.sh
new file mode 100755
index 00000000..06851578
--- /dev/null
+++ b/.travis/setup.sh
@@ -0,0 +1,97 @@
+#! /bin/bash
+
+set -e
+
+source .travis/common.sh
+
+##########################################################################
+
+# Fixing Travis's git clone
+echo
+echo 'Fixing git setup...' && echo -en 'travis_fold:start:before_install.git\\r'
+echo
+git fetch --unshallow && git fetch --tags
+
+# For pull requests, we get more info about the git source.
+if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
+ echo "- Fetching from pull request source"
+ git remote add source https://github.com/$TRAVIS_PULL_REQUEST_SLUG.git
+ git fetch source && git fetch --tags
+
+ echo "- Fetching the actual pull request"
+ git fetch origin pull/$TRAVIS_PULL_REQUEST/head:pull-$TRAVIS_PULL_REQUEST-head
+ git fetch origin pull/$TRAVIS_PULL_REQUEST/merge:pull-$TRAVIS_PULL_REQUEST-merge
+
+ git log -n 5 --graph pull-$TRAVIS_PULL_REQUEST-merge
+fi
+
+# For building branches we need to fix the "detached head" state.
+if [ z"$TRAVIS_BRANCH" != z ]; then
+ TRAVIS_COMMIT_ACTUAL=$(git log --pretty=format:'%H' -n 1)
+ echo "- Fixing detached head (current $TRAVIS_COMMIT_ACTUAL -> $TRAVIS_COMMIT)"
+ git remote -v
+ git branch -v
+ if [ x"$(git show-ref -s HEAD)" = x"$TRAVIS_COMMIT" ]; then
+ echo "Checked out at $TRAVIS_COMMIT"
+ else
+ if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
+ git fetch source $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from source"
+ fi
+ git fetch origin $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from origin"
+ fi
+ git branch -D $TRAVIS_BRANCH || true
+ git checkout $TRAVIS_COMMIT -b $TRAVIS_BRANCH
+ git branch -v
+fi
+
+# Output status information.
+git status
+git describe --tags
+git log -n 5 --graph
+echo
+echo -en 'travis_fold:end:before_install.git\\r'
+echo
+
+##########################################################################
+
+# Mac OS X specific setup.
+if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+ (
+ echo
+ echo 'Setting up brew...' && echo -en 'travis_fold:start:before_install.brew\\r'
+ echo
+ brew update
+ brew tap Homebrew/bundle
+ brew bundle
+ brew install ccache
+ brew install gcc@7
+ echo
+ echo -en 'travis_fold:end:before_install.brew\\r'
+ echo
+ )
+fi
+
+##########################################################################
+
+# Install iverilog
+(
+ if [ ! -e ~/.local-bin/bin/iverilog ]; then
+ echo
+ echo 'Building iverilog...' && echo -en 'travis_fold:start:before_install.iverilog\\r'
+ echo
+ mkdir -p ~/.local-src
+ mkdir -p ~/.local-bin
+ cd ~/.local-src
+ git clone git://github.com/steveicarus/iverilog.git
+ cd iverilog
+ autoconf
+ ./configure --prefix=$HOME/.local-bin
+ make
+ make install
+ echo
+ echo -en 'travis_fold:end:before_install.iverilog\\r'
+ echo
+ fi
+)
+
+##########################################################################
diff --git a/Brewfile b/Brewfile
new file mode 100644
index 00000000..0c58ce16
--- /dev/null
+++ b/Brewfile
@@ -0,0 +1,8 @@
+brew "bison"
+brew "flex"
+brew "gawk"
+brew "libffi"
+brew "git"
+brew "graphviz"
+brew "pkg-config"
+brew "python3"
diff --git a/CHANGELOG b/CHANGELOG
index bfea999a..01c78ab3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,19 @@ List of major changes and improvements between releases
=======================================================
+Yosys 0.7 .. Yosys ???
+----------------------
+
+ * MAX10 and Cyclone IV Support
+ - Added initial version of metacommand "synth_intel".
+ - Improved write_verilog command to produce VQM netlist for Quartus Prime.
+ - Added support for MAX10 FPGA family synthesis.
+ - Added support for Cyclone IV family synthesis.
+ - Added example of implementation for DE2i-150 board.
+ - Added example of implementation for MAX10 development kit.
+ - Added LFSR example from Asic World.
+
+
Yosys 0.6 .. Yosys 0.7
----------------------
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..a01b7b69
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,13 @@
+Copyright (C) 2012 - 2017 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.
diff --git a/CodingReadme b/CodingReadme
index cbe1fb8b..b64e7917 100644
--- a/CodingReadme
+++ b/CodingReadme
@@ -21,7 +21,7 @@ Here is a the C++ code for a "hello_world" Yosys command (hello.cc):
struct HelloWorldPass : public Pass {
HelloWorldPass() : Pass("hello_world") { }
- virtual void execute(vector<string>, Design*) {
+ void execute(vector<string>, Design*) override {
log("Hello World!\n");
}
} HelloWorldPass;
@@ -373,6 +373,7 @@ Finally run all tests with "make config-{clang,gcc,gcc-4.8}":
cd ~yosys
make clean
make test
+ make ystests
make vloghtb
make install
@@ -411,3 +412,98 @@ Updating the website:
git commit -am update
make push
+
+
+Cross-Building for Windows with MXE
+===================================
+
+Check http://mxe.cc/#requirements and install all missing requirements.
+
+As root (or other user with write access to /usr/local/src):
+
+ cd /usr/local/src
+ git clone https://github.com/mxe/mxe.git
+ cd mxe
+
+ make -j$(nproc) MXE_PLUGIN_DIRS="plugins/tcl.tk" \
+ MXE_TARGETS="i686-w64-mingw32.static" \
+ gcc tcl readline
+
+Then as regular user in some directory where you build stuff:
+
+ git clone https://github.com/cliffordwolf/yosys.git yosys-win32
+ cd yosys-win32
+ make config-mxe
+ make -j$(nproc) mxebin
+
+
+
+How to add unit test
+====================
+
+Unit test brings some advantages, briefly, we can list some of them (reference
+[1](https://en.wikipedia.org/wiki/Unit_testing)):
+
+* Tests reduce bugs in new features;
+* Tests reduce bugs in existing features;
+* Tests are good documentation;
+* Tests reduce the cost of change;
+* Tests allow refactoring;
+
+With those advantages in mind, it was required to choose a framework which fits
+well with C/C++ code. Hence, it was chosen (google test)
+[https://github.com/google/googletest], because it is largely used and it is
+relatively easy learn.
+
+Install and configure google test (manually)
+--------------------------------------------
+
+In this section, you will see a brief description of how to install google
+test. However, it is strongly recommended that you take a look to the official
+repository (https://github.com/google/googletest) and refers to that if you
+have any problem to install it. Follow the steps below:
+
+* Install: cmake and pthread
+* Clone google test project from: https://github.com/google/googletest and
+ enter in the project directory
+* Inside project directory, type:
+
+```
+cmake -DBUILD_SHARED_LIBS=ON .
+make
+```
+
+* After compilation, copy all "*.so" inside directory "googlemock" and
+ "googlemock/gtest" to "/usr/lib/"
+* Done! Now you can compile your tests.
+
+If you have any problem, go to the official repository to find help.
+
+Ps.: Some distros already have googletest packed. If your distro supports it,
+you can use it instead of compile.
+
+Create new unit test
+--------------------
+
+If you want to add new unit tests for Yosys, just follow the steps below:
+
+* Go to directory "yosys/test/unit/"
+* In this directory you can find something similar Yosys's directory structure.
+ To create your unit test file you have to follow this pattern:
+ fileNameToImplementUnitTest + Test.cc. E.g.: if you want to implement the
+ unit test for kernel/celledges.cc, you will need to create a file like this:
+ tests/unit/kernel/celledgesTest.cc;
+* Implement your unit test
+
+Run unit test
+-------------
+
+To compile and run all unit tests, just go to yosys root directory and type:
+```
+make unit-test
+```
+
+If you want to remove all unit test files, type:
+```
+make clean-unit-test
+```
diff --git a/Makefile b/Makefile
index 0a61fe65..7698047e 100644
--- a/Makefile
+++ b/Makefile
@@ -5,19 +5,29 @@ CONFIG := clang
# CONFIG := emcc
# CONFIG := mxe
# CONFIG := msys2
+# CONFIG := msys2-64
# features (the more the better)
ENABLE_TCL := 1
ENABLE_ABC := 1
ENABLE_PLUGINS := 1
ENABLE_READLINE := 1
+ENABLE_EDITLINE := 0
ENABLE_VERIFIC := 0
ENABLE_COVER := 1
ENABLE_LIBYOSYS := 0
+ENABLE_PROTOBUF := 0
# other configuration flags
+ENABLE_GCOV := 0
ENABLE_GPROF := 0
+ENABLE_DEBUG := 0
ENABLE_NDEBUG := 0
+LINK_CURSES := 0
+LINK_TERMCAP := 0
+LINK_ABC := 0
+# Needed for environments that don't have proper thread support (i.e. emscripten)
+DISABLE_ABC_THREADS := 0
# clang sanitizers
SANITIZER =
@@ -27,6 +37,7 @@ SANITIZER =
# SANITIZER = cfi
+OS := $(shell uname -s)
PREFIX ?= /usr/local
INSTALL_SUDO :=
@@ -44,35 +55,51 @@ TARGETS = yosys$(EXE) yosys-config
PRETTY = 1
SMALL = 0
+# Unit test
+UNITESTPATH := tests/unit
+
all: top-all
YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST)))
VPATH := $(YOSYS_SRC)
-CXXFLAGS += -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include
-LDFLAGS += -L$(LIBDIR)
-LDLIBS = -lstdc++ -lm
-
-PKG_CONFIG = pkg-config
-SED = sed
-BISON = bison
-
-ifeq (Darwin,$(findstring Darwin,$(shell uname)))
- # 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 = sed
+CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include
+LDFLAGS := $(LDFLAGS) -L$(LIBDIR)
+LDLIBS := $(LDLIBS) -lstdc++ -lm
+PLUGIN_LDFLAGS :=
+
+PKG_CONFIG ?= pkg-config
+SED ?= sed
+BISON ?= bison
+STRIP ?= strip
+
+ifeq ($(OS), Darwin)
+PLUGIN_LDFLAGS += -undefined dynamic_lookup
+
+# homebrew search paths
+ifneq ($(shell which brew),)
+BREW_PREFIX := $(shell brew --prefix)/opt
+CXXFLAGS += -I$(BREW_PREFIX)/readline/include
+LDFLAGS += -L$(BREW_PREFIX)/readline/lib
+PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
+PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH)
+export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH)
+
+# macports search paths
+else ifneq ($(shell which port),)
+PORT_PREFIX := $(patsubst %/bin/port,%,$(shell which port))
+CXXFLAGS += -I$(PORT_PREFIX)/include
+LDFLAGS += -L$(PORT_PREFIX)/lib
+PKG_CONFIG_PATH := $(PORT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH)
+export PATH := $(PORT_PREFIX)/bin:$(PATH)
+endif
+
else
- LDFLAGS += -rdynamic
- LDLIBS += -lrt
+LDFLAGS += -rdynamic
+LDLIBS += -lrt
endif
-YOSYS_VER := 0.7
+YOSYS_VER := 0.7+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 61f6811.. | wc -l; })
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
@@ -82,10 +109,10 @@ 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 = eb6eca6807cc
+ABCREV = ae6716b
ABCPULL = 1
-ABCURL ?= https://bitbucket.org/alanmi/abc
-ABCMKARGS = CC="$(CXX)" CXX="$(CXX)"
+ABCURL ?= https://github.com/berkeley-abc/abc
+ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
# set ABCEXTERNAL = <abc-command> to use an external ABC instance
# Note: The in-tree ABC (yosys-abc) will not be installed when ABCEXTERNAL is set.
@@ -105,6 +132,7 @@ ifeq ($(CONFIG),clang)
CXX = clang
LD = clang++
CXXFLAGS += -std=c++11 -Os
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
ifneq ($(SANITIZER),)
$(info [Clang Sanitizer] $(SANITIZER))
@@ -127,16 +155,31 @@ else ifeq ($(CONFIG),gcc)
CXX = gcc
LD = gcc
CXXFLAGS += -std=c++11 -Os
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
+
+else ifeq ($(CONFIG),gcc-static)
+LD = $(CXX)
+LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -static
+LDLIBS := $(filter-out -lrt,$(LDLIBS))
+CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
+CXXFLAGS += -std=c++11 -Os
+ABCMKARGS = CC="$(CC)" CXX="$(CXX)" LD="$(LD)" ABC_USE_LIBSTDCXX=1 LIBS="-lm -lpthread -static" OPTFLAGS="-O" \
+ ARCHFLAGS="-DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING=1 -Wno-unused-but-set-variable $(ARCHFLAGS)" ABC_USE_NO_READLINE=1
+ifeq ($(DISABLE_ABC_THREADS),1)
+ABCMKARGS += "ABC_USE_NO_PTHREADS=1"
+endif
else ifeq ($(CONFIG),gcc-4.8)
CXX = gcc-4.8
LD = gcc-4.8
CXXFLAGS += -std=c++11 -Os
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
else ifeq ($(CONFIG),emcc)
CXX = emcc
LD = emcc
CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS))
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8"
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']"
@@ -150,6 +193,11 @@ EXE = .js
TARGETS := $(filter-out yosys-config,$(TARGETS))
EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip
+ifeq ($(ENABLE_ABC),1)
+LINK_ABC := 1
+DISABLE_ABC_THREADS := 1
+endif
+
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
@@ -164,29 +212,41 @@ yosys.html: misc/yosys.html
$(P) cp misc/yosys.html yosys.html
else ifeq ($(CONFIG),mxe)
-CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
-LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
-CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE
+PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config
+CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++
+LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++
+CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes
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 -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w"
-ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="$(CXX)" CXX="$(CXX)"
+ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
+ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
EXE = .exe
else ifeq ($(CONFIG),msys2)
-CXX = i686-w64-mingw32-gcc
-LD = i686-w64-mingw32-gcc
+CXX = i686-w64-mingw32-g++
+LD = i686-w64-mingw32-g++
CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
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 -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w"
-ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 CC="$(CXX)" CXX="$(CXX)"
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
+ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)"
+EXE = .exe
+
+else ifeq ($(CONFIG),msys2-64)
+CXX = x86_64-w64-mingw32-g++
+LD = x86_64-w64-mingw32-g++
+CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
+CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
+LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
+LDLIBS := $(filter-out -lrt,$(LDLIBS))
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
+ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)"
EXE = .exe
else ifneq ($(CONFIG),none)
-$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2)
+$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2, msys2-64)
endif
ifeq ($(ENABLE_LIBYOSYS),1)
@@ -195,22 +255,67 @@ endif
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
+ifeq ($(OS), FreeBSD)
+CXXFLAGS += -I/usr/local/include
+endif
LDLIBS += -lreadline
+ifeq ($(LINK_CURSES),1)
+LDLIBS += -lcurses
+ABCMKARGS += "ABC_READLINE_LIBRARIES=-lcurses -lreadline"
+endif
+ifeq ($(LINK_TERMCAP),1)
+LDLIBS += -ltermcap
+ABCMKARGS += "ABC_READLINE_LIBRARIES=-lreadline -ltermcap"
+endif
ifeq ($(CONFIG),mxe)
-LDLIBS += -lpdcurses
+LDLIBS += -ltermcap
+endif
+else
+ifeq ($(ENABLE_EDITLINE),1)
+CXXFLAGS += -DYOSYS_ENABLE_EDITLINE
+LDLIBS += -ledit -ltinfo -lbsd
+else
+ABCMKARGS += "ABC_USE_NO_READLINE=1"
endif
endif
+ifeq ($(DISABLE_ABC_THREADS),1)
+ABCMKARGS += "ABC_USE_NO_PTHREADS=1"
+endif
+
ifeq ($(ENABLE_PLUGINS),1)
-CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell $(PKG_CONFIG) --silence-errors --cflags libffi)
-LDLIBS += $(shell $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ldl
+CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS
+LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi)
+ifneq ($(OS), FreeBSD)
+LDLIBS += -ldl
+endif
endif
ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
+ifeq ($(OS), FreeBSD)
+TCL_INCLUDE ?= /usr/local/include/$(TCL_VERSION)
+else
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
-CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
-LDLIBS += -l$(TCL_VERSION)
+endif
+
+ifeq ($(CONFIG),mxe)
+CXXFLAGS += -DYOSYS_ENABLE_TCL
+LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz
+else
+CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
+ifeq ($(OS), FreeBSD)
+# FreeBSD uses tcl8.6, but lib is named "libtcl86"
+LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION) | tr -d '.')
+else
+LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION))
+endif
+endif
+endif
+
+ifeq ($(ENABLE_GCOV),1)
+CXXFLAGS += --coverage
+LDFLAGS += --coverage
endif
ifeq ($(ENABLE_GPROF),1)
@@ -219,21 +324,40 @@ LDFLAGS += -pg
endif
ifeq ($(ENABLE_NDEBUG),1)
-CXXFLAGS := -O3 -DNDEBUG $(filter-out -Os,$(CXXFLAGS))
+CXXFLAGS := -O3 -DNDEBUG $(filter-out -Os -ggdb,$(CXXFLAGS))
+endif
+
+ifeq ($(ENABLE_DEBUG),1)
+ifeq ($(CONFIG),clang)
+CXXFLAGS := -O0 -DDEBUG $(filter-out -Os,$(CXXFLAGS))
+else
+CXXFLAGS := -Og -DDEBUG $(filter-out -Os,$(CXXFLAGS))
+endif
endif
ifeq ($(ENABLE_ABC),1)
CXXFLAGS += -DYOSYS_ENABLE_ABC
+ifeq ($(LINK_ABC),1)
+CXXFLAGS += -DYOSYS_LINK_ABC
+ifeq ($(DISABLE_ABC_THREADS),0)
+LDLIBS += -lpthread
+endif
+else
ifeq ($(ABCEXTERNAL),)
TARGETS += yosys-abc$(EXE)
endif
endif
+endif
ifeq ($(ENABLE_VERIFIC),1)
VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
-VERIFIC_COMPONENTS ?= verilog vhdl database util containers sdf
+VERIFIC_COMPONENTS ?= verilog vhdl database util containers sdf hier_tree
CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC
-LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS))
+LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -lz
+endif
+
+ifeq ($(ENABLE_PROTOBUF),1)
+LDLIBS += $(shell pkg-config --cflags --libs protobuf)
endif
ifeq ($(ENABLE_COVER),1)
@@ -347,6 +471,10 @@ include techlibs/common/Makefile.inc
endif
+ifeq ($(LINK_ABC),1)
+OBJS += yosys-libabc.a
+endif
+
top-all: $(TARGETS) $(EXTRA_TARGETS)
@echo ""
@echo " Build successful."
@@ -377,35 +505,50 @@ kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile
$(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
$(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; }" > kernel/version_$(GIT_REV).cc
+ifeq ($(ENABLE_VERIFIC),1)
+CXXFLAGS_NOVERIFIC = $(foreach v,$(CXXFLAGS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v)))
+LDLIBS_NOVERIFIC = $(foreach v,$(LDLIBS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v)))
+else
+CXXFLAGS_NOVERIFIC = $(CXXFLAGS)
+LDLIBS_NOVERIFIC = $(LDLIBS)
+endif
+
yosys-config: misc/yosys-config.in
- $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(CXXFLAGS))#;' \
- -e 's#@CXX@#$(CXX)#;' -e 's#@LDFLAGS@#$(LDFLAGS)#;' -e 's#@LDLIBS@#$(LDLIBS)#;' \
- -e 's#@BINDIR@#$(BINDIR)#;' -e 's#@DATDIR@#$(DATDIR)#;' < $< > yosys-config
+ $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC)))#;' \
+ -e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LDFLAGS@#$(strip $(LDFLAGS) $(PLUGIN_LDFLAGS))#;' -e 's#@LDLIBS@#$(strip $(LDLIBS_NOVERIFIC))#;' \
+ -e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > yosys-config
$(Q) chmod +x yosys-config
-abc/abc-$(ABCREV)$(EXE):
+abc/abc-$(ABCREV)$(EXE) abc/libabc-$(ABCREV).a:
$(P)
ifneq ($(ABCREV),default)
- $(Q) if ( cd abc 2> /dev/null && hg identify; ) | grep -q +; then \
+ $(Q) if test -d abc/.hg; then \
+ echo 'REEBE: NOP qverpgbel vf n ut jbexvat pbcl! Erzbir nop/ naq er-eha "znxr".' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
+ fi
+ $(Q) if ( cd abc 2> /dev/null && ! git diff-index --quiet HEAD; ); then \
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi
- $(Q) if test "`cd abc 2> /dev/null && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
+ $(Q) if test "`cd abc 2> /dev/null && git rev-parse --short HEAD`" != "$(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 $(ABCURL):"; set -x; \
- test -d abc || hg clone $(ABCURL) abc; \
- cd abc && $(MAKE) DEP= clean && hg pull && hg update -r $(ABCREV); \
+ test -d abc || git clone $(ABCURL) abc; \
+ cd abc && $(MAKE) DEP= clean && git fetch origin master && git checkout $(ABCREV); \
fi
endif
$(Q) rm -f abc/abc-[0-9a-f]*
- $(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) PROG="abc-$(ABCREV)$(EXE)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: "
+ $(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc-$(ABCREV)",PROG="abc-$(ABCREV)$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc-$(ABCREV).a)
ifeq ($(ABCREV),default)
.PHONY: abc/abc-$(ABCREV)$(EXE)
+.PHONY: abc/libabc-$(ABCREV).a
endif
yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
$(P) cp abc/abc-$(ABCREV)$(EXE) yosys-abc$(EXE)
+yosys-libabc.a: abc/libabc-$(ABCREV).a
+ $(P) cp abc/libabc-$(ABCREV).a yosys-libabc.a
+
ifneq ($(SEED),)
SEEDOPT="-S $(SEED)"
else
@@ -442,18 +585,44 @@ vloghtb: $(TARGETS) $(EXTRA_TARGETS)
@echo " Passed \"make vloghtb\"."
@echo ""
+ystests: $(TARGETS) $(EXTRA_TARGETS)
+ rm -rf tests/ystests
+ git clone https://github.com/YosysHQ/yosys-tests.git tests/ystests
+ +PATH="$$PWD:$$PATH" cd tests/ystests && $(MAKE)
+ @echo ""
+ @echo " Finished \"make ystests\"."
+ @echo ""
+
+# Unit test
+unit-test: libyosys.so
+ @$(MAKE) -C $(UNITESTPATH) CXX="$(CXX)" CPPFLAGS="$(CPPFLAGS)" \
+ CXXFLAGS="$(CXXFLAGS)" LDLIBS="$(LDLIBS)" ROOTPATH="$(CURDIR)"
+
+clean-unit-test:
+ @$(MAKE) -C $(UNITESTPATH) clean
+
install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
- $(INSTALL_SUDO) install $(TARGETS) $(DESTDIR)$(BINDIR)
+ $(INSTALL_SUDO) cp $(TARGETS) $(DESTDIR)$(BINDIR)
+ifneq ($(filter yosys,$(TARGETS)),)
+ $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/yosys
+endif
+ifneq ($(filter yosys-abc,$(TARGETS)),)
+ $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/yosys-abc
+endif
+ifneq ($(filter yosys-filterlib,$(TARGETS)),)
+ $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/yosys-filterlib
+endif
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)
+ $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so
$(INSTALL_SUDO) ldconfig
endif
uninstall:
- $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR),$(notdir $(TARGETS)))
+ $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR)/,$(notdir $(TARGETS)))
$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR)
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so
@@ -471,16 +640,30 @@ clean:
rm -rf share
if test -d manual; then cd manual && sh clean.sh; fi
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
- rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
+ rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
+ rm -rf tests/asicworld/*.out tests/asicworld/*.log
+ rm -rf tests/hana/*.out tests/hana/*.log
+ rm -rf tests/simple/*.out tests/simple/*.log
+ rm -rf tests/memories/*.out tests/memories/*.log tests/memories/*.dmp
+ rm -rf tests/sat/*.log tests/techmap/*.log tests/various/*.log
+ rm -rf tests/bram/temp tests/fsm/temp tests/realmath/temp tests/share/temp tests/smv/temp
+ rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_*
+ rm -f tests/tools/cmp_tbdata
clean-abc:
$(MAKE) -C abc DEP= clean
- rm -f yosys-abc$(EXE) abc/abc-[0-9a-f]*
+ rm -f yosys-abc$(EXE) yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a
mrproper: clean
git clean -xdf
+coverage:
+ ./yosys -qp 'help; help -all'
+ rm -rf coverage.info coverage_html
+ lcov --capture -d . --no-external -o coverage.info
+ genhtml coverage.info --output-directory coverage_html
+
qtcreator:
{ for file in $(basename $(OBJS)); do \
for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \
@@ -520,6 +703,12 @@ config-clang: clean
config-gcc: clean
echo 'CONFIG := gcc' > Makefile.conf
+config-gcc-static: clean
+ echo 'CONFIG := gcc-static' > Makefile.conf
+ echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
+ echo 'ENABLE_READLINE := 0' >> Makefile.conf
+ echo 'ENABLE_TCL := 0' >> Makefile.conf
+
config-gcc-4.8: clean
echo 'CONFIG := gcc-4.8' > Makefile.conf
@@ -532,13 +721,19 @@ config-emcc: clean
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-msys2: clean
echo 'CONFIG := msys2' > Makefile.conf
+config-msys2-64: clean
+ echo 'CONFIG := msys2-64' > Makefile.conf
+
+config-gcov: clean
+ echo 'CONFIG := gcc' > Makefile.conf
+ echo 'ENABLE_GCOV := 1' >> Makefile.conf
+ echo 'ENABLE_DEBUG := 1' >> Makefile.conf
+
config-gprof: clean
echo 'CONFIG := gcc' > Makefile.conf
echo 'ENABLE_GPROF := 1' >> Makefile.conf
@@ -559,6 +754,6 @@ echo-git-rev:
-include kernel/*.d
-include techlibs/*/*.d
-.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator
-.PHONY: config-clean config-clang config-gcc config-gcc-4.8 config-gprof config-sudo
+.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator coverage vcxsrc mxebin
+.PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-gprof config-sudo
diff --git a/README b/README.md
index 8e43d444..424d9bbf 100644
--- a/README
+++ b/README.md
@@ -1,26 +1,23 @@
+```
+yosys -- Yosys Open SYnthesis Suite
- /-----------------------------------------------------------------------------\
- | |
- | yosys -- Yosys Open SYnthesis Suite |
- | |
- | Copyright (C) 2012 - 2016 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. |
- | |
- \-----------------------------------------------------------------------------/
+Copyright (C) 2012 - 2017 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.
-yosys -- Yosys Open SYnthesis Suite
+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.
+```
+
+
+yosys – Yosys Open SYnthesis Suite
===================================
This is a framework for RTL synthesis tools. It currently has
@@ -41,29 +38,40 @@ Web Site
========
More information and documentation can be found on the Yosys web site:
+http://www.clifford.at/yosys/
- http://www.clifford.at/yosys/
-
-
-Getting Started
-===============
+Setup
+======
You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is
recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
-TCL, readline and libffi are optional (see ENABLE_* settings in Makefile).
-Xdot (graphviz) is used by the "show" command in yosys to display schematics.
+TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
+Xdot (graphviz) is used by the ``show`` command in yosys to display schematics.
+
For example on Ubuntu Linux 16.04 LTS the following commands will install all
prerequisites for building yosys:
$ sudo apt-get install build-essential clang bison flex \
- libreadline-dev gawk tcl-dev libffi-dev git mercurial \
+ libreadline-dev gawk tcl-dev libffi-dev git \
graphviz xdot pkg-config python3
+Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies:
+
+ $ brew tap Homebrew/bundle && brew bundle
+ $ sudo port install bison flex readline gawk libffi \
+ git graphviz pkgconfig python36
+
+On FreeBSD use the following command to install all prerequisites:
+
+ # pkg install bison flex readline gawk libffi\
+ git graphviz pkgconfig python3 python36 tcl-wrapper
+
+On FreeBSD system use gmake instead of make. To run tests use:
+ % MAKE=gmake CC=cc gmake test
+
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
+more information: http://www.clifford.at/yosys/download.html
To configure the build system to use a specific compiler, use one of
@@ -74,7 +82,7 @@ For other compilers and build configurations it might be
necessary to make some changes to the config section of the
Makefile.
- $ vi Makefile ..or..
+ $ vi Makefile # ..or..
$ vi Makefile.conf
To build Yosys simply type 'make' in this directory.
@@ -86,6 +94,9 @@ To build Yosys simply type 'make' in this directory.
Note that this also downloads, builds and installs ABC (using yosys-abc
as executable name).
+Getting Started
+===============
+
Yosys can be used with the interactive command shell, with
synthesis scripts or with command line arguments. Let's perform
a simple synthesis job using the interactive command shell:
@@ -93,8 +104,8 @@ a simple synthesis job using the interactive command shell:
$ ./yosys
yosys>
-the command "help" can be used to print a list of all available
-commands and "help <command>" to print details on the specified command:
+the command ``help`` can be used to print a list of all available
+commands and ``help <command>`` to print details on the specified command:
yosys> help help
@@ -110,16 +121,16 @@ elaborate design hierarchy:
yosys> hierarchy
-convert processes ("always" blocks) to netlist elements and perform
+convert processes (``always`` blocks) to netlist elements and perform
some simple optimizations:
yosys> proc; opt
-display design netlist using xdot:
+display design netlist using ``xdot``:
yosys> show
-the same thing using 'gv' as postscript viewer:
+the same thing using ``gv`` as postscript viewer:
yosys> show -format ps -viewer gv
@@ -171,8 +182,8 @@ The following very basic synthesis script should work well with all designs:
techmap; opt
If ABC is enabled in the Yosys build configuration and a cell library is given
-in the liberty file mycells.lib, the following synthesis script will synthesize
-for the given cell library:
+in the liberty file ``mycells.lib``, the following synthesis script will
+synthesize for the given cell library:
# the high-level stuff
hierarchy; proc; fsm; opt; memory; opt
@@ -190,16 +201,17 @@ for the given cell library:
clean
If you do not have a liberty file but want to test this synthesis script,
-you can use the file examples/cmos/cmos_cells.lib from the yosys sources.
+you can use the file ``examples/cmos/cmos_cells.lib`` from the yosys sources.
Liberty file downloads for and information about free and open ASIC standard
cell libraries can be found here:
- http://www.vlsitechnology.org/html/libraries.html
- http://www.vlsitechnology.org/synopsys/vsclib013.lib
+- http://www.vlsitechnology.org/html/libraries.html
+- http://www.vlsitechnology.org/synopsys/vsclib013.lib
-The command "synth" provides a good default synthesis script (see "help synth").
-If possible a synthesis script should borrow from "synth". For example:
+The command ``synth`` provides a good default synthesis script (see
+``help synth``). If possible a synthesis script should borrow from ``synth``.
+For example:
# the high-level stuff
hierarchy
@@ -224,11 +236,11 @@ for them:
- Non-synthesizable language features as defined in
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
-- The "tri", "triand", "trior", "wand" and "wor" net types
+- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types
-- The "config" keyword and library map files
+- The ``config`` keyword and library map files
-- The "disable", "primitive" and "specify" statements
+- The ``disable``, ``primitive`` and ``specify`` statements
- Latched logic (is synthesized as logic with feedback loops)
@@ -236,83 +248,83 @@ for them:
Verilog Attributes and non-standard features
============================================
-- The 'full_case' attribute on case statements is supported
- (also the non-standard "// synopsys full_case" directive)
+- The ``full_case`` attribute on case statements is supported
+ (also the non-standard ``// synopsys full_case`` directive)
-- The 'parallel_case' attribute on case statements is supported
- (also the non-standard "// synopsys parallel_case" directive)
+- The ``parallel_case`` attribute on case statements is supported
+ (also the non-standard ``// synopsys parallel_case`` directive)
-- The "// synopsys translate_off" and "// synopsys translate_on"
- directives are also supported (but the use of `ifdef .. `endif
+- The ``// synopsys translate_off`` and ``// synopsys translate_on``
+ directives are also supported (but the use of ``` `ifdef .. `endif ```
is strongly recommended instead).
-- The "nomem2reg" attribute on modules or arrays prohibits the
+- The ``nomem2reg`` attribute on modules or arrays prohibits the
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
+- 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
+- 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
+- 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
not affect clocked storage elements such as flip-flops.
-- The "nosync" attribute on registers prohibits the generation of a
+- The ``nosync`` attribute on registers prohibits the generation of a
storage element. The register itself will always have all bits set
to 'x' (undefined). The variable may only be used as blocking assigned
temporary variable within an always block. This is mostly used internally
by yosys to synthesize Verilog functions and access arrays.
-- The "onehot" attribute on wires mark them as onehot state register. This
+- 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
+- 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
passes to identify input and output ports of cells. The Verilog backend
also does not output blackbox modules on default.
-- The "keep" attribute on cells and wires is used to mark objects that should
+- 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
+ 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"
+- 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
- to add the necessary reset logic.
+- 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 to add the necessary reset logic.
-- The "top" attribute on a module marks this module as the top of the
- design hierarchy. The "hierarchy" command sets this attribute when called
- with "-top". Other commands, such as "flatten" and various backends
+- The ``top`` attribute on a module marks this module as the top of the
+ design hierarchy. The ``hierarchy`` command sets this attribute when called
+ with ``-top``. Other commands, such as ``flatten`` and various backends
use this attribute to determine the top module.
-- The "src" attribute is set on cells and wires created by to the string
- "<hdl-file-name>:<line-number>" by the HDL front-end and is then carried
+- The ``src`` attribute is set on cells and wires created by to the string
+ ``<hdl-file-name>:<line-number>`` by the HDL front-end and is then carried
through the synthesis. When entities are combined, a new |-separated
string is created that contains all the string from the original entities.
-- In addition to the (* ... *) attribute syntax, yosys supports
- the non-standard {* ... *} attribute syntax to set default attributes
- for everything that comes after the {* ... *} statement. (Reset
- by adding an empty {* *} statement.)
+- In addition to the ``(* ... *)`` attribute syntax, yosys supports
+ the non-standard ``{* ... *}`` attribute syntax to set default attributes
+ for everything that comes after the ``{* ... *}`` statement. (Reset
+ by adding an empty ``{* *}`` statement.)
- In module parameter and port declarations, and cell port and parameter
lists, a trailing comma is ignored. This simplifies writing verilog code
generators a bit in some cases.
-- Modules can be declared with "module mod_name(...);" (with three dots
+- Modules can be declared with ``module mod_name(...);`` (with three dots
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.
@@ -326,7 +338,7 @@ Verilog Attributes and non-standard features
assign b = 42;
"""
-- The attribute "via_celltype" can be used to implement a Verilog task or
+- The attribute ``via_celltype`` can be used to implement a Verilog task or
function by instantiating the specified cell type. The value is the name
of the cell type to use. For functions the name of the output port can
be specified by appending it to the cell type separated by a whitespace.
@@ -354,9 +366,9 @@ Verilog Attributes and non-standard features
endmodule
- A limited subset of DPI-C functions is supported. The plugin mechanism
- (see "help plugin") can be used to load .so files with implementations
+ (see ``help plugin``) can be used to load .so files with implementations
of DPI-C routines. As a non-standard extension it is possible to specify
- a plugin alias using the "<alias>:" syntax. for example:
+ a plugin alias using the ``<alias>:`` syntax. For example:
module dpitest;
import "DPI-C" function foo:round = real my_round (real);
@@ -365,11 +377,11 @@ Verilog Attributes and non-standard features
$ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v'
-- Sized constants (the syntax <size>'s?[bodh]<value>) support constant
+- Sized constants (the syntax ``<size>'s?[bodh]<value>``) support constant
expressions as <size>. If the expression is not a simple identifier, it
- must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010
+ must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
-- The system tasks $finish and $display are supported in initial blocks
+- The system tasks ``$finish`` and ``$display`` are supported in initial blocks
in an unconditional context (only if/case statements on parameters
and constant values). The intended use for this is synthesis-time DRC.
@@ -377,42 +389,63 @@ Verilog Attributes and non-standard features
Non-standard or SystemVerilog features for formal verification
==============================================================
-- Support for "assert", "assume", and "restrict" is enabled when
- read_verilog is called with -formal.
+- Support for ``assert``, ``assume``, ``restrict``, and ``cover`` is enabled
+ when ``read_verilog`` is called with ``-formal``.
-- The system task $initstate evaluates to 1 in the initial state and
+- The system task ``$initstate`` evaluates to 1 in the initial state and
to 0 otherwise.
-- The system task $anyconst evaluates to any constant value.
+- The system function ``$anyconst`` evaluates to any constant value. This is
+ equivalent to declaring a reg as ``rand const``, but also works outside
+ of checkers. (Yosys also supports ``rand const`` outside checkers.)
-- The system task $anyseq evaluates to any value, possibly a different
- value in each cycle.
+- The system function ``$anyseq`` evaluates to any value, possibly a different
+ value in each cycle. This is equivalent to declaring a reg as ``rand``,
+ but also works outside of checkers. (Yosys also supports ``rand``
+ variables outside checkers.)
-- The SystemVerilog tasks $past, $stable, $rose and $fell are supported
- in any clocked block.
+- The system functions ``$allconst`` and ``$allseq`` can be used to construct
+ formal exist-forall problems. Assumptions only hold if the trace satisfies
+ the assumtion for all ``$allconst/$allseq`` values. For assertions and cover
+ statements it is sufficient if just one ``$allconst/$allseq`` value triggers
+ the property (similar to ``$anyconst/$anyseq``).
-- The syntax @($global_clock) can be used to create FFs that have no
- explicit clock input ($ff cells).
+- Wires/registers decalred using the ``anyconst/anyseq/allconst/allseq`` attribute
+ (for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if driven
+ by a ``$anyconst/$anyseq/$allconst/$allseq`` function.
+
+- The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are
+ supported in any clocked block.
+
+- The syntax ``@($global_clock)`` can be used to create FFs that have no
+ explicit clock input ($ff cells). The same can be achieved by using
+ ``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>``
+ is marked with the ``(* gclk *)`` Verilog attribute.
Supported features from SystemVerilog
=====================================
-When read_verilog is called with -sv, it accepts some language features
+When ``read_verilog`` is called with ``-sv``, it accepts some language features
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.
+- 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.
+
+- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are
+ also supported. The same limitations as with the ``assert`` statement apply.
-- The "assume" and "restrict" statements from SystemVerilog are also
- supported. The same limitations as with the "assert" statement apply.
+- The keywords ``always_comb``, ``always_ff`` and ``always_latch``, ``logic``
+ and ``bit`` are supported.
-- The keywords "always_comb", "always_ff" and "always_latch", "logic" and
- "bit" are supported.
+- Declaring free variables with ``rand`` and ``rand const`` is supported.
+
+- Checkers without a port list that do not need to be instantiated (but instead
+ behave like a named block) are supported.
- SystemVerilog packages are supported. Once a SystemVerilog file is read
- into a design with "read_verilog", all its packages are available to
+ into a design with ``read_verilog``, all its packages are available to
SystemVerilog files being read into the same design afterwards.
@@ -448,4 +481,3 @@ Notes:
- To run `make manual` you need to have installed yosys with `make install`,
otherwise it will fail on finding `kernel/yosys.h` while building
`PRESENTATION_Prog`.
-
diff --git a/backends/aiger/Makefile.inc b/backends/aiger/Makefile.inc
new file mode 100644
index 00000000..0fc37e95
--- /dev/null
+++ b/backends/aiger/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += backends/aiger/aiger.o
+
diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc
new file mode 100644
index 00000000..c323691a
--- /dev/null
+++ b/backends/aiger/aiger.cc
@@ -0,0 +1,754 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void aiger_encode(std::ostream &f, int x)
+{
+ log_assert(x >= 0);
+
+ while (x & ~0x7f) {
+ f.put((x & 0x7f) | 0x80);
+ x = x >> 7;
+ }
+
+ f.put(x);
+}
+
+struct AigerWriter
+{
+ Module *module;
+ bool zinit_mode;
+ SigMap sigmap;
+
+ dict<SigBit, bool> init_map;
+ pool<SigBit> input_bits, output_bits;
+ dict<SigBit, SigBit> not_map, ff_map, alias_map;
+ dict<SigBit, pair<SigBit, SigBit>> and_map;
+ vector<pair<SigBit, SigBit>> asserts, assumes;
+ vector<pair<SigBit, SigBit>> liveness, fairness;
+ pool<SigBit> initstate_bits;
+
+ vector<pair<int, int>> aig_gates;
+ vector<int> aig_latchin, aig_latchinit, aig_outputs;
+ int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0;
+ int aig_b = 0, aig_c = 0, aig_j = 0, aig_f = 0;
+
+ dict<SigBit, int> aig_map;
+ dict<SigBit, int> ordered_outputs;
+ dict<SigBit, int> ordered_latches;
+
+ dict<SigBit, int> init_inputs;
+ int initstate_ff = 0;
+
+ int mkgate(int a0, int a1)
+ {
+ aig_m++, aig_a++;
+ aig_gates.push_back(a0 > a1 ? make_pair(a0, a1) : make_pair(a1, a0));
+ return 2*aig_m;
+ }
+
+ int bit2aig(SigBit bit)
+ {
+ if (aig_map.count(bit) == 0)
+ {
+ aig_map[bit] = -1;
+
+ if (initstate_bits.count(bit)) {
+ log_assert(initstate_ff > 0);
+ aig_map[bit] = initstate_ff;
+ } else
+ if (not_map.count(bit)) {
+ int a = bit2aig(not_map.at(bit)) ^ 1;
+ aig_map[bit] = a;
+ } else
+ if (and_map.count(bit)) {
+ auto args = and_map.at(bit);
+ int a0 = bit2aig(args.first);
+ int a1 = bit2aig(args.second);
+ aig_map[bit] = mkgate(a0, a1);
+ } else
+ if (alias_map.count(bit)) {
+ aig_map[bit] = bit2aig(alias_map.at(bit));
+ }
+
+ if (bit == State::Sx || bit == State::Sz)
+ log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n");
+ }
+
+ log_assert(aig_map.at(bit) >= 0);
+ return aig_map.at(bit);
+ }
+
+ AigerWriter(Module *module, bool zinit_mode) : module(module), zinit_mode(zinit_mode), sigmap(module)
+ {
+ pool<SigBit> undriven_bits;
+ pool<SigBit> unused_bits;
+
+ // promote public wires
+ for (auto wire : module->wires())
+ if (wire->name[0] == '\\')
+ sigmap.add(wire);
+
+ // promote input wires
+ for (auto wire : module->wires())
+ if (wire->port_input)
+ sigmap.add(wire);
+
+ // promote output wires
+ for (auto wire : module->wires())
+ if (wire->port_output)
+ sigmap.add(wire);
+
+ for (auto wire : module->wires())
+ {
+ if (wire->attributes.count("\\init")) {
+ SigSpec initsig = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(wire) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ init_map[initsig[i]] = initval[i] == State::S1;
+ }
+
+ for (int i = 0; i < GetSize(wire); i++)
+ {
+ SigBit wirebit(wire, i);
+ SigBit bit = sigmap(wirebit);
+
+ if (bit.wire == nullptr) {
+ if (wire->port_output) {
+ aig_map[wirebit] = (bit == State::S1) ? 1 : 0;
+ output_bits.insert(wirebit);
+ }
+ continue;
+ }
+
+ undriven_bits.insert(bit);
+ unused_bits.insert(bit);
+
+ if (wire->port_input)
+ input_bits.insert(bit);
+
+ if (wire->port_output) {
+ if (bit != wirebit)
+ alias_map[wirebit] = bit;
+ output_bits.insert(wirebit);
+ }
+ }
+ }
+
+ for (auto bit : input_bits)
+ undriven_bits.erase(bit);
+
+ for (auto bit : output_bits)
+ unused_bits.erase(bit);
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type == "$_NOT_")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
+ unused_bits.erase(A);
+ undriven_bits.erase(Y);
+ not_map[Y] = A;
+ continue;
+ }
+
+ if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_"))
+ {
+ SigBit D = sigmap(cell->getPort("\\D").as_bit());
+ SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
+ unused_bits.erase(D);
+ undriven_bits.erase(Q);
+ ff_map[Q] = D;
+ continue;
+ }
+
+ if (cell->type == "$_AND_")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit B = sigmap(cell->getPort("\\B").as_bit());
+ SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
+ unused_bits.erase(A);
+ unused_bits.erase(B);
+ undriven_bits.erase(Y);
+ and_map[Y] = make_pair(A, B);
+ continue;
+ }
+
+ if (cell->type == "$initstate")
+ {
+ SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
+ undriven_bits.erase(Y);
+ initstate_bits.insert(Y);
+ continue;
+ }
+
+ if (cell->type == "$assert")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit EN = sigmap(cell->getPort("\\EN").as_bit());
+ unused_bits.erase(A);
+ unused_bits.erase(EN);
+ asserts.push_back(make_pair(A, EN));
+ continue;
+ }
+
+ if (cell->type == "$assume")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit EN = sigmap(cell->getPort("\\EN").as_bit());
+ unused_bits.erase(A);
+ unused_bits.erase(EN);
+ assumes.push_back(make_pair(A, EN));
+ continue;
+ }
+
+ if (cell->type == "$live")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit EN = sigmap(cell->getPort("\\EN").as_bit());
+ unused_bits.erase(A);
+ unused_bits.erase(EN);
+ liveness.push_back(make_pair(A, EN));
+ continue;
+ }
+
+ if (cell->type == "$fair")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit EN = sigmap(cell->getPort("\\EN").as_bit());
+ unused_bits.erase(A);
+ unused_bits.erase(EN);
+ fairness.push_back(make_pair(A, EN));
+ continue;
+ }
+
+ if (cell->type == "$anyconst")
+ {
+ for (auto bit : sigmap(cell->getPort("\\Y"))) {
+ undriven_bits.erase(bit);
+ ff_map[bit] = bit;
+ }
+ continue;
+ }
+
+ if (cell->type == "$anyseq")
+ {
+ for (auto bit : sigmap(cell->getPort("\\Y"))) {
+ undriven_bits.erase(bit);
+ input_bits.insert(bit);
+ }
+ continue;
+ }
+
+ log_error("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
+ }
+
+ for (auto bit : unused_bits)
+ undriven_bits.erase(bit);
+
+ if (!undriven_bits.empty()) {
+ undriven_bits.sort();
+ for (auto bit : undriven_bits) {
+ log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit));
+ input_bits.insert(bit);
+ }
+ log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module));
+ }
+
+ init_map.sort();
+ input_bits.sort();
+ output_bits.sort();
+ not_map.sort();
+ ff_map.sort();
+ and_map.sort();
+
+ aig_map[State::S0] = 0;
+ aig_map[State::S1] = 1;
+
+ for (auto bit : input_bits) {
+ aig_m++, aig_i++;
+ aig_map[bit] = 2*aig_m;
+ }
+
+ if (zinit_mode)
+ {
+ for (auto it : ff_map) {
+ if (init_map.count(it.first))
+ continue;
+ aig_m++, aig_i++;
+ init_inputs[it.first] = 2*aig_m;
+ }
+ }
+
+ int fair_live_inputs_cnt = GetSize(liveness);
+ int fair_live_inputs_m = aig_m;
+
+ aig_m += fair_live_inputs_cnt;
+ aig_i += fair_live_inputs_cnt;
+
+ for (auto it : ff_map) {
+ aig_m++, aig_l++;
+ aig_map[it.first] = 2*aig_m;
+ ordered_latches[it.first] = aig_l-1;
+ if (init_map.count(it.first) == 0)
+ aig_latchinit.push_back(2);
+ else
+ aig_latchinit.push_back(init_map.at(it.first) ? 1 : 0);
+ }
+
+ if (!initstate_bits.empty() || !init_inputs.empty()) {
+ aig_m++, aig_l++;
+ initstate_ff = 2*aig_m+1;
+ aig_latchinit.push_back(0);
+ }
+
+ int fair_live_latches_cnt = GetSize(fairness) + 2*GetSize(liveness);
+ int fair_live_latches_m = aig_m;
+ int fair_live_latches_l = aig_l;
+
+ aig_m += fair_live_latches_cnt;
+ aig_l += fair_live_latches_cnt;
+
+ for (int i = 0; i < fair_live_latches_cnt; i++)
+ aig_latchinit.push_back(0);
+
+ if (zinit_mode)
+ {
+ for (auto it : ff_map)
+ {
+ int l = ordered_latches[it.first];
+
+ if (aig_latchinit.at(l) == 1)
+ aig_map[it.first] ^= 1;
+
+ if (aig_latchinit.at(l) == 2)
+ {
+ int gated_ffout = mkgate(aig_map[it.first], initstate_ff^1);
+ int gated_initin = mkgate(init_inputs[it.first], initstate_ff);
+ aig_map[it.first] = mkgate(gated_ffout^1, gated_initin^1)^1;
+ }
+ }
+ }
+
+ for (auto it : ff_map) {
+ int a = bit2aig(it.second);
+ int l = ordered_latches[it.first];
+ if (zinit_mode && aig_latchinit.at(l) == 1)
+ aig_latchin.push_back(a ^ 1);
+ else
+ aig_latchin.push_back(a);
+ }
+
+ if (!initstate_bits.empty() || !init_inputs.empty())
+ aig_latchin.push_back(1);
+
+ for (auto bit : output_bits) {
+ aig_o++;
+ ordered_outputs[bit] = aig_o-1;
+ aig_outputs.push_back(bit2aig(bit));
+ }
+
+ for (auto it : asserts) {
+ aig_b++;
+ int bit_a = bit2aig(it.first);
+ int bit_en = bit2aig(it.second);
+ aig_outputs.push_back(mkgate(bit_a^1, bit_en));
+ }
+
+ for (auto it : assumes) {
+ aig_c++;
+ int bit_a = bit2aig(it.first);
+ int bit_en = bit2aig(it.second);
+ aig_outputs.push_back(mkgate(bit_a^1, bit_en)^1);
+ }
+
+ for (auto it : liveness)
+ {
+ int input_m = ++fair_live_inputs_m;
+ int latch_m1 = ++fair_live_latches_m;
+ int latch_m2 = ++fair_live_latches_m;
+
+ log_assert(GetSize(aig_latchin) == fair_live_latches_l);
+ fair_live_latches_l += 2;
+
+ int bit_a = bit2aig(it.first);
+ int bit_en = bit2aig(it.second);
+ int bit_s = 2*input_m;
+ int bit_q1 = 2*latch_m1;
+ int bit_q2 = 2*latch_m2;
+
+ int bit_d1 = mkgate(mkgate(bit_s, bit_en)^1, bit_q1^1)^1;
+ int bit_d2 = mkgate(mkgate(bit_d1, bit_a)^1, bit_q2^1)^1;
+
+ aig_j++;
+ aig_latchin.push_back(bit_d1);
+ aig_latchin.push_back(bit_d2);
+ aig_outputs.push_back(mkgate(bit_q1, bit_q2^1));
+ }
+
+ for (auto it : fairness)
+ {
+ int latch_m = ++fair_live_latches_m;
+
+ log_assert(GetSize(aig_latchin) == fair_live_latches_l);
+ fair_live_latches_l += 1;
+
+ int bit_a = bit2aig(it.first);
+ int bit_en = bit2aig(it.second);
+ int bit_q = 2*latch_m;
+
+ aig_f++;
+ aig_latchin.push_back(mkgate(mkgate(bit_q^1, bit_en^1)^1, bit_a^1));
+ aig_outputs.push_back(bit_q^1);
+ }
+ }
+
+ void write_aiger(std::ostream &f, bool ascii_mode, bool miter_mode, bool symbols_mode)
+ {
+ int aig_obc = aig_o + aig_b + aig_c;
+ int aig_obcj = aig_obc + aig_j;
+ int aig_obcjf = aig_obcj + aig_f;
+
+ log_assert(aig_m == aig_i + aig_l + aig_a);
+ log_assert(aig_l == GetSize(aig_latchin));
+ log_assert(aig_l == GetSize(aig_latchinit));
+ log_assert(aig_obcjf == GetSize(aig_outputs));
+
+ if (miter_mode) {
+ if (aig_b || aig_c || aig_j || aig_f)
+ log_error("Running AIGER back-end in -miter mode, but design contains $assert, $assume, $live and/or $fair cells!\n");
+ f << stringf("%s %d %d %d 0 %d %d\n", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_a, aig_o);
+ } else {
+ f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a);
+ if (aig_b || aig_c || aig_j || aig_f)
+ f << stringf(" %d %d %d %d", aig_b, aig_c, aig_j, aig_f);
+ f << stringf("\n");
+ }
+
+ if (ascii_mode)
+ {
+ for (int i = 0; i < aig_i; i++)
+ f << stringf("%d\n", 2*i+2);
+
+ for (int i = 0; i < aig_l; i++) {
+ if (zinit_mode || aig_latchinit.at(i) == 0)
+ f << stringf("%d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i));
+ else if (aig_latchinit.at(i) == 1)
+ f << stringf("%d %d 1\n", 2*(aig_i+i)+2, aig_latchin.at(i));
+ else if (aig_latchinit.at(i) == 2)
+ f << stringf("%d %d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i), 2*(aig_i+i)+2);
+ }
+
+ for (int i = 0; i < aig_obc; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = aig_obc; i < aig_obcj; i++)
+ f << stringf("1\n");
+
+ for (int i = aig_obc; i < aig_obcj; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = aig_obcj; i < aig_obcjf; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = 0; i < aig_a; i++)
+ f << stringf("%d %d %d\n", 2*(aig_i+aig_l+i)+2, aig_gates.at(i).first, aig_gates.at(i).second);
+ }
+ else
+ {
+ for (int i = 0; i < aig_l; i++) {
+ if (zinit_mode || aig_latchinit.at(i) == 0)
+ f << stringf("%d\n", aig_latchin.at(i));
+ else if (aig_latchinit.at(i) == 1)
+ f << stringf("%d 1\n", aig_latchin.at(i));
+ else if (aig_latchinit.at(i) == 2)
+ f << stringf("%d %d\n", aig_latchin.at(i), 2*(aig_i+i)+2);
+ }
+
+ for (int i = 0; i < aig_obc; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = aig_obc; i < aig_obcj; i++)
+ f << stringf("1\n");
+
+ for (int i = aig_obc; i < aig_obcj; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = aig_obcj; i < aig_obcjf; i++)
+ f << stringf("%d\n", aig_outputs.at(i));
+
+ for (int i = 0; i < aig_a; i++) {
+ int lhs = 2*(aig_i+aig_l+i)+2;
+ int rhs0 = aig_gates.at(i).first;
+ int rhs1 = aig_gates.at(i).second;
+ int delta0 = lhs - rhs0;
+ int delta1 = rhs0 - rhs1;
+ aiger_encode(f, delta0);
+ aiger_encode(f, delta1);
+ }
+ }
+
+ if (symbols_mode)
+ {
+ dict<string, vector<string>> symbols;
+
+ for (auto wire : module->wires())
+ {
+ if (wire->name[0] == '$')
+ continue;
+
+ SigSpec sig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(wire); i++)
+ {
+ if (sig[i].wire == nullptr) {
+ if (wire->port_output)
+ sig[i] = SigBit(wire, i);
+ else
+ continue;
+ }
+
+ if (wire->port_input) {
+ int a = aig_map.at(sig[i]);
+ log_assert((a & 1) == 0);
+ if (GetSize(wire) != 1)
+ symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s[%d]", log_id(wire), i));
+ else
+ symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s", log_id(wire)));
+ }
+
+ if (wire->port_output) {
+ int o = ordered_outputs.at(SigSpec(wire, i));
+ if (GetSize(wire) != 1)
+ symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s[%d]", log_id(wire), i));
+ else
+ symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", log_id(wire)));
+ }
+
+ if (init_inputs.count(sig[i])) {
+ int a = init_inputs.at(sig[i]);
+ log_assert((a & 1) == 0);
+ if (GetSize(wire) != 1)
+ symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", log_id(wire), i));
+ else
+ symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", log_id(wire)));
+ }
+
+ if (ordered_latches.count(sig[i])) {
+ int l = ordered_latches.at(sig[i]);
+ const char *p = (zinit_mode && (aig_latchinit.at(l) == 1)) ? "!" : "";
+ if (GetSize(wire) != 1)
+ symbols[stringf("l%d", l)].push_back(stringf("%s%s[%d]", p, log_id(wire), i));
+ else
+ symbols[stringf("l%d", l)].push_back(stringf("%s%s", p, log_id(wire)));
+ }
+ }
+ }
+
+ symbols.sort();
+
+ for (auto &sym : symbols) {
+ f << sym.first;
+ std::sort(sym.second.begin(), sym.second.end());
+ for (auto &s : sym.second)
+ f << " " << s;
+ f << std::endl;
+ }
+ }
+
+ f << stringf("c\nGenerated by %s\n", yosys_version_str);
+ }
+
+ void write_map(std::ostream &f, bool verbose_map)
+ {
+ dict<int, string> input_lines;
+ dict<int, string> init_lines;
+ dict<int, string> output_lines;
+ dict<int, string> latch_lines;
+ dict<int, string> wire_lines;
+
+ for (auto wire : module->wires())
+ {
+ if (!verbose_map && wire->name[0] == '$')
+ continue;
+
+ SigSpec sig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(wire); i++)
+ {
+ if (aig_map.count(sig[i]) == 0 || sig[i].wire == nullptr)
+ continue;
+
+ int a = aig_map.at(sig[i]);
+
+ if (verbose_map)
+ wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire));
+
+ if (wire->port_input) {
+ log_assert((a & 1) == 0);
+ input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire));
+ }
+
+ if (wire->port_output) {
+ int o = ordered_outputs.at(sig[i]);
+ output_lines[o] += stringf("output %d %d %s\n", o, i, log_id(wire));
+ }
+
+ if (init_inputs.count(sig[i])) {
+ int a = init_inputs.at(sig[i]);
+ log_assert((a & 1) == 0);
+ init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, i, log_id(wire));
+ }
+
+ if (ordered_latches.count(sig[i])) {
+ int l = ordered_latches.at(sig[i]);
+ if (zinit_mode && (aig_latchinit.at(l) == 1))
+ latch_lines[l] += stringf("invlatch %d %d %s\n", l, i, log_id(wire));
+ else
+ latch_lines[l] += stringf("latch %d %d %s\n", l, i, log_id(wire));
+ }
+ }
+ }
+
+ input_lines.sort();
+ for (auto &it : input_lines)
+ f << it.second;
+
+ init_lines.sort();
+ for (auto &it : init_lines)
+ f << it.second;
+
+ output_lines.sort();
+ for (auto &it : output_lines)
+ f << it.second;
+
+ latch_lines.sort();
+ for (auto &it : latch_lines)
+ f << it.second;
+
+ wire_lines.sort();
+ for (auto &it : wire_lines)
+ f << it.second;
+ }
+};
+
+struct AigerBackend : public Backend {
+ AigerBackend() : Backend("aiger", "write design to AIGER file") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_aiger [options] [filename]\n");
+ log("\n");
+ log("Write the current design to an AIGER file. The design must be flattened and\n");
+ log("must not contain any cell types except $_AND_, $_NOT_, simple FF types,\n");
+ log("$assert and $assume cells, and $initstate cells.\n");
+ log("\n");
+ log("$assert and $assume cells are converted to AIGER bad state properties and\n");
+ log("invariant constraints.\n");
+ log("\n");
+ log(" -ascii\n");
+ log(" write ASCII version of AGIER format\n");
+ log("\n");
+ log(" -zinit\n");
+ log(" convert FFs to zero-initialized FFs, adding additional inputs for\n");
+ log(" uninitialized FFs.\n");
+ log("\n");
+ log(" -miter\n");
+ log(" design outputs are AIGER bad state properties\n");
+ log("\n");
+ log(" -symbols\n");
+ log(" include a symbol table in the generated AIGER file\n");
+ log("\n");
+ log(" -map <filename>\n");
+ log(" write an extra file with port and latch symbols\n");
+ log("\n");
+ log(" -vmap <filename>\n");
+ log(" like -map, but more verbose\n");
+ log("\n");
+ }
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool ascii_mode = false;
+ bool zinit_mode = false;
+ bool miter_mode = false;
+ bool symbols_mode = false;
+ bool verbose_map = false;
+ std::string map_filename;
+
+ log_header(design, "Executing AIGER backend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-ascii") {
+ ascii_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-zinit") {
+ zinit_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-miter") {
+ miter_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-symbols") {
+ symbols_mode = true;
+ continue;
+ }
+ if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
+ map_filename = args[++argidx];
+ continue;
+ }
+ if (map_filename.empty() && args[argidx] == "-vmap" && argidx+1 < args.size()) {
+ map_filename = args[++argidx];
+ verbose_map = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ Module *top_module = design->top_module();
+
+ if (top_module == nullptr)
+ log_error("Can't find top module in current design!\n");
+
+ AigerWriter writer(top_module, zinit_mode);
+ writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
+
+ if (!map_filename.empty()) {
+ std::ofstream mapf;
+ mapf.open(map_filename.c_str(), std::ofstream::trunc);
+ if (mapf.fail())
+ log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno));
+ writer.write_map(mapf, verbose_map);
+ }
+ }
+} AigerBackend;
+
+PRIVATE_NAMESPACE_END
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index d9d0cc17..0db5ff27 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -38,8 +38,10 @@ struct BlifDumperConfig
bool impltf_mode;
bool gates_mode;
bool cname_mode;
+ bool iname_mode;
bool param_mode;
bool attr_mode;
+ bool iattr_mode;
bool blackbox_mode;
bool noalias_mode;
@@ -48,7 +50,8 @@ struct BlifDumperConfig
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),
- cname_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false), noalias_mode(false) { }
+ cname_mode(false), iname_mode(false), param_mode(false), attr_mode(false), iattr_mode(false),
+ blackbox_mode(false), noalias_mode(false) { }
};
struct BlifDumper
@@ -112,7 +115,7 @@ struct BlifDumper
str[i] = '?';
if (sig.wire->width != 1)
- str += stringf("[%d]", sig.offset);
+ str += stringf("[%d]", sig.wire->upto ? sig.wire->start_offset+sig.wire->width-sig.offset-1 : sig.wire->start_offset+sig.offset);
cstr_buf.push_back(str);
return cstr_buf.back().c_str();
@@ -240,106 +243,118 @@ struct BlifDumper
if (!config->icells_mode && cell->type == "$_NOT_") {
f << stringf(".names %s %s\n0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_AND_") {
f << stringf(".names %s %s %s\n11 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_OR_") {
f << stringf(".names %s %s %s\n1- 1\n-1 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_XOR_") {
f << stringf(".names %s %s %s\n10 1\n01 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_NAND_") {
f << stringf(".names %s %s %s\n0- 1\n-0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_NOR_") {
f << stringf(".names %s %s %s\n00 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_XNOR_") {
f << stringf(".names %s %s %s\n11 1\n00 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
+ }
+
+ if (!config->icells_mode && cell->type == "$_ANDNOT_") {
+ f << stringf(".names %s %s %s\n10 1\n",
+ cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
+ goto internal_cell;
+ }
+
+ if (!config->icells_mode && cell->type == "$_ORNOT_") {
+ f << stringf(".names %s %s %s\n1- 1\n-0 1\n",
+ cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_AOI3_") {
f << stringf(".names %s %s %s %s\n-00 1\n0-0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_OAI3_") {
f << stringf(".names %s %s %s %s\n00- 1\n--0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_AOI4_") {
f << stringf(".names %s %s %s %s %s\n-0-0 1\n-00- 1\n0--0 1\n0-0- 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_OAI4_") {
f << stringf(".names %s %s %s %s %s\n00-- 1\n--00 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_MUX_") {
f << stringf(".names %s %s %s %s\n1-0 1\n-11 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_FF_") {
f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_DFF_N_") {
f << stringf(".latch %s %s fe %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_DFF_P_") {
f << stringf(".latch %s %s re %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_DLATCH_N_") {
f << stringf(".latch %s %s al %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_DLATCH_P_") {
f << stringf(".latch %s %s ah %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$lut") {
@@ -361,7 +376,7 @@ struct BlifDumper
}
f << " 1\n";
}
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$sop") {
@@ -389,7 +404,7 @@ struct BlifDumper
}
f << " 1\n";
}
- continue;
+ goto internal_cell;
}
f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type));
@@ -409,6 +424,14 @@ struct BlifDumper
dump_params(".attr", cell->attributes);
if (config->param_mode)
dump_params(".param", cell->parameters);
+
+ if (0) {
+ internal_cell:
+ if (config->iname_mode)
+ f << stringf(".cname %s\n", cstr(cell->name));
+ if (config->iattr_mode)
+ dump_params(".attr", cell->attributes);
+ }
}
for (auto &conn : module->connections())
@@ -441,7 +464,7 @@ struct BlifDumper
struct BlifBackend : public Backend {
BlifBackend() : Backend("blif", "write design to BLIF file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -499,6 +522,11 @@ struct BlifBackend : public Backend {
log(" -cname\n");
log(" use the non-standard .cname statement to write cell names\n");
log("\n");
+ log(" -iname, -iattr\n");
+ log(" enable -cname and -attr functionality for .names statements\n");
+ log(" (the .cname and .attr statements will be included in the BLIF\n");
+ log(" output after the truth table for the .names statement)\n");
+ log("\n");
log(" -blackbox\n");
log(" write blackbox cells with .blackbox statement.\n");
log("\n");
@@ -506,7 +534,7 @@ struct BlifBackend : public Backend {
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)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string top_module_name;
std::string buf_type, buf_in, buf_out;
@@ -575,6 +603,14 @@ struct BlifBackend : public Backend {
config.attr_mode = true;
continue;
}
+ if (args[argidx] == "-iname") {
+ config.iname_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-iattr") {
+ config.iattr_mode = true;
+ continue;
+ }
if (args[argidx] == "-blackbox") {
config.blackbox_mode = true;
continue;
diff --git a/backends/btor/README b/backends/btor/README
deleted file mode 100644
index efcf0d8f..00000000
--- a/backends/btor/README
+++ /dev/null
@@ -1,23 +0,0 @@
-
-This is the Yosys BTOR backend.
-It is developed by Ahmed Irfan <irfan@fbk.eu> - Fondazione Bruno Kessler, Trento, Italy
-
-Master git repository for the BTOR backend:
-https://github.com/ahmedirfan1983/yosys
-
-
-[[CITE]] BTOR: Bit-Precise Modelling of Word-Level Problems for Model Checking
-Johannes Kepler University, Linz, Austria
-http://fmv.jku.at/papers/BrummayerBiereLonsing-BPR08.pdf
-
-
-Todos:
-------
-
-- Add checks for unsupported stuff
- - unsupported cell types
- - async resets
- - etc..
-
-- Add support for $lut cells
-
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index bbe90e85..58d2a862 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -2,7 +2,6 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Copyright (C) 2014 Ahmed Irfan <irfan@fbk.eu>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,1093 +17,1112 @@
*
*/
-// [[CITE]] BTOR: Bit-Precise Modelling of Word-Level Problems for Model Checking
-// Johannes Kepler University, Linz, Austria
-// http://fmv.jku.at/papers/BrummayerBiereLonsing-BPR08.pdf
-
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
-#include <math.h>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-struct BtorDumperConfig
+struct BtorWorker
{
- bool subckt_mode;
- bool conn_mode;
- bool impltf_mode;
+ std::ostream &f;
+ SigMap sigmap;
+ RTLIL::Module *module;
+ bool verbose;
+ bool single_bad;
- std::string buf_type, buf_in, buf_out;
- std::string true_type, true_out, false_type, false_out;
+ int next_nid = 1;
+ int initstate_nid = -1;
- BtorDumperConfig() : subckt_mode(false), conn_mode(false), impltf_mode(false) { }
-};
+ // <width> => <sid>
+ dict<int, int> sorts_bv;
-struct WireInfo
-{
- RTLIL::IdString cell_name;
- const RTLIL::SigChunk *chunk;
+ // (<address-width>, <data-width>) => <sid>
+ dict<pair<int, int>, int> sorts_mem;
- WireInfo(RTLIL::IdString c, const RTLIL::SigChunk* ch) : cell_name(c), chunk(ch) { }
-};
+ // SigBit => (<nid>, <bitidx>)
+ dict<SigBit, pair<int, int>> bit_nid;
-struct WireInfoOrder
-{
- bool operator() (const WireInfo& x, const WireInfo& y)
+ // <nid> => <bvwidth>
+ dict<int, int> nid_width;
+
+ // SigSpec => <nid>
+ dict<SigSpec, int> sig_nid;
+
+ // bit to driving cell
+ dict<SigBit, Cell*> bit_cell;
+
+ // nids for constants
+ dict<Const, int> consts;
+
+ // ff inputs that need to be evaluated (<nid>, <ff_cell>)
+ vector<pair<int, Cell*>> ff_todo;
+
+ pool<Cell*> cell_recursion_guard;
+ vector<int> bad_properties;
+ dict<SigBit, bool> initbits;
+ pool<Wire*> statewires;
+ string indent;
+
+ void btorf(const char *fmt, ...)
{
- return x.chunk < y.chunk;
+ va_list ap;
+ va_start(ap, fmt);
+ f << indent << vstringf(fmt, ap);
+ va_end(ap);
}
-};
-struct BtorDumper
-{
- std::ostream &f;
- RTLIL::Module *module;
- RTLIL::Design *design;
- BtorDumperConfig *config;
- CellTypes ct;
+ void btorf_push(const string &id)
+ {
+ if (verbose) {
+ f << indent << stringf(" ; begin %s\n", id.c_str());
+ indent += " ";
+ }
+ }
- SigMap sigmap;
- std::map<RTLIL::IdString, std::set<WireInfo,WireInfoOrder>> inter_wire_map;//<wire, dependency list> for mapping the intermediate wires that are output of some cell
- std::map<RTLIL::IdString, int> line_ref;//mapping of ids to line_num of the btor file
- std::map<RTLIL::SigSpec, int> sig_ref;//mapping of sigspec to the line_num of the btor file
- int line_num;//last line number of btor file
- std::string str;//temp string for writing file
- std::map<RTLIL::IdString, bool> basic_wires;//input wires and registers
- RTLIL::IdString curr_cell; //current cell being dumped
- std::map<std::string, std::string> cell_type_translation, s_cell_type_translation; //RTLIL to BTOR translation
- std::map<int, std::set<std::pair<int,int>>> mem_next; // memory (line_number)'s set of condition and write
- BtorDumper(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig *config) :
- f(f), module(module), design(design), config(config), ct(design), sigmap(module)
+ void btorf_pop(const string &id)
{
- line_num=0;
- str.clear();
- for(auto it=module->wires_.begin(); it!=module->wires_.end(); ++it)
- {
- if(it->second->port_input)
- {
- basic_wires[it->first]=true;
- }
- else
- {
- basic_wires[it->first]=false;
- }
- inter_wire_map[it->first].clear();
+ if (verbose) {
+ indent = indent.substr(4);
+ f << indent << stringf(" ; end %s\n", id.c_str());
}
- curr_cell.clear();
- //assert
- cell_type_translation["$assert"] = "root";
- //unary
- cell_type_translation["$not"] = "not";
- cell_type_translation["$neg"] = "neg";
- cell_type_translation["$reduce_and"] = "redand";
- cell_type_translation["$reduce_or"] = "redor";
- cell_type_translation["$reduce_xor"] = "redxor";
- cell_type_translation["$reduce_bool"] = "redor";
- //binary
- cell_type_translation["$and"] = "and";
- cell_type_translation["$or"] = "or";
- cell_type_translation["$xor"] = "xor";
- cell_type_translation["$xnor"] = "xnor";
- cell_type_translation["$shr"] = "srl";
- cell_type_translation["$shl"] = "sll";
- cell_type_translation["$sshr"] = "sra";
- cell_type_translation["$sshl"] = "sll";
- cell_type_translation["$shift"] = "srl";
- cell_type_translation["$shiftx"] = "srl";
- cell_type_translation["$lt"] = "ult";
- cell_type_translation["$le"] = "ulte";
- cell_type_translation["$gt"] = "ugt";
- cell_type_translation["$ge"] = "ugte";
- cell_type_translation["$eq"] = "eq";
- cell_type_translation["$eqx"] = "eq";
- cell_type_translation["$ne"] = "ne";
- cell_type_translation["$nex"] = "ne";
- cell_type_translation["$add"] = "add";
- cell_type_translation["$sub"] = "sub";
- cell_type_translation["$mul"] = "mul";
- cell_type_translation["$mod"] = "urem";
- cell_type_translation["$div"] = "udiv";
- //mux
- cell_type_translation["$mux"] = "cond";
- //reg
- cell_type_translation["$dff"] = "next";
- cell_type_translation["$adff"] = "next";
- cell_type_translation["$dffsr"] = "next";
- //memories
- //nothing here
- //slice
- cell_type_translation["$slice"] = "slice";
- //concat
- cell_type_translation["$concat"] = "concat";
-
- //signed cell type translation
- //binary
- s_cell_type_translation["$modx"] = "srem";
- s_cell_type_translation["$mody"] = "smod";
- s_cell_type_translation["$div"] = "sdiv";
- s_cell_type_translation["$lt"] = "slt";
- s_cell_type_translation["$le"] = "slte";
- s_cell_type_translation["$gt"] = "sgt";
- s_cell_type_translation["$ge"] = "sgte";
+ }
+ int get_bv_sid(int width)
+ {
+ if (sorts_bv.count(width) == 0) {
+ int nid = next_nid++;
+ btorf("%d sort bitvec %d\n", nid, width);
+ sorts_bv[width] = nid;
+ }
+ return sorts_bv.at(width);
}
- vector<shared_str> cstr_buf;
+ int get_mem_sid(int abits, int dbits)
+ {
+ pair<int, int> key(abits, dbits);
+ if (sorts_mem.count(key) == 0) {
+ int addr_sid = get_bv_sid(abits);
+ int data_sid = get_bv_sid(dbits);
+ int nid = next_nid++;
+ btorf("%d sort array %d %d\n", nid, addr_sid, data_sid);
+ sorts_mem[key] = nid;
+ }
+ return sorts_mem.at(key);
+ }
- const char *cstr(const RTLIL::IdString id)
+ void add_nid_sig(int nid, const SigSpec &sig)
{
- str = RTLIL::unescape_id(id);
- for (size_t i = 0; i < str.size(); ++i)
- if (str[i] == '#' || str[i] == '=')
- str[i] = '?';
- cstr_buf.push_back(str);
- return cstr_buf.back().c_str();
+ if (verbose)
+ f << indent << stringf("; %d %s\n", nid, log_signal(sig));
+
+ for (int i = 0; i < GetSize(sig); i++)
+ bit_nid[sig[i]] = make_pair(nid, i);
+
+ sig_nid[sig] = nid;
+ nid_width[nid] = GetSize(sig);
}
- int dump_wire(RTLIL::Wire* wire)
+ void export_cell(Cell *cell)
{
- if(basic_wires[wire->name])
+ log_assert(cell_recursion_guard.count(cell) == 0);
+ cell_recursion_guard.insert(cell);
+ btorf_push(log_id(cell));
+
+ if (cell->type.in("$add", "$sub", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx",
+ "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
{
- log("writing wire %s\n", cstr(wire->name));
- auto it = line_ref.find(wire->name);
- if(it==std::end(line_ref))
+ string btor_op;
+ if (cell->type == "$add") btor_op = "add";
+ if (cell->type == "$sub") btor_op = "sub";
+ if (cell->type.in("$shl", "$sshl")) btor_op = "sll";
+ if (cell->type == "$shr") btor_op = "srl";
+ if (cell->type == "$sshr") btor_op = "sra";
+ if (cell->type.in("$shift", "$shiftx")) btor_op = "shift";
+ if (cell->type.in("$and", "$_AND_")) btor_op = "and";
+ if (cell->type.in("$or", "$_OR_")) btor_op = "or";
+ if (cell->type.in("$xor", "$_XOR_")) btor_op = "xor";
+ if (cell->type == "$_NAND_") btor_op = "nand";
+ if (cell->type == "$_NOR_") btor_op = "nor";
+ if (cell->type.in("$xnor", "$_XNOR_")) btor_op = "xnor";
+ log_assert(!btor_op.empty());
+
+ int width = GetSize(cell->getPort("\\Y"));
+ width = std::max(width, GetSize(cell->getPort("\\A")));
+ width = std::max(width, GetSize(cell->getPort("\\B")));
+
+ bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false;
+ bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false;
+
+ if (btor_op == "shift" && !b_signed)
+ btor_op = "srl";
+
+ if (cell->type.in("$shl", "$sshl", "$shr", "$sshr"))
+ b_signed = false;
+
+ if (cell->type == "$sshr" && !a_signed)
+ btor_op = "srl";
+
+ int sid = get_bv_sid(width);
+ int nid;
+
+ if (btor_op == "shift")
{
- ++line_num;
- line_ref[wire->name]=line_num;
- str = stringf("%d var %d %s", line_num, wire->width, cstr(wire->name));
- f << stringf("%s\n", str.c_str());
- return line_num;
+ int nid_a = get_sig_nid(cell->getPort("\\A"), width, false);
+ int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed);
+
+ int nid_r = next_nid++;
+ btorf("%d srl %d %d %d\n", nid_r, sid, nid_a, nid_b);
+
+ int nid_b_neg = next_nid++;
+ btorf("%d neg %d %d\n", nid_b_neg, sid, nid_b);
+
+ int nid_l = next_nid++;
+ btorf("%d sll %d %d %d\n", nid_l, sid, nid_a, nid_b_neg);
+
+ int sid_bit = get_bv_sid(1);
+ int nid_zero = get_sig_nid(Const(0, width));
+ int nid_b_ltz = next_nid++;
+ btorf("%d slt %d %d %d\n", nid_b_ltz, sid_bit, nid_b, nid_zero);
+
+ nid = next_nid++;
+ btorf("%d ite %d %d %d %d\n", nid, sid, nid_b_ltz, nid_l, nid_r);
}
- else return it->second;
+ else
+ {
+ int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed);
+ int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed);
+
+ nid = next_nid++;
+ btorf("%d %s %d %d %d\n", nid, btor_op.c_str(), sid, nid_a, nid_b);
+ }
+
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
+
+ if (GetSize(sig) < width) {
+ int sid = get_bv_sid(GetSize(sig));
+ int nid2 = next_nid++;
+ btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1);
+ nid = nid2;
+ }
+
+ add_nid_sig(nid, sig);
+ goto okay;
}
- else // case when the wire is not basic wire
+
+ if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
{
- log("case of non-basic wire - %s\n", cstr(wire->name));
- auto it = line_ref.find(wire->name);
- if(it==std::end(line_ref))
- {
- std::set<WireInfo, WireInfoOrder>& dep_set = inter_wire_map.at(wire->name);
- int wire_line = 0;
- int wire_width = 0;
- for(auto dep_set_it=dep_set.begin(); dep_set_it!=dep_set.end(); ++dep_set_it)
- {
- RTLIL::IdString cell_id = dep_set_it->cell_name;
- if(cell_id == curr_cell)
- break;
- log(" -- found cell %s\n", cstr(cell_id));
- RTLIL::Cell* cell = module->cells_.at(cell_id);
- const RTLIL::SigSpec* cell_output = get_cell_output(cell);
- int cell_line = dump_cell(cell);
-
- if(dep_set.size()==1 && wire->width == cell_output->size())
- {
- wire_line = cell_line;
- break;
- }
- else
- {
- int prev_wire_line=0; //previously dumped wire line
- int start_bit=0;
- for(unsigned j=0; j<cell_output->chunks().size(); ++j)
- {
- start_bit+=cell_output->chunks().at(j).width;
- if(cell_output->chunks().at(j).wire->name == wire->name)
- {
- prev_wire_line = wire_line;
- wire_line = ++line_num;
- str = stringf("%d slice %d %d %d %d;1", line_num, cell_output->chunks().at(j).width,
- cell_line, start_bit-1, start_bit-cell_output->chunks().at(j).width);
- f << stringf("%s\n", str.c_str());
- wire_width += cell_output->chunks().at(j).width;
- if(prev_wire_line!=0)
- {
- ++line_num;
- str = stringf("%d concat %d %d %d", line_num, wire_width, wire_line, prev_wire_line);
- f << stringf("%s\n", str.c_str());
- wire_line = line_num;
- }
- }
- }
- }
- }
- if(dep_set.size()==0)
- {
- log(" - checking sigmap\n");
- RTLIL::SigSpec s = RTLIL::SigSpec(wire);
- wire_line = dump_sigspec(&s, s.size());
- line_ref[wire->name]=wire_line;
- }
- line_ref[wire->name]=wire_line;
- return wire_line;
+ int sid = get_bv_sid(1);
+ int nid_a = get_sig_nid(cell->getPort("\\A"));
+ int nid_b = get_sig_nid(cell->getPort("\\B"));
+
+ int nid1 = next_nid++;
+ int nid2 = next_nid++;
+
+ if (cell->type == "$_ANDNOT_") {
+ btorf("%d not %d %d\n", nid1, sid, nid_b);
+ btorf("%d and %d %d %d\n", nid2, sid, nid_a, nid1);
}
- else
- {
- log(" -- already processed wire\n");
- return it->second;
+
+ if (cell->type == "$_ORNOT_") {
+ btorf("%d not %d %d\n", nid1, sid, nid_b);
+ btorf("%d or %d %d %d\n", nid2, sid, nid_a, nid1);
}
+
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
+ add_nid_sig(nid2, sig);
+ goto okay;
}
- log_abort();
- return -1;
- }
- int dump_memory(const RTLIL::Memory* memory)
- {
- log("writing memory %s\n", cstr(memory->name));
- auto it = line_ref.find(memory->name);
- if(it==std::end(line_ref))
+ if (cell->type.in("$_OAI3_", "$_AOI3_"))
{
- ++line_num;
- int address_bits = ceil_log2(memory->size);
- str = stringf("%d array %d %d", line_num, memory->width, address_bits);
- line_ref[memory->name]=line_num;
- f << stringf("%s\n", str.c_str());
- return line_num;
+ int sid = get_bv_sid(1);
+ int nid_a = get_sig_nid(cell->getPort("\\A"));
+ int nid_b = get_sig_nid(cell->getPort("\\B"));
+ int nid_c = get_sig_nid(cell->getPort("\\C"));
+
+ int nid1 = next_nid++;
+ int nid2 = next_nid++;
+ int nid3 = next_nid++;
+
+ if (cell->type == "$_OAI3_") {
+ btorf("%d or %d %d %d\n", nid1, sid, nid_a, nid_b);
+ btorf("%d and %d %d %d\n", nid2, sid, nid1, nid_c);
+ btorf("%d not %d %d\n", nid3, sid, nid2);
+ }
+
+ if (cell->type == "$_AOI3_") {
+ btorf("%d and %d %d %d\n", nid1, sid, nid_a, nid_b);
+ btorf("%d or %d %d %d\n", nid2, sid, nid1, nid_c);
+ btorf("%d not %d %d\n", nid3, sid, nid2);
+ }
+
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
+ add_nid_sig(nid3, sig);
+ goto okay;
}
- else return it->second;
- }
- int dump_memory_next(const RTLIL::Memory* memory)
- {
- auto mem_it = line_ref.find(memory->name);
- int address_bits = ceil_log2(memory->size);
- if(mem_it==std::end(line_ref))
- {
- log("can not write next of a memory that is not dumped yet\n");
- log_abort();
- }
- else
- {
- auto acond_list_it = mem_next.find(mem_it->second);
- if(acond_list_it!=std::end(mem_next))
+ if (cell->type.in("$_OAI4_", "$_AOI4_"))
{
- std::set<std::pair<int,int>>& cond_list = acond_list_it->second;
- if(cond_list.empty())
- {
- return 0;
- }
- auto it=cond_list.begin();
- ++line_num;
- str = stringf("%d acond %d %d %d %d %d", line_num, memory->width, address_bits, it->first, it->second, mem_it->second);
- f << stringf("%s\n", str.c_str());
- ++it;
- for(; it!=cond_list.end(); ++it)
- {
- ++line_num;
- str = stringf("%d acond %d %d %d %d %d", line_num, memory->width, address_bits, it->first, it->second, line_num-1);
- f << stringf("%s\n", str.c_str());
- }
- ++line_num;
- str = stringf("%d anext %d %d %d %d", line_num, memory->width, address_bits, mem_it->second, line_num-1);
- f << stringf("%s\n", str.c_str());
- return 1;
+ int sid = get_bv_sid(1);
+ int nid_a = get_sig_nid(cell->getPort("\\A"));
+ int nid_b = get_sig_nid(cell->getPort("\\B"));
+ int nid_c = get_sig_nid(cell->getPort("\\C"));
+ int nid_d = get_sig_nid(cell->getPort("\\D"));
+
+ int nid1 = next_nid++;
+ int nid2 = next_nid++;
+ int nid3 = next_nid++;
+ int nid4 = next_nid++;
+
+ if (cell->type == "$_OAI4_") {
+ btorf("%d or %d %d %d\n", nid1, sid, nid_a, nid_b);
+ btorf("%d or %d %d %d\n", nid2, sid, nid_c, nid_d);
+ btorf("%d and %d %d %d\n", nid3, sid, nid1, nid2);
+ btorf("%d not %d %d\n", nid4, sid, nid3);
+ }
+
+ if (cell->type == "$_AOI4_") {
+ btorf("%d and %d %d %d\n", nid1, sid, nid_a, nid_b);
+ btorf("%d and %d %d %d\n", nid2, sid, nid_c, nid_d);
+ btorf("%d or %d %d %d\n", nid3, sid, nid1, nid2);
+ btorf("%d not %d %d\n", nid4, sid, nid3);
+ }
+
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
+ add_nid_sig(nid4, sig);
+ goto okay;
}
- return 0;
- }
- }
- int dump_const(const RTLIL::Const* data, int width, int offset)
- {
- log("writing const \n");
- if((data->flags & RTLIL::CONST_FLAG_STRING) == 0)
+ if (cell->type.in("$lt", "$le", "$eq", "$eqx", "$ne", "$nex", "$ge", "$gt"))
{
- if(width<0)
- width = data->bits.size() - offset;
+ string btor_op;
+ if (cell->type == "$lt") btor_op = "lt";
+ if (cell->type == "$le") btor_op = "lte";
+ if (cell->type.in("$eq", "$eqx")) btor_op = "eq";
+ if (cell->type.in("$ne", "$nex")) btor_op = "ne";
+ if (cell->type == "$ge") btor_op = "gte";
+ if (cell->type == "$gt") btor_op = "gt";
+ log_assert(!btor_op.empty());
+
+ int width = 1;
+ width = std::max(width, GetSize(cell->getPort("\\A")));
+ width = std::max(width, GetSize(cell->getPort("\\B")));
+
+ bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false;
+ bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false;
+
+ int sid = get_bv_sid(1);
+ int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed);
+ int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed);
+
+ int nid = next_nid++;
+ if (cell->type.in("$lt", "$le", "$ge", "$gt")) {
+ btorf("%d %c%s %d %d %d\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b);
+ } else {
+ btorf("%d %s %d %d %d\n", nid, btor_op.c_str(), sid, nid_a, nid_b);
+ }
- std::string data_str = data->as_string();
- //if(offset > 0)
- data_str = data_str.substr(offset, width);
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
- ++line_num;
- str = stringf("%d const %d %s", line_num, width, data_str.c_str());
- f << stringf("%s\n", str.c_str());
- return line_num;
+ if (GetSize(sig) > 1) {
+ int sid = get_bv_sid(GetSize(sig));
+ int nid2 = next_nid++;
+ btorf("%d uext %d %d %d\n", nid2, sid, nid, GetSize(sig) - 1);
+ nid = nid2;
+ }
+
+ add_nid_sig(nid, sig);
+ goto okay;
}
- else
- log("writing const error\n");
- log_abort();
- return -1;
- }
- int dump_sigchunk(const RTLIL::SigChunk* chunk)
- {
- log("writing sigchunk\n");
- int l=-1;
- if(chunk->wire == NULL)
+ if (cell->type.in("$not", "$neg", "$_NOT_"))
{
- RTLIL::Const data_const(chunk->data);
- l=dump_const(&data_const, chunk->width, chunk->offset);
+ string btor_op;
+ if (cell->type.in("$not", "$_NOT_")) btor_op = "not";
+ if (cell->type == "$neg") btor_op = "neg";
+ log_assert(!btor_op.empty());
+
+ int width = GetSize(cell->getPort("\\Y"));
+ width = std::max(width, GetSize(cell->getPort("\\A")));
+
+ bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false;
+
+ int sid = get_bv_sid(width);
+ int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed);
+
+ int nid = next_nid++;
+ btorf("%d %s %d %d\n", nid, btor_op.c_str(), sid, nid_a);
+
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
+
+ if (GetSize(sig) < width) {
+ int sid = get_bv_sid(GetSize(sig));
+ int nid2 = next_nid++;
+ btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1);
+ nid = nid2;
+ }
+
+ add_nid_sig(nid, sig);
+ goto okay;
}
- else
+
+ if (cell->type.in("$logic_and", "$logic_or", "$logic_not"))
{
- if (chunk->width == chunk->wire->width && chunk->offset == 0)
- l = dump_wire(chunk->wire);
+ string btor_op;
+ if (cell->type == "$logic_and") btor_op = "and";
+ if (cell->type == "$logic_or") btor_op = "or";
+ if (cell->type == "$logic_not") btor_op = "not";
+ log_assert(!btor_op.empty());
+
+ int sid = get_bv_sid(1);
+ int nid_a = get_sig_nid(cell->getPort("\\A"));
+ int nid_b = btor_op != "not" ? get_sig_nid(cell->getPort("\\B")) : 0;
+
+ if (GetSize(cell->getPort("\\A")) > 1) {
+ int nid_red_a = next_nid++;
+ btorf("%d redor %d %d\n", nid_red_a, sid, nid_a);
+ nid_a = nid_red_a;
+ }
+
+ if (btor_op != "not" && GetSize(cell->getPort("\\B")) > 1) {
+ int nid_red_b = next_nid++;
+ btorf("%d redor %d %d\n", nid_red_b, sid, nid_b);
+ nid_b = nid_red_b;
+ }
+
+ int nid = next_nid++;
+ if (btor_op != "not")
+ btorf("%d %s %d %d %d\n", nid, btor_op.c_str(), sid, nid_a, nid_b);
else
- {
- int wire_line_num = dump_wire(chunk->wire);
- log_assert(wire_line_num>0);
- ++line_num;
- str = stringf("%d slice %d %d %d %d;2", line_num, chunk->width, wire_line_num,
- chunk->width + chunk->offset - 1, chunk->offset);
- f << stringf("%s\n", str.c_str());
- l = line_num;
+ btorf("%d %s %d %d\n", nid, btor_op.c_str(), sid, nid_a);
+
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
+
+ if (GetSize(sig) > 1) {
+ int sid = get_bv_sid(GetSize(sig));
+ int zeros_nid = get_sig_nid(Const(0, GetSize(sig)-1));
+ int nid2 = next_nid++;
+ btorf("%d concat %d %d %d\n", nid2, sid, zeros_nid, nid);
+ nid = nid2;
}
+
+ add_nid_sig(nid, sig);
+ goto okay;
}
- return l;
- }
- int dump_sigspec(const RTLIL::SigSpec* sig, int expected_width)
- {
- log("writing sigspec\n");
- RTLIL::SigSpec s = sigmap(*sig);
- int l = -1;
- auto it = sig_ref.find(s);
- if(it == std::end(sig_ref))
+ if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor"))
{
- if (s.is_chunk())
- {
- l = dump_sigchunk(&s.chunks().front());
+ string btor_op;
+ if (cell->type == "$reduce_and") btor_op = "redand";
+ if (cell->type.in("$reduce_or", "$reduce_bool")) btor_op = "redor";
+ if (cell->type.in("$reduce_xor", "$reduce_xnor")) btor_op = "redxor";
+ log_assert(!btor_op.empty());
+
+ int sid = get_bv_sid(1);
+ int nid_a = get_sig_nid(cell->getPort("\\A"));
+
+ int nid = next_nid++;
+ btorf("%d %s %d %d\n", nid, btor_op.c_str(), sid, nid_a);
+
+ if (cell->type == "$reduce_xnor") {
+ int nid2 = next_nid++;
+ btorf("%d not %d %d %d\n", nid2, sid, nid);
+ nid = nid2;
}
- else
- {
- int l1, l2, w1, w2;
- l1 = dump_sigchunk(&s.chunks().front());
- log_assert(l1>0);
- w1 = s.chunks().front().width;
- for (unsigned i=1; i < s.chunks().size(); ++i)
- {
- l2 = dump_sigchunk(&s.chunks().at(i));
- log_assert(l2>0);
- w2 = s.chunks().at(i).width;
- ++line_num;
- str = stringf("%d concat %d %d %d", line_num, w1+w2, l2, l1);
- f << stringf("%s\n", str.c_str());
- l1=line_num;
- w1+=w2;
- }
- l = line_num;
+
+ SigSpec sig = sigmap(cell->getPort("\\Y"));
+
+ if (GetSize(sig) > 1) {
+ int sid = get_bv_sid(GetSize(sig));
+ int zeros_nid = get_sig_nid(Const(0, GetSize(sig)-1));
+ int nid2 = next_nid++;
+ btorf("%d concat %d %d %d\n", nid2, sid, zeros_nid, nid);
+ nid = nid2;
}
- sig_ref[s] = l;
+
+ add_nid_sig(nid, sig);
+ goto okay;
}
- else
+
+ if (cell->type.in("$mux", "$_MUX_"))
{
- l = it->second;
+ SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = sigmap(cell->getPort("\\B"));
+ SigSpec sig_s = sigmap(cell->getPort("\\S"));
+ SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+
+ int nid_a = get_sig_nid(sig_a);
+ int nid_b = get_sig_nid(sig_b);
+ int nid_s = get_sig_nid(sig_s);
+
+ int sid = get_bv_sid(GetSize(sig_y));
+ int nid = next_nid++;
+ btorf("%d ite %d %d %d %d\n", nid, sid, nid_s, nid_b, nid_a);
+
+ add_nid_sig(nid, sig_y);
+ goto okay;
}
- if (expected_width != s.size())
+ if (cell->type == "$pmux")
{
- log(" - changing width of sigspec\n");
- //TODO: this block may not be needed anymore, due to explicit type conversion by "splice" command
- if(expected_width > s.size())
- {
- //TODO: case the signal is signed
- ++line_num;
- str = stringf ("%d zero %d", line_num, expected_width - s.size());
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf ("%d concat %d %d %d", line_num, expected_width, line_num-1, l);
- f << stringf("%s\n", str.c_str());
- l = line_num;
+ SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = sigmap(cell->getPort("\\B"));
+ SigSpec sig_s = sigmap(cell->getPort("\\S"));
+ SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+
+ int width = GetSize(sig_a);
+ int sid = get_bv_sid(width);
+ int nid = get_sig_nid(sig_a);
+
+ for (int i = 0; i < GetSize(sig_s); i++) {
+ int nid_b = get_sig_nid(sig_b.extract(i*width, width));
+ int nid_s = get_sig_nid(sig_s.extract(i));
+ int nid2 = next_nid++;
+ btorf("%d ite %d %d %d %d\n", nid2, sid, nid_s, nid_b, nid);
+ nid = nid2;
}
- else if(expected_width < s.size())
- {
- ++line_num;
- str = stringf ("%d slice %d %d %d %d;3", line_num, expected_width, l, expected_width-1, 0);
- f << stringf("%s\n", str.c_str());
- l = line_num;
+
+ add_nid_sig(nid, sig_y);
+ goto okay;
+ }
+
+ if (cell->type.in("$dff", "$ff", "$_DFF_P_", "$_DFF_N", "$_FF_"))
+ {
+ SigSpec sig_d = sigmap(cell->getPort("\\D"));
+ SigSpec sig_q = sigmap(cell->getPort("\\Q"));
+
+ IdString symbol;
+
+ if (sig_q.is_wire()) {
+ Wire *w = sig_q.as_wire();
+ if (w->port_id == 0) {
+ statewires.insert(w);
+ symbol = w->name;
+ }
+ }
+
+ int sid = get_bv_sid(GetSize(sig_q));
+ int nid = next_nid++;
+
+ if (symbol.empty())
+ btorf("%d state %d\n", nid, sid);
+ else
+ btorf("%d state %d %s\n", nid, sid, log_id(symbol));
+
+ Const initval;
+ for (int i = 0; i < GetSize(sig_q); i++)
+ if (initbits.count(sig_q[i]))
+ initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0);
+ else
+ initval.bits.push_back(State::Sx);
+
+ if (!initval.is_fully_undef()) {
+ int nid_init_val = get_sig_nid(initval);
+ int nid_init = next_nid++;
+ if (verbose)
+ btorf("; initval = %s\n", log_signal(initval));
+ btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val);
}
+
+ ff_todo.push_back(make_pair(nid, cell));
+ add_nid_sig(nid, sig_q);
+ goto okay;
}
- log_assert(l>0);
- return l;
- }
- int dump_cell(const RTLIL::Cell* cell)
- {
- auto it = line_ref.find(cell->name);
- if(it==std::end(line_ref))
+ if (cell->type.in("$anyconst", "$anyseq"))
{
- curr_cell = cell->name;
- //assert cell
- if(cell->type == "$assert")
- {
- log("writing assert cell - %s\n", cstr(cell->type));
- const RTLIL::SigSpec* expr = &cell->getPort(RTLIL::IdString("\\A"));
- const RTLIL::SigSpec* en = &cell->getPort(RTLIL::IdString("\\EN"));
- log_assert(expr->size() == 1);
- log_assert(en->size() == 1);
- int expr_line = dump_sigspec(expr, 1);
- int en_line = dump_sigspec(en, 1);
- int one_line = ++line_num;
- str = stringf("%d one 1", line_num);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf("%d %s %d %d %d", line_num, cell_type_translation.at("$eq").c_str(), 1, en_line, one_line);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf("%d %s %d %d %d %d", line_num, cell_type_translation.at("$mux").c_str(), 1, line_num-1,
- expr_line, one_line);
- f << stringf("%s\n", str.c_str());
- int cell_line = ++line_num;
- str = stringf("%d %s %d %d", line_num, cell_type_translation.at("$assert").c_str(), 1, -1*(line_num-1));
- //multiplying the line number with -1, which means logical negation
- //the reason for negative sign is that the properties in btor are given as "negation of the original property"
- //bug identified by bobosoft
- //http://www.reddit.com/r/yosys/comments/1w3xig/btor_backend_bug/
- f << stringf("%s\n", str.c_str());
- line_ref[cell->name]=cell_line;
+ SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+
+ int sid = get_bv_sid(GetSize(sig_y));
+ int nid = next_nid++;
+
+ btorf("%d state %d\n", nid, sid);
+
+ if (cell->type == "$anyconst") {
+ int nid2 = next_nid++;
+ btorf("%d next %d %d %d\n", nid2, sid, nid, nid);
}
- //unary cells
- else if(cell->type == "$not" || cell->type == "$neg" || cell->type == "$pos" || cell->type == "$reduce_and" ||
- cell->type == "$reduce_or" || cell->type == "$reduce_xor" || cell->type == "$reduce_bool")
+
+ add_nid_sig(nid, sig_y);
+ goto okay;
+ }
+
+ if (cell->type == "$initstate")
+ {
+ SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+
+ if (initstate_nid < 0)
{
- log("writing unary cell - %s\n", cstr(cell->type));
- int w = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
- int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- w = w>output_width ? w:output_width; //padding of w
- int l = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), w);
- int cell_line = l;
- if(cell->type != "$pos")
- {
- cell_line = ++line_num;
- bool reduced = (cell->type == "$not" || cell->type == "$neg") ? false : true;
- str = stringf ("%d %s %d %d", cell_line, cell_type_translation.at(cell->type.str()).c_str(), reduced?output_width:w, l);
- f << stringf("%s\n", str.c_str());
- }
- if(output_width < w && (cell->type == "$not" || cell->type == "$neg" || cell->type == "$pos"))
- {
- ++line_num;
- str = stringf ("%d slice %d %d %d %d;4", line_num, output_width, cell_line, output_width-1, 0);
- f << stringf("%s\n", str.c_str());
- cell_line = line_num;
- }
- line_ref[cell->name]=cell_line;
+ int sid = get_bv_sid(1);
+ int one_nid = get_sig_nid(Const(1, 1));
+ int zero_nid = get_sig_nid(Const(0, 1));
+ initstate_nid = next_nid++;
+ btorf("%d state %d\n", initstate_nid, sid);
+ btorf("%d init %d %d %d\n", next_nid++, sid, initstate_nid, one_nid);
+ btorf("%d next %d %d %d\n", next_nid++, sid, initstate_nid, zero_nid);
}
- else if(cell->type == "$reduce_xnor" || cell->type == "$logic_not")//no direct translation in btor
+
+ add_nid_sig(initstate_nid, sig_y);
+ goto okay;
+ }
+
+ if (cell->type == "$mem")
+ {
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+ int rdports = cell->getParam("\\RD_PORTS").as_int();
+ int wrports = cell->getParam("\\WR_PORTS").as_int();
+
+ Const wr_clk_en = cell->getParam("\\WR_CLK_ENABLE");
+ Const rd_clk_en = cell->getParam("\\RD_CLK_ENABLE");
+
+ bool asyncwr = wr_clk_en.is_fully_zero();
+
+ if (!asyncwr && !wr_clk_en.is_fully_ones())
+ log_error("Memory %s.%s has mixed async/sync write ports.\n",
+ log_id(module), log_id(cell));
+
+ if (!rd_clk_en.is_fully_zero())
+ log_error("Memory %s.%s has sync read ports.\n",
+ log_id(module), log_id(cell));
+
+ SigSpec sig_rd_addr = sigmap(cell->getPort("\\RD_ADDR"));
+ SigSpec sig_rd_data = sigmap(cell->getPort("\\RD_DATA"));
+
+ SigSpec sig_wr_addr = sigmap(cell->getPort("\\WR_ADDR"));
+ SigSpec sig_wr_data = sigmap(cell->getPort("\\WR_DATA"));
+ SigSpec sig_wr_en = sigmap(cell->getPort("\\WR_EN"));
+
+ int data_sid = get_bv_sid(width);
+ int bool_sid = get_bv_sid(1);
+ int sid = get_mem_sid(abits, width);
+ int nid = next_nid++;
+ int nid_head = nid;
+
+ if (cell->name[0] == '$')
+ btorf("%d state %d\n", nid, sid);
+ else
+ btorf("%d state %d %s\n", nid, sid, log_id(cell));
+
+ if (asyncwr)
{
- log("writing unary cell - %s\n", cstr(cell->type));
- int w = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
- int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- log_assert(output_width == 1);
- int l = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), w);
- if(cell->type == "$logic_not" && w > 1)
+ for (int port = 0; port < wrports; port++)
{
- ++line_num;
- str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_or").c_str(), output_width, l);
- f << stringf("%s\n", str.c_str());
- }
- else if(cell->type == "$reduce_xnor")
- {
- ++line_num;
- str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_xor").c_str(), output_width, l);
- f << stringf("%s\n", str.c_str());
+ SigSpec wa = sig_wr_addr.extract(port*abits, abits);
+ SigSpec wd = sig_wr_data.extract(port*width, width);
+ SigSpec we = sig_wr_en.extract(port*width, width);
+
+ int wa_nid = get_sig_nid(wa);
+ int wd_nid = get_sig_nid(wd);
+ int we_nid = get_sig_nid(we);
+
+ int nid2 = next_nid++;
+ btorf("%d read %d %d %d\n", nid2, data_sid, nid_head, wa_nid);
+
+ int nid3 = next_nid++;
+ btorf("%d not %d %d\n", nid3, data_sid, we_nid);
+
+ int nid4 = next_nid++;
+ btorf("%d and %d %d %d\n", nid4, data_sid, nid2, nid3);
+
+ int nid5 = next_nid++;
+ btorf("%d and %d %d %d\n", nid5, data_sid, wd_nid, we_nid);
+
+ int nid6 = next_nid++;
+ btorf("%d or %d %d %d\n", nid6, data_sid, nid5, nid4);
+
+ int nid7 = next_nid++;
+ btorf("%d write %d %d %d %d\n", nid7, sid, nid_head, wa_nid, nid6);
+
+ int nid8 = next_nid++;
+ btorf("%d redor %d %d\n", nid8, bool_sid, we_nid);
+
+ int nid9 = next_nid++;
+ btorf("%d ite %d %d %d %d\n", nid9, sid, nid8, nid7, nid_head);
+
+ nid_head = nid9;
}
- ++line_num;
- str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$not").c_str(), output_width, l);
- f << stringf("%s\n", str.c_str());
- line_ref[cell->name]=line_num;
}
- //binary cells
- else if(cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" ||
- cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" ||
- cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt" )
+
+ for (int port = 0; port < rdports; port++)
{
- log("writing binary cell - %s\n", cstr(cell->type));
- int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- 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 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();
-
- log_assert(l1_signed == l2_signed);
- l1_width = l1_width > output_width ? l1_width : output_width;
- l1_width = l1_width > l2_width ? l1_width : l2_width;
- l2_width = l2_width > l1_width ? l2_width : l1_width;
-
- int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
- int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
-
- ++line_num;
- std::string op = cell_type_translation.at(cell->type.str());
- if(cell->type == "$lt" || cell->type == "$le" ||
- cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" ||
- cell->type == "$ge" || cell->type == "$gt")
- {
- if(l1_signed)
- op = s_cell_type_translation.at(cell->type.str());
- }
+ SigSpec ra = sig_rd_addr.extract(port*abits, abits);
+ SigSpec rd = sig_rd_data.extract(port*width, width);
+
+ int ra_nid = get_sig_nid(ra);
+ int rd_nid = next_nid++;
- str = stringf ("%d %s %d %d %d", line_num, op.c_str(), output_width, l1, l2);
- f << stringf("%s\n", str.c_str());
+ btorf("%d read %d %d %d\n", rd_nid, data_sid, nid_head, ra_nid);
- line_ref[cell->name]=line_num;
+ add_nid_sig(rd_nid, rd);
}
- else if(cell->type == "$add" || cell->type == "$sub" || cell->type == "$mul" || cell->type == "$div" ||
- cell->type == "$mod" )
- {
- //TODO: division by zero case
- log("writing binary cell - %s\n", cstr(cell->type));
- int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- bool l1_signed = cell->parameters.at(RTLIL::IdString("\\A_SIGNED")).as_bool();
- bool l2_signed = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
- int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
- int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
-
- log_assert(l1_signed == l2_signed);
- l1_width = l1_width > output_width ? l1_width : output_width;
- l1_width = l1_width > l2_width ? l1_width : l2_width;
- l2_width = l2_width > l1_width ? l2_width : l1_width;
-
- int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
- int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
-
- ++line_num;
- std::string op = cell_type_translation.at(cell->type.str());
- if(cell->type == "$div" && l1_signed)
- op = s_cell_type_translation.at(cell->type.str());
- else if(cell->type == "$mod")
- {
- if(l1_signed)
- op = s_cell_type_translation.at("$modx");
- else if(l2_signed)
- op = s_cell_type_translation.at("$mody");
- }
- str = stringf ("%d %s %d %d %d", line_num, op.c_str(), l1_width, l1, l2);
- f << stringf("%s\n", str.c_str());
- if(output_width < l1_width)
- {
- ++line_num;
- str = stringf ("%d slice %d %d %d %d;5", line_num, output_width, line_num-1, output_width-1, 0);
- f << stringf("%s\n", str.c_str());
- }
- line_ref[cell->name]=line_num;
+ if (!asyncwr)
+ {
+ ff_todo.push_back(make_pair(nid, cell));
}
- else if(cell->type == "$shr" || cell->type == "$shl" || cell->type == "$sshr" || cell->type == "$sshl" || cell->type == "$shift" || cell->type == "$shiftx")
+ else
{
- log("writing binary cell - %s\n", cstr(cell->type));
- int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- bool l1_signed = cell->parameters.at(RTLIL::IdString("\\A_SIGNED")).as_bool();
- //bool l2_signed = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
- int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
- l1_width = 1 << ceil_log2(l1_width);
- int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
- //log_assert(l2_width <= ceil_log2(l1_width)) );
- int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
- int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), ceil_log2(l1_width));
- int cell_output = ++line_num;
- str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), l1_width, l1, l2);
- f << stringf("%s\n", str.c_str());
-
- if(l2_width > ceil_log2(l1_width))
- {
- int extra_width = l2_width - ceil_log2(l1_width);
- l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
- ++line_num;
- str = stringf ("%d slice %d %d %d %d;6", line_num, extra_width, l2, l2_width-1, l2_width-extra_width);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf ("%d one %d", line_num, extra_width);
- f << stringf("%s\n", str.c_str());
- int mux = ++line_num;
- str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at("$gt").c_str(), 1, line_num-2, line_num-1);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf("%d %s %d", line_num, l1_signed && cell->type == "$sshr" ? "ones":"zero", l1_width);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf ("%d %s %d %d %d %d", line_num, cell_type_translation.at("$mux").c_str(), l1_width, mux, line_num-1, cell_output);
- f << stringf("%s\n", str.c_str());
- cell_output = line_num;
- }
+ int nid2 = next_nid++;
+ btorf("%d next %d %d %d\n", nid2, sid, nid, nid_head);
+ }
- if(output_width < l1_width)
- {
- ++line_num;
- str = stringf ("%d slice %d %d %d %d;5", line_num, output_width, cell_output, output_width-1, 0);
- f << stringf("%s\n", str.c_str());
- cell_output = line_num;
+ goto okay;
+ }
+
+ log_error("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
+
+ okay:
+ btorf_pop(log_id(cell));
+ cell_recursion_guard.erase(cell);
+ }
+
+ int get_sig_nid(SigSpec sig, int to_width = -1, bool is_signed = false)
+ {
+ int nid = -1;
+ sigmap.apply(sig);
+
+ for (auto bit : sig)
+ if (bit == State::Sx)
+ goto has_undef_bits;
+
+ if (0)
+ {
+ has_undef_bits:
+ SigSpec sig_mask_undef, sig_noundef;
+ int first_undef = -1;
+
+ for (int i = 0; i < GetSize(sig); i++)
+ if (sig[i] == State::Sx) {
+ if (first_undef < 0)
+ first_undef = i;
+ sig_mask_undef.append(State::S1);
+ sig_noundef.append(State::S0);
+ } else {
+ sig_mask_undef.append(State::S0);
+ sig_noundef.append(sig[i]);
}
- line_ref[cell->name] = cell_output;
- }
- else if(cell->type == "$logic_and" || cell->type == "$logic_or")//no direct translation in btor
+
+ if (to_width < 0 || first_undef < to_width)
{
- log("writing binary cell - %s\n", cstr(cell->type));
- int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
- log_assert(output_width == 1);
- int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), output_width);
- int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), output_width);
- int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
- int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
- if(l1_width >1)
- {
- ++line_num;
- str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_or").c_str(), output_width, l1);
- f << stringf("%s\n", str.c_str());
- l1 = line_num;
+ int sid = get_bv_sid(GetSize(sig));
+
+ int nid_input = next_nid++;
+ btorf("%d input %d\n", nid_input, sid);
+
+ int nid_masked_input;
+ if (sig_mask_undef.is_fully_ones()) {
+ nid_masked_input = nid_input;
+ } else {
+ int nid_mask_undef = get_sig_nid(sig_mask_undef);
+ nid_masked_input = next_nid++;
+ btorf("%d and %d %d %d\n", nid_masked_input, sid, nid_input, nid_mask_undef);
}
- if(l2_width > 1)
- {
- ++line_num;
- str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_or").c_str(), output_width, l2);
- f << stringf("%s\n", str.c_str());
- l2 = line_num;
- }
- if(cell->type == "$logic_and")
- {
- ++line_num;
- str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at("$and").c_str(), output_width, l1, l2);
- }
- else if(cell->type == "$logic_or")
- {
- ++line_num;
- str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at("$or").c_str(), output_width, l1, l2);
+
+ if (sig_noundef.is_fully_zero()) {
+ nid = nid_masked_input;
+ } else {
+ int nid_noundef = get_sig_nid(sig_noundef);
+ nid = next_nid++;
+ btorf("%d or %d %d %d\n", nid, sid, nid_masked_input, nid_noundef);
}
- f << stringf("%s\n", str.c_str());
- line_ref[cell->name]=line_num;
- }
- //multiplexers
- else if(cell->type == "$mux")
- {
- log("writing mux cell\n");
- int output_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
- int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), output_width);
- int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), output_width);
- int s = dump_sigspec(&cell->getPort(RTLIL::IdString("\\S")), 1);
- ++line_num;
- str = stringf ("%d %s %d %d %d %d",
- line_num, cell_type_translation.at(cell->type.str()).c_str(), output_width, s, l2, l1);
- //if s is 0 then l1, if s is 1 then l2 //according to the implementation of mux cell
- f << stringf("%s\n", str.c_str());
- line_ref[cell->name]=line_num;
+
+ goto extend_or_trim;
}
- else if(cell->type == "$pmux")
- {
- log("writing pmux cell\n");
- int output_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
- int select_width = cell->parameters.at(RTLIL::IdString("\\S_WIDTH")).as_int();
- int default_case = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), output_width);
- int cases = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), output_width*select_width);
- int select = dump_sigspec(&cell->getPort(RTLIL::IdString("\\S")), select_width);
- int *c = new int[select_width];
-
- for (int i=0; i<select_width; ++i)
- {
- ++line_num;
- str = stringf ("%d slice 1 %d %d %d", line_num, select, i, i);
- f << stringf("%s\n", str.c_str());
- c[i] = line_num;
- ++line_num;
- str = stringf ("%d slice %d %d %d %d", line_num, output_width, cases, i*output_width+output_width-1,
- i*output_width);
- f << stringf("%s\n", str.c_str());
- }
-
- ++line_num;
- str = stringf ("%d cond %d %d %d %d", line_num, output_width, c[select_width-1], c[select_width-1]+1, default_case);
- f << stringf("%s\n", str.c_str());
-
- for (int i=select_width-2; i>=0; --i)
- {
- ++line_num;
- str = stringf ("%d cond %d %d %d %d", line_num, output_width, c[i], c[i]+1, line_num-1);
- f << stringf("%s\n", str.c_str());
- }
-
- line_ref[cell->name]=line_num;
- }
- //registers
- else if(cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffsr")
+
+ sig = sig_noundef;
+ }
+
+ if (sig_nid.count(sig) == 0)
+ {
+ // <nid>, <bitidx>
+ vector<pair<int, int>> nidbits;
+
+ // collect all bits
+ for (int i = 0; i < GetSize(sig); i++)
{
- //TODO: remodelling of adff cells
- log("writing cell - %s\n", cstr(cell->type));
- int output_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
- log(" - width is %d\n", output_width);
- int cond = dump_sigspec(&cell->getPort(RTLIL::IdString("\\CLK")), 1);
- bool polarity = cell->parameters.at(RTLIL::IdString("\\CLK_POLARITY")).as_bool();
- const RTLIL::SigSpec* cell_output = &cell->getPort(RTLIL::IdString("\\Q"));
- int value = dump_sigspec(&cell->getPort(RTLIL::IdString("\\D")), output_width);
- unsigned start_bit = 0;
- for(unsigned i=0; i<cell_output->chunks().size(); ++i)
+ SigBit bit = sig[i];
+
+ if (bit_nid.count(bit) == 0)
{
- output_width = cell_output->chunks().at(i).width;
- log_assert( output_width == cell_output->chunks().at(i).wire->width);//full reg is given the next value
- int reg = dump_wire(cell_output->chunks().at(i).wire);//register
- int slice = value;
- if(cell_output->chunks().size()>1)
+ if (bit.wire == nullptr)
{
- start_bit+=output_width;
- slice = ++line_num;
- str = stringf ("%d slice %d %d %d %d;", line_num, output_width, value, start_bit-1,
- start_bit-output_width);
- f << stringf("%s\n", str.c_str());
- }
- if(cell->type == "$dffsr")
- {
- int sync_reset = dump_sigspec(&cell->getPort(RTLIL::IdString("\\CLR")), 1);
- bool sync_reset_pol = cell->parameters.at(RTLIL::IdString("\\CLR_POLARITY")).as_bool();
- int sync_reset_value = dump_sigspec(&cell->getPort(RTLIL::IdString("\\SET")),
- output_width);
- bool sync_reset_value_pol = cell->parameters.at(RTLIL::IdString("\\SET_POLARITY")).as_bool();
- ++line_num;
- str = stringf ("%d %s %d %s%d %s%d %d", line_num, cell_type_translation.at("$mux").c_str(),
- output_width, sync_reset_pol ? "":"-", sync_reset, sync_reset_value_pol? "":"-",
- sync_reset_value, slice);
- f << stringf("%s\n", str.c_str());
- slice = line_num;
- }
- ++line_num;
- str = stringf ("%d %s %d %s%d %d %d", line_num, cell_type_translation.at("$mux").c_str(),
- output_width, polarity?"":"-", cond, slice, reg);
+ Const c(bit.data);
+
+ while (i+GetSize(c) < GetSize(sig) && sig[i+GetSize(c)].wire == nullptr)
+ c.bits.push_back(sig[i+GetSize(c)].data);
+
+ if (consts.count(c) == 0) {
+ int sid = get_bv_sid(GetSize(c));
+ int nid = next_nid++;
+ btorf("%d const %d %s\n", nid, sid, c.as_string().c_str());
+ consts[c] = nid;
+ nid_width[nid] = GetSize(c);
+ }
+
+ int nid = consts.at(c);
- f << stringf("%s\n", str.c_str());
- int next = line_num;
- if(cell->type == "$adff")
+ for (int j = 0; j < GetSize(c); j++)
+ nidbits.push_back(make_pair(nid, j));
+
+ i += GetSize(c)-1;
+ continue;
+ }
+ else
{
- int async_reset = dump_sigspec(&cell->getPort(RTLIL::IdString("\\ARST")), 1);
- bool async_reset_pol = cell->parameters.at(RTLIL::IdString("\\ARST_POLARITY")).as_bool();
- int async_reset_value = dump_const(&cell->parameters.at(RTLIL::IdString("\\ARST_VALUE")),
- output_width, 0);
- ++line_num;
- str = stringf ("%d %s %d %s%d %d %d", line_num, cell_type_translation.at("$mux").c_str(),
- output_width, async_reset_pol ? "":"-", async_reset, async_reset_value, next);
- f << stringf("%s\n", str.c_str());
+ if (bit_cell.count(bit) == 0)
+ log_error("No driver for signal bit %s.\n", log_signal(bit));
+ export_cell(bit_cell.at(bit));
+ log_assert(bit_nid.count(bit));
}
- ++line_num;
- str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(),
- output_width, reg, next);
- f << stringf("%s\n", str.c_str());
}
- line_ref[cell->name]=line_num;
- }
- //memories
- else if(cell->type == "$memrd")
- {
- log("writing memrd cell\n");
- if (cell->parameters.at("\\CLK_ENABLE").as_bool() == true)
- log_error("The btor backen does not support $memrd cells with built-in registers. Run memory_dff with -wr_only.\n");
- str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string();
- int mem = dump_memory(module->memories.at(RTLIL::IdString(str.c_str())));
- int address_width = cell->parameters.at(RTLIL::IdString("\\ABITS")).as_int();
- int address = dump_sigspec(&cell->getPort(RTLIL::IdString("\\ADDR")), address_width);
- int data_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
- ++line_num;
- str = stringf("%d read %d %d %d", line_num, data_width, mem, address);
- f << stringf("%s\n", str.c_str());
- line_ref[cell->name]=line_num;
+
+ nidbits.push_back(bit_nid.at(bit));
}
- else if(cell->type == "$memwr")
+
+ int width = 0;
+ int nid = -1;
+
+ // group bits and emit slice-concat chain
+ for (int i = 0; i < GetSize(nidbits); i++)
{
- log("writing memwr cell\n");
- if (cell->parameters.at("\\CLK_ENABLE").as_bool() == false)
- log_error("The btor backen does not support $memwr cells without built-in registers. Run memory_dff (but with -wr_only).\n");
- int clk = dump_sigspec(&cell->getPort(RTLIL::IdString("\\CLK")), 1);
- bool polarity = cell->parameters.at(RTLIL::IdString("\\CLK_POLARITY")).as_bool();
- int enable = dump_sigspec(&cell->getPort(RTLIL::IdString("\\EN")), 1);
- int address_width = cell->parameters.at(RTLIL::IdString("\\ABITS")).as_int();
- int address = dump_sigspec(&cell->getPort(RTLIL::IdString("\\ADDR")), address_width);
- int data_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
- int data = dump_sigspec(&cell->getPort(RTLIL::IdString("\\DATA")), data_width);
- str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string();
- int mem = dump_memory(module->memories.at(RTLIL::IdString(str.c_str())));
- //check if the memory has already next
- /*
- auto it = mem_next.find(mem);
- if(it != std::end(mem_next))
- {
- ++line_num;
- str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string();
- RTLIL::Memory *memory = module->memories.at(RTLIL::IdString(str.c_str()));
- int address_bits = ceil_log2(memory->size);
- str = stringf("%d array %d %d", line_num, memory->width, address_bits);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf("%d eq 1 %d %d; mem invar", line_num, mem, line_num - 1);
- f << stringf("%s\n", str.c_str());
- mem = line_num - 1;
+ int nid2 = nidbits[i].first;
+ int lower = nidbits[i].second;
+ int upper = lower;
+
+ while (i+1 < GetSize(nidbits) && nidbits[i+1].first == nidbits[i].first &&
+ nidbits[i+1].second == nidbits[i].second+1)
+ upper++, i++;
+
+ int nid3 = nid2;
+
+ if (lower != 0 || upper+1 != nid_width.at(nid2)) {
+ int sid = get_bv_sid(upper-lower+1);
+ nid3 = next_nid++;
+ btorf("%d slice %d %d %d %d\n", nid3, sid, nid2, upper, lower);
}
- */
- ++line_num;
- if(polarity)
- str = stringf("%d one 1", line_num);
- else
- str = stringf("%d zero 1", line_num);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf("%d eq 1 %d %d", line_num, clk, line_num-1);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf("%d and 1 %d %d", line_num, line_num-1, enable);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf("%d write %d %d %d %d %d", line_num, data_width, address_width, mem, address, data);
- f << stringf("%s\n", str.c_str());
- /*
- ++line_num;
- str = stringf("%d acond %d %d %d %d %d", line_num, data_width, address_width, line_num-2, line_num-1, mem);
- f << stringf("%s\n", str.c_str());
- ++line_num;
- str = stringf("%d anext %d %d %d %d", line_num, data_width, address_width, mem, line_num-1);
- f << stringf("%s\n", str.c_str());
- */
- mem_next[mem].insert(std::make_pair(line_num-1, line_num));
+
+ int nid4 = nid3;
+
+ if (nid >= 0) {
+ int sid = get_bv_sid(width+upper-lower+1);
+ nid4 = next_nid++;
+ btorf("%d concat %d %d %d\n", nid4, sid, nid3, nid);
+ }
+
+ width += upper-lower+1;
+ nid = nid4;
}
- else if(cell->type == "$slice")
+
+ sig_nid[sig] = nid;
+ nid_width[nid] = width;
+ }
+
+ nid = sig_nid.at(sig);
+
+ extend_or_trim:
+ if (to_width >= 0 && to_width != GetSize(sig))
+ {
+ if (to_width < GetSize(sig))
{
- log("writing slice cell\n");
- const RTLIL::SigSpec* input = &cell->getPort(RTLIL::IdString("\\A"));
- 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 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();
- ++line_num;
- str = stringf("%d %s %d %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), output_width, input_line, output_width+offset-1, offset);
- f << stringf("%s\n", str.c_str());
- line_ref[cell->name]=line_num;
+ int sid = get_bv_sid(to_width);
+ int nid2 = next_nid++;
+ btorf("%d slice %d %d %d 0\n", nid2, sid, nid, to_width-1);
+ nid = nid2;
}
- else if(cell->type == "$concat")
+ else
{
- log("writing concat cell\n");
- const RTLIL::SigSpec* input_a = &cell->getPort(RTLIL::IdString("\\A"));
- int input_a_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
- log_assert(input_a->size() == input_a_width);
- int input_a_line = dump_sigspec(input_a, input_a_width);
- const RTLIL::SigSpec* input_b = &cell->getPort(RTLIL::IdString("\\B"));
- int input_b_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
- log_assert(input_b->size() == input_b_width);
- int input_b_line = dump_sigspec(input_b, input_b_width);
- ++line_num;
- str = stringf("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), input_a_width+input_b_width,
- input_a_line, input_b_line);
- f << stringf("%s\n", str.c_str());
- line_ref[cell->name]=line_num;
+ int sid = get_bv_sid(to_width);
+ int nid2 = next_nid++;
+ btorf("%d %s %d %d %d\n", nid2, is_signed ? "sext" : "uext",
+ sid, nid, to_width - GetSize(sig));
+ nid = nid2;
}
- curr_cell.clear();
- return line_num;
- }
- else
- {
- return it->second;
}
+
+ return nid;
}
- const RTLIL::SigSpec* get_cell_output(RTLIL::Cell* cell)
+ BtorWorker(std::ostream &f, RTLIL::Module *module, bool verbose, bool single_bad) :
+ f(f), sigmap(module), module(module), verbose(verbose), single_bad(single_bad)
{
- const RTLIL::SigSpec *output_sig = nullptr;
- if (cell->type == "$memrd")
- {
- output_sig = &cell->getPort(RTLIL::IdString("\\DATA"));
- }
- else if(cell->type == "$memwr" || cell->type == "$assert")
+ btorf_push("inputs");
+
+ for (auto wire : module->wires())
{
- //no output
+ if (wire->attributes.count("\\init")) {
+ Const attrval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(wire) && i < GetSize(attrval); i++)
+ if (attrval[i] == State::S0 || attrval[i] == State::S1)
+ initbits[sigmap(SigBit(wire, i))] = (attrval[i] == State::S1);
+ }
+
+ if (!wire->port_id || !wire->port_input)
+ continue;
+
+ SigSpec sig = sigmap(wire);
+ int sid = get_bv_sid(GetSize(sig));
+ int nid = next_nid++;
+
+ btorf("%d input %d %s\n", nid, sid, log_id(wire));
+ add_nid_sig(nid, sig);
}
- else if(cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffsr")
+
+ btorf_pop("inputs");
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections())
{
- output_sig = &cell->getPort(RTLIL::IdString("\\Q"));
+ if (!cell->output(conn.first))
+ continue;
+
+ for (auto bit : sigmap(conn.second))
+ bit_cell[bit] = cell;
}
- else
+
+ for (auto wire : module->wires())
{
- output_sig = &cell->getPort(RTLIL::IdString("\\Y"));
- }
- return output_sig;
- }
+ if (!wire->port_id || !wire->port_output)
+ continue;
- void dump_property(RTLIL::Wire *wire)
- {
- int l = dump_wire(wire);
- ++line_num;
- str = stringf("%d root 1 %d", line_num, l);
- f << stringf("%s\n", str.c_str());
- }
+ btorf_push(stringf("output %s", log_id(wire)));
- void dump()
- {
- f << stringf(";module %s\n", cstr(module->name));
+ int sid = get_bv_sid(GetSize(wire));
+ int nid = get_sig_nid(wire);
+ btorf("%d output %d %d %s\n", next_nid++, sid, nid, log_id(wire));
+
+ btorf_pop(stringf("output %s", log_id(wire)));
+ }
- log("creating intermediate wires map\n");
- //creating map of intermediate wires as output of some cell
- for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = it->second;
- const RTLIL::SigSpec* output_sig = get_cell_output(cell);
- if(output_sig==nullptr)
- continue;
- RTLIL::SigSpec s = sigmap(*output_sig);
- output_sig = &s;
- log(" - %s\n", cstr(it->second->type));
- if (cell->type == "$memrd")
- {
- for(unsigned i=0; i<output_sig->chunks().size(); ++i)
- {
- RTLIL::Wire *w = output_sig->chunks().at(i).wire;
- RTLIL::IdString wire_id = w->name;
- inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks().at(i)));
- }
- }
- else if(cell->type == "$memwr")
+ if (cell->type == "$assume")
{
- continue;//nothing to do
- }
- else if(cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffsr")
- {
- RTLIL::IdString wire_id = output_sig->chunks().front().wire->name;
- for(unsigned i=0; i<output_sig->chunks().size(); ++i)
- {
- RTLIL::Wire *w = output_sig->chunks().at(i).wire;
- RTLIL::IdString wire_id = w->name;
- inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks().at(i)));
- basic_wires[wire_id] = true;
- }
+ btorf_push(log_id(cell));
+
+ int sid = get_bv_sid(1);
+ int nid_a = get_sig_nid(cell->getPort("\\A"));
+ int nid_en = get_sig_nid(cell->getPort("\\EN"));
+ int nid_not_en = next_nid++;
+ int nid_a_or_not_en = next_nid++;
+ int nid = next_nid++;
+
+ btorf("%d not %d %d\n", nid_not_en, sid, nid_en);
+ btorf("%d or %d %d %d\n", nid_a_or_not_en, sid, nid_a, nid_not_en);
+ btorf("%d constraint %d\n", nid, nid_a_or_not_en);
+
+ btorf_pop(log_id(cell));
}
- else
+
+ if (cell->type == "$assert")
{
- for(unsigned i=0; i<output_sig->chunks().size(); ++i)
- {
- RTLIL::Wire *w = output_sig->chunks().at(i).wire;
- RTLIL::IdString wire_id = w->name;
- inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks().at(i)));
+ btorf_push(log_id(cell));
+
+ int sid = get_bv_sid(1);
+ int nid_a = get_sig_nid(cell->getPort("\\A"));
+ int nid_en = get_sig_nid(cell->getPort("\\EN"));
+ int nid_not_a = next_nid++;
+ int nid_en_and_not_a = next_nid++;
+
+ btorf("%d not %d %d\n", nid_not_a, sid, nid_a);
+ btorf("%d and %d %d %d\n", nid_en_and_not_a, sid, nid_en, nid_not_a);
+
+ if (single_bad) {
+ bad_properties.push_back(nid_en_and_not_a);
+ } else {
+ int nid = next_nid++;
+ btorf("%d bad %d\n", nid, nid_en_and_not_a);
}
- }
- }
- log("writing input\n");
- std::map<int, RTLIL::Wire*> inputs, outputs;
- std::vector<RTLIL::Wire*> safety;
-
- for (auto &wire_it : module->wires_) {
- RTLIL::Wire *wire = wire_it.second;
- if (wire->port_input)
- inputs[wire->port_id] = wire;
- if (wire->port_output) {
- outputs[wire->port_id] = wire;
- if (wire->name.str().find("safety") != std::string::npos )
- safety.push_back(wire);
+ btorf_pop(log_id(cell));
}
}
- f << stringf(";inputs\n");
- for (auto &it : inputs) {
- RTLIL::Wire *wire = it.second;
- dump_wire(wire);
+ for (auto wire : module->wires())
+ {
+ if (wire->port_id || wire->name[0] == '$')
+ continue;
+
+ btorf_push(stringf("wire %s", log_id(wire)));
+
+ int sid = get_bv_sid(GetSize(wire));
+ int nid = get_sig_nid(sigmap(wire));
+
+ if (statewires.count(wire))
+ continue;
+
+ int this_nid = next_nid++;
+ btorf("%d uext %d %d %d %s\n", this_nid, sid, nid, 0, log_id(wire));
+
+ btorf_pop(stringf("wire %s", log_id(wire)));
+ continue;
}
- f << stringf("\n");
- log("writing memories\n");
- for(auto mem_it = module->memories.begin(); mem_it != module->memories.end(); ++mem_it)
+ while (!ff_todo.empty())
{
- dump_memory(mem_it->second);
- }
+ vector<pair<int, Cell*>> todo;
+ todo.swap(ff_todo);
+
+ for (auto &it : todo)
+ {
+ int nid = it.first;
+ Cell *cell = it.second;
+
+ btorf_push(stringf("next %s", log_id(cell)));
+
+ if (cell->type == "$mem")
+ {
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+ int wrports = cell->getParam("\\WR_PORTS").as_int();
+
+ SigSpec sig_wr_addr = sigmap(cell->getPort("\\WR_ADDR"));
+ SigSpec sig_wr_data = sigmap(cell->getPort("\\WR_DATA"));
+ SigSpec sig_wr_en = sigmap(cell->getPort("\\WR_EN"));
+
+ int data_sid = get_bv_sid(width);
+ int bool_sid = get_bv_sid(1);
+ int sid = get_mem_sid(abits, width);
+ int nid_head = nid;
+
+ for (int port = 0; port < wrports; port++)
+ {
+ SigSpec wa = sig_wr_addr.extract(port*abits, abits);
+ SigSpec wd = sig_wr_data.extract(port*width, width);
+ SigSpec we = sig_wr_en.extract(port*width, width);
+
+ int wa_nid = get_sig_nid(wa);
+ int wd_nid = get_sig_nid(wd);
+ int we_nid = get_sig_nid(we);
+
+ int nid2 = next_nid++;
+ btorf("%d read %d %d %d\n", nid2, data_sid, nid_head, wa_nid);
+
+ int nid3 = next_nid++;
+ btorf("%d not %d %d\n", nid3, data_sid, we_nid);
+
+ int nid4 = next_nid++;
+ btorf("%d and %d %d %d\n", nid4, data_sid, nid2, nid3);
+
+ int nid5 = next_nid++;
+ btorf("%d and %d %d %d\n", nid5, data_sid, wd_nid, we_nid);
+
+ int nid6 = next_nid++;
+ btorf("%d or %d %d %d\n", nid6, data_sid, nid5, nid4);
+
+ int nid7 = next_nid++;
+ btorf("%d write %d %d %d %d\n", nid7, sid, nid_head, wa_nid, nid6);
+
+ int nid8 = next_nid++;
+ btorf("%d redor %d %d\n", nid8, bool_sid, we_nid);
+
+ int nid9 = next_nid++;
+ btorf("%d ite %d %d %d %d\n", nid9, sid, nid8, nid7, nid_head);
+
+ nid_head = nid9;
+ }
+
+ int nid2 = next_nid++;
+ btorf("%d next %d %d %d\n", nid2, sid, nid, nid_head);
+ }
+ else
+ {
+ SigSpec sig = sigmap(cell->getPort("\\D"));
+ int nid_q = get_sig_nid(sig);
+ int sid = get_bv_sid(GetSize(sig));
+ btorf("%d next %d %d %d\n", next_nid++, sid, nid, nid_q);
+ }
- log("writing output wires\n");
- for (auto &it : outputs) {
- RTLIL::Wire *wire = it.second;
- dump_wire(wire);
+ btorf_pop(stringf("next %s", log_id(cell)));
+ }
}
- log("writing cells\n");
- for(auto cell_it = module->cells_.begin(); cell_it != module->cells_.end(); ++cell_it)
+ while (!bad_properties.empty())
{
- dump_cell(cell_it->second);
- }
+ vector<int> todo;
+ bad_properties.swap(todo);
- log("writing memory next");
- for(auto mem_it = module->memories.begin(); mem_it != module->memories.end(); ++mem_it)
- {
- dump_memory_next(mem_it->second);
- }
+ int sid = get_bv_sid(1);
+ int cursor = 0;
- for(auto it: safety)
- dump_property(it);
+ while (cursor+1 < GetSize(todo))
+ {
+ int nid_a = todo[cursor++];
+ int nid_b = todo[cursor++];
+ int nid = next_nid++;
- f << stringf("\n");
+ bad_properties.push_back(nid);
+ btorf("%d or %d %d %d\n", nid, sid, nid_a, nid_b);
+ }
- log("writing outputs info\n");
- f << stringf(";outputs\n");
- for (auto &it : outputs) {
- RTLIL::Wire *wire = it.second;
- int l = dump_wire(wire);
- f << stringf(";%d %s", l, cstr(wire->name));
+ if (!bad_properties.empty()) {
+ if (cursor < GetSize(todo))
+ bad_properties.push_back(todo[cursor++]);
+ log_assert(cursor == GetSize(todo));
+ } else {
+ int nid = next_nid++;
+ log_assert(cursor == 0);
+ log_assert(GetSize(todo) == 1);
+ btorf("%d bad %d\n", nid, todo[cursor]);
+ }
}
- f << stringf("\n");
- }
-
- static void dump(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig &config)
- {
- BtorDumper dumper(f, module, design, &config);
- dumper.dump();
}
};
struct BtorBackend : public Backend {
BtorBackend() : Backend("btor", "write design to BTOR file") { }
-
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" write_btor [filename]\n");
+ log(" write_btor [options] [filename]\n");
+ log("\n");
+ log("Write a BTOR description of the current design.\n");
+ log("\n");
+ log(" -v\n");
+ log(" Add comments and indentation to BTOR output file\n");
+ log("\n");
+ log(" -s\n");
+ log(" Output only a single bad property for all asserts\n");
log("\n");
- log("Write the current design to an BTOR file.\n");
}
-
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- std::string top_module_name;
- std::string buf_type, buf_in, buf_out;
- std::string true_type, true_out;
- std::string false_type, false_out;
- BtorDumperConfig config;
+ bool verbose = false, single_bad = false;
log_header(design, "Executing BTOR backend.\n");
- size_t argidx=1;
- extra_args(f, filename, args, argidx);
-
- if (top_module_name.empty())
- for (auto & mod_it:design->modules_)
- if (mod_it.second->get_bool_attribute("\\top"))
- top_module_name = mod_it.first.str();
-
- *f << stringf("; Generated by %s\n", yosys_version_str);
- *f << stringf("; %s developed and maintained by Clifford Wolf <clifford@clifford.at>\n", yosys_version_str);
- *f << stringf("; BTOR Backend developed by Ahmed Irfan <irfan@fbk.eu> - Fondazione Bruno Kessler, Trento, Italy\n");
- *f << stringf(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
-
- std::vector<RTLIL::Module*> mod_list;
-
- for (auto module_it : design->modules_)
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
{
- RTLIL::Module *module = module_it.second;
- if (module->get_bool_attribute("\\blackbox"))
+ if (args[argidx] == "-v") {
+ verbose = true;
continue;
-
- if (module->processes.size() != 0)
- log_error("Found unmapped processes in module %s: unmapped processes are not supported in BTOR backend!\n", RTLIL::id2cstr(module->name));
-
- if (module->name == RTLIL::escape_id(top_module_name)) {
- BtorDumper::dump(*f, module, design, config);
- top_module_name.clear();
+ }
+ if (args[argidx] == "-s") {
+ single_bad = true;
continue;
}
-
- mod_list.push_back(module);
+ break;
}
+ extra_args(f, filename, args, argidx);
+
+ RTLIL::Module *topmod = design->top_module();
+
+ if (topmod == nullptr)
+ log_cmd_error("No top module found.\n");
+
+ *f << stringf("; BTOR description generated by %s for module %s.\n",
+ yosys_version_str, log_id(topmod));
- if (!top_module_name.empty())
- log_error("Can't find top module `%s'!\n", top_module_name.c_str());
+ BtorWorker(*f, topmod, verbose, single_bad);
- for (auto module : mod_list)
- BtorDumper::dump(*f, module, design, config);
+ *f << stringf("; end of yosys output\n");
}
} BtorBackend;
diff --git a/backends/btor/test_cells.sh b/backends/btor/test_cells.sh
new file mode 100644
index 00000000..e0f1a051
--- /dev/null
+++ b/backends/btor/test_cells.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+set -ex
+
+rm -rf test_cells.tmp
+mkdir -p test_cells.tmp
+cd test_cells.tmp
+
+../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod'
+
+for fn in test_*.il; do
+ ../../../yosys -p "
+ read_ilang $fn
+ rename gold gate
+ synth
+
+ read_ilang $fn
+ miter -equiv -make_assert -flatten gold gate main
+ hierarchy -top main
+ write_btor ${fn%.il}.btor
+ "
+ boolectormc -kmax 1 --trace-gen --stop-first -v ${fn%.il}.btor > ${fn%.il}.out
+ if grep " SATISFIABLE" ${fn%.il}.out; then
+ echo "Check failed for ${fn%.il}."
+ exit 1
+ fi
+done
+
+echo "OK."
+
diff --git a/backends/btor/verilog2btor.sh b/backends/btor/verilog2btor.sh
deleted file mode 100755
index dfd7f1a8..00000000
--- a/backends/btor/verilog2btor.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-
-#
-# Script to write BTOR from Verilog design
-#
-
-if [ "$#" -ne 3 ]; then
- echo "Usage: $0 input.v output.btor top-module-name" >&2
- exit 1
-fi
-if ! [ -e "$1" ]; then
- echo "$1 not found" >&2
- exit 1
-fi
-
-FULL_PATH=$(readlink -f $1)
-DIR=$(dirname $FULL_PATH)
-
-./yosys -q -p "
-read_verilog -sv $1;
-hierarchy -top $3;
-hierarchy -libdir $DIR;
-hierarchy -check;
-proc;
-opt; opt_expr -mux_undef; opt;
-rename -hide;;;
-#techmap -map +/pmux2mux.v;;
-splice; opt;
-memory_dff -wr_only;
-memory_collect;;
-flatten;;
-memory_unpack;
-splitnets -driver;
-setundef -zero -undriven;
-opt;;;
-write_btor $2;"
-
diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc
index d16f1831..5f9ec54f 100644
--- a/backends/edif/edif.cc
+++ b/backends/edif/edif.cc
@@ -31,65 +31,66 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str()
+#define EDIF_DEFR(_id, _ren, _bl, _br) edif_names(RTLIL::unescape_id(_id), true, _ren, _bl, _br).c_str()
#define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false).c_str()
-namespace
+struct EdifNames
{
- struct EdifNames
- {
- int counter;
- std::set<std::string> generated_names, used_names;
- std::map<std::string, std::string> name_map;
+ int counter;
+ char delim_left, delim_right;
+ std::set<std::string> generated_names, used_names;
+ std::map<std::string, std::string> name_map;
- EdifNames() : counter(1) { }
+ EdifNames() : counter(1), delim_left('['), delim_right(']') { }
- std::string operator()(std::string id, bool define)
- {
- if (define) {
- std::string new_id = operator()(id, false);
- return new_id != id ? stringf("(rename %s \"%s\")", new_id.c_str(), id.c_str()) : id;
- }
+ std::string operator()(std::string id, bool define, bool port_rename = false, int range_left = 0, int range_right = 0)
+ {
+ if (define) {
+ std::string new_id = operator()(id, false);
+ if (port_rename)
+ return stringf("(rename %s \"%s%c%d:%d%c\")", new_id.c_str(), id.c_str(), delim_left, range_left, range_right, delim_right);
+ return new_id != id ? stringf("(rename %s \"%s\")", new_id.c_str(), id.c_str()) : id;
+ }
- if (name_map.count(id) > 0)
- return name_map.at(id);
- if (generated_names.count(id) > 0)
- goto do_rename;
- if (id == "GND" || id == "VCC")
- goto do_rename;
+ if (name_map.count(id) > 0)
+ return name_map.at(id);
+ if (generated_names.count(id) > 0)
+ goto do_rename;
+ if (id == "GND" || id == "VCC")
+ goto do_rename;
- for (size_t i = 0; i < id.size(); i++) {
- if ('A' <= id[i] && id[i] <= 'Z')
- continue;
- if ('a' <= id[i] && id[i] <= 'z')
- continue;
- if ('0' <= id[i] && id[i] <= '9' && i > 0)
- continue;
- if (id[i] == '_' && i > 0 && i != id.size()-1)
- continue;
- goto do_rename;
- }
+ for (size_t i = 0; i < id.size(); i++) {
+ if ('A' <= id[i] && id[i] <= 'Z')
+ continue;
+ if ('a' <= id[i] && id[i] <= 'z')
+ continue;
+ if ('0' <= id[i] && id[i] <= '9' && i > 0)
+ continue;
+ if (id[i] == '_' && i > 0 && i != id.size()-1)
+ continue;
+ goto do_rename;
+ }
- used_names.insert(id);
- return id;
+ used_names.insert(id);
+ return id;
- do_rename:;
- std::string gen_name;
- while (1) {
- gen_name = stringf("id%05d", counter++);
- if (generated_names.count(gen_name) == 0 &&
- used_names.count(gen_name) == 0)
- break;
- }
- generated_names.insert(gen_name);
- name_map[id] = gen_name;
- return gen_name;
+ do_rename:;
+ std::string gen_name;
+ while (1) {
+ gen_name = stringf("id%05d", counter++);
+ if (generated_names.count(gen_name) == 0 &&
+ used_names.count(gen_name) == 0)
+ break;
}
- };
-}
+ generated_names.insert(gen_name);
+ name_map[id] = gen_name;
+ return gen_name;
+ }
+};
struct EdifBackend : public Backend {
EdifBackend() : Backend("edif", "write design to EDIF netlist file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -105,17 +106,21 @@ struct EdifBackend : public Backend {
log(" if the design contains constant nets. use \"hilomap\" to map to custom\n");
log(" constant drivers first)\n");
log("\n");
+ log(" -pvector {par|bra|ang}\n");
+ log(" sets the delimiting character for module port rename clauses to\n");
+ log(" parentheses, square brackets, or angle brackets.\n");
+ log("\n");
log("Unfortunately there are different \"flavors\" of the EDIF file format. This\n");
log("command generates EDIF files for the Xilinx place&route tools. It might be\n");
log("necessary to make small modifications to this command when a different tool\n");
log("is targeted.\n");
log("\n");
}
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing EDIF backend.\n");
-
std::string top_module_name;
+ bool port_rename = false;
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
bool nogndvcc = false;
CellTypes ct(design);
@@ -132,6 +137,19 @@ struct EdifBackend : public Backend {
nogndvcc = true;
continue;
}
+ if (args[argidx] == "-pvector" && argidx+1 < args.size()) {
+ std::string parray;
+ port_rename = true;
+ parray = args[++argidx];
+ if (parray == "par") {
+ edif_names.delim_left = '(';edif_names.delim_right = ')';
+ } else if (parray == "ang") {
+ edif_names.delim_left = '<';edif_names.delim_right = '>';
+ } else {
+ edif_names.delim_left = '[';edif_names.delim_right = ']';
+ }
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
@@ -214,8 +232,18 @@ struct EdifBackend : public Backend {
}
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);
+ else {
+ int b[2] = {port_it.second-1, 0};
+ auto m = design->module(cell_it.first);
+ if (m) {
+ auto w = m->wire(port_it.first);
+ if (w) {
+ b[w->upto ? 0 : 1] = w->start_offset;
+ b[w->upto ? 1 : 0] = w->start_offset+GetSize(w)-1;
+ }
+ }
+ *f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEFR(port_it.first, port_rename, b[0], b[1]), port_it.second, dir);
+ }
}
*f << stringf(" )\n");
*f << stringf(" )\n");
@@ -283,10 +311,13 @@ struct EdifBackend : public Backend {
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire));
net_join_db[sig].insert(stringf("(portRef %s)", EDIF_REF(wire->name)));
} else {
- *f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEF(wire->name), wire->width, dir);
+ int b[2];
+ b[wire->upto ? 0 : 1] = wire->start_offset;
+ b[wire->upto ? 1 : 0] = wire->start_offset + GetSize(wire) - 1;
+ *f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEFR(wire->name, port_rename, b[0], b[1]), wire->width, dir);
for (int i = 0; i < wire->width; i++) {
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i));
- net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), i));
+ net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1));
}
}
}
@@ -323,20 +354,48 @@ struct EdifBackend : public Backend {
for (auto &p : cell->connections()) {
RTLIL::SigSpec sig = sigmap(p.second);
for (int i = 0; i < GetSize(sig); i++)
- if (sig.size() == 1)
+ if (sig[i].wire == NULL && sig[i] != RTLIL::State::S0 && sig[i] != RTLIL::State::S1)
+ log_warning("Bit %d of cell port %s.%s.%s driven by %s will be left unconnected in EDIF output.\n",
+ i, log_id(module), log_id(cell), log_id(p.first), log_signal(sig[i]));
+ else if (sig.size() == 1)
net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)));
- else
- net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))", EDIF_REF(p.first), i, EDIF_REF(cell->name)));
+ else {
+ int member_idx = GetSize(sig)-i-1;
+ auto m = design->module(cell->type);
+ if (m) {
+ auto w = m->wire(p.first);
+ if (w)
+ member_idx = GetSize(w)-i-1;
+ }
+ net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))",
+ EDIF_REF(p.first), member_idx, EDIF_REF(cell->name)));
+ }
}
}
for (auto &it : net_join_db) {
RTLIL::SigBit sig = it.first;
- if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1)
- continue;
- std::string netname = log_signal(sig);
- for (size_t i = 0; i < netname.size(); i++)
- if (netname[i] == ' ' || netname[i] == '\\')
- netname.erase(netname.begin() + i--);
+ if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) {
+ if (sig == RTLIL::State::Sx) {
+ for (auto &ref : it.second)
+ log_warning("Exporting x-bit on %s as zero bit.\n", ref.c_str());
+ sig = RTLIL::State::S0;
+ } else {
+ for (auto &ref : it.second)
+ log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.c_str());
+ log_abort();
+ }
+ }
+ std::string netname;
+ if (sig == RTLIL::State::S0)
+ netname = "GND_NET";
+ else if (sig == RTLIL::State::S1)
+ netname = "VCC_NET";
+ else {
+ netname = log_signal(sig);
+ for (size_t i = 0; i < netname.size(); i++)
+ if (netname[i] == ' ' || netname[i] == '\\')
+ netname.erase(netname.begin() + i--);
+ }
*f << stringf(" (net %s (joined\n", EDIF_DEF(netname));
for (auto &ref : it.second)
*f << stringf(" %s\n", ref.c_str());
diff --git a/backends/edif/runtest.py b/backends/edif/runtest.py
new file mode 100644
index 00000000..826876a8
--- /dev/null
+++ b/backends/edif/runtest.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+
+import os
+import numpy as np
+
+enable_upto = True
+enable_offset = True
+enable_hierarchy = True
+enable_logic = True
+
+def make_module(f, modname, width, subs):
+ print("module %s (A, B, C, X, Y, Z);" % modname, file=f)
+ inbits = list()
+ outbits = list()
+
+ for p in "ABC":
+ offset = np.random.randint(10) if enable_offset else 0
+ if enable_upto and np.random.randint(2):
+ print(" input [%d:%d] %s;" % (offset, offset+width-1, p), file=f)
+ else:
+ print(" input [%d:%d] %s;" % (offset+width-1, offset, p), file=f)
+ for i in range(offset, offset+width):
+ inbits.append("%s[%d]" % (p, i))
+
+ for p in "XYZ":
+ offset = np.random.randint(10) if enable_offset else 0
+ if enable_upto and np.random.randint(2):
+ print(" output [%d:%d] %s;" % (offset, offset+width-1, p), file=f)
+ else:
+ print(" output [%d:%d] %s;" % (offset+width-1, offset, p), file=f)
+ for i in range(offset, offset+width):
+ outbits.append("%s[%d]" % (p, i))
+
+ instidx = 0
+ subcandidates = list(subs.keys())
+
+ while len(outbits) > 0:
+ submod = None
+ if len(subcandidates):
+ submod = np.random.choice(subcandidates)
+ subcandidates.remove(submod)
+
+ if submod is None or 3*subs[submod] >= len(outbits):
+ for bit in outbits:
+ if enable_logic:
+ print(" assign %s = %s & ~%s;" % (bit, np.random.choice(inbits), np.random.choice(inbits)), file=f)
+ else:
+ print(" assign %s = %s;" % (bit, np.random.choice(inbits)), file=f)
+ break
+
+ instidx += 1
+ print(" %s inst%d (" % (submod, instidx), file=f)
+
+ for p in "ABC":
+ print(" .%s({%s})," % (p, ",".join(np.random.choice(inbits, subs[submod]))), file=f)
+
+ for p in "XYZ":
+ bits = list(np.random.choice(outbits, subs[submod], False))
+ for bit in bits:
+ outbits.remove(bit)
+ print(" .%s({%s})%s" % (p, ",".join(bits), "," if p != "Z" else ""), file=f)
+
+ print(" );", file=f);
+
+ print("endmodule", file=f)
+
+with open("test_top.v", "w") as f:
+ if enable_hierarchy:
+ make_module(f, "sub1", 2, {})
+ make_module(f, "sub2", 3, {})
+ make_module(f, "sub3", 4, {})
+ make_module(f, "sub4", 8, {"sub1": 2, "sub2": 3, "sub3": 4})
+ make_module(f, "sub5", 8, {"sub1": 2, "sub2": 3, "sub3": 4})
+ make_module(f, "sub6", 8, {"sub1": 2, "sub2": 3, "sub3": 4})
+ make_module(f, "top", 32, {"sub4": 8, "sub5": 8, "sub6": 8})
+ else:
+ make_module(f, "top", 32, {})
+
+os.system("set -x; ../../yosys -p 'synth_xilinx -top top; write_edif -pvector par test_syn.edif' test_top.v")
+
+with open("test_syn.tcl", "w") as f:
+ print("read_edif test_syn.edif", file=f)
+ print("link_design", file=f)
+ print("write_verilog -force test_syn.v", file=f)
+
+os.system("set -x; vivado -nojournal -nolog -mode batch -source test_syn.tcl")
+
+with open("test_tb.v", "w") as f:
+ print("module tb;", file=f)
+ print(" reg [31:0] A, B, C;", file=f)
+ print(" wire [31:0] X, Y, Z;", file=f)
+ print("", file=f)
+ print(" top uut (", file=f)
+ print(" .A(A),", file=f)
+ print(" .B(B),", file=f)
+ print(" .C(C),", file=f)
+ print(" .X(X),", file=f)
+ print(" .Y(Y),", file=f)
+ print(" .Z(Z)", file=f)
+ print(" );", file=f)
+ print("", file=f)
+ print(" initial begin", file=f)
+ for i in range(100):
+ print(" A = 32'h%08x;" % np.random.randint(2**32), file=f)
+ print(" B = 32'h%08x;" % np.random.randint(2**32), file=f)
+ print(" C = 32'h%08x;" % np.random.randint(2**32), file=f)
+ print(" #10;", file=f)
+ print(" $display(\"%x %x %x\", X, Y, Z);", file=f)
+ print(" #10;", file=f)
+ print(" $finish;", file=f)
+ print(" end", file=f)
+ print("endmodule", file=f)
+
+os.system("set -x; iverilog -o test_gold test_tb.v test_top.v")
+os.system("set -x; iverilog -o test_gate test_tb.v test_syn.v ../../techlibs/xilinx/cells_sim.v")
+
+os.system("set -x; ./test_gold > test_gold.out")
+os.system("set -x; ./test_gate > test_gate.out")
+
+os.system("set -x; md5sum test_gold.out test_gate.out")
+
diff --git a/backends/firrtl/.gitignore b/backends/firrtl/.gitignore
new file mode 100644
index 00000000..a2ac93ab
--- /dev/null
+++ b/backends/firrtl/.gitignore
@@ -0,0 +1,2 @@
+test.fir
+test_out.v
diff --git a/backends/firrtl/Makefile.inc b/backends/firrtl/Makefile.inc
new file mode 100644
index 00000000..fdf100d3
--- /dev/null
+++ b/backends/firrtl/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += backends/firrtl/firrtl.o
+
diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
new file mode 100644
index 00000000..94236d0b
--- /dev/null
+++ b/backends/firrtl/firrtl.cc
@@ -0,0 +1,677 @@
+/*
+ * 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/cellaigs.h"
+#include "kernel/log.h"
+#include <string>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+pool<string> used_names;
+dict<IdString, string> namecache;
+int autoid_counter;
+
+typedef unsigned FDirection;
+static const FDirection NODIRECTION = 0x0;
+static const FDirection IN = 0x1;
+static const FDirection OUT = 0x2;
+static const FDirection INOUT = 0x3;
+
+// Get a port direction with respect to a specific module.
+FDirection getPortFDirection(IdString id, Module *module)
+{
+ Wire *wire = module->wires_.at(id);
+ FDirection direction = NODIRECTION;
+ if (wire && wire->port_id)
+ {
+ if (wire->port_input)
+ direction |= IN;
+ if (wire->port_output)
+ direction |= OUT;
+ }
+ return direction;
+}
+
+string next_id()
+{
+ string new_id;
+
+ while (1) {
+ new_id = stringf("_%d", autoid_counter++);
+ if (used_names.count(new_id) == 0) break;
+ }
+
+ used_names.insert(new_id);
+ return new_id;
+}
+
+const char *make_id(IdString id)
+{
+ if (namecache.count(id) != 0)
+ return namecache.at(id).c_str();
+
+ string new_id = log_id(id);
+
+ for (int i = 0; i < GetSize(new_id); i++)
+ {
+ char &ch = new_id[i];
+ if ('a' <= ch && ch <= 'z') continue;
+ if ('A' <= ch && ch <= 'Z') continue;
+ if ('0' <= ch && ch <= '9' && i != 0) continue;
+ if ('_' == ch) continue;
+ ch = '_';
+ }
+
+ while (used_names.count(new_id) != 0)
+ new_id += '_';
+
+ namecache[id] = new_id;
+ used_names.insert(new_id);
+ return namecache.at(id).c_str();
+}
+
+struct FirrtlWorker
+{
+ Module *module;
+ std::ostream &f;
+
+ dict<SigBit, pair<string, int>> reverse_wire_map;
+ string unconn_id;
+ RTLIL::Design *design;
+ std::string indent;
+
+ void register_reverse_wire_map(string id, SigSpec sig)
+ {
+ for (int i = 0; i < GetSize(sig); i++)
+ reverse_wire_map[sig[i]] = make_pair(id, i);
+ }
+
+ FirrtlWorker(Module *module, std::ostream &f, RTLIL::Design *theDesign) : module(module), f(f), design(theDesign), indent(" ")
+ {
+ }
+
+ string make_expr(const SigSpec &sig)
+ {
+ string expr;
+
+ for (auto chunk : sig.chunks())
+ {
+ string new_expr;
+
+ if (chunk.wire == nullptr)
+ {
+ std::vector<RTLIL::State> bits = chunk.data;
+ new_expr = stringf("UInt<%d>(\"h", GetSize(bits));
+
+ while (GetSize(bits) % 4 != 0)
+ bits.push_back(State::S0);
+
+ for (int i = GetSize(bits)-4; i >= 0; i -= 4)
+ {
+ int val = 0;
+ if (bits[i+0] == State::S1) val += 1;
+ if (bits[i+1] == State::S1) val += 2;
+ if (bits[i+2] == State::S1) val += 4;
+ if (bits[i+3] == State::S1) val += 8;
+ new_expr.push_back(val < 10 ? '0' + val : 'a' + val - 10);
+ }
+
+ new_expr += "\")";
+ }
+ else if (chunk.offset == 0 && chunk.width == chunk.wire->width)
+ {
+ new_expr = make_id(chunk.wire->name);
+ }
+ else
+ {
+ string wire_id = make_id(chunk.wire->name);
+ new_expr = stringf("bits(%s, %d, %d)", wire_id.c_str(), chunk.offset + chunk.width - 1, chunk.offset);
+ }
+
+ if (expr.empty())
+ expr = new_expr;
+ else
+ expr = "cat(" + new_expr + ", " + expr + ")";
+ }
+
+ return expr;
+ }
+
+ std::string fid(RTLIL::IdString internal_id)
+ {
+ const char *str = internal_id.c_str();
+ return *str == '\\' ? str + 1 : str;
+ }
+
+
+ std::string cellname(RTLIL::Cell *cell)
+ {
+ return fid(cell->name).c_str();
+ }
+
+ void process_instance(RTLIL::Cell *cell, vector<string> &wire_exprs)
+ {
+ std::string cell_type = fid(cell->type);
+
+ std::string cell_name = cellname(cell);
+ std::string cell_name_comment;
+ if (cell_name != fid(cell->name))
+ cell_name_comment = " /* " + fid(cell->name) + " */ ";
+ else
+ cell_name_comment = "";
+ // Find the module corresponding to this instance.
+ auto instModule = design->module(cell->type);
+ wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), cell_type.c_str()));
+
+ for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
+ if (it->second.size() > 0) {
+ const SigSpec &secondSig = it->second;
+ const std::string firstName = cell_name + "." + make_id(it->first);
+ const std::string secondName = make_expr(secondSig);
+ // Find the direction for this port.
+ FDirection dir = getPortFDirection(it->first, instModule);
+ std::string source, sink;
+ switch (dir) {
+ case INOUT:
+ log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", log_id(cell_type), log_signal(it->second));
+ case OUT:
+ source = firstName;
+ sink = secondName;
+ break;
+ case NODIRECTION:
+ log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", log_id(cell_type), log_signal(it->second));
+ /* FALL_THROUGH */
+ case IN:
+ source = secondName;
+ sink = firstName;
+ break;
+ default:
+ log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", log_id(cell_type), log_signal(it->second), dir);
+ break;
+ }
+ wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str()));
+ }
+ }
+ wire_exprs.push_back(stringf("\n"));
+
+ }
+
+ void run()
+ {
+ f << stringf(" module %s:\n", make_id(module->name));
+ vector<string> port_decls, wire_decls, cell_exprs, wire_exprs;
+
+ for (auto wire : module->wires())
+ {
+ const auto wireName = make_id(wire->name);
+ if (wire->port_id)
+ {
+ if (wire->port_input && wire->port_output)
+ log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
+ port_decls.push_back(stringf(" %s %s: UInt<%d>\n", wire->port_input ? "input" : "output",
+ wireName, wire->width));
+ }
+ else
+ {
+ wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", wireName, wire->width));
+ }
+ }
+
+ for (auto cell : module->cells())
+ {
+ // Is this cell is a module instance?
+ if (cell->type[0] != '$')
+ {
+ process_instance(cell, wire_exprs);
+ continue;
+ }
+ if (cell->type.in("$not", "$logic_not", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_bool", "$reduce_xnor"))
+ {
+ string y_id = make_id(cell->name);
+ bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
+ int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
+ string a_expr = make_expr(cell->getPort("\\A"));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+
+ if (cell->parameters.at("\\A_SIGNED").as_bool()) {
+ a_expr = "asSInt(" + a_expr + ")";
+ }
+
+ // Don't use the results of logical operations (a single bit) to control padding
+ if (!(cell->type.in("$eq", "$eqx", "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$reduce_bool", "$logic_not") && y_width == 1) ) {
+ a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+ }
+
+ string primop;
+ bool always_uint = false;
+ if (cell->type == "$not") primop = "not";
+ if (cell->type == "$neg") primop = "neg";
+ if (cell->type == "$logic_not") {
+ primop = "eq";
+ a_expr = stringf("%s, UInt(0)", a_expr.c_str());
+ }
+ if (cell->type == "$reduce_and") primop = "andr";
+ if (cell->type == "$reduce_or") primop = "orr";
+ if (cell->type == "$reduce_xor") primop = "xorr";
+ if (cell->type == "$reduce_xnor") {
+ primop = "not";
+ a_expr = stringf("xorr(%s)", a_expr.c_str());
+ }
+ if (cell->type == "$reduce_bool") {
+ primop = "neq";
+ // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
+ bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
+ int a_width = cell->parameters.at("\\A_WIDTH").as_int();
+ a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width);
+ }
+
+ string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str());
+
+ if ((is_signed && !always_uint))
+ expr = stringf("asUInt(%s)", expr.c_str());
+
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+
+ continue;
+ }
+ if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx",
+ "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
+ "$logic_and", "$logic_or"))
+ {
+ string y_id = make_id(cell->name);
+ bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
+ int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
+ string a_expr = make_expr(cell->getPort("\\A"));
+ string b_expr = make_expr(cell->getPort("\\B"));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+
+ if (cell->parameters.at("\\A_SIGNED").as_bool()) {
+ a_expr = "asSInt(" + a_expr + ")";
+ }
+ // Shift amount is always unsigned, and needn't be padded to result width.
+ if (!cell->type.in("$shr", "$sshr", "$shl", "$sshl")) {
+ if (cell->parameters.at("\\B_SIGNED").as_bool()) {
+ b_expr = "asSInt(" + b_expr + ")";
+ }
+ b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
+ }
+
+ a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+
+ if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) {
+ a_expr = "asUInt(" + a_expr + ")";
+ }
+
+ string primop;
+ bool always_uint = false;
+ if (cell->type == "$add") primop = "add";
+ if (cell->type == "$sub") primop = "sub";
+ if (cell->type == "$mul") primop = "mul";
+ if (cell->type == "$div") primop = "div";
+ if (cell->type == "$mod") primop = "rem";
+ if (cell->type == "$and") {
+ primop = "and";
+ always_uint = true;
+ }
+ if (cell->type == "$or" ) {
+ primop = "or";
+ always_uint = true;
+ }
+ if (cell->type == "$xor") {
+ primop = "xor";
+ always_uint = true;
+ }
+ if ((cell->type == "$eq") | (cell->type == "$eqx")) {
+ primop = "eq";
+ always_uint = true;
+ }
+ if ((cell->type == "$ne") | (cell->type == "$nex")) {
+ primop = "neq";
+ always_uint = true;
+ }
+ if (cell->type == "$gt") {
+ primop = "gt";
+ always_uint = true;
+ }
+ if (cell->type == "$ge") {
+ primop = "geq";
+ always_uint = true;
+ }
+ if (cell->type == "$lt") {
+ primop = "lt";
+ always_uint = true;
+ }
+ if (cell->type == "$le") {
+ primop = "leq";
+ always_uint = true;
+ }
+ if ((cell->type == "$shl") | (cell->type == "$sshl")) primop = "dshl";
+ if ((cell->type == "$shr") | (cell->type == "$sshr")) primop = "dshr";
+ if ((cell->type == "$logic_and")) {
+ primop = "and";
+ a_expr = "neq(" + a_expr + ", UInt(0))";
+ b_expr = "neq(" + b_expr + ", UInt(0))";
+ always_uint = true;
+ }
+ if ((cell->type == "$logic_or")) {
+ primop = "or";
+ a_expr = "neq(" + a_expr + ", UInt(0))";
+ b_expr = "neq(" + b_expr + ", UInt(0))";
+ always_uint = true;
+ }
+
+ if (!cell->parameters.at("\\B_SIGNED").as_bool()) {
+ b_expr = "asUInt(" + b_expr + ")";
+ }
+
+ string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
+
+ if ((is_signed && !always_uint) || cell->type.in("$sub"))
+ expr = stringf("asUInt(%s)", expr.c_str());
+
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+
+ continue;
+ }
+
+ if (cell->type.in("$mux"))
+ {
+ string y_id = make_id(cell->name);
+ int width = cell->parameters.at("\\WIDTH").as_int();
+ string a_expr = make_expr(cell->getPort("\\A"));
+ string b_expr = make_expr(cell->getPort("\\B"));
+ string s_expr = make_expr(cell->getPort("\\S"));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), width));
+
+ string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
+
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+
+ continue;
+ }
+
+ if (cell->type.in("$mem"))
+ {
+ string mem_id = make_id(cell->name);
+ int abits = cell->parameters.at("\\ABITS").as_int();
+ int width = cell->parameters.at("\\WIDTH").as_int();
+ int size = cell->parameters.at("\\SIZE").as_int();
+ int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
+ int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
+
+ Const initdata = cell->parameters.at("\\INIT");
+ for (State bit : initdata.bits)
+ if (bit != State::Sx)
+ log_error("Memory with initialization data: %s.%s\n", log_id(module), log_id(cell));
+
+ Const rd_clk_enable = cell->parameters.at("\\RD_CLK_ENABLE");
+ Const wr_clk_enable = cell->parameters.at("\\WR_CLK_ENABLE");
+ Const wr_clk_polarity = cell->parameters.at("\\WR_CLK_POLARITY");
+
+ int offset = cell->parameters.at("\\OFFSET").as_int();
+ if (offset != 0)
+ log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell));
+
+ cell_exprs.push_back(stringf(" mem %s:\n", mem_id.c_str()));
+ cell_exprs.push_back(stringf(" data-type => UInt<%d>\n", width));
+ cell_exprs.push_back(stringf(" depth => %d\n", size));
+
+ for (int i = 0; i < rd_ports; i++)
+ cell_exprs.push_back(stringf(" reader => r%d\n", i));
+
+ for (int i = 0; i < wr_ports; i++)
+ cell_exprs.push_back(stringf(" writer => w%d\n", i));
+
+ cell_exprs.push_back(stringf(" read-latency => 0\n"));
+ cell_exprs.push_back(stringf(" write-latency => 1\n"));
+ cell_exprs.push_back(stringf(" read-under-write => undefined\n"));
+
+ for (int i = 0; i < rd_ports; i++)
+ {
+ if (rd_clk_enable[i] != State::S0)
+ log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
+
+ SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width);
+ string addr_expr = make_expr(cell->getPort("\\RD_ADDR").extract(i*abits, abits));
+
+ cell_exprs.push_back(stringf(" %s.r%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str()));
+ cell_exprs.push_back(stringf(" %s.r%d.en <= UInt<1>(1)\n", mem_id.c_str(), i));
+ cell_exprs.push_back(stringf(" %s.r%d.clk <= asClock(UInt<1>(0))\n", mem_id.c_str(), i));
+
+ register_reverse_wire_map(stringf("%s.r%d.data", mem_id.c_str(), i), data_sig);
+ }
+
+ for (int i = 0; i < wr_ports; i++)
+ {
+ if (wr_clk_enable[i] != State::S1)
+ log_error("Unclocked write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
+
+ if (wr_clk_polarity[i] != State::S1)
+ log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
+
+ string addr_expr = make_expr(cell->getPort("\\WR_ADDR").extract(i*abits, abits));
+ string data_expr = make_expr(cell->getPort("\\WR_DATA").extract(i*width, width));
+ string clk_expr = make_expr(cell->getPort("\\WR_CLK").extract(i));
+
+ SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width);
+ string wen_expr = make_expr(wen_sig[0]);
+
+ for (int i = 1; i < GetSize(wen_sig); i++)
+ if (wen_sig[0] != wen_sig[i])
+ log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
+
+ cell_exprs.push_back(stringf(" %s.w%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str()));
+ cell_exprs.push_back(stringf(" %s.w%d.data <= %s\n", mem_id.c_str(), i, data_expr.c_str()));
+ cell_exprs.push_back(stringf(" %s.w%d.en <= %s\n", mem_id.c_str(), i, wen_expr.c_str()));
+ cell_exprs.push_back(stringf(" %s.w%d.mask <= UInt<1>(1)\n", mem_id.c_str(), i));
+ cell_exprs.push_back(stringf(" %s.w%d.clk <= asClock(%s)\n", mem_id.c_str(), i, clk_expr.c_str()));
+ }
+
+ continue;
+ }
+
+ if (cell->type.in("$dff"))
+ {
+ bool clkpol = cell->parameters.at("\\CLK_POLARITY").as_bool();
+ if (clkpol == false)
+ log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell));
+
+ string q_id = make_id(cell->name);
+ int width = cell->parameters.at("\\WIDTH").as_int();
+ string expr = make_expr(cell->getPort("\\D"));
+ string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")";
+
+ wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", q_id.c_str(), width, clk_expr.c_str()));
+
+ cell_exprs.push_back(stringf(" %s <= %s\n", q_id.c_str(), expr.c_str()));
+ register_reverse_wire_map(q_id, cell->getPort("\\Q"));
+
+ continue;
+ }
+
+ log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
+ }
+
+ for (auto conn : module->connections())
+ {
+ string y_id = next_id();
+ int y_width = GetSize(conn.first);
+ string expr = make_expr(conn.second);
+
+ wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+ cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ register_reverse_wire_map(y_id, conn.first);
+ }
+
+ for (auto wire : module->wires())
+ {
+ string expr;
+
+ if (wire->port_input)
+ continue;
+
+ int cursor = 0;
+ bool is_valid = false;
+ bool make_unconn_id = false;
+
+ while (cursor < wire->width)
+ {
+ int chunk_width = 1;
+ string new_expr;
+
+ SigBit start_bit(wire, cursor);
+
+ if (reverse_wire_map.count(start_bit))
+ {
+ pair<string, int> start_map = reverse_wire_map.at(start_bit);
+
+ while (cursor+chunk_width < wire->width)
+ {
+ SigBit stop_bit(wire, cursor+chunk_width);
+
+ if (reverse_wire_map.count(stop_bit) == 0)
+ break;
+
+ pair<string, int> stop_map = reverse_wire_map.at(stop_bit);
+ stop_map.second -= chunk_width;
+
+ if (start_map != stop_map)
+ break;
+
+ chunk_width++;
+ }
+
+ new_expr = stringf("bits(%s, %d, %d)", start_map.first.c_str(),
+ start_map.second + chunk_width - 1, start_map.second);
+ is_valid = true;
+ }
+ else
+ {
+ if (unconn_id.empty()) {
+ unconn_id = next_id();
+ make_unconn_id = true;
+ }
+ new_expr = unconn_id;
+ }
+
+ if (expr.empty())
+ expr = new_expr;
+ else
+ expr = "cat(" + new_expr + ", " + expr + ")";
+
+ cursor += chunk_width;
+ }
+
+ if (is_valid) {
+ if (make_unconn_id) {
+ wire_decls.push_back(stringf(" wire %s: UInt<1>\n", unconn_id.c_str()));
+ wire_decls.push_back(stringf(" %s is invalid\n", unconn_id.c_str()));
+ }
+ wire_exprs.push_back(stringf(" %s <= %s\n", make_id(wire->name), expr.c_str()));
+ } else {
+ if (make_unconn_id) {
+ unconn_id.clear();
+ }
+ wire_decls.push_back(stringf(" %s is invalid\n", make_id(wire->name)));
+ }
+ }
+
+ for (auto str : port_decls)
+ f << str;
+
+ f << stringf("\n");
+
+ for (auto str : wire_decls)
+ f << str;
+
+ f << stringf("\n");
+
+ for (auto str : cell_exprs)
+ f << str;
+
+ f << stringf("\n");
+
+ for (auto str : wire_exprs)
+ f << str;
+ }
+};
+
+struct FirrtlBackend : public Backend {
+ FirrtlBackend() : Backend("firrtl", "write design to a FIRRTL file") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_firrtl [options] [filename]\n");
+ log("\n");
+ log("Write a FIRRTL netlist of the current design.\n");
+ log("\n");
+ }
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-aig") {
+ // aig_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ log_header(design, "Executing FIRRTL backend.\n");
+
+ Module *top = design->top_module();
+
+ if (top == nullptr)
+ log_error("No top module found!\n");
+
+ namecache.clear();
+ autoid_counter = 0;
+
+ for (auto module : design->modules()) {
+ make_id(module->name);
+ for (auto wire : module->wires())
+ if (wire->port_id)
+ make_id(wire->name);
+ }
+
+ *f << stringf("circuit %s:\n", make_id(top->name));
+
+ for (auto module : design->modules())
+ {
+ FirrtlWorker worker(module, *f, design);
+ worker.run();
+ }
+
+ namecache.clear();
+ autoid_counter = 0;
+ }
+} FirrtlBackend;
+
+PRIVATE_NAMESPACE_END
diff --git a/backends/firrtl/test.sh b/backends/firrtl/test.sh
new file mode 100644
index 00000000..fe7e3a32
--- /dev/null
+++ b/backends/firrtl/test.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+set -ex
+
+cd ../../
+make
+cd backends/firrtl
+
+../../yosys -q -p 'prep -nordff; write_firrtl test.fir' $1
+
+firrtl -i test.fir -o test_out.v -ll Info
+
+../../yosys -p "
+ read_verilog $1
+ rename Top gold
+
+ read_verilog test_out.v
+ rename Top gate
+
+ prep
+ memory_map
+ miter -equiv -flatten gold gate miter
+ hierarchy -top miter
+
+ sat -verify -prove trigger 0 -set-init-zero -seq 10 miter
+"
diff --git a/backends/firrtl/test.v b/backends/firrtl/test.v
new file mode 100644
index 00000000..c6d62a84
--- /dev/null
+++ b/backends/firrtl/test.v
@@ -0,0 +1,63 @@
+module test(
+ input clk, wen,
+ input [7:0] uns,
+ input signed [7:0] a, b,
+ input signed [23:0] c,
+ input signed [2:0] sel,
+ output [15:0] s, d, y, z, u, q, p, mul, div, mod, mux, And, Or, Xor, eq, neq, gt, lt, geq, leq, eqx, shr, sshr, shl, sshl, Land, Lor, Lnot, Not, Neg, pos, Andr, Orr, Xorr, Xnorr, Reduce_bool,
+ output [7:0] PMux
+);
+ //initial begin
+ //$display("shr = %b", shr);
+ //end
+ assign s = a+{b[6:2], 2'b1};
+ assign d = a-b;
+ assign y = x;
+ assign z[7:0] = s+d;
+ assign z[15:8] = s-d;
+ assign p = a & b | x;
+ assign mul = a * b;
+ assign div = a / b;
+ assign mod = a % b;
+ assign mux = x[0] ? a : b;
+ assign And = a & b;
+ assign Or = a | b;
+ assign Xor = a ^ b;
+ assign Not = ~a;
+ assign Neg = -a;
+ assign eq = a == b;
+ assign neq = a != b;
+ assign gt = a > b;
+ assign lt = a < b;
+ assign geq = a >= b;
+ assign leq = a <= b;
+ assign eqx = a === b;
+ assign shr = a >> b; //0111111111000000
+ assign sshr = a >>> b;
+ assign shl = a << b;
+ assign sshl = a <<< b;
+ assign Land = a && b;
+ assign Lor = a || b;
+ assign Lnot = !a;
+ assign pos = $signed(uns);
+ assign Andr = &a;
+ assign Orr = |a;
+ assign Xorr = ^a;
+ assign Xnorr = ~^a;
+ always @*
+ if(!a) begin
+ Reduce_bool = a;
+ end else begin
+ Reduce_bool = b;
+ end
+ //always @(sel or c or a)
+ // begin
+ // case (sel)
+ // 3'b000: PMux = a;
+ // 3'b001: PMux = c[7:0];
+ // 3'b010: PMux = c[15:8];
+ // 3'b100: PMux = c[23:16];
+ // endcase
+ // end
+
+endmodule
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
index 16d1a97f..4c58ea08 100644
--- a/backends/ilang/ilang_backend.cc
+++ b/backends/ilang/ilang_backend.cc
@@ -219,7 +219,7 @@ void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
{
f << stringf("%s" "sync ", indent.c_str());
switch (sy->type) {
- if (0) case RTLIL::ST0: f << stringf("low ");
+ case RTLIL::ST0: f << stringf("low ");
if (0) case RTLIL::ST1: f << stringf("high ");
if (0) case RTLIL::STp: f << stringf("posedge ");
if (0) case RTLIL::STn: f << stringf("negedge ");
@@ -382,7 +382,7 @@ PRIVATE_NAMESPACE_BEGIN
struct IlangBackend : public Backend {
IlangBackend() : Backend("ilang", "write design to ilang file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -395,7 +395,7 @@ struct IlangBackend : public Backend {
log(" only write selected parts of the design.\n");
log("\n");
}
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool selected = false;
@@ -422,7 +422,7 @@ struct IlangBackend : public Backend {
struct DumpPass : public Pass {
DumpPass() : Pass("dump", "print parts of the design in ilang format") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -445,7 +445,7 @@ struct DumpPass : public Pass {
log(" like -outfile but append instead of overwrite\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string filename;
bool flag_m = false, flag_n = false, append = false;
diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc
index 34cb52fb..2eb08dbe 100644
--- a/backends/intersynth/intersynth.cc
+++ b/backends/intersynth/intersynth.cc
@@ -46,7 +46,7 @@ static std::string netname(std::set<std::string> &conntypes_code, std::set<std::
struct IntersynthBackend : public Backend {
IntersynthBackend() : Backend("intersynth", "write design to InterSynth netlist file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -71,7 +71,7 @@ struct IntersynthBackend : public Backend {
log("http://www.clifford.at/intersynth/\n");
log("\n");
}
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing INTERSYNTH backend.\n");
log_push();
diff --git a/backends/json/json.cc b/backends/json/json.cc
index 4baffa33..f5c68798 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -93,8 +93,10 @@ struct JsonWriter
f << get_string(param.second.decode_string());
else if (GetSize(param.second.bits) > 32)
f << get_string(param.second.as_string());
- else
+ else if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
f << stringf("%d", param.second.as_int());
+ else
+ f << stringf("%u", param.second.as_int());
first = false;
}
}
@@ -201,6 +203,8 @@ struct JsonWriter
void write_design(Design *design_)
{
design = design_;
+ design->sort();
+
f << stringf("{\n");
f << stringf(" \"creator\": %s,\n", get_string(yosys_version_str).c_str());
f << stringf(" \"modules\": {\n");
@@ -248,7 +252,7 @@ struct JsonWriter
struct JsonBackend : public Backend {
JsonBackend() : Backend("json", "write design to a JSON file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -333,6 +337,10 @@ struct JsonBackend : public Backend {
log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
log("a number.\n");
log("\n");
+ log("Numeric parameter and attribute values up to 32 bits are written as decimal\n");
+ log("values. Numbers larger than that are written as string holding the binary\n");
+ log("representation of the value.\n");
+ log("\n");
log("For example the following Verilog code:\n");
log("\n");
log(" module test(input x, y);\n");
@@ -452,7 +460,7 @@ struct JsonBackend : public Backend {
log("format. A program processing this format must ignore all unknown fields.\n");
log("\n");
}
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool aig_mode = false;
@@ -476,7 +484,7 @@ struct JsonBackend : public Backend {
struct JsonPass : public Pass {
JsonPass() : Pass("json", "write design in JSON format") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -493,7 +501,7 @@ struct JsonPass : public Pass {
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)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string filename;
bool aig_mode = false;
diff --git a/backends/protobuf/.gitignore b/backends/protobuf/.gitignore
new file mode 100644
index 00000000..849b38d4
--- /dev/null
+++ b/backends/protobuf/.gitignore
@@ -0,0 +1,2 @@
+yosys.pb.cc
+yosys.pb.h
diff --git a/backends/protobuf/Makefile.inc b/backends/protobuf/Makefile.inc
new file mode 100644
index 00000000..834cad42
--- /dev/null
+++ b/backends/protobuf/Makefile.inc
@@ -0,0 +1,8 @@
+ifeq ($(ENABLE_PROTOBUF),1)
+
+backends/protobuf/yosys.pb.cc backends/protobuf/yosys.pb.h: misc/yosys.proto
+ $(Q) cd misc && protoc --cpp_out "../backends/protobuf" yosys.proto
+
+OBJS += backends/protobuf/protobuf.o backends/protobuf/yosys.pb.o
+
+endif
diff --git a/backends/protobuf/protobuf.cc b/backends/protobuf/protobuf.cc
new file mode 100644
index 00000000..f56147ce
--- /dev/null
+++ b/backends/protobuf/protobuf.cc
@@ -0,0 +1,370 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * 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 <google/protobuf/text_format.h>
+
+#include "kernel/rtlil.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/cellaigs.h"
+#include "kernel/log.h"
+#include "yosys.pb.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ProtobufDesignSerializer
+{
+ bool aig_mode_;
+ bool use_selection_;
+ yosys::pb::Design *pb_;
+
+ Design *design_;
+ Module *module_;
+
+ SigMap sigmap_;
+ int sigidcounter_;
+ dict<SigBit, uint64_t> sigids_;
+ pool<Aig> aig_models_;
+
+
+ ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
+ aig_mode_(aig_mode), use_selection_(use_selection) { }
+
+ string get_name(IdString name)
+ {
+ return RTLIL::unescape_id(name);
+ }
+
+
+ void serialize_parameters(google::protobuf::Map<std::string, yosys::pb::Parameter> *out,
+ const dict<IdString, Const> &parameters)
+ {
+ for (auto &param : parameters) {
+ std::string key = get_name(param.first);
+
+
+ yosys::pb::Parameter pb_param;
+
+ if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) {
+ pb_param.set_str(param.second.decode_string());
+ } else if (GetSize(param.second.bits) > 64) {
+ pb_param.set_str(param.second.as_string());
+ } else {
+ pb_param.set_int_(param.second.as_int());
+ }
+
+ (*out)[key] = pb_param;
+ }
+ }
+
+ void get_bits(yosys::pb::BitVector *out, SigSpec sig)
+ {
+ for (auto bit : sigmap_(sig)) {
+ auto sig = out->add_signal();
+
+ // Constant driver.
+ if (bit.wire == nullptr) {
+ if (bit == State::S0) sig->set_constant(sig->CONSTANT_DRIVER_LOW);
+ else if (bit == State::S1) sig->set_constant(sig->CONSTANT_DRIVER_HIGH);
+ else if (bit == State::Sz) sig->set_constant(sig->CONSTANT_DRIVER_Z);
+ else sig->set_constant(sig->CONSTANT_DRIVER_X);
+ continue;
+ }
+
+ // Signal - give it a unique identifier.
+ if (sigids_.count(bit) == 0) {
+ sigids_[bit] = sigidcounter_++;
+ }
+ sig->set_id(sigids_[bit]);
+ }
+ }
+
+ void serialize_module(yosys::pb::Module* out, Module *module)
+ {
+ module_ = module;
+ log_assert(module_->design == design_);
+ sigmap_.set(module_);
+ sigids_.clear();
+ sigidcounter_ = 0;
+
+ serialize_parameters(out->mutable_attribute(), module_->attributes);
+
+ for (auto n : module_->ports) {
+ Wire *w = module->wire(n);
+ if (use_selection_ && !module_->selected(w))
+ continue;
+
+ yosys::pb::Module::Port pb_port;
+ pb_port.set_direction(w->port_input ? w->port_output ?
+ yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT : yosys::pb::DIRECTION_OUTPUT);
+ get_bits(pb_port.mutable_bits(), w);
+ (*out->mutable_port())[get_name(n)] = pb_port;
+ }
+
+ for (auto c : module_->cells()) {
+ if (use_selection_ && !module_->selected(c))
+ continue;
+
+ yosys::pb::Module::Cell pb_cell;
+ pb_cell.set_hide_name(c->name[0] == '$');
+ pb_cell.set_type(get_name(c->type));
+
+ if (aig_mode_) {
+ Aig aig(c);
+ if (aig.name.empty())
+ continue;
+ pb_cell.set_model(aig.name);
+ aig_models_.insert(aig);
+ }
+ serialize_parameters(pb_cell.mutable_parameter(), c->parameters);
+ serialize_parameters(pb_cell.mutable_attribute(), c->attributes);
+
+ if (c->known()) {
+ for (auto &conn : c->connections()) {
+ yosys::pb::Direction direction = yosys::pb::DIRECTION_OUTPUT;
+ if (c->input(conn.first))
+ direction = c->output(conn.first) ? yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT;
+ (*pb_cell.mutable_port_direction())[get_name(conn.first)] = direction;
+ }
+ }
+ for (auto &conn : c->connections()) {
+ yosys::pb::BitVector vec;
+ get_bits(&vec, conn.second);
+ (*pb_cell.mutable_connection())[get_name(conn.first)] = vec;
+ }
+
+ (*out->mutable_cell())[get_name(c->name)] = pb_cell;
+ }
+
+ for (auto w : module_->wires()) {
+ if (use_selection_ && !module_->selected(w))
+ continue;
+
+ auto netname = out->add_netname();
+ netname->set_hide_name(w->name[0] == '$');
+ get_bits(netname->mutable_bits(), w);
+ serialize_parameters(netname->mutable_attributes(), w->attributes);
+ }
+ }
+
+
+ void serialize_models(google::protobuf::Map<string, yosys::pb::Model> *models)
+ {
+ for (auto &aig : aig_models_) {
+ yosys::pb::Model pb_model;
+ for (auto &node : aig.nodes) {
+ auto pb_node = pb_model.add_node();
+ if (node.portbit >= 0) {
+ if (node.inverter) {
+ pb_node->set_type(pb_node->TYPE_NPORT);
+ } else {
+ pb_node->set_type(pb_node->TYPE_PORT);
+ }
+ auto port = pb_node->mutable_port();
+ port->set_portname(log_id(node.portname));
+ port->set_bitindex(node.portbit);
+ } else if (node.left_parent < 0 && node.right_parent < 0) {
+ if (node.inverter) {
+ pb_node->set_type(pb_node->TYPE_TRUE);
+ } else {
+ pb_node->set_type(pb_node->TYPE_FALSE);
+ }
+ } else {
+ if (node.inverter) {
+ pb_node->set_type(pb_node->TYPE_NAND);
+ } else {
+ pb_node->set_type(pb_node->TYPE_AND);
+ }
+ auto gate = pb_node->mutable_gate();
+ gate->set_left(node.left_parent);
+ gate->set_right(node.right_parent);
+ }
+ for (auto &op : node.outports) {
+ auto pb_op = pb_node->add_out_port();
+ pb_op->set_name(log_id(op.first));
+ pb_op->set_bit_index(op.second);
+ }
+ }
+ (*models)[aig.name] = pb_model;
+ }
+ }
+
+ void serialize_design(yosys::pb::Design *pb, Design *design)
+ {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+ pb_ = pb;
+ pb_->Clear();
+ pb_->set_creator(yosys_version_str);
+
+ design_ = design;
+ design_->sort();
+
+ auto modules = use_selection_ ? design_->selected_modules() : design_->modules();
+ for (auto mod : modules) {
+ yosys::pb::Module pb_mod;
+ serialize_module(&pb_mod, mod);
+ (*pb->mutable_modules())[mod->name.str()] = pb_mod;
+ }
+
+ serialize_models(pb_->mutable_models());
+ }
+};
+
+struct ProtobufBackend : public Backend {
+ ProtobufBackend(): Backend("protobuf", "write design to a Protocol Buffer file") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_protobuf [options] [filename]\n");
+ log("\n");
+ log("Write a JSON netlist of the current design.\n");
+ log("\n");
+ log(" -aig\n");
+ log(" include AIG models for the different gate types\n");
+ log("\n");
+ log(" -text\n");
+ log(" output protobuf in Text/ASCII representation\n");
+ log("\n");
+ log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n");
+ log("Yosys source code distribution.\n");
+ log("\n");
+ }
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool aig_mode = false;
+ bool text_mode = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-aig") {
+ aig_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-text") {
+ text_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ log_header(design, "Executing Protobuf backend.\n");
+
+ yosys::pb::Design pb;
+ ProtobufDesignSerializer serializer(false, aig_mode);
+ serializer.serialize_design(&pb, design);
+
+ if (text_mode) {
+ string out;
+ google::protobuf::TextFormat::PrintToString(pb, &out);
+ *f << out;
+ } else {
+ pb.SerializeToOstream(f);
+ }
+ }
+} ProtobufBackend;
+
+struct ProtobufPass : public Pass {
+ ProtobufPass() : Pass("protobuf", "write design in Protobuf format") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" protobuf [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(" -aig\n");
+ log(" include AIG models for the different gate types\n");
+ log("\n");
+ log(" -text\n");
+ log(" output protobuf in Text/ASCII representation\n");
+ log("\n");
+ log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n");
+ log("Yosys source code distribution.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ std::string filename;
+ bool aig_mode = false;
+ bool text_mode = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-o" && argidx+1 < args.size()) {
+ filename = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-aig") {
+ aig_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-text") {
+ text_mode = true;
+ 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;
+ }
+
+ yosys::pb::Design pb;
+ ProtobufDesignSerializer serializer(true, aig_mode);
+ serializer.serialize_design(&pb, design);
+
+ if (text_mode) {
+ string out;
+ google::protobuf::TextFormat::PrintToString(pb, &out);
+ *f << out;
+ } else {
+ pb.SerializeToOstream(f);
+ }
+
+ if (!filename.empty()) {
+ delete f;
+ } else {
+ log("%s", buf.str().c_str());
+ }
+ }
+} ProtobufPass;
+
+PRIVATE_NAMESPACE_END;
diff --git a/backends/simplec/.gitignore b/backends/simplec/.gitignore
new file mode 100644
index 00000000..f0879616
--- /dev/null
+++ b/backends/simplec/.gitignore
@@ -0,0 +1,2 @@
+test00_tb
+test00_uut.c
diff --git a/backends/simplec/Makefile.inc b/backends/simplec/Makefile.inc
new file mode 100644
index 00000000..fee1376c
--- /dev/null
+++ b/backends/simplec/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += backends/simplec/simplec.o
+
diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc
new file mode 100644
index 00000000..349bc5a6
--- /dev/null
+++ b/backends/simplec/simplec.cc
@@ -0,0 +1,810 @@
+/*
+ * 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/utils.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct HierDirtyFlags;
+
+static pool<string> reserved_cids;
+static dict<IdString, string> id2cid;
+
+static string cid(IdString id)
+{
+ if (id2cid.count(id) == 0)
+ {
+ string s = id.str();
+ if (GetSize(s) < 2) log_abort();
+
+ if (s[0] == '\\')
+ s = s.substr(1);
+
+ if ('0' <= s[0] && s[0] <= '9') {
+ s = "_" + s;
+ }
+
+ for (int i = 0; i < GetSize(s); i++) {
+ if ('0' <= s[i] && s[i] <= '9') continue;
+ if ('A' <= s[i] && s[i] <= 'Z') continue;
+ if ('a' <= s[i] && s[i] <= 'z') continue;
+ s[i] = '_';
+ }
+
+ while (reserved_cids.count(s))
+ s += "_";
+
+ reserved_cids.insert(s);
+ id2cid[id] = s;
+ }
+
+ return id2cid.at(id);
+}
+
+struct HierDirtyFlags
+{
+ int dirty;
+ Module *module;
+ IdString hiername;
+ HierDirtyFlags *parent;
+ pool<SigBit> dirty_bits;
+ pool<Cell*> dirty_cells;
+ pool<SigBit> sticky_dirty_bits;
+ dict<IdString, HierDirtyFlags*> children;
+ string prefix, log_prefix;
+
+ HierDirtyFlags(Module *module, IdString hiername, HierDirtyFlags *parent, const string &prefix, const string &log_prefix) :
+ dirty(0), module(module), hiername(hiername), parent(parent), prefix(prefix), log_prefix(log_prefix)
+ {
+ for (Cell *cell : module->cells()) {
+ Module *mod = module->design->module(cell->type);
+ if (mod) children[cell->name] = new HierDirtyFlags(mod, cell->name, this,
+ prefix + cid(cell->name) + ".", log_prefix + "." + prefix + log_id(cell->name));
+ }
+ }
+
+ ~HierDirtyFlags()
+ {
+ for (auto &child : children)
+ delete child.second;
+ }
+
+ void set_dirty(SigBit bit)
+ {
+ if (dirty_bits.count(bit))
+ return;
+
+ dirty_bits.insert(bit);
+ sticky_dirty_bits.insert(bit);
+
+ HierDirtyFlags *p = this;
+ while (p != nullptr) {
+ p->dirty++;
+ p = p->parent;
+ }
+ }
+
+ void unset_dirty(SigBit bit)
+ {
+ if (dirty_bits.count(bit) == 0)
+ return;
+
+ dirty_bits.erase(bit);
+
+ HierDirtyFlags *p = this;
+ while (p != nullptr) {
+ p->dirty--;
+ log_assert(p->dirty >= 0);
+ p = p->parent;
+ }
+ }
+
+ void set_dirty(Cell *cell)
+ {
+ if (dirty_cells.count(cell))
+ return;
+
+ dirty_cells.insert(cell);
+
+ HierDirtyFlags *p = this;
+ while (p != nullptr) {
+ p->dirty++;
+ p = p->parent;
+ }
+ }
+
+ void unset_dirty(Cell *cell)
+ {
+ if (dirty_cells.count(cell) == 0)
+ return;
+
+ dirty_cells.erase(cell);
+
+ HierDirtyFlags *p = this;
+ while (p != nullptr) {
+ p->dirty--;
+ log_assert(p->dirty >= 0);
+ p = p->parent;
+ }
+ }
+};
+
+struct SimplecWorker
+{
+ bool verbose = false;
+ int max_uintsize = 32;
+
+ Design *design;
+ dict<Module*, SigMap> sigmaps;
+
+ vector<string> signal_declarations;
+ pool<int> generated_sigtypes;
+
+ vector<string> util_declarations;
+ pool<string> generated_utils;
+
+ vector<string> struct_declarations;
+ pool<IdString> generated_structs;
+
+ vector<string> funct_declarations;
+
+ dict<Module*, dict<SigBit, pool<tuple<Cell*, IdString, int>>>> bit2cell;
+ dict<Module*, dict<SigBit, pool<SigBit>>> bit2output;
+ dict<Module*, pool<SigBit>> driven_bits;
+
+ dict<Cell*, int> topoidx;
+
+ pool<string> activated_cells;
+ pool<string> reactivated_cells;
+
+ SimplecWorker(Design *design) : design(design)
+ {
+ }
+
+ string sigtype(int n)
+ {
+ string struct_name = stringf("signal%d_t", n);
+
+ if (generated_sigtypes.count(n) == 0)
+ {
+ signal_declarations.push_back("");
+ signal_declarations.push_back(stringf("#ifndef YOSYS_SIMPLEC_SIGNAL%d_T", n));
+ signal_declarations.push_back(stringf("#define YOSYS_SIMPLEC_SIGNAL%d_T", n));
+ signal_declarations.push_back(stringf("typedef struct {"));
+
+ for (int k = 8; k <= max_uintsize; k = 2*k)
+ if (n <= k && k <= max_uintsize) {
+ signal_declarations.push_back(stringf(" uint%d_t value_%d_0 : %d;", k, n-1, n));
+ goto end_struct;
+ }
+
+ for (int k = 0; k < n; k += max_uintsize) {
+ int bits = std::min(max_uintsize, n-k);
+ signal_declarations.push_back(stringf(" uint%d_t value_%d_%d : %d;", max_uintsize, k+bits-1, k, bits));
+ }
+
+ end_struct:
+ signal_declarations.push_back(stringf("} signal%d_t;", n));
+ signal_declarations.push_back(stringf("#endif"));
+ generated_sigtypes.insert(n);
+ }
+
+ return struct_name;
+ }
+
+ void util_ifdef_guard(string s)
+ {
+ for (int i = 0; i < GetSize(s); i++)
+ if ('a' <= s[i] && s[i] <= 'z')
+ s[i] -= 'a' - 'A';
+
+ util_declarations.push_back("");
+ util_declarations.push_back(stringf("#ifndef %s", s.c_str()));
+ util_declarations.push_back(stringf("#define %s", s.c_str()));
+ }
+
+ string util_get_bit(const string &signame, int n, int idx)
+ {
+ if (n == 1 && idx == 0)
+ return signame + ".value_0_0";
+
+ string util_name = stringf("yosys_simplec_get_bit_%d_of_%d", idx, n);
+
+ if (generated_utils.count(util_name) == 0)
+ {
+ util_ifdef_guard(util_name);
+ util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str()));
+ util_declarations.push_back(stringf("{"));
+
+ int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
+ string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize);
+
+ util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name.c_str(), word_offset));
+
+ util_declarations.push_back(stringf("}"));
+ util_declarations.push_back(stringf("#endif"));
+ generated_utils.insert(util_name);
+ }
+
+ return stringf("%s(&%s)", util_name.c_str(), signame.c_str());
+ }
+
+ string util_set_bit(const string &signame, int n, int idx, const string &expr)
+ {
+ if (n == 1 && idx == 0)
+ return stringf(" %s.value_0_0 = %s;", signame.c_str(), expr.c_str());
+
+ string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n);
+
+ if (generated_utils.count(util_name) == 0)
+ {
+ util_ifdef_guard(util_name);
+ util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str()));
+ util_declarations.push_back(stringf("{"));
+
+ int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
+ string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize);
+
+ #if 0
+ util_declarations.push_back(stringf(" if (value)"));
+ util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name.c_str(), word_offset));
+ util_declarations.push_back(stringf(" else"));
+ util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name.c_str(), word_offset));
+ #else
+ util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);",
+ value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset));
+ #endif
+
+ util_declarations.push_back(stringf("}"));
+ util_declarations.push_back(stringf("#endif"));
+ generated_utils.insert(util_name);
+ }
+
+ return stringf(" %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str());
+ }
+
+ void create_module_struct(Module *mod)
+ {
+ if (generated_structs.count(mod->name))
+ return;
+
+ generated_structs.insert(mod->name);
+ sigmaps[mod].set(mod);
+
+ for (Wire *w : mod->wires())
+ {
+ if (w->port_output)
+ for (auto bit : SigSpec(w))
+ bit2output[mod][sigmaps.at(mod)(bit)].insert(bit);
+ }
+
+ for (Cell *c : mod->cells())
+ {
+ for (auto &conn : c->connections())
+ {
+ if (!c->input(conn.first)) {
+ for (auto bit : sigmaps.at(mod)(conn.second))
+ driven_bits[mod].insert(bit);
+ continue;
+ }
+
+ int idx = 0;
+ for (auto bit : sigmaps.at(mod)(conn.second))
+ bit2cell[mod][bit].insert(tuple<Cell*, IdString, int>(c, conn.first, idx++));
+ }
+
+ if (design->module(c->type))
+ create_module_struct(design->module(c->type));
+ }
+
+ TopoSort<IdString> topo;
+
+ for (Cell *c : mod->cells())
+ {
+ topo.node(c->name);
+
+ for (auto &conn : c->connections())
+ {
+ if (!c->input(conn.first))
+ continue;
+
+ for (auto bit : sigmaps.at(mod)(conn.second))
+ for (auto &it : bit2cell[mod][bit])
+ topo.edge(c->name, std::get<0>(it)->name);
+ }
+ }
+
+ topo.analyze_loops = false;
+ topo.sort();
+
+ for (int i = 0; i < GetSize(topo.sorted); i++)
+ topoidx[mod->cell(topo.sorted[i])] = i;
+
+ string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name).c_str());
+
+ for (int i = 0; i < GetSize(ifdef_name); i++)
+ if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z')
+ ifdef_name[i] -= 'a' - 'A';
+
+ struct_declarations.push_back("");
+ struct_declarations.push_back(stringf("#ifndef %s", ifdef_name.c_str()));
+ struct_declarations.push_back(stringf("#define %s", ifdef_name.c_str()));
+ struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name).c_str()));
+ struct_declarations.push_back("{");
+
+ struct_declarations.push_back(" // Input Ports");
+ for (Wire *w : mod->wires())
+ if (w->port_input)
+ struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
+
+ struct_declarations.push_back("");
+ struct_declarations.push_back(" // Output Ports");
+ for (Wire *w : mod->wires())
+ if (!w->port_input && w->port_output)
+ struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
+
+ struct_declarations.push_back("");
+ struct_declarations.push_back(" // Internal Wires");
+ for (Wire *w : mod->wires())
+ if (!w->port_input && !w->port_output)
+ struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w)));
+
+ for (Cell *c : mod->cells())
+ if (design->module(c->type))
+ struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type).c_str(), cid(c->name).c_str(), log_id(c)));
+
+ struct_declarations.push_back(stringf("};"));
+ struct_declarations.push_back("#endif");
+ }
+
+ void eval_cell(HierDirtyFlags *work, Cell *cell)
+ {
+ if (cell->type.in("$_BUF_", "$_NOT_"))
+ {
+ SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
+ SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
+
+ string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+ string expr;
+
+ if (cell->type == "$_BUF_") expr = a_expr;
+ if (cell->type == "$_NOT_") expr = "!" + a_expr;
+
+ log_assert(y.wire);
+ funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+ stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
+
+ work->set_dirty(y);
+ return;
+ }
+
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
+ {
+ SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
+ SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
+ SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
+
+ string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+ string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
+ string expr;
+
+ if (cell->type == "$_AND_") expr = stringf("%s & %s", a_expr.c_str(), b_expr.c_str());
+ if (cell->type == "$_NAND_") expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str());
+ if (cell->type == "$_OR_") expr = stringf("%s | %s", a_expr.c_str(), b_expr.c_str());
+ if (cell->type == "$_NOR_") expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str());
+ if (cell->type == "$_XOR_") expr = stringf("%s ^ %s", a_expr.c_str(), b_expr.c_str());
+ if (cell->type == "$_XNOR_") expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str());
+ if (cell->type == "$_ANDNOT_") expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str());
+ if (cell->type == "$_ORNOT_") expr = stringf("%s | (!%s)", a_expr.c_str(), b_expr.c_str());
+
+ log_assert(y.wire);
+ funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+ stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
+
+ work->set_dirty(y);
+ return;
+ }
+
+ if (cell->type.in("$_AOI3_", "$_OAI3_"))
+ {
+ SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
+ SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
+ SigBit c = sigmaps.at(work->module)(cell->getPort("\\C"));
+ SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
+
+ string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+ string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
+ string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
+ string expr;
+
+ if (cell->type == "$_AOI3_") expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
+ if (cell->type == "$_OAI3_") expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
+
+ log_assert(y.wire);
+ funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+ stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
+
+ work->set_dirty(y);
+ return;
+ }
+
+ if (cell->type.in("$_AOI4_", "$_OAI4_"))
+ {
+ SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
+ SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
+ SigBit c = sigmaps.at(work->module)(cell->getPort("\\C"));
+ SigBit d = sigmaps.at(work->module)(cell->getPort("\\D"));
+ SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
+
+ string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+ string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
+ string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
+ string d_expr = d.wire ? util_get_bit(work->prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0";
+ string expr;
+
+ if (cell->type == "$_AOI4_") expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
+ if (cell->type == "$_OAI4_") expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
+
+ log_assert(y.wire);
+ funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+ stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
+
+ work->set_dirty(y);
+ return;
+ }
+
+ if (cell->type == "$_MUX_")
+ {
+ SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
+ SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
+ SigBit s = sigmaps.at(work->module)(cell->getPort("\\S"));
+ SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
+
+ string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+ string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
+ string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0";
+
+ // casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933)
+ string expr = stringf("%s ? (bool)%s : (bool)%s", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
+
+ log_assert(y.wire);
+ funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+ stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
+
+ work->set_dirty(y);
+ return;
+ }
+
+ log_error("No C model for %s available at the moment (FIXME).\n", log_id(cell->type));
+ }
+
+ void eval_dirty(HierDirtyFlags *work)
+ {
+ while (work->dirty)
+ {
+ if (verbose && (!work->dirty_bits.empty() || !work->dirty_cells.empty()))
+ log(" In %s:\n", work->log_prefix.c_str());
+
+ while (!work->dirty_bits.empty() || !work->dirty_cells.empty())
+ {
+ if (!work->dirty_bits.empty())
+ {
+ SigSpec dirtysig(work->dirty_bits);
+ dirtysig.sort_and_unify();
+
+ for (SigChunk chunk : dirtysig.chunks()) {
+ if (chunk.wire == nullptr)
+ continue;
+ if (verbose)
+ log(" Propagating %s.%s[%d:%d].\n", work->log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset);
+ funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix.c_str(), log_signal(chunk)));
+ }
+
+ for (SigBit bit : dirtysig)
+ {
+ if (bit2output[work->module].count(bit) && work->parent)
+ for (auto outbit : bit2output[work->module][bit])
+ {
+ Module *parent_mod = work->parent->module;
+ Cell *parent_cell = parent_mod->cell(work->hiername);
+
+ IdString port_name = outbit.wire->name;
+ int port_offset = outbit.offset;
+ SigBit parent_bit = sigmaps.at(parent_mod)(parent_cell->getPort(port_name)[port_offset]);
+
+ log_assert(bit.wire && parent_bit.wire);
+ funct_declarations.push_back(util_set_bit(work->parent->prefix + cid(parent_bit.wire->name), parent_bit.wire->width, parent_bit.offset,
+ util_get_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset)));
+ work->parent->set_dirty(parent_bit);
+
+ if (verbose)
+ log(" Propagating %s.%s[%d] -> %s.%s[%d].\n", work->log_prefix.c_str(), log_id(bit.wire), bit.offset,
+ work->parent->log_prefix.c_str(), log_id(parent_bit.wire), parent_bit.offset);
+ }
+
+ for (auto &port : bit2cell[work->module][bit])
+ {
+ if (work->children.count(std::get<0>(port)->name))
+ {
+ HierDirtyFlags *child = work->children.at(std::get<0>(port)->name);
+ SigBit child_bit = sigmaps.at(child->module)(SigBit(child->module->wire(std::get<1>(port)), std::get<2>(port)));
+ log_assert(bit.wire && child_bit.wire);
+
+ funct_declarations.push_back(util_set_bit(work->prefix + cid(child->hiername) + "." + cid(child_bit.wire->name),
+ child_bit.wire->width, child_bit.offset, util_get_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset)));
+ child->set_dirty(child_bit);
+
+ if (verbose)
+ log(" Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", work->log_prefix.c_str(), log_id(bit.wire), bit.offset,
+ work->log_prefix.c_str(), log_id(std::get<0>(port)), log_id(child_bit.wire), child_bit.offset);
+ } else {
+ if (verbose)
+ log(" Marking cell %s.%s (via %s.%s[%d]).\n", work->log_prefix.c_str(), log_id(std::get<0>(port)),
+ work->log_prefix.c_str(), log_id(bit.wire), bit.offset);
+ work->set_dirty(std::get<0>(port));
+ }
+ }
+ work->unset_dirty(bit);
+ }
+ }
+
+ if (!work->dirty_cells.empty())
+ {
+ Cell *cell = nullptr;
+ for (auto c : work->dirty_cells)
+ if (cell == nullptr || topoidx.at(cell) < topoidx.at(c))
+ cell = c;
+
+ string hiername = work->log_prefix + "." + log_id(cell);
+
+ if (verbose)
+ log(" Evaluating %s (%s, best of %d).\n", hiername.c_str(), log_id(cell->type), GetSize(work->dirty_cells));
+
+ if (activated_cells.count(hiername))
+ reactivated_cells.insert(hiername);
+ activated_cells.insert(hiername);
+
+ eval_cell(work, cell);
+ work->unset_dirty(cell);
+ }
+ }
+
+ for (auto &child : work->children)
+ eval_dirty(child.second);
+ }
+ }
+
+ void eval_sticky_dirty(HierDirtyFlags *work)
+ {
+ Module *mod = work->module;
+
+ for (Wire *w : mod->wires())
+ for (SigBit bit : SigSpec(w))
+ {
+ SigBit canonical_bit = sigmaps.at(mod)(bit);
+
+ if (canonical_bit == bit)
+ continue;
+
+ if (work->sticky_dirty_bits.count(canonical_bit) == 0)
+ continue;
+
+ if (bit.wire == nullptr || canonical_bit.wire == nullptr)
+ continue;
+
+ funct_declarations.push_back(util_set_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset,
+ util_get_bit(work->prefix + cid(canonical_bit.wire->name), canonical_bit.wire->width, canonical_bit.offset).c_str()));
+
+ if (verbose)
+ log(" Propagating alias %s.%s[%d] -> %s.%s[%d].\n",
+ work->log_prefix.c_str(), log_id(canonical_bit.wire), canonical_bit.offset,
+ work->log_prefix.c_str(), log_id(bit.wire), bit.offset);
+ }
+
+ work->sticky_dirty_bits.clear();
+
+ for (auto &child : work->children)
+ eval_sticky_dirty(child.second);
+ }
+
+ void make_func(HierDirtyFlags *work, const string &func_name, const vector<string> &preamble)
+ {
+ log("Generating function %s():\n", func_name.c_str());
+
+ activated_cells.clear();
+ reactivated_cells.clear();
+
+ funct_declarations.push_back("");
+ funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str()));
+ funct_declarations.push_back("{");
+ for (auto &line : preamble)
+ funct_declarations.push_back(line);
+ eval_dirty(work);
+ eval_sticky_dirty(work);
+ funct_declarations.push_back("}");
+
+ log(" Activated %d cells (%d activated more than once).\n", GetSize(activated_cells), GetSize(reactivated_cells));
+ }
+
+ void eval_init(HierDirtyFlags *work, vector<string> &preamble)
+ {
+ Module *module = work->module;
+
+ for (Wire *w : module->wires())
+ {
+ if (w->attributes.count("\\init"))
+ {
+ SigSpec sig = sigmaps.at(module)(w);
+ Const val = w->attributes.at("\\init");
+ val.bits.resize(GetSize(sig), State::Sx);
+
+ for (int i = 0; i < GetSize(sig); i++)
+ if (val[i] == State::S0 || val[i] == State::S1) {
+ SigBit bit = sig[i];
+ preamble.push_back(util_set_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset, val == State::S1 ? "true" : "false"));
+ work->set_dirty(bit);
+ }
+ }
+
+ for (SigBit bit : SigSpec(w))
+ {
+ SigBit val = sigmaps.at(module)(bit);
+
+ if (val == State::S0 || val == State::S1)
+ preamble.push_back(util_set_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset, val == State::S1 ? "true" : "false"));
+
+ if (driven_bits.at(module).count(val) == 0)
+ work->set_dirty(val);
+ }
+ }
+
+ work->set_dirty(State::S0);
+ work->set_dirty(State::S1);
+
+ for (auto &child : work->children)
+ eval_init(child.second, preamble);
+ }
+
+ void make_init_func(HierDirtyFlags *work)
+ {
+ vector<string> preamble;
+ eval_init(work, preamble);
+ make_func(work, cid(work->module->name) + "_init", preamble);
+ }
+
+ void make_eval_func(HierDirtyFlags *work)
+ {
+ Module *mod = work->module;
+ vector<string> preamble;
+
+ for (Wire *w : mod->wires()) {
+ if (w->port_input)
+ for (SigBit bit : sigmaps.at(mod)(w))
+ work->set_dirty(bit);
+ }
+
+ make_func(work, cid(work->module->name) + "_eval", preamble);
+ }
+
+ void make_tick_func(HierDirtyFlags* /* work */)
+ {
+ // FIXME
+ }
+
+ void run(Module *mod)
+ {
+ create_module_struct(mod);
+
+ HierDirtyFlags work(mod, IdString(), nullptr, "state->", log_id(mod->name));
+
+ make_init_func(&work);
+ make_eval_func(&work);
+ make_tick_func(&work);
+ }
+
+ void write(std::ostream &f)
+ {
+ f << "#include <stdint.h>" << std::endl;
+ f << "#include <stdbool.h>" << std::endl;
+
+ for (auto &line : signal_declarations)
+ f << line << std::endl;
+
+ for (auto &line : util_declarations)
+ f << line << std::endl;
+
+ for (auto &line : struct_declarations)
+ f << line << std::endl;
+
+ for (auto &line : funct_declarations)
+ f << line << std::endl;
+ }
+};
+
+struct SimplecBackend : public Backend {
+ SimplecBackend() : Backend("simplec", "convert design to simple C code") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_simplec [options] [filename]\n");
+ log("\n");
+ log("Write simple C code for simulating the design. The C code writen can be used to\n");
+ log("simulate the design in a C environment, but the purpose of this command is to\n");
+ log("generate code that works well with C-based formal verification.\n");
+ log("\n");
+ log(" -verbose\n");
+ log(" this will print the recursive walk used to export the modules.\n");
+ log("\n");
+ log(" -i8, -i16, -i32, -i64\n");
+ log(" set the maximum integer bit width to use in the generated code.\n");
+ log("\n");
+ log("THIS COMMAND IS UNDER CONSTRUCTION\n");
+ log("\n");
+ }
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ reserved_cids.clear();
+ id2cid.clear();
+
+ SimplecWorker worker(design);
+
+ log_header(design, "Executing SIMPLEC backend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-verbose") {
+ worker.verbose = true;
+ continue;
+ }
+ if (args[argidx] == "-i8") {
+ worker.max_uintsize = 8;
+ continue;
+ }
+ if (args[argidx] == "-i16") {
+ worker.max_uintsize = 16;
+ continue;
+ }
+ if (args[argidx] == "-i32") {
+ worker.max_uintsize = 32;
+ continue;
+ }
+ if (args[argidx] == "-i64") {
+ worker.max_uintsize = 64;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ Module *topmod = design->top_module();
+
+ if (topmod == nullptr)
+ log_error("Current design has no top module.\n");
+
+ worker.run(topmod);
+ worker.write(*f);
+ }
+} SimplecBackend;
+
+PRIVATE_NAMESPACE_END
diff --git a/backends/simplec/test00.sh b/backends/simplec/test00.sh
new file mode 100644
index 00000000..ede75727
--- /dev/null
+++ b/backends/simplec/test00.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+set -ex
+../../yosys -p 'synth -top test; write_simplec -verbose -i8 test00_uut.c' test00_uut.v
+clang -o test00_tb test00_tb.c
+./test00_tb
diff --git a/backends/simplec/test00_tb.c b/backends/simplec/test00_tb.c
new file mode 100644
index 00000000..7fac4826
--- /dev/null
+++ b/backends/simplec/test00_tb.c
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <assert.h>
+#include "test00_uut.c"
+
+uint32_t xorshift32()
+{
+ static uint32_t x32 = 314159265;
+ x32 ^= x32 << 13;
+ x32 ^= x32 >> 17;
+ x32 ^= x32 << 5;
+ return x32;
+}
+
+int main()
+{
+ struct test_state_t state;
+ uint32_t a, b, c, x, y, z, w;
+ bool first_eval = true;
+
+ for (int i = 0; i < 10; i++)
+ {
+ a = xorshift32();
+ b = xorshift32();
+ c = xorshift32();
+
+ x = (a & b) | c;
+ y = a & (b | c);
+ z = a ^ b ^ c;
+ w = z;
+
+ state.a.value_7_0 = a;
+ state.a.value_15_8 = a >> 8;
+ state.a.value_23_16 = a >> 16;
+ state.a.value_31_24 = a >> 24;
+
+ state.b.value_7_0 = b;
+ state.b.value_15_8 = b >> 8;
+ state.b.value_23_16 = b >> 16;
+ state.b.value_31_24 = b >> 24;
+
+ state.c.value_7_0 = c;
+ state.c.value_15_8 = c >> 8;
+ state.c.value_23_16 = c >> 16;
+ state.c.value_31_24 = c >> 24;
+
+ if (first_eval) {
+ first_eval = false;
+ test_init(&state);
+ } else {
+ test_eval(&state);
+ }
+
+ uint32_t uut_x = 0;
+ uut_x |= (uint32_t)state.x.value_7_0;
+ uut_x |= (uint32_t)state.x.value_15_8 << 8;
+ uut_x |= (uint32_t)state.x.value_23_16 << 16;
+ uut_x |= (uint32_t)state.x.value_31_24 << 24;
+
+ uint32_t uut_y = 0;
+ uut_y |= (uint32_t)state.y.value_7_0;
+ uut_y |= (uint32_t)state.y.value_15_8 << 8;
+ uut_y |= (uint32_t)state.y.value_23_16 << 16;
+ uut_y |= (uint32_t)state.y.value_31_24 << 24;
+
+ uint32_t uut_z = 0;
+ uut_z |= (uint32_t)state.z.value_7_0;
+ uut_z |= (uint32_t)state.z.value_15_8 << 8;
+ uut_z |= (uint32_t)state.z.value_23_16 << 16;
+ uut_z |= (uint32_t)state.z.value_31_24 << 24;
+
+ uint32_t uut_w = 0;
+ uut_w |= (uint32_t)state.w.value_7_0;
+ uut_w |= (uint32_t)state.w.value_15_8 << 8;
+ uut_w |= (uint32_t)state.w.value_23_16 << 16;
+ uut_w |= (uint32_t)state.w.value_31_24 << 24;
+
+ printf("---\n");
+ printf("A: 0x%08x\n", a);
+ printf("B: 0x%08x\n", b);
+ printf("C: 0x%08x\n", c);
+ printf("X: 0x%08x 0x%08x\n", x, uut_x);
+ printf("Y: 0x%08x 0x%08x\n", y, uut_y);
+ printf("Z: 0x%08x 0x%08x\n", z, uut_z);
+ printf("W: 0x%08x 0x%08x\n", w, uut_w);
+
+ assert(x == uut_x);
+ assert(y == uut_y);
+ assert(z == uut_z);
+ assert(w == uut_w);
+ }
+
+ return 0;
+}
diff --git a/backends/simplec/test00_uut.v b/backends/simplec/test00_uut.v
new file mode 100644
index 00000000..744dbe9e
--- /dev/null
+++ b/backends/simplec/test00_uut.v
@@ -0,0 +1,14 @@
+module test(input [31:0] a, b, c, output [31:0] x, y, z, w);
+ unit_x unit_x_inst (.a(a), .b(b), .c(c), .x(x));
+ unit_y unit_y_inst (.a(a), .b(b), .c(c), .y(y));
+ assign z = a ^ b ^ c, w = z;
+endmodule
+
+module unit_x(input [31:0] a, b, c, output [31:0] x);
+ assign x = (a & b) | c;
+endmodule
+
+module unit_y(input [31:0] a, b, c, output [31:0] y);
+ assign y = a & (b | c);
+endmodule
+
diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc
index eacda273..dce82f01 100644
--- a/backends/smt2/Makefile.inc
+++ b/backends/smt2/Makefile.inc
@@ -6,7 +6,7 @@ ifneq ($(CONFIG),emcc)
TARGETS += yosys-smtbmc
yosys-smtbmc: backends/smt2/smtbmc.py
- $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(__file__) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
+ $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
$(Q) chmod +x $@.new
$(Q) mv $@.new $@
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index ddac6900..e2777ae0 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -32,14 +32,18 @@ struct Smt2Worker
CellTypes ct;
SigMap sigmap;
RTLIL::Module *module;
- bool bvmode, memmode, wiresmode, verbose;
- int idcounter;
+ bool bvmode, memmode, wiresmode, verbose, statebv, statedt, forallmode;
+ dict<IdString, int> &mod_stbv_width;
+ int idcounter = 0, statebv_width = 0;
- std::vector<std::string> decls, trans, hier;
+ std::vector<std::string> decls, trans, hier, dtmembers;
std::map<RTLIL::SigBit, RTLIL::Cell*> bit_driver;
std::set<RTLIL::Cell*> exported_cells, hiercells, hiercells_queue;
pool<Cell*> recursive_cells, registers;
+ pool<SigBit> clock_posedge, clock_negedge;
+ vector<string> ex_state_eq, ex_input_eq;
+
std::map<RTLIL::SigBit, std::pair<int, int>> fcache;
std::map<Cell*, int> memarrays;
std::map<int, int> bvsizes;
@@ -63,17 +67,64 @@ struct Smt2Worker
return get_id(obj->name);
}
- Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool wiresmode, bool verbose) :
- ct(module->design), sigmap(module), module(module), bvmode(bvmode), memmode(memmode),
- wiresmode(wiresmode), verbose(verbose), idcounter(0)
+ void makebits(std::string name, int width = 0, std::string comment = std::string())
+ {
+ std::string decl_str;
+
+ if (statebv)
+ {
+ if (width == 0) {
+ decl_str = stringf("(define-fun |%s| ((state |%s_s|)) Bool (= ((_ extract %d %d) state) #b1))", name.c_str(), get_id(module), statebv_width, statebv_width);
+ statebv_width += 1;
+ } else {
+ decl_str = stringf("(define-fun |%s| ((state |%s_s|)) (_ BitVec %d) ((_ extract %d %d) state))", name.c_str(), get_id(module), width, statebv_width+width-1, statebv_width);
+ statebv_width += width;
+ }
+ }
+ else if (statedt)
+ {
+ if (width == 0) {
+ decl_str = stringf(" (|%s| Bool)", name.c_str());
+ } else {
+ decl_str = stringf(" (|%s| (_ BitVec %d))", name.c_str(), width);
+ }
+ }
+ else
+ {
+ if (width == 0) {
+ decl_str = stringf("(declare-fun |%s| (|%s_s|) Bool)", name.c_str(), get_id(module));
+ } else {
+ decl_str = stringf("(declare-fun |%s| (|%s_s|) (_ BitVec %d))", name.c_str(), get_id(module), width);
+ }
+ }
+
+ if (!comment.empty())
+ decl_str += " ; " + comment;
+
+ if (statedt)
+ dtmembers.push_back(decl_str + "\n");
+ else
+ decls.push_back(decl_str + "\n");
+ }
+
+ Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool wiresmode, bool verbose, bool statebv, bool statedt, bool forallmode,
+ dict<IdString, int> &mod_stbv_width, dict<IdString, dict<IdString, pair<bool, bool>>> &mod_clk_cache) :
+ ct(module->design), sigmap(module), module(module), bvmode(bvmode), memmode(memmode), wiresmode(wiresmode),
+ verbose(verbose), statebv(statebv), statedt(statedt), forallmode(forallmode), mod_stbv_width(mod_stbv_width)
{
- decls.push_back(stringf("(declare-sort |%s_s| 0)\n", get_id(module)));
- decls.push_back(stringf("(declare-fun |%s_is| (|%s_s|) Bool)\n", get_id(module), get_id(module)));
+ pool<SigBit> noclock;
+
+ makebits(stringf("%s_is", get_id(module)));
for (auto cell : module->cells())
- for (auto &conn : cell->connections()) {
+ for (auto &conn : cell->connections())
+ {
+ if (GetSize(conn.second) == 0)
+ continue;
+
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))
@@ -83,6 +134,66 @@ struct Smt2Worker
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));
+
+ if (cell->type.in("$mem") && conn.first.in("\\RD_CLK", "\\WR_CLK"))
+ {
+ SigSpec clk = sigmap(conn.second);
+ for (int i = 0; i < GetSize(clk); i++)
+ {
+ if (clk[i].wire == nullptr)
+ continue;
+
+ if (cell->getParam(conn.first == "\\RD_CLK" ? "\\RD_CLK_ENABLE" : "\\WR_CLK_ENABLE")[i] != State::S1)
+ continue;
+
+ if (cell->getParam(conn.first == "\\RD_CLK" ? "\\RD_CLK_POLARITY" : "\\WR_CLK_POLARITY")[i] == State::S1)
+ clock_posedge.insert(clk[i]);
+ else
+ clock_negedge.insert(clk[i]);
+ }
+ }
+ else
+ if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_") && conn.first.in("\\CLK", "\\C"))
+ {
+ bool posedge = (cell->type == "$_DFF_N_") || (cell->type == "$dff" && cell->getParam("\\CLK_POLARITY").as_bool());
+ for (auto bit : sigmap(conn.second)) {
+ if (posedge)
+ clock_posedge.insert(bit);
+ else
+ clock_negedge.insert(bit);
+ }
+ }
+ else
+ if (mod_clk_cache.count(cell->type) && mod_clk_cache.at(cell->type).count(conn.first))
+ {
+ for (auto bit : sigmap(conn.second)) {
+ if (mod_clk_cache.at(cell->type).at(conn.first).first)
+ clock_posedge.insert(bit);
+ if (mod_clk_cache.at(cell->type).at(conn.first).second)
+ clock_negedge.insert(bit);
+ }
+ }
+ else
+ {
+ for (auto bit : sigmap(conn.second))
+ noclock.insert(bit);
+ }
+ }
+
+ for (auto bit : noclock) {
+ clock_posedge.erase(bit);
+ clock_negedge.erase(bit);
+ }
+
+ for (auto wire : module->wires())
+ {
+ if (!wire->port_input || GetSize(wire) != 1)
+ continue;
+ SigBit bit = sigmap(wire);
+ if (clock_posedge.count(bit))
+ mod_clk_cache[module->name][wire->name].first = true;
+ if (clock_negedge.count(bit))
+ mod_clk_cache[module->name][wire->name].second = true;
}
}
@@ -162,8 +273,7 @@ struct Smt2Worker
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",
- get_id(module), idcounter, get_id(module), log_signal(bit)));
+ makebits(stringf("%s#%d", get_id(module), idcounter), 0, log_signal(bit));
register_bool(bit, idcounter++);
}
@@ -237,8 +347,7 @@ struct Smt2Worker
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",
- get_id(module), idcounter, get_id(module), j, log_signal(sig.extract(i, j))));
+ makebits(stringf("%s#%d", get_id(module), idcounter), j, log_signal(sig.extract(i, j)));
subexpr.push_back(stringf("(|%s#%d| %s)", get_id(module), idcounter, state_name));
register_bv(sig.extract(i, j), idcounter++);
}
@@ -288,7 +397,8 @@ struct Smt2Worker
if (type == 's' || type == 'd' || type == 'b') {
width = max(width, GetSize(cell->getPort("\\A")));
- width = max(width, GetSize(cell->getPort("\\B")));
+ if (cell->hasPort("\\B"))
+ width = max(width, GetSize(cell->getPort("\\B")));
}
if (cell->hasPort("\\A")) {
@@ -382,8 +492,7 @@ struct Smt2Worker
if (cell->type.in("$_FF_", "$_DFF_P_", "$_DFF_N_"))
{
registers.insert(cell);
- decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
- get_id(module), idcounter, get_id(module), log_signal(cell->getPort("\\Q"))));
+ makebits(stringf("%s#%d", get_id(module), idcounter), 0, log_signal(cell->getPort("\\Q")));
register_bool(cell->getPort("\\Q"), idcounter++);
recursive_cells.erase(cell);
return;
@@ -397,6 +506,8 @@ struct Smt2Worker
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 == "$_ANDNOT_") return export_gate(cell, "(and A (not B))");
+ if (cell->type == "$_ORNOT_") return export_gate(cell, "(or A (not B))");
if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)");
if (cell->type == "$_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))");
@@ -410,20 +521,22 @@ struct Smt2Worker
if (cell->type.in("$ff", "$dff"))
{
registers.insert(cell);
- decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
- get_id(module), idcounter, get_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))));
+ makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q")));
register_bv(cell->getPort("\\Q"), idcounter++);
recursive_cells.erase(cell);
return;
}
- if (cell->type.in("$anyconst", "$anyseq"))
+ if (cell->type.in("$anyconst", "$anyseq", "$allconst", "$allseq"))
{
registers.insert(cell);
- decls.push_back(stringf("; yosys-smt2-%s %s#%d %s\n", cell->type.c_str() + 1, get_id(module), idcounter,
- cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
- decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
- get_id(module), idcounter, get_id(module), GetSize(cell->getPort("\\Y")), log_signal(cell->getPort("\\Y"))));
+ string infostr = cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell);
+ if (cell->attributes.count("\\reg"))
+ infostr += " " + cell->attributes.at("\\reg").decode_string();
+ decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort("\\Y")), infostr.c_str()));
+ makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort("\\Y")), log_signal(cell->getPort("\\Y")));
+ if (cell->type == "$anyseq")
+ ex_input_eq.push_back(stringf(" (= (|%s#%d| state) (|%s#%d| other_state))", get_id(module), idcounter, get_id(module), idcounter));
register_bv(cell->getPort("\\Y"), idcounter++);
recursive_cells.erase(cell);
return;
@@ -467,6 +580,13 @@ struct Smt2Worker
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.in("$reduce_and", "$reduce_or", "$reduce_bool") &&
+ 2*GetSize(cell->getPort("\\A").chunks()) < GetSize(cell->getPort("\\A"))) {
+ bool is_and = cell->type == "$reduce_and";
+ string bits(GetSize(cell->getPort("\\A")), is_and ? '1' : '0');
+ return export_bvop(cell, stringf("(%s A #b%s)", is_and ? "=" : "distinct", bits.c_str()), 'b');
+ }
+
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);
@@ -513,30 +633,97 @@ struct Smt2Worker
int abits = cell->getParam("\\ABITS").as_int();
int width = cell->getParam("\\WIDTH").as_int();
int rd_ports = cell->getParam("\\RD_PORTS").as_int();
+ int wr_ports = cell->getParam("\\WR_PORTS").as_int();
- decls.push_back(stringf("(declare-fun |%s#%d#0| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
- get_id(module), arrayid, get_id(module), abits, width, get_id(cell)));
+ bool async_read = false;
+ if (!cell->getParam("\\WR_CLK_ENABLE").is_fully_ones()) {
+ if (!cell->getParam("\\WR_CLK_ENABLE").is_fully_zero())
+ log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", log_id(cell), log_id(module));
+ async_read = true;
+ }
- decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d\n", get_id(cell), abits, width, rd_ports));
- decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) (|%s#%d#0| state))\n",
- get_id(module), get_id(cell), get_id(module), abits, width, get_id(module), arrayid));
+ decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", get_id(cell), abits, width, rd_ports, wr_ports, async_read ? "async" : "sync"));
- for (int i = 0; i < rd_ports; i++)
+ string memstate;
+ if (async_read) {
+ memstate = stringf("%s#%d#final", get_id(module), arrayid);
+ } else {
+ memstate = stringf("%s#%d#0", get_id(module), arrayid);
+ }
+
+ if (statebv)
{
- SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(abits*i, abits);
- SigSpec data_sig = cell->getPort("\\RD_DATA").extract(width*i, width);
- std::string addr = get_bv(addr_sig);
+ int mem_size = cell->getParam("\\SIZE").as_int();
+ int mem_offset = cell->getParam("\\OFFSET").as_int();
+
+ makebits(memstate, width*mem_size, get_id(cell));
+ decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (_ BitVec %d) (|%s| state))\n",
+ get_id(module), get_id(cell), get_id(module), width*mem_size, memstate.c_str()));
+
+ for (int i = 0; i < rd_ports; i++)
+ {
+ SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(abits*i, abits);
+ SigSpec data_sig = cell->getPort("\\RD_DATA").extract(width*i, width);
+ std::string addr = get_bv(addr_sig);
+
+ if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool())
+ log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! "
+ "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(data_sig), log_id(cell), log_id(module));
+
+ decls.push_back(stringf("(define-fun |%s_m:R%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig)));
- if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool())
- log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! "
- "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(data_sig), log_id(cell), log_id(module));
+ std::string read_expr = "#b";
+ for (int k = 0; k < width; k++)
+ read_expr += "0";
- decls.push_back(stringf("(define-fun |%s_m:%d %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
- get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig)));
+ for (int k = 0; k < mem_size; k++)
+ read_expr = stringf("(ite (= (|%s_m:R%dA %s| state) #b%s) ((_ extract %d %d) (|%s| state))\n %s)",
+ get_id(module), i, get_id(cell), Const(k+mem_offset, abits).as_string().c_str(),
+ width*(k+1)-1, width*k, memstate.c_str(), read_expr.c_str());
- decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) (select (|%s#%d#0| state) %s)) ; %s\n",
- get_id(module), idcounter, get_id(module), width, get_id(module), arrayid, addr.c_str(), log_signal(data_sig)));
- register_bv(data_sig, idcounter++);
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d)\n %s) ; %s\n",
+ get_id(module), idcounter, get_id(module), width, read_expr.c_str(), log_signal(data_sig)));
+
+ decls.push_back(stringf("(define-fun |%s_m:R%dD %s| ((state |%s_s|)) (_ BitVec %d) (|%s#%d| state))\n",
+ get_id(module), i, get_id(cell), get_id(module), width, get_id(module), idcounter));
+
+ register_bv(data_sig, idcounter++);
+ }
+ }
+ else
+ {
+ if (statedt)
+ dtmembers.push_back(stringf(" (|%s| (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
+ memstate.c_str(), abits, width, get_id(cell)));
+ else
+ decls.push_back(stringf("(declare-fun |%s| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
+ memstate.c_str(), get_id(module), abits, width, get_id(cell)));
+
+ decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) (|%s| state))\n",
+ get_id(module), get_id(cell), get_id(module), abits, width, memstate.c_str()));
+
+ for (int i = 0; i < rd_ports; i++)
+ {
+ SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(abits*i, abits);
+ SigSpec data_sig = cell->getPort("\\RD_DATA").extract(width*i, width);
+ std::string addr = get_bv(addr_sig);
+
+ if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool())
+ log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! "
+ "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(data_sig), log_id(cell), log_id(module));
+
+ decls.push_back(stringf("(define-fun |%s_m:R%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig)));
+
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) (select (|%s| state) (|%s_m:R%dA %s| state))) ; %s\n",
+ get_id(module), idcounter, get_id(module), width, memstate.c_str(), get_id(module), i, get_id(cell), log_signal(data_sig)));
+
+ decls.push_back(stringf("(define-fun |%s_m:R%dD %s| ((state |%s_s|)) (_ BitVec %d) (|%s#%d| state))\n",
+ get_id(module), i, get_id(cell), get_id(module), width, get_id(module), idcounter));
+
+ register_bv(data_sig, idcounter++);
+ }
}
registers.insert(cell);
@@ -553,32 +740,38 @@ struct Smt2Worker
for (auto &conn : cell->connections())
{
+ if (GetSize(conn.second) == 0)
+ continue;
+
Wire *w = m->wire(conn.first);
SigSpec sig = sigmap(conn.second);
if (w->port_output && !w->port_input) {
if (GetSize(w) > 1) {
if (bvmode) {
- decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
- get_id(module), idcounter, get_id(module), GetSize(w), log_signal(sig)));
+ makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(w), log_signal(sig));
register_bv(sig, idcounter++);
} else {
for (int i = 0; i < GetSize(w); i++) {
- decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
- get_id(module), idcounter, get_id(module), log_signal(sig[i])));
+ makebits(stringf("%s#%d", get_id(module), idcounter), 0, log_signal(sig[i]));
register_bool(sig[i], idcounter++);
}
}
} else {
- decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
- get_id(module), idcounter, get_id(module), log_signal(sig)));
+ makebits(stringf("%s#%d", get_id(module), idcounter), 0, log_signal(sig));
register_bool(sig, idcounter++);
}
}
}
- decls.push_back(stringf("(declare-fun |%s_h %s| (|%s_s|) |%s_s|)\n",
- get_id(module), get_id(cell->name), get_id(module), get_id(cell->type)));
+ if (statebv)
+ makebits(stringf("%s_h %s", get_id(module), get_id(cell->name)), mod_stbv_width.at(cell->type));
+ else if (statedt)
+ dtmembers.push_back(stringf(" (|%s_h %s| |%s_s|)\n",
+ get_id(module), get_id(cell->name), get_id(cell->type)));
+ else
+ decls.push_back(stringf("(declare-fun |%s_h %s| (|%s_s|) |%s_s|)\n",
+ get_id(module), get_id(cell->name), get_id(module), get_id(cell->type)));
hiercells.insert(cell);
hiercells_queue.insert(cell);
@@ -617,17 +810,30 @@ struct Smt2Worker
decls.push_back(stringf("; yosys-smt2-register %s %d\n", get_id(wire), wire->width));
if (wire->get_bool_attribute("\\keep") || (wiresmode && wire->name[0] == '\\'))
decls.push_back(stringf("; yosys-smt2-wire %s %d\n", get_id(wire), wire->width));
+ if (GetSize(wire) == 1 && (clock_posedge.count(sig) || clock_negedge.count(sig)))
+ decls.push_back(stringf("; yosys-smt2-clock %s%s%s\n", get_id(wire),
+ clock_posedge.count(sig) ? " posedge" : "", clock_negedge.count(sig) ? " negedge" : ""));
if (bvmode && GetSize(sig) > 1) {
decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) (_ BitVec %d) %s)\n",
get_id(module), get_id(wire), get_id(module), GetSize(sig), get_bv(sig).c_str()));
+ if (wire->port_input)
+ ex_input_eq.push_back(stringf(" (= (|%s_n %s| state) (|%s_n %s| other_state))",
+ get_id(module), get_id(wire), get_id(module), get_id(wire)));
} else {
for (int i = 0; i < GetSize(sig); i++)
- if (GetSize(sig) > 1)
+ if (GetSize(sig) > 1) {
decls.push_back(stringf("(define-fun |%s_n %s %d| ((state |%s_s|)) Bool %s)\n",
get_id(module), get_id(wire), i, get_id(module), get_bool(sig[i]).c_str()));
- else
+ if (wire->port_input)
+ ex_input_eq.push_back(stringf(" (= (|%s_n %s %d| state) (|%s_n %s %d| other_state))",
+ get_id(module), get_id(wire), i, get_id(module), get_id(wire), i));
+ } else {
decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) Bool %s)\n",
get_id(module), get_id(wire), get_id(module), get_bool(sig[i]).c_str()));
+ if (wire->port_input)
+ ex_input_eq.push_back(stringf(" (= (|%s_n %s| state) (|%s_n %s| other_state))",
+ get_id(module), get_id(wire), get_id(module), get_id(wire)));
+ }
}
}
}
@@ -639,31 +845,104 @@ struct Smt2Worker
if (wire->attributes.count("\\init")) {
RTLIL::SigSpec sig = sigmap(wire);
Const val = wire->attributes.at("\\init");
- val.bits.resize(GetSize(sig));
+ val.bits.resize(GetSize(sig), State::Sx);
if (bvmode && GetSize(sig) > 1) {
- init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), get_id(wire)));
+ Const mask(State::S1, GetSize(sig));
+ bool use_mask = false;
+ for (int i = 0; i < GetSize(sig); i++)
+ if (val[i] != State::S0 && val[i] != State::S1) {
+ val[i] = State::S0;
+ mask[i] = State::S0;
+ use_mask = true;
+ }
+ if (use_mask)
+ init_list.push_back(stringf("(= (bvand %s #b%s) #b%s) ; %s", get_bv(sig).c_str(), mask.as_string().c_str(), val.as_string().c_str(), get_id(wire)));
+ else
+ init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), get_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", get_id(wire)));
+ if (val[i] == State::S0 || val[i] == State::S1)
+ init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val[i] == State::S1 ? "true" : "false", get_id(wire)));
}
}
if (verbose) log("=> export logic driving asserts\n");
- vector<string> assert_list, assume_list;
+ int assert_id = 0, assume_id = 0, cover_id = 0;
+ vector<string> assert_list, assume_list, cover_list;
+
for (auto cell : module->cells())
- if (cell->type.in("$assert", "$assume")) {
+ {
+ if (cell->type.in("$assert", "$assume", "$cover"))
+ {
+ int &id = cell->type == "$assert" ? assert_id :
+ cell->type == "$assume" ? assume_id :
+ cell->type == "$cover" ? cover_id : *(int*)nullptr;
+
+ char postfix = cell->type == "$assert" ? 'a' :
+ cell->type == "$assume" ? 'u' :
+ cell->type == "$cover" ? 'c' : 0;
+
string name_a = get_bool(cell->getPort("\\A"));
string name_en = get_bool(cell->getPort("\\EN"));
- decls.push_back(stringf("; yosys-smt2-%s %s#%d %s\n", cell->type.c_str() + 1, get_id(module), idcounter,
+ decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id,
cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
- decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n",
- get_id(module), idcounter, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell)));
- if (cell->type == "$assert")
- assert_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++));
+
+ if (cell->type == "$cover")
+ decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
+ get_id(module), postfix, id, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell)));
else
- assume_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++));
+ decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n",
+ get_id(module), postfix, id, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell)));
+
+ if (cell->type == "$assert")
+ assert_list.push_back(stringf("(|%s_a %d| state)", get_id(module), id));
+ else if (cell->type == "$assume")
+ assume_list.push_back(stringf("(|%s_u %d| state)", get_id(module), id));
+
+ id++;
}
+ }
+
+ if (verbose) log("=> export logic driving hierarchical cells\n");
+
+ for (auto cell : module->cells())
+ if (module->design->module(cell->type) != nullptr)
+ export_cell(cell);
+
+ while (!hiercells_queue.empty())
+ {
+ std::set<RTLIL::Cell*> queue;
+ queue.swap(hiercells_queue);
+
+ for (auto cell : queue)
+ {
+ string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name));
+ Module *m = module->design->module(cell->type);
+ log_assert(m != nullptr);
+
+ hier.push_back(stringf(" (= (|%s_is| state) (|%s_is| %s))\n",
+ get_id(module), get_id(cell->type), cell_state.c_str()));
+
+ for (auto &conn : cell->connections())
+ {
+ if (GetSize(conn.second) == 0)
+ continue;
+
+ Wire *w = m->wire(conn.first);
+ SigSpec sig = sigmap(conn.second);
+
+ if (bvmode || GetSize(w) == 1) {
+ hier.push_back(stringf(" (= %s (|%s_n %s| %s)) ; %s.%s\n", (GetSize(w) > 1 ? get_bv(sig) : get_bool(sig)).c_str(),
+ get_id(cell->type), get_id(w), cell_state.c_str(), get_id(cell->type), get_id(w)));
+ } else {
+ for (int i = 0; i < GetSize(w); i++)
+ hier.push_back(stringf(" (= %s (|%s_n %s %d| %s)) ; %s.%s[%d]\n", get_bool(sig[i]).c_str(),
+ get_id(cell->type), get_id(w), i, cell_state.c_str(), get_id(cell->type), get_id(w), i));
+ }
+ }
+ }
+ }
for (int iter = 1; !registers.empty(); iter++)
{
@@ -679,6 +958,7 @@ struct Smt2Worker
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(), get_id(cell), log_signal(cell->getPort("\\Q"))));
+ ex_state_eq.push_back(stringf("(= %s %s)", get_bool(cell->getPort("\\Q")).c_str(), get_bool(cell->getPort("\\Q"), "other_state").c_str()));
}
if (cell->type.in("$ff", "$dff"))
@@ -686,13 +966,16 @@ struct Smt2Worker
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(), get_id(cell), log_signal(cell->getPort("\\Q"))));
+ ex_state_eq.push_back(stringf("(= %s %s)", get_bv(cell->getPort("\\Q")).c_str(), get_bv(cell->getPort("\\Q"), "other_state").c_str()));
}
- if (cell->type == "$anyconst")
+ if (cell->type.in("$anyconst", "$allconst"))
{
std::string expr_d = get_bv(cell->getPort("\\Y"));
std::string expr_q = get_bv(cell->getPort("\\Y"), "next_state");
trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Y"))));
+ if (cell->type == "$anyconst")
+ ex_state_eq.push_back(stringf("(= %s %s)", get_bv(cell->getPort("\\Y")).c_str(), get_bv(cell->getPort("\\Y"), "other_state").c_str()));
}
if (cell->type == "$mem")
@@ -703,24 +986,111 @@ struct Smt2Worker
int width = cell->getParam("\\WIDTH").as_int();
int wr_ports = cell->getParam("\\WR_PORTS").as_int();
- for (int i = 0; i < wr_ports; i++)
+ bool async_read = false;
+ string initial_memstate, final_memstate;
+
+ if (!cell->getParam("\\WR_CLK_ENABLE").is_fully_ones()) {
+ log_assert(cell->getParam("\\WR_CLK_ENABLE").is_fully_zero());
+ async_read = true;
+ initial_memstate = stringf("%s#%d#0", get_id(module), arrayid);
+ final_memstate = stringf("%s#%d#final", get_id(module), arrayid);
+ }
+
+ if (statebv)
+ {
+ int mem_size = cell->getParam("\\SIZE").as_int();
+ int mem_offset = cell->getParam("\\OFFSET").as_int();
+
+ if (async_read) {
+ makebits(final_memstate, width*mem_size, get_id(cell));
+ }
+
+ for (int i = 0; i < wr_ports; i++)
+ {
+ SigSpec addr_sig = cell->getPort("\\WR_ADDR").extract(abits*i, abits);
+ SigSpec data_sig = cell->getPort("\\WR_DATA").extract(width*i, width);
+ SigSpec mask_sig = cell->getPort("\\WR_EN").extract(width*i, width);
+
+ std::string addr = get_bv(addr_sig);
+ std::string data = get_bv(data_sig);
+ std::string mask = get_bv(mask_sig);
+
+ decls.push_back(stringf("(define-fun |%s_m:W%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig)));
+ addr = stringf("(|%s_m:W%dA %s| state)", get_id(module), i, get_id(cell));
+
+ decls.push_back(stringf("(define-fun |%s_m:W%dD %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ get_id(module), i, get_id(cell), get_id(module), width, data.c_str(), log_signal(data_sig)));
+ data = stringf("(|%s_m:W%dD %s| state)", get_id(module), i, get_id(cell));
+
+ decls.push_back(stringf("(define-fun |%s_m:W%dM %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ get_id(module), i, get_id(cell), get_id(module), width, mask.c_str(), log_signal(mask_sig)));
+ mask = stringf("(|%s_m:W%dM %s| state)", get_id(module), i, get_id(cell));
+
+ std::string data_expr;
+
+ for (int k = mem_size-1; k >= 0; k--) {
+ std::string new_data = stringf("(bvor (bvand %s %s) (bvand ((_ extract %d %d) (|%s#%d#%d| state)) (bvnot %s)))",
+ data.c_str(), mask.c_str(), width*(k+1)-1, width*k, get_id(module), arrayid, i, mask.c_str());
+ data_expr += stringf("\n (ite (= %s #b%s) %s ((_ extract %d %d) (|%s#%d#%d| state)))",
+ addr.c_str(), Const(k+mem_offset, abits).as_string().c_str(), new_data.c_str(),
+ width*(k+1)-1, width*k, get_id(module), arrayid, i);
+ }
+
+ decls.push_back(stringf("(define-fun |%s#%d#%d| ((state |%s_s|)) (_ BitVec %d) (concat%s)) ; %s\n",
+ get_id(module), arrayid, i+1, get_id(module), width*mem_size, data_expr.c_str(), get_id(cell)));
+ }
+ }
+ else
{
- std::string addr = get_bv(cell->getPort("\\WR_ADDR").extract(abits*i, abits));
- std::string data = get_bv(cell->getPort("\\WR_DATA").extract(width*i, width));
- std::string mask = get_bv(cell->getPort("\\WR_EN").extract(width*i, width));
+ if (async_read) {
+ if (statedt)
+ dtmembers.push_back(stringf(" (|%s| (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
+ initial_memstate.c_str(), abits, width, get_id(cell)));
+ else
+ decls.push_back(stringf("(declare-fun |%s| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
+ initial_memstate.c_str(), get_id(module), abits, width, get_id(cell)));
+ }
+
+ for (int i = 0; i < wr_ports; i++)
+ {
+ SigSpec addr_sig = cell->getPort("\\WR_ADDR").extract(abits*i, abits);
+ SigSpec data_sig = cell->getPort("\\WR_DATA").extract(width*i, width);
+ SigSpec mask_sig = cell->getPort("\\WR_EN").extract(width*i, width);
+
+ std::string addr = get_bv(addr_sig);
+ std::string data = get_bv(data_sig);
+ std::string mask = get_bv(mask_sig);
+
+ decls.push_back(stringf("(define-fun |%s_m:W%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig)));
+ addr = stringf("(|%s_m:W%dA %s| state)", get_id(module), i, get_id(cell));
+
+ decls.push_back(stringf("(define-fun |%s_m:W%dD %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ get_id(module), i, get_id(cell), get_id(module), width, data.c_str(), log_signal(data_sig)));
+ data = stringf("(|%s_m:W%dD %s| state)", get_id(module), i, get_id(cell));
+
+ decls.push_back(stringf("(define-fun |%s_m:W%dM %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ get_id(module), i, get_id(cell), get_id(module), width, mask.c_str(), log_signal(mask_sig)));
+ mask = stringf("(|%s_m:W%dM %s| state)", get_id(module), i, get_id(cell));
- data = stringf("(bvor (bvand %s %s) (bvand (select (|%s#%d#%d| state) %s) (bvnot %s)))",
- data.c_str(), mask.c_str(), get_id(module), arrayid, i, addr.c_str(), mask.c_str());
+ data = stringf("(bvor (bvand %s %s) (bvand (select (|%s#%d#%d| state) %s) (bvnot %s)))",
+ data.c_str(), mask.c_str(), get_id(module), arrayid, i, addr.c_str(), mask.c_str());
- decls.push_back(stringf("(define-fun |%s#%d#%d| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) "
- "(store (|%s#%d#%d| state) %s %s)) ; %s\n",
- get_id(module), arrayid, i+1, get_id(module), abits, width,
- get_id(module), arrayid, i, addr.c_str(), data.c_str(), get_id(cell)));
+ decls.push_back(stringf("(define-fun |%s#%d#%d| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) "
+ "(store (|%s#%d#%d| state) %s %s)) ; %s\n",
+ get_id(module), arrayid, i+1, get_id(module), abits, width,
+ get_id(module), arrayid, i, addr.c_str(), data.c_str(), get_id(cell)));
+ }
}
std::string expr_d = stringf("(|%s#%d#%d| state)", get_id(module), arrayid, wr_ports);
std::string expr_q = stringf("(|%s#%d#0| next_state)", get_id(module), arrayid);
trans.push_back(stringf(" (= %s %s) ; %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell)));
+ ex_state_eq.push_back(stringf("(= (|%s#%d#0| state) (|%s#%d#0| other_state))", get_id(module), arrayid, get_id(module), arrayid));
+
+ if (async_read)
+ hier.push_back(stringf(" (= %s (|%s| state)) ; %s\n", expr_d.c_str(), final_memstate.c_str(), get_id(cell)));
Const init_data = cell->getParam("\\INIT");
int memsize = cell->getParam("\\SIZE").as_int();
@@ -737,46 +1107,20 @@ struct Smt2Worker
if (bit == State::S0 || bit == State::S1)
gen_init_constr = true;
- if (gen_init_constr) {
- init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]",
- get_id(module), arrayid, Const(i, abits).as_string().c_str(),
- initword.as_string().c_str(), get_id(cell), i));
+ if (gen_init_constr)
+ {
+ if (statebv)
+ /* FIXME */;
+ else
+ init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]",
+ get_id(module), arrayid, Const(i, abits).as_string().c_str(),
+ initword.as_string().c_str(), get_id(cell), i));
}
}
}
}
}
- if (verbose) log("=> export logic driving hierarchical cells\n");
-
- while (!hiercells_queue.empty())
- {
- std::set<RTLIL::Cell*> queue;
- queue.swap(hiercells_queue);
-
- for (auto cell : queue)
- {
- string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name));
- Module *m = module->design->module(cell->type);
- log_assert(m != nullptr);
-
- for (auto &conn : cell->connections())
- {
- Wire *w = m->wire(conn.first);
- SigSpec sig = sigmap(conn.second);
-
- if (bvmode || GetSize(w) == 1) {
- hier.push_back(stringf(" (= %s (|%s_n %s| %s)) ; %s.%s\n", (GetSize(w) > 1 ? get_bv(sig) : get_bool(sig)).c_str(),
- get_id(cell->type), get_id(w), cell_state.c_str(), get_id(cell->type), get_id(w)));
- } else {
- for (int i = 0; i < GetSize(w); i++)
- hier.push_back(stringf(" (= %s (|%s_n %s %d| %s)) ; %s.%s[%d]\n", get_bool(sig[i]).c_str(),
- get_id(cell->type), get_id(w), i, cell_state.c_str(), get_id(cell->type), get_id(w), i));
- }
- }
- }
- }
-
if (verbose) log("=> finalizing SMT2 representation of %s.\n", log_id(module));
for (auto c : hiercells) {
@@ -786,6 +1130,37 @@ struct Smt2Worker
hier.push_back(stringf(" (|%s_h| (|%s_h %s| state))\n", get_id(c->type), get_id(module), get_id(c->name)));
trans.push_back(stringf(" (|%s_t| (|%s_h %s| state) (|%s_h %s| next_state))\n",
get_id(c->type), get_id(module), get_id(c->name), get_id(module), get_id(c->name)));
+ ex_state_eq.push_back(stringf("(|%s_ex_state_eq| (|%s_h %s| state) (|%s_h %s| other_state))\n",
+ get_id(c->type), get_id(module), get_id(c->name), get_id(module), get_id(c->name)));
+ }
+
+ if (forallmode)
+ {
+ string expr = ex_state_eq.empty() ? "true" : "(and";
+ if (!ex_state_eq.empty()) {
+ if (GetSize(ex_state_eq) == 1) {
+ expr = "\n " + ex_state_eq.front() + "\n";
+ } else {
+ for (auto &str : ex_state_eq)
+ expr += stringf("\n %s", str.c_str());
+ expr += "\n)";
+ }
+ }
+ decls.push_back(stringf("(define-fun |%s_ex_state_eq| ((state |%s_s|) (other_state |%s_s|)) Bool %s)\n",
+ get_id(module), get_id(module), get_id(module), expr.c_str()));
+
+ expr = ex_input_eq.empty() ? "true" : "(and";
+ if (!ex_input_eq.empty()) {
+ if (GetSize(ex_input_eq) == 1) {
+ expr = "\n " + ex_input_eq.front() + "\n";
+ } else {
+ for (auto &str : ex_input_eq)
+ expr += stringf("\n %s", str.c_str());
+ expr += "\n)";
+ }
+ }
+ decls.push_back(stringf("(define-fun |%s_ex_input_eq| ((state |%s_s|) (other_state |%s_s|)) Bool %s)\n",
+ get_id(module), get_id(module), get_id(module), expr.c_str()));
}
string assert_expr = assert_list.empty() ? "true" : "(and";
@@ -832,6 +1207,18 @@ struct Smt2Worker
{
f << stringf("; yosys-smt2-module %s\n", get_id(module));
+ if (statebv) {
+ f << stringf("(define-sort |%s_s| () (_ BitVec %d))\n", get_id(module), statebv_width);
+ mod_stbv_width[module->name] = statebv_width;
+ } else
+ if (statedt) {
+ f << stringf("(declare-datatype |%s_s| ((|%s_mk|\n", get_id(module), get_id(module));
+ for (auto it : dtmembers)
+ f << it;
+ f << stringf(")))\n");
+ } else
+ f << stringf("(declare-sort |%s_s| 0)\n", get_id(module));
+
for (auto it : decls)
f << it;
@@ -864,44 +1251,92 @@ struct Smt2Worker
struct Smt2Backend : public Backend {
Smt2Backend() : Backend("smt2", "write design to SMT-LIBv2 file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---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("'<mod>' this will declare the sort '<mod>_s' (state of the module) and will\n");
+ log("define and declare functions operating on that state.\n");
+ log("\n");
+ log("The following SMT2 functions are generated for a module with name '<mod>'.\n");
+ log("Some declarations/definitions are printed with a special comment. A prover\n");
+ log("using the SMT2 files can use those comments to collect all relevant metadata\n");
+ log("about the design.\n");
+ log("\n");
+ log(" ; yosys-smt2-module <mod>\n");
+ log(" (declare-sort |<mod>_s| 0)\n");
+ log(" The sort representing a state of module <mod>.\n");
+ log("\n");
+ log(" (define-fun |<mod>_h| ((state |<mod>_s|)) Bool (...))\n");
+ log(" This function must be asserted for each state to establish the\n");
+ log(" design hierarchy.\n");
+ log("\n");
+ log(" ; yosys-smt2-input <wirename> <width>\n");
+ log(" ; yosys-smt2-output <wirename> <width>\n");
+ log(" ; yosys-smt2-register <wirename> <width>\n");
+ log(" ; yosys-smt2-wire <wirename> <width>\n");
+ log(" (define-fun |<mod>_n <wirename>| (|<mod>_s|) (_ BitVec <width>))\n");
+ log(" (define-fun |<mod>_n <wirename>| (|<mod>_s|) Bool)\n");
+ log(" For each port, register, and wire with the 'keep' attribute set an\n");
+ log(" accessor function is generated. Single-bit wires are returned as Bool,\n");
+ log(" multi-bit wires as BitVec.\n");
+ log("\n");
+ log(" ; yosys-smt2-cell <submod> <instancename>\n");
+ log(" (declare-fun |<mod>_h <instancename>| (|<mod>_s|) |<submod>_s|)\n");
+ log(" There is a function like that for each hierarchical instance. It\n");
+ log(" returns the sort that represents the state of the sub-module that\n");
+ log(" implements the instance.\n");
+ log("\n");
+ log(" (declare-fun |<mod>_is| (|<mod>_s|) Bool)\n");
+ log(" This function must be asserted 'true' for initial states, and 'false'\n");
+ log(" otherwise.\n");
+ log("\n");
+ log(" (define-fun |<mod>_i| ((state |<mod>_s|)) Bool (...))\n");
+ log(" This function must be asserted 'true' for initial states. For\n");
+ log(" non-initial states it must be left unconstrained.\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("By default only ports, registers, and wires with the 'keep' attribute set are\n");
- log("made available via such functions. With the -nobv option, multi-bit wires are\n");
- log("exported as separate functions of type Bool for the individual bits. Without\n");
- log("-nobv multi-bit wires are exported as single functions of type BitVec.\n");
+ log(" (define-fun |<mod>_t| ((state |<mod>_s|) (next_state |<mod>_s|)) Bool (...))\n");
+ log(" This function evaluates to 'true' if the states 'state' and\n");
+ log(" 'next_state' form a valid state transition.\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(" (define-fun |<mod>_a| ((state |<mod>_s|)) Bool (...))\n");
+ log(" This function evaluates to 'true' if all assertions hold in the state.\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(" (define-fun |<mod>_u| ((state |<mod>_s|)) Bool (...))\n");
+ log(" This function evaluates to 'true' if all assumptions hold in the state.\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(" ; yosys-smt2-assert <id> <filename:linenum>\n");
+ log(" (define-fun |<mod>_a <id>| ((state |<mod>_s|)) Bool (...))\n");
+ log(" Each $assert cell is converted into one of this functions. The function\n");
+ log(" evaluates to 'true' if the assert statement holds in the state.\n");
log("\n");
- log("The '<mod>_i' function evaluates to 'true' when the given state conforms\n");
- log("to the initial state. Furthermore the '<mod>_is' function should be asserted\n");
- log("to be true for initial states in addition to '<mod>_i', and should be\n");
- log("asserted to be false for non-initial states.\n");
+ log(" ; yosys-smt2-assume <id> <filename:linenum>\n");
+ log(" (define-fun |<mod>_u <id>| ((state |<mod>_s|)) Bool (...))\n");
+ log(" Each $assume cell is converted into one of this functions. The function\n");
+ log(" evaluates to 'true' if the assume statement holds in the state.\n");
log("\n");
- log("For hierarchical designs, the '<mod>_h' function must be asserted for each\n");
- log("state to establish the design hierarchy. The '<mod>_h <cellname>' function\n");
- log("evaluates to the state corresponding to the given cell within <mod>.\n");
+ log(" ; yosys-smt2-cover <id> <filename:linenum>\n");
+ log(" (define-fun |<mod>_c <id>| ((state |<mod>_s|)) Bool (...))\n");
+ log(" Each $cover cell is converted into one of this functions. The function\n");
+ log(" evaluates to 'true' if the cover statement is activated in the state.\n");
+ log("\n");
+ log("Options:\n");
log("\n");
log(" -verbose\n");
log(" this will print the recursive walk used to export the modules.\n");
log("\n");
+ log(" -stbv\n");
+ log(" Use a BitVec sort to represent a state instead of an uninterpreted\n");
+ log(" sort. As a side-effect this will prevent use of arrays to model\n");
+ log(" memories.\n");
+ log("\n");
+ log(" -stdt\n");
+ log(" Use SMT-LIB 2.6 style datatypes to represent a state instead of an\n");
+ log(" uninterpreted sort.\n");
+ log("\n");
log(" -nobv\n");
log(" disable support for BitVec (FixedSizeBitVectors theory). without this\n");
log(" option multi-bit wires are represented using the BitVec sort and\n");
@@ -972,10 +1407,11 @@ struct Smt2Backend : public Backend {
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)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::ifstream template_f;
- bool bvmode = true, memmode = true, wiresmode = false, verbose = false;
+ bool bvmode = true, memmode = true, wiresmode = false, verbose = false, statebv = false, statedt = false;
+ bool forallmode = false;
log_header(design, "Executing SMT2 backend.\n");
@@ -992,6 +1428,16 @@ struct Smt2Backend : public Backend {
log_warning("Options -bv and -mem are now the default. Support for -bv and -mem will be removed in the future.\n");
continue;
}
+ if (args[argidx] == "-stbv") {
+ statebv = true;
+ statedt = false;
+ continue;
+ }
+ if (args[argidx] == "-stdt") {
+ statebv = false;
+ statedt = true;
+ continue;
+ }
if (args[argidx] == "-nobv") {
bvmode = false;
memmode = false;
@@ -1033,6 +1479,12 @@ struct Smt2Backend : public Backend {
if (!memmode)
*f << stringf("; yosys-smt2-nomem\n");
+ if (statebv)
+ *f << stringf("; yosys-smt2-stbv\n");
+
+ if (statedt)
+ *f << stringf("; yosys-smt2-stdt\n");
+
std::vector<RTLIL::Module*> sorted_modules;
// extract module dependencies
@@ -1062,17 +1514,31 @@ struct Smt2Backend : public Backend {
module_deps.erase(sorted_modules.at(sorted_modules_idx++));
}
+ dict<IdString, int> mod_stbv_width;
+ dict<IdString, dict<IdString, pair<bool, bool>>> mod_clk_cache;
Module *topmod = design->top_module();
std::string topmod_id;
for (auto module : sorted_modules)
+ for (auto cell : module->cells())
+ if (cell->type.in("$allconst", "$allseq"))
+ goto found_forall;
+ if (0) {
+ found_forall:
+ forallmode = true;
+ *f << stringf("; yosys-smt2-forall\n");
+ if (!statebv && !statedt)
+ log_error("Forall-exists problems are only supported in -stbv or -stdt mode.\n");
+ }
+
+ for (auto module : sorted_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, memmode, wiresmode, verbose);
+ Smt2Worker worker(module, bvmode, memmode, wiresmode, verbose, statebv, statedt, forallmode, mod_stbv_width, mod_clk_cache);
worker.run();
worker.write(*f);
diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py
index 04c25f91..6af2a5ac 100644
--- a/backends/smt2/smtbmc.py
+++ b/backends/smt2/smtbmc.py
@@ -22,21 +22,32 @@ import os, sys, getopt, re
from smtio import SmtIo, SmtOpts, MkVcd
from collections import defaultdict
+got_topt = False
skip_steps = 0
step_size = 1
num_steps = 20
+append_steps = 0
vcdfile = None
cexfile = None
+aimfile = None
+aiwfile = None
+aigheader = True
vlogtbfile = None
+vlogtbtop = None
inconstr = list()
outconstr = None
gentrace = False
+covermode = False
tempind = False
dumpall = False
assume_skipped = None
final_only = False
topmod = None
noinfo = False
+presat = False
+smtcinit = False
+smtctop = None
+noinit = False
so = SmtOpts()
@@ -56,6 +67,9 @@ yosys-smtbmc [options] <yosys_smt2_output>
-i
instead of BMC run temporal induction
+ -c
+ instead of regular BMC run cover analysis
+
-m <module_name>
name of the top module
@@ -65,10 +79,30 @@ yosys-smtbmc [options] <yosys_smt2_output>
--cex <cex_filename>
read cex file as written by ABC's "write_cex -n"
+ --aig <prefix>
+ read AIGER map file (as written by Yosys' "write_aiger -map")
+ and AIGER witness file. The file names are <prefix>.aim for
+ the map file and <prefix>.aiw for the witness file.
+
+ --aig <aim_filename>:<aiw_filename>
+ like above, but for map files and witness files that do not
+ share a filename prefix (or use differen file extensions).
+
+ --aig-noheader
+ the AIGER witness file does not include the status and
+ properties lines.
+
--noinfo
only run the core proof, do not collect and print any
additional information (e.g. which assert failed)
+ --presat
+ check if the design with assumptions but without assertions
+ is SAT before checking if assertions are UNSAT. This will
+ detect if there are contradicting assumtions. In some cases
+ this will also help to "warmup" the solver, potentially
+ yielding a speedup.
+
--final-only
only check final constraints, assume base case
@@ -85,25 +119,48 @@ yosys-smtbmc [options] <yosys_smt2_output>
--dump-vlogtb <verilog_filename>
write trace as Verilog test bench
+ --vlogtb-top <hierarchical_name>
+ use the given entity as top module for the generated
+ Verilog test bench. The <hierarchical_name> is relative
+ to the design top module without the top module name.
+
--dump-smtc <constr_filename>
write trace as constraints file
+ --smtc-init
+ write just the last state as initial constraint to smtc file
+
+ --smtc-top <old>[:<new>]
+ replace <old> with <new> in constraints dumped to smtc
+ file and only dump object below <old> in design hierarchy.
+
+ --noinit
+ do not assume initial conditions in state 0
+
--dump-all
when using -g or -i, create a dump file for each
step. The character '%' is replaces in all dump
filenames with the step number.
+
+ --append <num_steps>
+ add <num_steps> time steps at the end of the trace
+ when creating a counter example (this additional time
+ steps will still be constrained by assumtions)
""" + so.helpmsg())
sys.exit(1)
try:
- opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igm:", so.longopts +
- ["final-only", "assume-skipped=", "smtc=", "cex=", "dump-vcd=", "dump-vlogtb=", "dump-smtc=", "dump-all", "noinfo"])
+ opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts +
+ ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "presat",
+ "dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=",
+ "smtc-init", "smtc-top=", "noinit"])
except:
usage()
for o, a in opts:
if o == "-t":
+ got_topt = True
a = a.split(":")
if len(a) == 1:
num_steps = int(a[0])
@@ -115,7 +172,7 @@ for o, a in opts:
step_size = int(a[1])
num_steps = int(a[2])
else:
- assert 0
+ assert False
elif o == "--assume-skipped":
assume_skipped = int(a)
elif o == "--final-only":
@@ -124,20 +181,46 @@ for o, a in opts:
inconstr.append(a)
elif o == "--cex":
cexfile = a
+ elif o == "--aig":
+ if ":" in a:
+ aimfile, aiwfile = a.split(":")
+ else:
+ aimfile = a + ".aim"
+ aiwfile = a + ".aiw"
+ elif o == "--aig-noheader":
+ aigheader = False
elif o == "--dump-vcd":
vcdfile = a
elif o == "--dump-vlogtb":
vlogtbfile = a
+ elif o == "--vlogtb-top":
+ vlogtbtop = a
elif o == "--dump-smtc":
outconstr = a
+ elif o == "--smtc-init":
+ smtcinit = True
+ elif o == "--smtc-top":
+ smtctop = a.split(":")
+ if len(smtctop) == 1:
+ smtctop.append("")
+ assert len(smtctop) == 2
+ smtctop = tuple(smtctop)
elif o == "--dump-all":
dumpall = True
+ elif o == "--presat":
+ presat = True
elif o == "--noinfo":
noinfo = True
+ elif o == "--noinit":
+ noinit = True
+ elif o == "--append":
+ append_steps = int(a)
elif o == "-i":
tempind = True
elif o == "-g":
gentrace = True
+ elif o == "-c":
+ covermode = True
elif o == "-m":
topmod = a
elif so.handle(o, a):
@@ -148,6 +231,8 @@ for o, a in opts:
if len(args) != 1:
usage()
+if sum([tempind, gentrace, covermode]) > 1:
+ usage()
constr_final_start = None
constr_asserts = defaultdict(list)
@@ -182,12 +267,11 @@ for fn in inconstr:
current_states = set(["final-%d" % i for i in range(0, num_steps+1)])
constr_final_start = 0
elif len(tokens) == 2:
- i = int(tokens[1])
- assert i < 0
- current_states = set(["final-%d" % i for i in range(-i, num_steps+1)])
- constr_final_start = -i if constr_final_start is None else min(constr_final_start, -i)
+ arg = abs(int(tokens[1]))
+ current_states = set(["final-%d" % i for i in range(arg, num_steps+1)])
+ constr_final_start = arg if constr_final_start is None else min(constr_final_start, arg)
else:
- assert 0
+ assert False
continue
if tokens[0] == "state":
@@ -206,18 +290,17 @@ for fn in inconstr:
for i in range(lower, upper+1):
current_states.add(i)
else:
- assert 0
+ assert False
continue
if tokens[0] == "always":
if len(tokens) == 1:
current_states = set(range(0, num_steps+1))
elif len(tokens) == 2:
- i = int(tokens[1])
- assert i < 0
- current_states = set(range(-i, num_steps+1))
+ arg = abs(int(tokens[1]))
+ current_states = set(range(arg, num_steps+1))
else:
- assert 0
+ assert False
continue
if tokens[0] == "assert":
@@ -244,7 +327,7 @@ for fn in inconstr:
so.logic = " ".join(tokens[1:])
continue
- assert 0
+ assert False
def get_constr_expr(db, state, final=False, getvalues=False):
@@ -255,7 +338,7 @@ def get_constr_expr(db, state, final=False, getvalues=False):
if state not in db:
return ([], [], []) if getvalues else "true"
- netref_regex = re.compile(r'(^|[( ])\[(-?[0-9]+:|)([^\]]*)\](?=[ )]|$)')
+ netref_regex = re.compile(r'(^|[( ])\[(-?[0-9]+:|)([^\]]*|\S*)\](?=[ )]|$)')
def replace_netref(match):
state_sel = match.group(2)
@@ -318,6 +401,11 @@ assert topmod is not None
assert topmod in smt.modinfo
if cexfile is not None:
+ if not got_topt:
+ assume_skipped = 0
+ skip_steps = 0
+ num_steps = 0
+
with open(cexfile, "r") as f:
cex_regex = re.compile(r'([^\[@=]+)(\[\d+\])?([^@=]*)(@\d+)=([01])')
for entry in f.read().split():
@@ -349,6 +437,144 @@ if cexfile is not None:
# print("cex@%d: %s" % (step, smtexpr))
constr_assumes[step].append((cexfile, smtexpr))
+ if not got_topt:
+ skip_steps = max(skip_steps, step)
+ num_steps = max(num_steps, step+1)
+
+if aimfile is not None:
+ input_map = dict()
+ init_map = dict()
+ latch_map = dict()
+
+ if not got_topt:
+ assume_skipped = 0
+ skip_steps = 0
+ num_steps = 0
+
+ with open(aimfile, "r") as f:
+ for entry in f.read().splitlines():
+ entry = entry.split()
+
+ if entry[0] == "input":
+ input_map[int(entry[1])] = (entry[3], int(entry[2]))
+ continue
+
+ if entry[0] == "init":
+ init_map[int(entry[1])] = (entry[3], int(entry[2]))
+ continue
+
+ if entry[0] in ["latch", "invlatch"]:
+ latch_map[int(entry[1])] = (entry[3], int(entry[2]), entry[0] == "invlatch")
+ continue
+
+ if entry[0] in ["output", "wire"]:
+ continue
+
+ assert False
+
+ with open(aiwfile, "r") as f:
+ got_state = False
+ got_ffinit = False
+ step = 0
+
+ if not aigheader:
+ got_state = True
+
+ for entry in f.read().splitlines():
+ if len(entry) == 0 or entry[0] in "bcjfu.":
+ continue
+
+ if not got_state:
+ got_state = True
+ assert entry == "1"
+ continue
+
+ if not got_ffinit:
+ got_ffinit = True
+ if len(init_map) == 0:
+ for i in range(len(entry)):
+ if entry[i] == "x":
+ continue
+
+ if i in latch_map:
+ value = int(entry[i])
+ name = latch_map[i][0]
+ bitidx = latch_map[i][1]
+ invert = latch_map[i][2]
+
+ if invert:
+ value = 1 - value
+
+ path = smt.get_path(topmod, name)
+ width = smt.net_width(topmod, path)
+
+ if width == 1:
+ assert bitidx == 0
+ smtexpr = "(= [%s] %s)" % (name, "true" if value else "false")
+ else:
+ smtexpr = "(= ((_ extract %d %d) [%s]) #b%d)" % (bitidx, bitidx, name, value)
+
+ constr_assumes[0].append((cexfile, smtexpr))
+ continue
+
+ for i in range(len(entry)):
+ if entry[i] == "x":
+ continue
+
+ if (step == 0) and (i in init_map):
+ value = int(entry[i])
+ name = init_map[i][0]
+ bitidx = init_map[i][1]
+
+ path = smt.get_path(topmod, name)
+
+ if not smt.net_exists(topmod, path):
+ match = re.match(r"(.*)\[(\d+)\]$", path[-1])
+ if match:
+ path[-1] = match.group(1)
+ addr = int(match.group(2))
+
+ if not match or not smt.mem_exists(topmod, path):
+ print_msg("Ignoring init value for unknown net: %s" % (name))
+ continue
+
+ meminfo = smt.mem_info(topmod, path)
+ smtexpr = "(select [%s] #b%s)" % (".".join(path), bin(addr)[2:].zfill(meminfo[0]))
+ width = meminfo[1]
+
+ else:
+ smtexpr = "[%s]" % name
+ width = smt.net_width(topmod, path)
+
+ if width == 1:
+ assert bitidx == 0
+ smtexpr = "(= %s %s)" % (smtexpr, "true" if value else "false")
+ else:
+ smtexpr = "(= ((_ extract %d %d) %s) #b%d)" % (bitidx, bitidx, smtexpr, value)
+
+ constr_assumes[0].append((cexfile, smtexpr))
+
+ if i in input_map:
+ value = int(entry[i])
+ name = input_map[i][0]
+ bitidx = input_map[i][1]
+
+ path = smt.get_path(topmod, name)
+ width = smt.net_width(topmod, path)
+
+ if width == 1:
+ assert bitidx == 0
+ smtexpr = "(= [%s] %s)" % (name, "true" if value else "false")
+ else:
+ smtexpr = "(= ((_ extract %d %d) [%s]) #b%d)" % (bitidx, bitidx, name, value)
+
+ constr_assumes[step].append((cexfile, smtexpr))
+
+ if not got_topt:
+ skip_steps = max(skip_steps, step)
+ num_steps = max(num_steps, step+1)
+ step += 1
+
def write_vcd_trace(steps_start, steps_stop, index):
filename = vcdfile.replace("%", index)
print_msg("Writing trace to VCD file: %s" % (filename))
@@ -363,14 +589,123 @@ def write_vcd_trace(steps_start, steps_stop, index):
if n.startswith("$"):
hidden_net = True
if not hidden_net:
- vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath))
+ edge = smt.net_clock(topmod, netpath)
+ if edge is None:
+ vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath))
+ else:
+ vcd.add_clock([topmod] + netpath, edge)
path_list.append(netpath)
+ mem_trace_data = dict()
+ for mempath in sorted(smt.hiermems(topmod)):
+ abits, width, rports, wports, asyncwr = smt.mem_info(topmod, mempath)
+
+ expr_id = list()
+ expr_list = list()
+ for i in range(steps_start, steps_stop):
+ for j in range(rports):
+ expr_id.append(('R', i-steps_start, j, 'A'))
+ expr_id.append(('R', i-steps_start, j, 'D'))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dA" % j))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dD" % j))
+ for j in range(wports):
+ expr_id.append(('W', i-steps_start, j, 'A'))
+ expr_id.append(('W', i-steps_start, j, 'D'))
+ expr_id.append(('W', i-steps_start, j, 'M'))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dA" % j))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dD" % j))
+ expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dM" % j))
+
+ rdata = list()
+ wdata = list()
+ addrs = set()
+
+ for eid, edat in zip(expr_id, smt.get_list(expr_list)):
+ t, i, j, f = eid
+
+ if t == 'R':
+ c = rdata
+ elif t == 'W':
+ c = wdata
+ else:
+ assert False
+
+ while len(c) <= i:
+ c.append(list())
+ c = c[i]
+
+ while len(c) <= j:
+ c.append(dict())
+ c = c[j]
+
+ c[f] = smt.bv2bin(edat)
+
+ if f == 'A':
+ addrs.add(c[f])
+
+ for addr in addrs:
+ tdata = list()
+ data = ["x"] * width
+ gotread = False
+
+ if len(wdata) == 0 and len(rdata) != 0:
+ wdata = [[]] * len(rdata)
+
+ assert len(rdata) == len(wdata)
+
+ for i in range(len(wdata)):
+ if not gotread:
+ for j_data in rdata[i]:
+ if j_data["A"] == addr:
+ data = list(j_data["D"])
+ gotread = True
+ break
+
+ if gotread:
+ buf = data[:]
+ for i in reversed(range(len(tdata))):
+ for k in range(width):
+ if tdata[i][k] == "x":
+ tdata[i][k] = buf[k]
+ else:
+ buf[k] = tdata[i][k]
+
+ if not asyncwr:
+ tdata.append(data[:])
+
+ for j_data in wdata[i]:
+ if j_data["A"] != addr:
+ continue
+
+ D = j_data["D"]
+ M = j_data["M"]
+
+ for k in range(width):
+ if M[k] == "1":
+ data[k] = D[k]
+
+ if asyncwr:
+ tdata.append(data[:])
+
+ assert len(tdata) == len(rdata)
+
+ netpath = mempath[:]
+ netpath[-1] += "<%0*x>" % ((len(addr)+3) // 4, int(addr, 2))
+ vcd.add_net([topmod] + netpath, width)
+
+ for i in range(steps_start, steps_stop):
+ if i not in mem_trace_data:
+ mem_trace_data[i] = list()
+ mem_trace_data[i].append((netpath, "".join(tdata[i-steps_start])))
+
for i in range(steps_start, steps_stop):
vcd.set_time(i)
value_list = smt.get_net_bin_list(topmod, path_list, "s%d" % i)
for path, value in zip(path_list, value_list):
vcd.set_net([topmod] + path, value)
+ if i in mem_trace_data:
+ for path, value in mem_trace_data[i]:
+ vcd.set_net([topmod] + path, value)
vcd.set_time(steps_stop)
@@ -379,18 +714,38 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
filename = vlogtbfile.replace("%", index)
print_msg("Writing trace to Verilog testbench: %s" % (filename))
+ vlogtb_topmod = topmod
+ vlogtb_state = "s@@step_idx@@"
+
+ if vlogtbtop is not None:
+ for item in vlogtbtop.split("."):
+ if item in smt.modinfo[vlogtb_topmod].cells:
+ vlogtb_state = "(|%s_h %s| %s)" % (vlogtb_topmod, item, vlogtb_state)
+ vlogtb_topmod = smt.modinfo[vlogtb_topmod].cells[item]
+ else:
+ print_msg("Vlog top module '%s' not found: no cell '%s' in module '%s'" % (vlogtbtop, item, vlogtb_topmod))
+ break
+
with open(filename, "w") as f:
+ print("`ifndef VERILATOR", file=f)
print("module testbench;", file=f)
print(" reg [4095:0] vcdfile;", file=f)
- print(" reg clock = 0, genclock = 1;", file=f)
+ print(" reg clock;", file=f)
+ print("`else", file=f)
+ print("module testbench(input clock, output reg genclock);", file=f)
+ print(" initial genclock = 1;", file=f)
+ print("`endif", file=f)
+
+ print(" reg genclock = 1;", file=f)
+ print(" reg [31:0] cycle = 0;", file=f)
primary_inputs = list()
clock_inputs = set()
- for name in smt.modinfo[topmod].inputs:
+ for name in smt.modinfo[vlogtb_topmod].inputs:
if name in ["clk", "clock", "CLK", "CLOCK"]:
clock_inputs.add(name)
- width = smt.modinfo[topmod].wsize[name]
+ width = smt.modinfo[vlogtb_topmod].wsize[name]
primary_inputs.append((name, width))
for name, width in primary_inputs:
@@ -399,27 +754,32 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
else:
print(" reg [%d:0] PI_%s;" % (width-1, name), file=f)
- print(" %s UUT (" % topmod, file=f)
+ print(" %s UUT (" % vlogtb_topmod, file=f)
print(",\n".join(" .{name}(PI_{name})".format(name=name) for name, _ in primary_inputs), file=f)
print(" );", file=f)
+ print("`ifndef VERILATOR", file=f)
print(" initial begin", file=f)
print(" if ($value$plusargs(\"vcd=%s\", vcdfile)) begin", file=f)
print(" $dumpfile(vcdfile);", file=f)
print(" $dumpvars(0, testbench);", file=f)
print(" end", file=f)
+ print(" #5 clock = 0;", file=f)
print(" while (genclock) begin", file=f)
- print(" #5; clock = 0;", file=f)
- print(" #5; clock = 1;", file=f)
+ print(" #5 clock = 0;", file=f)
+ print(" #5 clock = 1;", file=f)
print(" end", file=f)
print(" end", file=f)
+ print("`endif", file=f)
print(" initial begin", file=f)
- regs = sorted(smt.hiernets(topmod, regs_only=True))
- regvals = smt.get_net_bin_list(topmod, regs, "s%d" % steps_start)
+ regs = sorted(smt.hiernets(vlogtb_topmod, regs_only=True))
+ regvals = smt.get_net_bin_list(vlogtb_topmod, regs, vlogtb_state.replace("@@step_idx@@", str(steps_start)))
+ print("`ifndef VERILATOR", file=f)
print(" #1;", file=f)
+ print("`endif", file=f)
for reg, val in zip(regs, regvals):
hidden_net = False
for n in reg:
@@ -427,40 +787,74 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
hidden_net = True
print(" %sUUT.%s = %d'b%s;" % ("// " if hidden_net else "", ".".join(reg), len(val), val), file=f)
- mems = sorted(smt.hiermems(topmod))
+ anyconsts = sorted(smt.hieranyconsts(vlogtb_topmod))
+ for info in anyconsts:
+ if info[3] is not None:
+ modstate = smt.net_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(steps_start)), info[0])
+ value = smt.bv2bin(smt.get("(|%s| %s)" % (info[1], modstate)))
+ print(" UUT.%s = %d'b%s;" % (".".join(info[0] + [info[3]]), len(value), value), file=f);
+
+ mems = sorted(smt.hiermems(vlogtb_topmod))
for mempath in mems:
- abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
- mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
+ abits, width, rports, wports, asyncwr = smt.mem_info(vlogtb_topmod, mempath)
addr_expr_list = list()
+ data_expr_list = list()
for i in range(steps_start, steps_stop):
- for j in range(ports):
- addr_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, j))
+ for j in range(rports):
+ addr_expr_list.append(smt.mem_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(i)), mempath, "R%dA" % j))
+ data_expr_list.append(smt.mem_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(i)), mempath, "R%dD" % j))
- addr_list = set()
- for val in smt.get_list(addr_expr_list):
- addr_list.add(smt.bv2int(val))
+ addr_list = smt.get_list(addr_expr_list)
+ data_list = smt.get_list(data_expr_list)
- expr_list = list()
- for i in addr_list:
- expr_list.append("(select %s #b%s)" % (mem, format(i, "0%db" % abits)))
+ addr_data = dict()
+ for addr, data in zip(addr_list, data_list):
+ addr = smt.bv2bin(addr)
+ data = smt.bv2bin(data)
+ if addr not in addr_data:
+ addr_data[addr] = data
- for i, val in zip(addr_list, smt.get_list(expr_list)):
- val = smt.bv2bin(val)
- print(" UUT.%s[%d] = %d'b%s;" % (".".join(mempath), i, len(val), val), file=f)
+ for addr, data in addr_data.items():
+ print(" UUT.%s[%d'b%s] = %d'b%s;" % (".".join(mempath), len(addr), addr, len(data), data), file=f)
+
+ print("", file=f)
+ anyseqs = sorted(smt.hieranyseqs(vlogtb_topmod))
for i in range(steps_start, steps_stop):
pi_names = [[name] for name, _ in primary_inputs if name not in clock_inputs]
- pi_values = smt.get_net_bin_list(topmod, pi_names, "s%d" % i)
+ pi_values = smt.get_net_bin_list(vlogtb_topmod, pi_names, vlogtb_state.replace("@@step_idx@@", str(i)))
- print(" #1;", file=f)
print(" // state %d" % i, file=f)
+
if i > 0:
- print(" @(posedge clock);", file=f)
+ print(" if (cycle == %d) begin" % (i-1), file=f)
+
for name, val in zip(pi_names, pi_values):
- print(" PI_%s <= %d'b%s;" % (".".join(name), len(val), val), file=f)
+ if i > 0:
+ print(" PI_%s <= %d'b%s;" % (".".join(name), len(val), val), file=f)
+ else:
+ print(" PI_%s = %d'b%s;" % (".".join(name), len(val), val), file=f)
+
+ for info in anyseqs:
+ if info[3] is not None:
+ modstate = smt.net_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(i)), info[0])
+ value = smt.bv2bin(smt.get("(|%s| %s)" % (info[1], modstate)))
+ if i > 0:
+ print(" UUT.%s <= %d'b%s;" % (".".join(info[0] + [info[3]]), len(value), value), file=f);
+ else:
+ print(" UUT.%s = %d'b%s;" % (".".join(info[0] + [info[3]]), len(value), value), file=f);
+
+ if i > 0:
+ print(" end", file=f)
+ print("", file=f)
+
+ if i == 0:
+ print(" end", file=f)
+ print(" always @(posedge clock) begin", file=f)
- print(" genclock = 0;", file=f)
+ print(" genclock <= cycle < %d;" % (steps_stop-1), file=f)
+ print(" cycle <= cycle + 1;", file=f)
print(" end", file=f)
print("endmodule", file=f)
@@ -470,52 +864,71 @@ def write_constr_trace(steps_start, steps_stop, index):
filename = outconstr.replace("%", index)
print_msg("Writing trace to constraints file: %s" % (filename))
+ constr_topmod = topmod
+ constr_state = "s@@step_idx@@"
+ constr_prefix = ""
+
+ if smtctop is not None:
+ for item in smtctop[0].split("."):
+ assert item in smt.modinfo[constr_topmod].cells
+ constr_state = "(|%s_h %s| %s)" % (constr_topmod, item, constr_state)
+ constr_topmod = smt.modinfo[constr_topmod].cells[item]
+ if smtctop[1] != "":
+ constr_prefix = smtctop[1] + "."
+
+ if smtcinit:
+ steps_start = steps_stop - 1
+
with open(filename, "w") as f:
primary_inputs = list()
- for name in smt.modinfo[topmod].inputs:
- width = smt.modinfo[topmod].wsize[name]
+ for name in smt.modinfo[constr_topmod].inputs:
+ width = smt.modinfo[constr_topmod].wsize[name]
primary_inputs.append((name, width))
- if steps_start == 0:
+ if steps_start == 0 or smtcinit:
print("initial", file=f)
else:
print("state %d" % steps_start, file=f)
- regnames = sorted(smt.hiernets(topmod, regs_only=True))
- regvals = smt.get_net_list(topmod, regnames, "s%d" % steps_start)
+ regnames = sorted(smt.hiernets(constr_topmod, regs_only=True))
+ regvals = smt.get_net_list(constr_topmod, regnames, constr_state.replace("@@step_idx@@", str(steps_start)))
for name, val in zip(regnames, regvals):
- print("assume (= [%s] %s)" % (".".join(name), val), file=f)
+ print("assume (= [%s%s] %s)" % (constr_prefix, ".".join(name), val), file=f)
- mems = sorted(smt.hiermems(topmod))
+ mems = sorted(smt.hiermems(constr_topmod))
for mempath in mems:
- abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
- mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
+ abits, width, rports, wports, asyncwr = smt.mem_info(constr_topmod, mempath)
addr_expr_list = list()
+ data_expr_list = list()
for i in range(steps_start, steps_stop):
- for j in range(ports):
- addr_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, j))
+ for j in range(rports):
+ addr_expr_list.append(smt.mem_expr(constr_topmod, constr_state.replace("@@step_idx@@", str(i)), mempath, "R%dA" % j))
+ data_expr_list.append(smt.mem_expr(constr_topmod, constr_state.replace("@@step_idx@@", str(i)), mempath, "R%dD" % j))
- addr_list = set((smt.bv2int(val) for val in smt.get_list(addr_expr_list)))
+ addr_list = smt.get_list(addr_expr_list)
+ data_list = smt.get_list(data_expr_list)
- expr_list = list()
- for i in addr_list:
- expr_list.append("(select %s #b%s)" % (mem, format(i, "0%db" % abits)))
+ addr_data = dict()
+ for addr, data in zip(addr_list, data_list):
+ if addr not in addr_data:
+ addr_data[addr] = data
- for i, val in zip(addr_list, smt.get_list(expr_list)):
- print("assume (= (select [%s] #b%s) %s)" % (".".join(mempath), format(i, "0%db" % abits), val), file=f)
+ for addr, data in addr_data.items():
+ print("assume (= (select [%s%s] %s) %s)" % (constr_prefix, ".".join(mempath), addr, data), file=f)
for k in range(steps_start, steps_stop):
- print("", file=f)
- print("state %d" % k, file=f)
+ if not smtcinit:
+ print("", file=f)
+ print("state %d" % k, file=f)
pi_names = [[name] for name, _ in sorted(primary_inputs)]
- pi_values = smt.get_net_list(topmod, pi_names, "s%d" % k)
+ pi_values = smt.get_net_list(constr_topmod, pi_names, constr_state.replace("@@step_idx@@", str(k)))
for name, val in zip(pi_names, pi_values):
- print("assume (= [%s] %s)" % (".".join(name), val), file=f)
+ print("assume (= [%s%s] %s)" % (constr_prefix, ".".join(name), val), file=f)
def write_trace(steps_start, steps_stop, index):
@@ -529,30 +942,40 @@ def write_trace(steps_start, steps_stop, index):
write_constr_trace(steps_start, steps_stop, index)
-def print_failed_asserts_worker(mod, state, path):
+def print_failed_asserts_worker(mod, state, path, extrainfo):
assert mod in smt.modinfo
+ found_failed_assert = False
if smt.get("(|%s_a| %s)" % (mod, state)) in ["true", "#b1"]:
return
for cellname, celltype in smt.modinfo[mod].cells.items():
- print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname)
+ if print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname, extrainfo):
+ found_failed_assert = True
for assertfun, assertinfo in smt.modinfo[mod].asserts.items():
if smt.get("(|%s| %s)" % (assertfun, state)) in ["false", "#b0"]:
- print_msg("Assert failed in %s: %s" % (path, assertinfo))
+ print_msg("Assert failed in %s: %s%s" % (path, assertinfo, extrainfo))
+ found_failed_assert = True
+
+ return found_failed_assert
-def print_failed_asserts(state, final=False):
+def print_failed_asserts(state, final=False, extrainfo=""):
if noinfo: return
loc_list, expr_list, value_list = get_constr_expr(constr_asserts, state, final=final, getvalues=True)
+ found_failed_assert = False
for loc, expr, value in zip(loc_list, expr_list, value_list):
if smt.bv2int(value) == 0:
- print_msg("Assert %s failed: %s" % (loc, expr))
+ print_msg("Assert %s failed: %s%s" % (loc, expr, extrainfo))
+ found_failed_assert = True
if not final:
- print_failed_asserts_worker(topmod, "s%d" % state, topmod)
+ if print_failed_asserts_worker(topmod, "s%d" % state, topmod, extrainfo):
+ found_failed_assert = True
+
+ return found_failed_assert
def print_anyconsts_worker(mod, state, path):
@@ -562,7 +985,10 @@ def print_anyconsts_worker(mod, state, path):
print_anyconsts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname)
for fun, info in smt.modinfo[mod].anyconsts.items():
- print_msg("Value for anyconst in %s (%s): %d" % (path, info, smt.bv2int(smt.get("(|%s| %s)" % (fun, state)))))
+ if info[1] is None:
+ print_msg("Value for anyconst in %s (%s): %d" % (path, info[0], smt.bv2int(smt.get("(|%s| %s)" % (fun, state)))))
+ else:
+ print_msg("Value for anyconst %s.%s (%s): %d" % (path, info[1], info[0], smt.bv2int(smt.get("(|%s| %s)" % (fun, state)))))
def print_anyconsts(state):
@@ -570,23 +996,183 @@ def print_anyconsts(state):
print_anyconsts_worker(topmod, "s%d" % state, topmod)
+def get_cover_list(mod, base):
+ assert mod in smt.modinfo
+
+ cover_expr = list()
+ cover_desc = list()
+
+ for expr, desc in smt.modinfo[mod].covers.items():
+ cover_expr.append("(ite (|%s| %s) #b1 #b0)" % (expr, base))
+ cover_desc.append(desc)
+
+ for cell, submod in smt.modinfo[mod].cells.items():
+ e, d = get_cover_list(submod, "(|%s_h %s| %s)" % (mod, cell, base))
+ cover_expr += e
+ cover_desc += d
+
+ return cover_expr, cover_desc
+
+states = list()
+asserts_antecedent_cache = [list()]
+asserts_consequent_cache = [list()]
+asserts_cache_dirty = False
+
+def smt_state(step):
+ smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod))
+ states.append("s%d" % step)
+
+def smt_assert(expr):
+ if expr == "true":
+ return
+
+ smt.write("(assert %s)" % expr)
+
+def smt_assert_antecedent(expr):
+ if expr == "true":
+ return
+
+ smt.write("(assert %s)" % expr)
+
+ global asserts_cache_dirty
+ asserts_cache_dirty = True
+ asserts_antecedent_cache[-1].append(expr)
+
+def smt_assert_consequent(expr):
+ if expr == "true":
+ return
+
+ smt.write("(assert %s)" % expr)
+
+ global asserts_cache_dirty
+ asserts_cache_dirty = True
+ asserts_consequent_cache[-1].append(expr)
+
+def smt_forall_assert():
+ if not smt.forall:
+ return
+
+ global asserts_cache_dirty
+ asserts_cache_dirty = False
+
+ def make_assert_expr(asserts_cache):
+ expr = list()
+ for lst in asserts_cache:
+ expr += lst
+
+ assert len(expr) != 0
+
+ if len(expr) == 1:
+ expr = expr[0]
+ else:
+ expr = "(and %s)" % (" ".join(expr))
+ return expr
+
+ antecedent_expr = make_assert_expr(asserts_antecedent_cache)
+ consequent_expr = make_assert_expr(asserts_consequent_cache)
+
+ states_db = set(states)
+ used_states_db = set()
+ new_antecedent_expr = list()
+ new_consequent_expr = list()
+ assert_expr = list()
+
+ def make_new_expr(new_expr, expr):
+ cursor = 0
+ while cursor < len(expr):
+ l = 1
+ if expr[cursor] in '|"':
+ while cursor+l+1 < len(expr) and expr[cursor] != expr[cursor+l]:
+ l += 1
+ l += 1
+ elif expr[cursor] not in '() ':
+ while cursor+l < len(expr) and expr[cursor+l] not in '|"() ':
+ l += 1
+
+ word = expr[cursor:cursor+l]
+ if word in states_db:
+ used_states_db.add(word)
+ word += "_"
+
+ new_expr.append(word)
+ cursor += l
+
+ make_new_expr(new_antecedent_expr, antecedent_expr)
+ make_new_expr(new_consequent_expr, consequent_expr)
+
+ new_antecedent_expr = ["".join(new_antecedent_expr)]
+ new_consequent_expr = ["".join(new_consequent_expr)]
+
+ if states[0] in used_states_db:
+ new_antecedent_expr.append("(|%s_ex_state_eq| %s %s_)" % (topmod, states[0], states[0]))
+ for s in states:
+ if s in used_states_db:
+ new_antecedent_expr.append("(|%s_ex_input_eq| %s %s_)" % (topmod, s, s))
+
+ if len(new_antecedent_expr) == 0:
+ new_antecedent_expr = "true"
+ elif len(new_antecedent_expr) == 1:
+ new_antecedent_expr = new_antecedent_expr[0]
+ else:
+ new_antecedent_expr = "(and %s)" % (" ".join(new_antecedent_expr))
+
+ if len(new_consequent_expr) == 0:
+ new_consequent_expr = "true"
+ elif len(new_consequent_expr) == 1:
+ new_consequent_expr = new_consequent_expr[0]
+ else:
+ new_consequent_expr = "(and %s)" % (" ".join(new_consequent_expr))
+
+ assert_expr.append("(assert (forall (")
+ first_state = True
+ for s in states:
+ if s in used_states_db:
+ assert_expr.append("%s(%s_ |%s_s|)" % ("" if first_state else " ", s, topmod))
+ first_state = False
+ assert_expr.append(") (=> %s %s)))" % (new_antecedent_expr, new_consequent_expr))
+
+ smt.write("".join(assert_expr))
+
+def smt_push():
+ global asserts_cache_dirty
+ asserts_cache_dirty = True
+ asserts_antecedent_cache.append(list())
+ asserts_consequent_cache.append(list())
+ smt.write("(push 1)")
+
+def smt_pop():
+ global asserts_cache_dirty
+ asserts_cache_dirty = True
+ asserts_antecedent_cache.pop()
+ asserts_consequent_cache.pop()
+ smt.write("(pop 1)")
+
+def smt_check_sat():
+ if asserts_cache_dirty:
+ smt_forall_assert()
+ return smt.check_sat()
+
if tempind:
retstatus = False
skip_counter = step_size
for step in range(num_steps, -1, -1):
- smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod))
- smt.write("(assert (|%s_u| s%d))" % (topmod, step))
- smt.write("(assert (|%s_h| s%d))" % (topmod, step))
- smt.write("(assert (not (|%s_is| s%d)))" % (topmod, step))
- smt.write("(assert %s)" % get_constr_expr(constr_assumes, step))
+ if smt.forall:
+ print_msg("Temporal induction not supported for exists-forall problems.")
+ break
+
+ smt_state(step)
+ smt_assert_consequent("(|%s_u| s%d)" % (topmod, step))
+ smt_assert_antecedent("(|%s_h| s%d)" % (topmod, step))
+ smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step))
+ smt_assert_consequent(get_constr_expr(constr_assumes, step))
if step == num_steps:
- smt.write("(assert (not (and (|%s_a| s%d) %s)))" % (topmod, step, get_constr_expr(constr_asserts, step)))
+ smt_assert("(not (and (|%s_a| s%d) %s))" % (topmod, step, get_constr_expr(constr_asserts, step)))
else:
- smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step, step+1))
- smt.write("(assert (|%s_a| s%d))" % (topmod, step))
- smt.write("(assert %s)" % get_constr_expr(constr_asserts, step))
+ smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step, step+1))
+ smt_assert("(|%s_a| s%d)" % (topmod, step))
+ smt_assert(get_constr_expr(constr_asserts, step))
if step > num_steps-skip_steps:
print_msg("Skipping induction in step %d.." % (step))
@@ -600,9 +1186,9 @@ if tempind:
skip_counter = 0
print_msg("Trying induction in step %d.." % (step))
- if smt.check_sat() == "sat":
+ if smt_check_sat() == "sat":
if step == 0:
- print("%s Temporal induction failed!" % smt.timestamp())
+ print_msg("Temporal induction failed!")
print_anyconsts(num_steps)
print_failed_asserts(num_steps)
write_trace(step, num_steps+1, '%')
@@ -613,33 +1199,135 @@ if tempind:
write_trace(step, num_steps+1, "%d" % step)
else:
- print("%s Temporal induction successful." % smt.timestamp())
+ print_msg("Temporal induction successful.")
retstatus = True
break
+elif covermode:
+ cover_expr, cover_desc = get_cover_list(topmod, "state")
+ cover_mask = "1" * len(cover_desc)
+
+ if len(cover_expr) > 1:
+ cover_expr = "(concat %s)" % " ".join(cover_expr)
+ elif len(cover_expr) == 1:
+ cover_expr = cover_expr[0]
+ else:
+ cover_expr = "#b0"
+
+ coveridx = 0
+ smt.write("(define-fun covers_0 ((state |%s_s|)) (_ BitVec %d) %s)" % (topmod, len(cover_desc), cover_expr))
-else: # not tempind
+ step = 0
+ retstatus = False
+ found_failed_assert = False
+
+ assert step_size == 1
+
+ while step < num_steps:
+ smt_state(step)
+ smt_assert_consequent("(|%s_u| s%d)" % (topmod, step))
+ smt_assert_antecedent("(|%s_h| s%d)" % (topmod, step))
+ smt_assert_consequent(get_constr_expr(constr_assumes, step))
+
+ if step == 0:
+ if noinit:
+ smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step))
+ else:
+ smt_assert_antecedent("(|%s_i| s0)" % (topmod))
+ smt_assert_antecedent("(|%s_is| s0)" % (topmod))
+
+ else:
+ smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step-1, step))
+ smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step))
+
+ while "1" in cover_mask:
+ print_msg("Checking cover reachability in step %d.." % (step))
+ smt_push()
+ smt_assert("(distinct (covers_%d s%d) #b%s)" % (coveridx, step, "0" * len(cover_desc)))
+
+ if smt_check_sat() == "unsat":
+ smt_pop()
+ break
+
+ if append_steps > 0:
+ for i in range(step+1, step+1+append_steps):
+ print_msg("Appending additional step %d." % i)
+ smt_state(i)
+ smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, i))
+ smt_assert_consequent("(|%s_u| s%d)" % (topmod, i))
+ smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
+ smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
+ smt_assert_consequent(get_constr_expr(constr_assumes, i))
+ print_msg("Re-solving with appended steps..")
+ assert smt_check_sat() == "sat"
+
+ reached_covers = smt.bv2bin(smt.get("(covers_%d s%d)" % (coveridx, step)))
+ assert len(reached_covers) == len(cover_desc)
+
+ new_cover_mask = []
+
+ for i in range(len(reached_covers)):
+ if reached_covers[i] == "0":
+ new_cover_mask.append(cover_mask[i])
+ continue
+
+ print_msg("Reached cover statement at %s in step %d." % (cover_desc[i], step))
+ new_cover_mask.append("0")
+
+ cover_mask = "".join(new_cover_mask)
+
+ for i in range(step+1+append_steps):
+ if print_failed_asserts(i, extrainfo=" (step %d)" % i):
+ found_failed_assert = True
+
+ write_trace(0, step+1+append_steps, "%d" % coveridx)
+
+ if found_failed_assert:
+ break
+
+ coveridx += 1
+ smt_pop()
+ smt.write("(define-fun covers_%d ((state |%s_s|)) (_ BitVec %d) (bvand (covers_%d state) #b%s))" % (coveridx, topmod, len(cover_desc), coveridx-1, cover_mask))
+
+ if found_failed_assert:
+ break
+
+ if "1" not in cover_mask:
+ retstatus = True
+ break
+
+ step += 1
+
+ if "1" in cover_mask:
+ for i in range(len(cover_mask)):
+ if cover_mask[i] == "1":
+ print_msg("Unreached cover statement at %s." % cover_desc[i])
+
+else: # not tempind, covermode
step = 0
retstatus = True
while step < num_steps:
- smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod))
- smt.write("(assert (|%s_u| s%d))" % (topmod, step))
- smt.write("(assert (|%s_h| s%d))" % (topmod, step))
- smt.write("(assert %s)" % get_constr_expr(constr_assumes, step))
+ smt_state(step)
+ smt_assert_consequent("(|%s_u| s%d)" % (topmod, step))
+ smt_assert_antecedent("(|%s_h| s%d)" % (topmod, step))
+ smt_assert_consequent(get_constr_expr(constr_assumes, step))
if step == 0:
- smt.write("(assert (|%s_i| s0))" % (topmod))
- smt.write("(assert (|%s_is| s0))" % (topmod))
+ if noinit:
+ smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step))
+ else:
+ smt_assert_antecedent("(|%s_i| s0)" % (topmod))
+ smt_assert_antecedent("(|%s_is| s0)" % (topmod))
else:
- smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step-1, step))
- smt.write("(assert (not (|%s_is| s%d)))" % (topmod, step))
+ smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step-1, step))
+ smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step))
if step < skip_steps:
if assume_skipped is not None and step >= assume_skipped:
print_msg("Skipping step %d (and assuming pass).." % (step))
- smt.write("(assert (|%s_a| s%d))" % (topmod, step))
- smt.write("(assert %s)" % get_constr_expr(constr_asserts, step))
+ smt_assert("(|%s_a| s%d)" % (topmod, step))
+ smt_assert(get_constr_expr(constr_asserts, step))
else:
print_msg("Skipping step %d.." % (step))
step += 1
@@ -648,39 +1336,61 @@ else: # not tempind
last_check_step = step
for i in range(1, step_size):
if step+i < num_steps:
- smt.write("(declare-fun s%d () |%s_s|)" % (step+i, topmod))
- smt.write("(assert (|%s_u| s%d))" % (topmod, step+i))
- smt.write("(assert (|%s_h| s%d))" % (topmod, step+i))
- smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step+i-1, step+i))
- smt.write("(assert %s)" % get_constr_expr(constr_assumes, step+i))
+ smt_state(step+i)
+ smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step+i))
+ smt_assert_consequent("(|%s_u| s%d)" % (topmod, step+i))
+ smt_assert_antecedent("(|%s_h| s%d)" % (topmod, step+i))
+ smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step+i-1, step+i))
+ smt_assert_consequent(get_constr_expr(constr_assumes, step+i))
last_check_step = step+i
if not gentrace:
+ if presat:
+ if last_check_step == step:
+ print_msg("Checking assumptions in step %d.." % (step))
+ else:
+ print_msg("Checking assumptions in steps %d to %d.." % (step, last_check_step))
+
+ if smt_check_sat() == "unsat":
+ print("%s Warmup failed!" % smt.timestamp())
+ retstatus = False
+ break
+
if not final_only:
if last_check_step == step:
- print_msg("Checking asserts in step %d.." % (step))
+ print_msg("Checking assertions in step %d.." % (step))
else:
- print_msg("Checking asserts in steps %d to %d.." % (step, last_check_step))
- smt.write("(push 1)")
+ print_msg("Checking assertions in steps %d to %d.." % (step, last_check_step))
+ smt_push()
- smt.write("(assert (not (and %s)))" % " ".join(["(|%s_a| s%d)" % (topmod, i) for i in range(step, last_check_step+1)] +
+ smt_assert("(not (and %s))" % " ".join(["(|%s_a| s%d)" % (topmod, i) for i in range(step, last_check_step+1)] +
[get_constr_expr(constr_asserts, i) for i in range(step, last_check_step+1)]))
- if smt.check_sat() == "sat":
+ if smt_check_sat() == "sat":
print("%s BMC failed!" % smt.timestamp())
+ if append_steps > 0:
+ for i in range(last_check_step+1, last_check_step+1+append_steps):
+ print_msg("Appending additional step %d." % i)
+ smt_state(i)
+ smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, i))
+ smt_assert_consequent("(|%s_u| s%d)" % (topmod, i))
+ smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
+ smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
+ smt_assert_consequent(get_constr_expr(constr_assumes, i))
+ assert smt_check_sat() == "sat"
print_anyconsts(step)
for i in range(step, last_check_step+1):
print_failed_asserts(i)
- write_trace(0, last_check_step+1, '%')
+ write_trace(0, last_check_step+1+append_steps, '%')
retstatus = False
break
- smt.write("(pop 1)")
+ smt_pop()
if (constr_final_start is not None) or (last_check_step+1 != num_steps):
for i in range(step, last_check_step+1):
- smt.write("(assert (|%s_a| s%d))" % (topmod, i))
- smt.write("(assert %s)" % get_constr_expr(constr_asserts, i))
+ smt_assert("(|%s_a| s%d)" % (topmod, i))
+ smt_assert(get_constr_expr(constr_asserts, i))
if constr_final_start is not None:
for i in range(step, last_check_step+1):
@@ -688,12 +1398,12 @@ else: # not tempind
continue
print_msg("Checking final constraints in step %d.." % (i))
- smt.write("(push 1)")
+ smt_push()
- smt.write("(assert %s)" % get_constr_expr(constr_assumes, i, final=True))
- smt.write("(assert (not %s))" % get_constr_expr(constr_asserts, i, final=True))
+ smt_assert_consequent(get_constr_expr(constr_assumes, i, final=True))
+ smt_assert("(not %s)" % get_constr_expr(constr_asserts, i, final=True))
- if smt.check_sat() == "sat":
+ if smt_check_sat() == "sat":
print("%s BMC failed!" % smt.timestamp())
print_anyconsts(i)
print_failed_asserts(i, final=True)
@@ -701,17 +1411,17 @@ else: # not tempind
retstatus = False
break
- smt.write("(pop 1)")
+ smt_pop()
if not retstatus:
break
else: # gentrace
for i in range(step, last_check_step+1):
- smt.write("(assert (|%s_a| s%d))" % (topmod, i))
- smt.write("(assert %s)" % get_constr_expr(constr_asserts, i))
+ smt_assert("(|%s_a| s%d)" % (topmod, i))
+ smt_assert(get_constr_expr(constr_asserts, i))
print_msg("Solving for step %d.." % (last_check_step))
- if smt.check_sat() != "sat":
+ if smt_check_sat() != "sat":
print("%s No solution found!" % smt.timestamp())
retstatus = False
break
@@ -722,7 +1432,7 @@ else: # not tempind
step += step_size
- if gentrace:
+ if gentrace and retstatus:
print_anyconsts(0)
write_trace(0, num_steps, '%')
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
index 865eed1f..3fc823e3 100644
--- a/backends/smt2/smtio.py
+++ b/backends/smt2/smtio.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python3
#
# yosys -- Yosys Open SYnthesis Suite
#
@@ -17,10 +16,55 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
-import sys, subprocess, re
+import sys, re, os, signal
+import subprocess
+if os.name == "posix":
+ import resource
from copy import deepcopy
from select import select
from time import time
+from queue import Queue, Empty
+from threading import Thread
+
+
+# This is needed so that the recursive SMT2 S-expression parser
+# does not run out of stack frames when parsing large expressions
+if os.name == "posix":
+ smtio_reclimit = 64 * 1024
+ smtio_stacksize = 128 * 1024 * 1024
+ if sys.getrecursionlimit() < smtio_reclimit:
+ sys.setrecursionlimit(smtio_reclimit)
+ if resource.getrlimit(resource.RLIMIT_STACK)[0] < smtio_stacksize:
+ resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, -1))
+
+
+# currently running solvers (so we can kill them)
+running_solvers = dict()
+forced_shutdown = False
+solvers_index = 0
+
+def force_shutdown(signum, frame):
+ global forced_shutdown
+ if not forced_shutdown:
+ forced_shutdown = True
+ if signum is not None:
+ print("<%s>" % signal.Signals(signum).name)
+ for p in running_solvers.values():
+ # os.killpg(os.getpgid(p.pid), signal.SIGTERM)
+ os.kill(p.pid, signal.SIGTERM)
+ sys.exit(1)
+
+if os.name == "posix":
+ signal.signal(signal.SIGHUP, force_shutdown)
+signal.signal(signal.SIGINT, force_shutdown)
+signal.signal(signal.SIGTERM, force_shutdown)
+
+def except_hook(exctype, value, traceback):
+ if not forced_shutdown:
+ sys.__excepthook__(exctype, value, traceback)
+ force_shutdown(None, None)
+
+sys.excepthook = except_hook
hex_dict = {
@@ -41,25 +85,38 @@ class SmtModInfo:
self.memories = dict()
self.wires = set()
self.wsize = dict()
+ self.clocks = dict()
self.cells = dict()
self.asserts = dict()
+ self.covers = dict()
self.anyconsts = dict()
+ self.anyseqs = dict()
+ self.allconsts = dict()
+ self.allseqs = dict()
+ self.asize = dict()
class SmtIo:
def __init__(self, opts=None):
+ global solvers_index
+
self.logic = None
self.logic_qf = True
self.logic_ax = True
self.logic_uf = True
self.logic_bv = True
+ self.logic_dt = False
+ self.forall = False
self.produce_models = True
self.smt2cache = [list()]
self.p = None
+ self.p_index = solvers_index
+ solvers_index += 1
if opts is not None:
self.logic = opts.logic
self.solver = opts.solver
+ self.solver_opts = opts.solver_opts
self.debug_print = opts.debug_print
self.debug_file = opts.debug_file
self.dummy_file = opts.dummy_file
@@ -70,34 +127,57 @@ class SmtIo:
self.nocomments = opts.nocomments
else:
- self.solver = "z3"
+ self.solver = "yices"
+ self.solver_opts = list()
self.debug_print = False
self.debug_file = None
self.dummy_file = None
- self.timeinfo = True
+ self.timeinfo = os.name != "nt"
self.unroll = False
self.noincr = False
self.info_stmts = list()
self.nocomments = False
+ self.start_time = time()
+
+ self.modinfo = dict()
+ self.curmod = None
+ self.topmod = None
+ self.setup_done = False
+
+ def __del__(self):
+ if self.p is not None and not forced_shutdown:
+ os.killpg(os.getpgid(self.p.pid), signal.SIGTERM)
+ if running_solvers is not None:
+ del running_solvers[self.p_index]
+
+ def setup(self):
+ assert not self.setup_done
+
+ if self.forall:
+ self.unroll = False
+
if self.solver == "yices":
- self.popen_vargs = ['yices-smt2', '--incremental']
+ self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts
if self.solver == "z3":
- self.popen_vargs = ['z3', '-smt2', '-in']
+ self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts
if self.solver == "cvc4":
- self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2']
+ self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
if self.solver == "mathsat":
- self.popen_vargs = ['mathsat']
+ self.popen_vargs = ['mathsat'] + self.solver_opts
if self.solver == "boolector":
- self.popen_vargs = ['boolector', '--smt2', '-i']
+ self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
self.unroll = True
if self.solver == "abc":
- self.popen_vargs = ['yosys-abc', '-S', '%blast; &sweep -C 5000; &syn4; &cec -s -m -C 2000']
+ if len(self.solver_opts) > 0:
+ self.popen_vargs = ['yosys-abc', '-S', '; '.join(self.solver_opts)]
+ else:
+ self.popen_vargs = ['yosys-abc', '-S', '%blast; &sweep -C 5000; &syn4; &cec -s -m -C 2000']
self.logic_ax = False
self.unroll = True
self.noincr = True
@@ -109,9 +189,10 @@ class SmtIo:
if self.dummy_file is not None:
self.dummy_fd = open(self.dummy_file, "w")
if not self.noincr:
- self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ self.p_open()
if self.unroll:
+ assert not self.forall
self.logic_uf = False
self.unroll_idcnt = 0
self.unroll_buffer = ""
@@ -121,36 +202,27 @@ class SmtIo:
self.unroll_cache = dict()
self.unroll_stack = list()
- self.start_time = time()
-
- self.modinfo = dict()
- self.curmod = None
- self.topmod = None
- self.setup_done = False
-
- def setup(self):
- assert not self.setup_done
-
if self.logic is None:
self.logic = ""
if self.logic_qf: self.logic += "QF_"
if self.logic_ax: self.logic += "A"
if self.logic_uf: self.logic += "UF"
if self.logic_bv: self.logic += "BV"
+ if self.logic_dt: self.logic = "ALL"
self.setup_done = True
+ for stmt in self.info_stmts:
+ self.write(stmt)
+
if self.produce_models:
self.write("(set-option :produce-models true)")
self.write("(set-logic %s)" % self.logic)
- for stmt in self.info_stmts:
- self.write(stmt)
-
def timestamp(self):
secs = int(time() - self.start_time)
- return "## %6d %3d:%02d:%02d " % (secs, secs // (60*60), (secs // 60) % 60, secs % 60)
+ return "## %3d:%02d:%02d " % (secs // (60*60), (secs // 60) % 60, secs % 60)
def replace_in_stmt(self, stmt, pat, repl):
if stmt == pat:
@@ -201,18 +273,75 @@ class SmtIo:
return stmt
+ def p_thread_main(self):
+ while True:
+ data = self.p.stdout.readline().decode("ascii")
+ if data == "": break
+ self.p_queue.put(data)
+ self.p_queue.put("")
+ self.p_running = False
+
+ def p_open(self):
+ assert self.p is None
+ self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ running_solvers[self.p_index] = self.p
+ self.p_running = True
+ self.p_next = None
+ self.p_queue = Queue()
+ self.p_thread = Thread(target=self.p_thread_main)
+ self.p_thread.start()
+
+ def p_write(self, data, flush):
+ assert self.p is not None
+ self.p.stdin.write(bytes(data, "ascii"))
+ if flush: self.p.stdin.flush()
+
+ def p_read(self):
+ assert self.p is not None
+ if self.p_next is not None:
+ data = self.p_next
+ self.p_next = None
+ return data
+ if not self.p_running:
+ return ""
+ return self.p_queue.get()
+
+ def p_poll(self, timeout=0.1):
+ assert self.p is not None
+ assert self.p_running
+ if self.p_next is not None:
+ return False
+ try:
+ self.p_next = self.p_queue.get(True, timeout)
+ return False
+ except Empty:
+ return True
+
+ def p_close(self):
+ assert self.p is not None
+ self.p.stdin.close()
+ self.p_thread.join()
+ assert not self.p_running
+ del running_solvers[self.p_index]
+ self.p = None
+ self.p_next = None
+ self.p_queue = None
+ self.p_thread = None
+
def write(self, stmt, unroll=True):
if stmt.startswith(";"):
self.info(stmt)
+ if not self.setup_done:
+ self.info_stmts.append(stmt)
+ return
elif not self.setup_done:
self.setup()
stmt = stmt.strip()
if self.nocomments or self.unroll:
- if stmt.startswith(";"):
- return
- stmt = re.sub(r" ;.*", "", stmt)
+ stmt = re.sub(r" *;.*", "", stmt)
+ if stmt == "": return
if unroll and self.unroll:
stmt = self.unroll_buffer + stmt
@@ -271,20 +400,17 @@ class SmtIo:
if self.solver != "dummy":
if self.noincr:
if self.p is not None and not stmt.startswith("(get-"):
- self.p.stdin.close()
- self.p = None
+ self.p_close()
if stmt == "(push 1)":
self.smt2cache.append(list())
elif stmt == "(pop 1)":
self.smt2cache.pop()
else:
if self.p is not None:
- self.p.stdin.write(bytes(stmt + "\n", "ascii"))
- self.p.stdin.flush()
+ self.p_write(stmt + "\n", True)
self.smt2cache[-1].append(stmt)
else:
- self.p.stdin.write(bytes(stmt + "\n", "ascii"))
- self.p.stdin.flush()
+ self.p_write(stmt + "\n", True)
def info(self, stmt):
if not stmt.startswith("; yosys-smt2-"):
@@ -300,6 +426,15 @@ class SmtIo:
if self.logic is None:
self.logic_bv = False
+ if fields[1] == "yosys-smt2-stdt":
+ if self.logic is None:
+ self.logic_dt = True
+
+ if fields[1] == "yosys-smt2-forall":
+ if self.logic is None:
+ self.logic_qf = False
+ self.forall = True
+
if fields[1] == "yosys-smt2-module":
self.curmod = fields[2]
self.modinfo[self.curmod] = SmtModInfo()
@@ -323,17 +458,40 @@ class SmtIo:
self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
if fields[1] == "yosys-smt2-memory":
- self.modinfo[self.curmod].memories[fields[2]] = (int(fields[3]), int(fields[4]), int(fields[5]))
+ self.modinfo[self.curmod].memories[fields[2]] = (int(fields[3]), int(fields[4]), int(fields[5]), int(fields[6]), fields[7] == "async")
if fields[1] == "yosys-smt2-wire":
self.modinfo[self.curmod].wires.add(fields[2])
self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
+ if fields[1] == "yosys-smt2-clock":
+ for edge in fields[3:]:
+ if fields[2] not in self.modinfo[self.curmod].clocks:
+ self.modinfo[self.curmod].clocks[fields[2]] = edge
+ elif self.modinfo[self.curmod].clocks[fields[2]] != edge:
+ self.modinfo[self.curmod].clocks[fields[2]] = "event"
+
if fields[1] == "yosys-smt2-assert":
- self.modinfo[self.curmod].asserts[fields[2]] = fields[3]
+ self.modinfo[self.curmod].asserts["%s_a %s" % (self.curmod, fields[2])] = fields[3]
+
+ if fields[1] == "yosys-smt2-cover":
+ self.modinfo[self.curmod].covers["%s_c %s" % (self.curmod, fields[2])] = fields[3]
if fields[1] == "yosys-smt2-anyconst":
- self.modinfo[self.curmod].anyconsts[fields[2]] = fields[3]
+ self.modinfo[self.curmod].anyconsts[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5])
+ self.modinfo[self.curmod].asize[fields[2]] = int(fields[3])
+
+ if fields[1] == "yosys-smt2-anyseq":
+ self.modinfo[self.curmod].anyseqs[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5])
+ self.modinfo[self.curmod].asize[fields[2]] = int(fields[3])
+
+ if fields[1] == "yosys-smt2-allconst":
+ self.modinfo[self.curmod].allconsts[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5])
+ self.modinfo[self.curmod].asize[fields[2]] = int(fields[3])
+
+ if fields[1] == "yosys-smt2-allseq":
+ self.modinfo[self.curmod].allseqs[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5])
+ self.modinfo[self.curmod].asize[fields[2]] = int(fields[3])
def hiernets(self, top, regs_only=False):
def hiernets_worker(nets, mod, cursor):
@@ -347,6 +505,54 @@ class SmtIo:
hiernets_worker(nets, top, [])
return nets
+ def hieranyconsts(self, top):
+ def worker(results, mod, cursor):
+ for name, value in sorted(self.modinfo[mod].anyconsts.items()):
+ width = self.modinfo[mod].asize[name]
+ results.append((cursor, name, value[0], value[1], width))
+ for cellname, celltype in sorted(self.modinfo[mod].cells.items()):
+ worker(results, celltype, cursor + [cellname])
+
+ results = list()
+ worker(results, top, [])
+ return results
+
+ def hieranyseqs(self, top):
+ def worker(results, mod, cursor):
+ for name, value in sorted(self.modinfo[mod].anyseqs.items()):
+ width = self.modinfo[mod].asize[name]
+ results.append((cursor, name, value[0], value[1], width))
+ for cellname, celltype in sorted(self.modinfo[mod].cells.items()):
+ worker(results, celltype, cursor + [cellname])
+
+ results = list()
+ worker(results, top, [])
+ return results
+
+ def hierallconsts(self, top):
+ def worker(results, mod, cursor):
+ for name, value in sorted(self.modinfo[mod].allconsts.items()):
+ width = self.modinfo[mod].asize[name]
+ results.append((cursor, name, value[0], value[1], width))
+ for cellname, celltype in sorted(self.modinfo[mod].cells.items()):
+ worker(results, celltype, cursor + [cellname])
+
+ results = list()
+ worker(results, top, [])
+ return results
+
+ def hierallseqs(self, top):
+ def worker(results, mod, cursor):
+ for name, value in sorted(self.modinfo[mod].allseqs.items()):
+ width = self.modinfo[mod].asize[name]
+ results.append((cursor, name, value[0], value[1], width))
+ for cellname, celltype in sorted(self.modinfo[mod].cells.items()):
+ worker(results, celltype, cursor + [cellname])
+
+ results = list()
+ worker(results, top, [])
+ return results
+
def hiermems(self, top):
def hiermems_worker(mems, mod, cursor):
for memname in sorted(self.modinfo[mod].memories.keys()):
@@ -366,7 +572,7 @@ class SmtIo:
if self.solver == "dummy":
line = self.dummy_fd.readline().strip()
else:
- line = self.p.stdout.readline().decode("ascii").strip()
+ line = self.p_read().strip()
if self.dummy_file is not None:
self.dummy_fd.write(line + "\n")
@@ -379,12 +585,14 @@ class SmtIo:
if count_brackets == 0:
break
if self.solver != "dummy" and self.p.poll():
- print("SMT Solver terminated unexpectedly: %s" % "".join(stmt))
+ print("%s Solver terminated unexpectedly: %s" % (self.timestamp(), "".join(stmt)), flush=True)
sys.exit(1)
stmt = "".join(stmt)
if stmt.startswith("(error"):
- print("SMT Solver Error: %s" % stmt, file=sys.stderr)
+ print("%s Solver Error: %s" % (self.timestamp(), stmt), flush=True)
+ if self.solver != "dummy":
+ self.p_close()
sys.exit(1)
return stmt
@@ -399,15 +607,13 @@ class SmtIo:
if self.solver != "dummy":
if self.noincr:
if self.p is not None:
- self.p.stdin.close()
- self.p = None
- self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ self.p_close()
+ self.p_open()
for cache_ctx in self.smt2cache:
for cache_stmt in cache_ctx:
- self.p.stdin.write(bytes(cache_stmt + "\n", "ascii"))
+ self.p_write(cache_stmt + "\n", False)
- self.p.stdin.write(bytes("(check-sat)\n", "ascii"))
- self.p.stdin.flush()
+ self.p_write("(check-sat)\n", True)
if self.timeinfo:
i = 0
@@ -415,7 +621,7 @@ class SmtIo:
count = 0
num_bs = 0
- while select([self.p.stdout], [], [], 0.1) == ([], [], []):
+ while self.p_poll():
count += 1
if count < 25:
@@ -444,11 +650,43 @@ class SmtIo:
print("\b \b" * num_bs, end="", file=sys.stderr)
sys.stderr.flush()
+ else:
+ count = 0
+ while self.p_poll(60):
+ count += 1
+ msg = None
+
+ if count == 1:
+ msg = "1 minute"
+
+ elif count in [5, 10, 15, 30]:
+ msg = "%d minutes" % count
+
+ elif count == 60:
+ msg = "1 hour"
+
+ elif count % 60 == 0:
+ msg = "%d hours" % (count // 60)
+
+ if msg is not None:
+ print("%s waiting for solver (%s)" % (self.timestamp(), msg), flush=True)
+
result = self.read()
+
if self.debug_file:
print("(set-info :status %s)" % result, file=self.debug_file)
print("(check-sat)", file=self.debug_file)
self.debug_file.flush()
+
+ if result not in ["sat", "unsat"]:
+ if result == "":
+ print("%s Unexpected EOF response from solver." % (self.timestamp()), flush=True)
+ else:
+ print("%s Unexpected response from solver: %s" % (self.timestamp(), result), flush=True)
+ if self.solver != "dummy":
+ self.p_close()
+ sys.exit(1)
+
return result
def parse(self, stmt):
@@ -503,6 +741,9 @@ class SmtIo:
return h
def bv2bin(self, v):
+ if type(v) is list and len(v) == 3 and v[0] == "_" and v[1].startswith("bv"):
+ x, n = int(v[1][2:]), int(v[2])
+ return "".join("1" if (x & (1 << i)) else "0" for i in range(n-1, -1, -1))
if v == "true": return "1"
if v == "false": return "0"
if v.startswith("#b"):
@@ -539,6 +780,9 @@ class SmtIo:
return [".".join(path)]
def net_expr(self, mod, base, path):
+ if len(path) == 0:
+ return base
+
if len(path) == 1:
assert mod in self.modinfo
if path[0] == "":
@@ -568,23 +812,54 @@ class SmtIo:
assert net_path[-1] in self.modinfo[mod].wsize
return self.modinfo[mod].wsize[net_path[-1]]
- def mem_expr(self, mod, base, path, portidx=None, infomode=False):
+ def net_clock(self, mod, net_path):
+ for i in range(len(net_path)-1):
+ assert mod in self.modinfo
+ assert net_path[i] in self.modinfo[mod].cells
+ mod = self.modinfo[mod].cells[net_path[i]]
+
+ assert mod in self.modinfo
+ if net_path[-1] not in self.modinfo[mod].clocks:
+ return None
+ return self.modinfo[mod].clocks[net_path[-1]]
+
+ def net_exists(self, mod, net_path):
+ for i in range(len(net_path)-1):
+ if mod not in self.modinfo: return False
+ if net_path[i] not in self.modinfo[mod].cells: return False
+ mod = self.modinfo[mod].cells[net_path[i]]
+
+ if mod not in self.modinfo: return False
+ if net_path[-1] not in self.modinfo[mod].wsize: return False
+ return True
+
+ def mem_exists(self, mod, mem_path):
+ for i in range(len(mem_path)-1):
+ if mod not in self.modinfo: return False
+ if mem_path[i] not in self.modinfo[mod].cells: return False
+ mod = self.modinfo[mod].cells[mem_path[i]]
+
+ if mod not in self.modinfo: return False
+ if mem_path[-1] not in self.modinfo[mod].memories: return False
+ return True
+
+ def mem_expr(self, mod, base, path, port=None, infomode=False):
if len(path) == 1:
assert mod in self.modinfo
assert path[0] in self.modinfo[mod].memories
if infomode:
return self.modinfo[mod].memories[path[0]]
- return "(|%s_m%s %s| %s)" % (mod, "" if portidx is None else ":%d" % portidx, path[0], base)
+ return "(|%s_m%s %s| %s)" % (mod, "" if port is None else ":%s" % port, path[0], base)
assert mod in self.modinfo
assert path[0] in self.modinfo[mod].cells
nextmod = self.modinfo[mod].cells[path[0]]
nextbase = "(|%s_h %s| %s)" % (mod, path[0], base)
- return self.mem_expr(nextmod, nextbase, path[1:], portidx=portidx, infomode=infomode)
+ return self.mem_expr(nextmod, nextbase, path[1:], port=port, infomode=infomode)
- def mem_info(self, mod, base, path):
- return self.mem_expr(mod, base, path, infomode=True)
+ def mem_info(self, mod, path):
+ return self.mem_expr(mod, "", path, infomode=True)
def get_net(self, mod_name, net_path, state_name):
return self.get(self.net_expr(mod_name, state_name, net_path))
@@ -607,19 +882,21 @@ class SmtIo:
def wait(self):
if self.p is not None:
self.p.wait()
+ self.p_close()
class SmtOpts:
def __init__(self):
- self.shortopts = "s:v"
+ self.shortopts = "s:S:v"
self.longopts = ["unroll", "noincr", "noprogress", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments"]
- self.solver = "z3"
+ self.solver = "yices"
+ self.solver_opts = list()
self.debug_print = False
self.debug_file = None
self.dummy_file = None
self.unroll = False
self.noincr = False
- self.timeinfo = True
+ self.timeinfo = os.name != "nt"
self.logic = None
self.info_stmts = list()
self.nocomments = False
@@ -627,6 +904,8 @@ class SmtOpts:
def handle(self, o, a):
if o == "-s":
self.solver = a
+ elif o == "-S":
+ self.solver_opts.append(a)
elif o == "-v":
self.debug_print = True
elif o == "--unroll":
@@ -634,7 +913,7 @@ class SmtOpts:
elif o == "--noincr":
self.noincr = True
elif o == "--noprogress":
- self.timeinfo = True
+ self.timeinfo = False
elif o == "--dump-smt2":
self.debug_file = open(a, "w")
elif o == "--logic":
@@ -652,8 +931,11 @@ class SmtOpts:
def helpmsg(self):
return """
-s <solver>
- set SMT solver: z3, cvc4, yices, mathsat, boolector, dummy
- default: z3
+ set SMT solver: z3, yices, boolector, cvc4, mathsat, dummy
+ default: yices
+
+ -S <opt>
+ pass <opt> as command line argument to the solver
--logic <smt2_logic>
use the specified SMT2 logic (e.g. QF_AUFBV)
@@ -674,6 +956,7 @@ class SmtOpts:
--noprogress
disable timer display during solving
+ (this option is set implicitly on Windows)
--dump-smt2 <filename>
write smt2 statements to file
@@ -691,6 +974,7 @@ class MkVcd:
self.f = f
self.t = -1
self.nets = dict()
+ self.clocks = dict()
def add_net(self, path, width):
path = tuple(path)
@@ -698,11 +982,25 @@ class MkVcd:
key = "n%d" % len(self.nets)
self.nets[path] = (key, width)
+ def add_clock(self, path, edge):
+ path = tuple(path)
+ assert self.t == -1
+ key = "n%d" % len(self.nets)
+ self.nets[path] = (key, 1)
+ self.clocks[path] = (key, edge)
+
def set_net(self, path, bits):
path = tuple(path)
assert self.t >= 0
assert path in self.nets
- print("b%s %s" % (bits, self.nets[path][0]), file=self.f)
+ if path not in self.clocks:
+ print("b%s %s" % (bits, self.nets[path][0]), file=self.f)
+
+ def escape_name(self, name):
+ name = re.sub(r"\[([0-9a-zA-Z_]*[a-zA-Z_][0-9a-zA-Z_]*)\]", r"<\1>", name)
+ if re.match("[\[\]]", name) and name[0] != "\\":
+ name = "\\" + name
+ return name
def set_time(self, t):
assert t >= self.t
@@ -710,22 +1008,52 @@ class MkVcd:
if self.t == -1:
print("$var integer 32 t smt_step $end", file=self.f)
print("$var event 1 ! smt_clock $end", file=self.f)
+
scope = []
for path in sorted(self.nets):
- while len(scope)+1 > len(path) or (len(scope) > 0 and scope[-1] != path[len(scope)-1]):
+ key, width = self.nets[path]
+
+ uipath = list(path)
+ if "." in uipath[-1]:
+ uipath = uipath[0:-1] + uipath[-1].split(".")
+ for i in range(len(uipath)):
+ uipath[i] = re.sub(r"\[([^\]]*)\]", r"<\1>", uipath[i])
+
+ while uipath[:len(scope)] != scope:
print("$upscope $end", file=self.f)
scope = scope[:-1]
- while len(scope)+1 < len(path):
- print("$scope module %s $end" % path[len(scope)], file=self.f)
- scope.append(path[len(scope)-1])
- key, width = self.nets[path]
- print("$var wire %d %s %s $end" % (width, key, path[-1]), file=self.f)
+
+ while uipath[:-1] != scope:
+ print("$scope module %s $end" % uipath[len(scope)], file=self.f)
+ scope.append(uipath[len(scope)])
+
+ if path in self.clocks and self.clocks[path][1] == "event":
+ print("$var event 1 %s %s $end" % (key, uipath[-1]), file=self.f)
+ else:
+ print("$var wire %d %s %s $end" % (width, key, uipath[-1]), file=self.f)
+
for i in range(len(scope)):
print("$upscope $end", file=self.f)
+
print("$enddefinitions $end", file=self.f)
+
self.t = t
assert self.t >= 0
+
+ if self.t > 0:
+ print("#%d" % (10 * self.t - 5), file=self.f)
+ for path in sorted(self.clocks.keys()):
+ if self.clocks[path][1] == "posedge":
+ print("b0 %s" % self.nets[path][0], file=self.f)
+ elif self.clocks[path][1] == "negedge":
+ print("b1 %s" % self.nets[path][0], file=self.f)
+
print("#%d" % (10 * self.t), file=self.f)
print("1!", file=self.f)
print("b%s t" % format(self.t, "032b"), file=self.f)
+ for path in sorted(self.clocks.keys()):
+ if self.clocks[path][1] == "negedge":
+ print("b0 %s" % self.nets[path][0], file=self.f)
+ else:
+ print("b1 %s" % self.nets[path][0], file=self.f)
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index 162ce490..b8383412 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -507,15 +507,19 @@ struct SmvWorker
continue;
}
- if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
{
string op;
- if (cell->type.in("$_AND_", "$_NAND_")) op = "&";
- if (cell->type.in("$_OR_", "$_NOR_")) op = "|";
+ if (cell->type.in("$_AND_", "$_NAND_", "$_ANDNOT_")) op = "&";
+ if (cell->type.in("$_OR_", "$_NOR_", "$_ORNOT_")) op = "|";
if (cell->type.in("$_XOR_")) op = "xor";
if (cell->type.in("$_XNOR_")) op = "xnor";
+ if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
+ assignments.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")),
+ rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
+ else
if (cell->type.in("$_NAND_", "$_NOR_"))
assignments.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
@@ -671,7 +675,7 @@ struct SmvWorker
struct SmvBackend : public Backend {
SmvBackend() : Backend("smv", "write design to SMV file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -689,7 +693,7 @@ struct SmvBackend : public Backend {
log("THIS COMMAND IS UNDER CONSTRUCTION\n");
log("\n");
}
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::ifstream template_f;
bool verbose = false;
diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc
index 4101cbf9..b6a3f1e7 100644
--- a/backends/spice/spice.cc
+++ b/backends/spice/spice.cc
@@ -132,7 +132,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
struct SpiceBackend : public Backend {
SpiceBackend() : Backend("spice", "write design to SPICE netlist file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -161,7 +161,7 @@ struct SpiceBackend : public Backend {
log(" set the specified module as design top module\n");
log("\n");
}
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string top_module_name;
RTLIL::Module *top_module = NULL;
diff --git a/backends/table/Makefile.inc b/backends/table/Makefile.inc
new file mode 100644
index 00000000..8cd1dc61
--- /dev/null
+++ b/backends/table/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += backends/table/table.o
+
diff --git a/backends/table/table.cc b/backends/table/table.cc
new file mode 100644
index 00000000..979273dd
--- /dev/null
+++ b/backends/table/table.cc
@@ -0,0 +1,120 @@
+/*
+ * 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 TableBackend : public Backend {
+ TableBackend() : Backend("table", "write design as connectivity table") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_table [options] [filename]\n");
+ log("\n");
+ log("Write the current design as connectivity table. The output is a tab-separated\n");
+ log("ASCII table with the following columns:\n");
+ log("\n");
+ log(" module name\n");
+ log(" cell name\n");
+ log(" cell type\n");
+ log(" cell port\n");
+ log(" direction\n");
+ log(" signal\n");
+ log("\n");
+ log("module inputs and outputs are output using cell type and port '-' and with\n");
+ log("'pi' (primary input) or 'po' (primary output) or 'pio' as direction.\n");
+ }
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing TABLE backend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ // top_module_name = args[++argidx];
+ // continue;
+ // }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ design->sort();
+
+ for (auto module : design->modules())
+ {
+ if (module->get_bool_attribute("\\blackbox"))
+ continue;
+
+ SigMap sigmap(module);
+
+ for (auto wire : module->wires())
+ {
+ if (wire->port_id == 0)
+ continue;
+
+ *f << log_id(module) << "\t";
+ *f << log_id(wire) << "\t";
+ *f << "-" << "\t";
+ *f << "-" << "\t";
+
+ if (wire->port_input && wire->port_output)
+ *f << "pio" << "\t";
+ else if (wire->port_input)
+ *f << "pi" << "\t";
+ else if (wire->port_output)
+ *f << "po" << "\t";
+ else
+ log_abort();
+
+ *f << log_signal(sigmap(wire)) << "\n";
+ }
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections())
+ {
+ *f << log_id(module) << "\t";
+ *f << log_id(cell) << "\t";
+ *f << log_id(cell->type) << "\t";
+ *f << log_id(conn.first) << "\t";
+
+ if (cell->input(conn.first) && cell->output(conn.first))
+ *f << "inout" << "\t";
+ else if (cell->input(conn.first))
+ *f << "in" << "\t";
+ else if (cell->output(conn.first))
+ *f << "out" << "\t";
+ else
+ *f << "unkown" << "\t";
+
+ *f << log_signal(sigmap(conn.second)) << "\n";
+ }
+ }
+ }
+} TableBackend;
+
+PRIVATE_NAMESPACE_END
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index a617215f..44e4e5f9 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -33,13 +33,15 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-bool verbose, norename, noattr, attr2comment, noexpr, nodec, nostr, defparam;
+bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal;
int auto_name_counter, auto_name_offset, auto_name_digits;
std::map<RTLIL::IdString, int> auto_name_map;
std::set<RTLIL::IdString> reg_wires, reg_ct;
std::string auto_prefix;
RTLIL::Module *active_module;
+dict<RTLIL::SigBit, RTLIL::State> active_initdata;
+SigMap active_sigmap;
void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
{
@@ -159,23 +161,73 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
if (width < 0)
width = data.bits.size() - offset;
if (nostr)
- goto dump_bits;
+ goto dump_hex;
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
if (width == 32 && !no_decimal && !nodec) {
int32_t val = 0;
for (int i = offset+width-1; i >= offset; i--) {
log_assert(i < (int)data.bits.size());
if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
- goto dump_bits;
+ goto dump_hex;
if (data.bits[i] == RTLIL::S1)
val |= 1 << (i - offset);
}
- if (set_signed && val < 0)
+ if (decimal)
+ f << stringf("%d", val);
+ else if (set_signed && val < 0)
f << stringf("-32'sd%u", -val);
else
f << stringf("32'%sd%u", set_signed ? "s" : "", val);
} else {
- dump_bits:
+ dump_hex:
+ if (nohex)
+ goto dump_bin;
+ vector<char> bin_digits, hex_digits;
+ for (int i = offset; i < offset+width; i++) {
+ log_assert(i < (int)data.bits.size());
+ switch (data.bits[i]) {
+ case RTLIL::S0: bin_digits.push_back('0'); break;
+ case RTLIL::S1: bin_digits.push_back('1'); break;
+ case RTLIL::Sx: bin_digits.push_back('x'); break;
+ case RTLIL::Sz: bin_digits.push_back('z'); break;
+ case RTLIL::Sa: bin_digits.push_back('z'); break;
+ case RTLIL::Sm: log_error("Found marker state in final netlist.");
+ }
+ }
+ if (GetSize(bin_digits) == 0)
+ goto dump_bin;
+ while (GetSize(bin_digits) % 4 != 0)
+ if (bin_digits.back() == '1')
+ bin_digits.push_back('0');
+ else
+ bin_digits.push_back(bin_digits.back());
+ for (int i = 0; i < GetSize(bin_digits); i += 4)
+ {
+ char bit_3 = bin_digits[i+3];
+ char bit_2 = bin_digits[i+2];
+ char bit_1 = bin_digits[i+1];
+ char bit_0 = bin_digits[i+0];
+ if (bit_3 == 'x' || bit_2 == 'x' || bit_1 == 'x' || bit_0 == 'x') {
+ if (bit_3 != 'x' || bit_2 != 'x' || bit_1 != 'x' || bit_0 != 'x')
+ goto dump_bin;
+ hex_digits.push_back('x');
+ continue;
+ }
+ if (bit_3 == 'z' || bit_2 == 'z' || bit_1 == 'z' || bit_0 == 'z') {
+ if (bit_3 != 'z' || bit_2 != 'z' || bit_1 != 'z' || bit_0 != 'z')
+ goto dump_bin;
+ hex_digits.push_back('z');
+ continue;
+ }
+ int val = 8*(bit_3 - '0') + 4*(bit_2 - '0') + 2*(bit_1 - '0') + (bit_0 - '0');
+ hex_digits.push_back(val < 10 ? '0' + val : 'a' + val - 10);
+ }
+ f << stringf("%d'%sh", width, set_signed ? "s" : "");
+ for (int i = GetSize(hex_digits)-1; i >= 0; i--)
+ f << hex_digits[i];
+ }
+ if (0) {
+ dump_bin:
f << stringf("%d'%sb", width, set_signed ? "s" : "");
if (width == 0)
f << stringf("0");
@@ -214,6 +266,26 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
}
}
+void dump_reg_init(std::ostream &f, SigSpec sig)
+{
+ Const initval;
+ bool gotinit = false;
+
+ for (auto bit : active_sigmap(sig)) {
+ if (active_initdata.count(bit)) {
+ initval.bits.push_back(active_initdata.at(bit));
+ gotinit = true;
+ } else {
+ initval.bits.push_back(State::Sx);
+ }
+ }
+
+ if (gotinit) {
+ f << " = ";
+ dump_const(f, initval);
+ }
+}
+
void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
{
if (chunk.wire == NULL) {
@@ -302,12 +374,12 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
if (wire->port_input && wire->port_output)
f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
if (reg_wires.count(wire->name)) {
- f << stringf("%s" "reg%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
+ f << stringf("%s" "reg%s %s", indent.c_str(), range.c_str(), id(wire->name).c_str());
if (wire->attributes.count("\\init")) {
- f << stringf("%s" "initial %s = ", indent.c_str(), id(wire->name).c_str());
+ f << stringf(" = ");
dump_const(f, wire->attributes.at("\\init"));
- f << stringf(";\n");
}
+ f << stringf(";\n");
} else if (!wire->port_input && !wire->port_output)
f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
#endif
@@ -400,7 +472,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
- if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) {
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort("\\Y"));
f << stringf(" = ");
@@ -408,16 +480,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
f << stringf("~(");
dump_cell_expr_port(f, cell, "A", false);
f << stringf(" ");
- if (cell->type.in("$_AND_", "$_NAND_"))
+ if (cell->type.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
f << stringf("&");
- if (cell->type.in("$_OR_", "$_NOR_"))
+ if (cell->type.in("$_OR_", "$_NOR_", "$_ORNOT_"))
f << stringf("|");
if (cell->type.in("$_XOR_", "$_XNOR_"))
f << stringf("^");
dump_attributes(f, "", cell->attributes, ' ');
f << stringf(" ");
+ if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
+ f << stringf("~(");
dump_cell_expr_port(f, cell, "B", false);
- if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
+ if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
f << stringf(")");
f << stringf(";\n");
return true;
@@ -474,8 +548,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
- if (!out_is_reg_wire)
- f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
+ dump_reg_init(f, cell->getPort("\\Q"));
+ f << ";\n";
+ }
dump_attributes(f, indent, cell->attributes);
f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
@@ -514,8 +591,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
- if (!out_is_reg_wire)
- f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
+ dump_reg_init(f, cell->getPort("\\Q"));
+ f << ";\n";
+ }
dump_attributes(f, indent, cell->attributes);
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
@@ -598,6 +678,23 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
#undef HANDLE_UNIOP
#undef HANDLE_BINOP
+ if (cell->type == "$shiftx")
+ {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Y"));
+ f << stringf(" = ");
+ dump_sigspec(f, cell->getPort("\\A"));
+ f << stringf("[");
+ if (cell->getParam("\\B_SIGNED").as_bool())
+ f << stringf("$signed(");
+ dump_sigspec(f, cell->getPort("\\B"));
+ if (cell->getParam("\\B_SIGNED").as_bool())
+ f << stringf(")");
+ f << stringf(" +: %d", cell->getParam("\\Y_WIDTH").as_int());
+ f << stringf("];\n");
+ return true;
+ }
+
if (cell->type == "$mux")
{
f << stringf("%s" "assign ", indent.c_str());
@@ -698,8 +795,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
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());
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg [%d:0] %s", indent.c_str(), width-1, reg_name.c_str());
+ dump_reg_init(f, sig_q);
+ f << ";\n";
+ }
for (int i = 0; i < width; i++) {
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
@@ -754,8 +854,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
- if (!out_is_reg_wire)
- f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
+ dump_reg_init(f, cell->getPort("\\Q"));
+ f << ";\n";
+ }
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
dump_sigspec(f, sig_clk);
@@ -794,6 +897,42 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
+ if (cell->type == "$dlatch")
+ {
+ RTLIL::SigSpec sig_en;
+ bool pol_en = false;
+
+ 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);
+
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
+ dump_reg_init(f, cell->getPort("\\Q"));
+ f << ";\n";
+ }
+
+ f << stringf("%s" "always @*\n", indent.c_str());
+
+ 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");
+
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Q"));
+ f << stringf(" = %s;\n", reg_name.c_str());
+ }
+
+ return true;
+ }
+
if (cell->type == "$mem")
{
RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
@@ -806,7 +945,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
// for memory block make something like:
// reg [7:0] memid [3:0];
// initial begin
- // memid[0] <= ...
+ // memid[0] = ...
// end
f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size-1, 0);
if (use_init)
@@ -814,7 +953,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
f << stringf("%s" "initial begin\n", indent.c_str());
for (int i=0; i<size; i++)
{
- f << stringf("%s" " %s[%d] <= ", indent.c_str(), mem_id.c_str(), i);
+ f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i);
dump_const(f, cell->parameters["\\INIT"].extract(i*width, width));
f << stringf(";\n");
}
@@ -912,7 +1051,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en;
bool wr_clk_posedge;
- SigMap sigmap(active_module);
+
// write ports
for (int i=0; i < nwrite_ports; i++)
{
@@ -937,7 +1076,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
int start_i = i, width = 1;
SigBit wen_bit = sig_wr_en[i];
- while (i+1 < GetSize(sig_wr_en) && sigmap(sig_wr_en[i+1]) == sigmap(wen_bit))
+ while (i+1 < GetSize(sig_wr_en) && active_sigmap(sig_wr_en[i+1]) == active_sigmap(wen_bit))
i++, width++;
if (wen_bit == State::S0)
@@ -1251,6 +1390,16 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
reg_wires.clear();
reset_auto_counter(module);
active_module = module;
+ active_sigmap.set(module);
+ active_initdata.clear();
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init")) {
+ SigSpec sig = active_sigmap(wire);
+ Const val = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
+ active_initdata[sig[i]] = val.bits.at(i);
+ }
if (!module->processes.empty())
log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
@@ -1327,11 +1476,13 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
f << stringf("%s" "endmodule\n", indent.c_str());
active_module = NULL;
+ active_sigmap.clear();
+ active_initdata.clear();
}
struct VerilogBackend : public Backend {
VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1362,6 +1513,14 @@ struct VerilogBackend : public Backend {
log(" not bit pattern. This option decativates this feature and instead\n");
log(" will write out all constants in binary.\n");
log("\n");
+ log(" -decimal\n");
+ log(" dump 32-bit constants in decimal and without size and radix\n");
+ log("\n");
+ log(" -nohex\n");
+ log(" constant values that are compatible with hex output are usually\n");
+ log(" dumped as hex values. This option decativates this feature and\n");
+ log(" instead will write out all constants in binary.\n");
+ log("\n");
log(" -nostr\n");
log(" Parameters and attributes that are specified as strings in the\n");
log(" original input will be output as strings by this back-end. This\n");
@@ -1391,7 +1550,7 @@ struct VerilogBackend : public Backend {
log("this command is called on a design with RTLIL processes.\n");
log("\n");
}
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing Verilog backend.\n");
@@ -1401,8 +1560,10 @@ struct VerilogBackend : public Backend {
attr2comment = false;
noexpr = false;
nodec = false;
+ nohex = false;
nostr = false;
defparam = false;
+ decimal = false;
auto_prefix = "";
bool blackboxes = false;
@@ -1412,6 +1573,8 @@ struct VerilogBackend : public Backend {
reg_ct.insert("$dff");
reg_ct.insert("$adff");
+ reg_ct.insert("$dffe");
+ reg_ct.insert("$dlatch");
reg_ct.insert("$_DFF_N_");
reg_ct.insert("$_DFF_P_");
@@ -1461,6 +1624,10 @@ struct VerilogBackend : public Backend {
nodec = true;
continue;
}
+ if (arg == "-nohex") {
+ nohex = true;
+ continue;
+ }
if (arg == "-nostr") {
nostr = true;
continue;
@@ -1469,6 +1636,10 @@ struct VerilogBackend : public Backend {
defparam = true;
continue;
}
+ if (arg == "-decimal") {
+ decimal = true;
+ continue;
+ }
if (arg == "-blackboxes") {
blackboxes = true;
continue;
diff --git a/examples/aiger/.gitignore b/examples/aiger/.gitignore
new file mode 100644
index 00000000..3524e936
--- /dev/null
+++ b/examples/aiger/.gitignore
@@ -0,0 +1,5 @@
+demo.aig
+demo.aim
+demo.aiw
+demo.smt2
+demo.vcd
diff --git a/examples/aiger/README b/examples/aiger/README
new file mode 100644
index 00000000..4e7694e9
--- /dev/null
+++ b/examples/aiger/README
@@ -0,0 +1,22 @@
+AIGER is a format for And-Inverter Graphs (AIGs).
+See http://fmv.jku.at/aiger/ for details.
+
+AIGER is used in the Hardware Model Checking Competition (HWMCC),
+therefore all solvers competing in the competition have to support
+the format.
+
+The example in this directory is using super_prove as solver. Check
+http://downloads.bvsrc.org/super_prove/ for the lates release. (See
+https://bitbucket.org/sterin/super_prove_build for sources.)
+
+The "demo.sh" script in this directory expects a "super_prove" executable
+in the PATH. E.g. extract the release to /usr/local/libexec/super_prove
+and then create a /usr/local/bin/super_prove file with the following
+contents (and "chmod +x" that file):
+
+ #!/bin/bash
+ exec /usr/local/libexec/super_prove/bin/super_prove.sh "$@"
+
+The "demo.sh" script also expects the "z3" SMT2 solver in the PATH for
+converting the witness file generated by super_prove to VCD using
+yosys-smtbmc. See https://github.com/Z3Prover/z3 for install notes.
diff --git a/examples/aiger/demo.sh b/examples/aiger/demo.sh
new file mode 100644
index 00000000..8728b672
--- /dev/null
+++ b/examples/aiger/demo.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+set -ex
+yosys -p '
+ read_verilog -formal demo.v
+ prep -flatten -nordff -top demo
+ write_smt2 -wires demo.smt2
+ flatten demo; delete -output
+ memory_map; opt -full
+ techmap; opt -fast
+ abc -fast -g AND; opt_clean
+ write_aiger -map demo.aim demo.aig
+'
+super_prove demo.aig > demo.aiw
+yosys-smtbmc --dump-vcd demo.vcd --aig demo demo.smt2
diff --git a/examples/aiger/demo.v b/examples/aiger/demo.v
new file mode 100644
index 00000000..b9828742
--- /dev/null
+++ b/examples/aiger/demo.v
@@ -0,0 +1,12 @@
+module demo(input clk, reset, ctrl);
+ localparam NBITS = 10;
+ reg [NBITS-1:0] counter;
+ initial counter[NBITS-2] = 0;
+ initial counter[0] = 1;
+ always @(posedge clk) begin
+ counter <= reset ? 1 : ctrl ? counter + 1 : counter - 1;
+ assume(counter != 0);
+ assume(counter != 1 << (NBITS-1));
+ assert(counter != (1 << NBITS)-1);
+ end
+endmodule
diff --git a/examples/basys3/example.xdc b/examples/basys3/example.xdc
index c1fd0e92..8cdaa199 100644
--- a/examples/basys3/example.xdc
+++ b/examples/basys3/example.xdc
@@ -19,3 +19,6 @@ 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]
+set_property CONFIG_VOLTAGE 3.3 [current_design]
+set_property CFGBVS VCCO [current_design]
+
diff --git a/examples/basys3/run_prog.tcl b/examples/basys3/run_prog.tcl
index d711af84..b078ad51 100644
--- a/examples/basys3/run_prog.tcl
+++ b/examples/basys3/run_prog.tcl
@@ -1,3 +1,4 @@
+open_hw
connect_hw_server
open_hw_target [lindex [get_hw_targets] 0]
set_property PROGRAM.FILE example.bit [lindex [get_hw_devices] 0]
diff --git a/examples/cmos/counter.ys b/examples/cmos/counter.ys
index a784f346..d0b09366 100644
--- a/examples/cmos/counter.ys
+++ b/examples/cmos/counter.ys
@@ -1,11 +1,12 @@
-
read_verilog counter.v
read_verilog -lib cmos_cells.v
-proc;; memory;; techmap;;
-
+synth
dfflibmap -liberty cmos_cells.lib
-abc -liberty cmos_cells.lib;;
+abc -liberty cmos_cells.lib
+opt_clean
+
+stat -liberty cmos_cells.lib
# http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib
# dfflibmap -liberty osu025_stdcells.lib
@@ -13,4 +14,3 @@ abc -liberty cmos_cells.lib;;
write_verilog synth.v
write_spice synth.sp
-
diff --git a/examples/cmos/counter_tb.v b/examples/cmos/counter_tb.v
index bcd7d992..11e82507 100644
--- a/examples/cmos/counter_tb.v
+++ b/examples/cmos/counter_tb.v
@@ -12,7 +12,7 @@ module counter_tb;
# 4 reset = 0;
# 6 $finish;
end
-
+
/* Make enable with period of 8 and 6,7 low */
reg en = 1;
always begin
@@ -25,7 +25,7 @@ module counter_tb;
/* Make a regular pulsing clock. */
reg clk = 0;
always #1 clk = !clk;
-
+
/* UUT */
wire [2:0] count;
counter c1 (clk, reset, en, count);
diff --git a/examples/cmos/testbench_digital.sh b/examples/cmos/testbench_digital.sh
index afaaf4d4..d7ab0fe1 100644
--- a/examples/cmos/testbench_digital.sh
+++ b/examples/cmos/testbench_digital.sh
@@ -4,7 +4,7 @@ set -ex
# iverlog simulation
echo "Doing Verilog simulation with iverilog"
-iverilog -o counter_tb counter.v counter_tb.v
+iverilog -o counter_tb counter.v counter_tb.v
./counter_tb; gtkwave counter_tb.gtkw &
# yosys synthesis
diff --git a/examples/cxx-api/evaldemo.cc b/examples/cxx-api/evaldemo.cc
index e5cc8d8e..34373487 100644
--- a/examples/cxx-api/evaldemo.cc
+++ b/examples/cxx-api/evaldemo.cc
@@ -22,7 +22,7 @@ struct EvalDemoPass : public Pass
{
EvalDemoPass() : Pass("evaldemo") { }
- virtual void execute(vector<string>, Design *design)
+ void execute(vector<string>, Design *design) YS_OVERRIDE
{
Module *module = design->top_module();
diff --git a/examples/gowin/.gitignore b/examples/gowin/.gitignore
new file mode 100644
index 00000000..71030bdb
--- /dev/null
+++ b/examples/gowin/.gitignore
@@ -0,0 +1,8 @@
+demo.bit
+demo.out
+demo.rpt
+demo_syn.v
+demo_out.v
+demo_tr.html
+testbench
+testbench.vcd
diff --git a/examples/gowin/README b/examples/gowin/README
new file mode 100644
index 00000000..0194e9f0
--- /dev/null
+++ b/examples/gowin/README
@@ -0,0 +1,17 @@
+Simple test project for Gowinsemi GW2A-55K Eval Board Mini.
+
+Follow the install instructions for the Gowinsemi tools below,
+then run "bash run.sh" in this directory.
+
+
+Install instructions for gowinTool_linux
+----------------------------------------
+
+1.) extract gowinTool_linux.zip
+
+2.) set GOWIN_HOME env variable to the full path to the
+gowinTool_linux directory
+
+3.) edit gowinTool_linux/bin/gwlicense.ini. Set lic="..." to
+the full path to the license file.
+
diff --git a/examples/gowin/demo.cst b/examples/gowin/demo.cst
new file mode 100644
index 00000000..22d7eb66
--- /dev/null
+++ b/examples/gowin/demo.cst
@@ -0,0 +1,41 @@
+// 50 MHz Clock
+IO_LOC "clk" D11;
+
+// LEDs
+IO_LOC "leds[0]" D22;
+IO_LOC "leds[1]" E22;
+IO_LOC "leds[2]" G22;
+IO_LOC "leds[3]" J22;
+IO_LOC "leds[4]" L22;
+IO_LOC "leds[5]" L19;
+IO_LOC "leds[6]" L20;
+IO_LOC "leds[7]" M21;
+IO_LOC "leds[8]" N19;
+IO_LOC "leds[9]" R19;
+IO_LOC "leds[10]" T18;
+IO_LOC "leds[11]" AA22;
+IO_LOC "leds[12]" U18;
+IO_LOC "leds[13]" V20;
+IO_LOC "leds[14]" AA21;
+IO_LOC "leds[15]" AB21;
+
+
+// 7-Segment Display
+IO_LOC "seg7dig[0]" E20;
+IO_LOC "seg7dig[1]" G18;
+IO_LOC "seg7dig[2]" G20;
+IO_LOC "seg7dig[3]" F21;
+IO_LOC "seg7dig[4]" J20;
+IO_LOC "seg7dig[5]" H21;
+IO_LOC "seg7dig[6]" H18;
+IO_LOC "seg7dig[7]" D20;
+IO_LOC "seg7sel[0]" C19;
+IO_LOC "seg7sel[1]" B22;
+IO_LOC "seg7sel[2]" C20;
+IO_LOC "seg7sel[3]" C21;
+
+// Switches
+IO_LOC "sw[0]" AB20;
+IO_LOC "sw[1]" AB19;
+IO_LOC "sw[2]" AB18;
+IO_LOC "sw[3]" AB17;
diff --git a/examples/gowin/demo.sdc b/examples/gowin/demo.sdc
new file mode 100644
index 00000000..6c90325f
--- /dev/null
+++ b/examples/gowin/demo.sdc
@@ -0,0 +1 @@
+create_clock -name clk -period 20 -waveform {0 10} [get_ports {clk}]
diff --git a/examples/gowin/demo.v b/examples/gowin/demo.v
new file mode 100644
index 00000000..6ea10838
--- /dev/null
+++ b/examples/gowin/demo.v
@@ -0,0 +1,12 @@
+module demo (
+ input clk,
+ input [3:0] sw,
+ output [15:0] leds,
+ output [7:0] seg7dig,
+ output [3:0] seg7sel
+);
+ localparam PRESCALE = 20;
+ reg [PRESCALE+3:0] counter = 0;
+ always @(posedge clk) counter <= counter + 1;
+ assign leds = 1 << counter[PRESCALE +: 4];
+endmodule
diff --git a/examples/gowin/run.sh b/examples/gowin/run.sh
new file mode 100644
index 00000000..33a7b5c3
--- /dev/null
+++ b/examples/gowin/run.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+set -ex
+yosys -p "synth_gowin -top demo -vout demo_syn.v" demo.v
+$GOWIN_HOME/bin/gowin -d demo_syn.v -cst demo.cst -sdc demo.sdc -p GW2A55-PBGA484-6 \
+ -warning_all -out demo_out.v -rpt demo.rpt -tr demo_tr.html -bit demo.bit
+
+# post place&route simulation (icarus verilog)
+if false; then
+ iverilog -D POST_IMPL -o testbench -s testbench testbench.v \
+ demo_out.v $(yosys-config --datdir/gowin/cells_sim.v)
+ vvp -N testbench
+fi
diff --git a/examples/gowin/testbench.v b/examples/gowin/testbench.v
new file mode 100644
index 00000000..6d206381
--- /dev/null
+++ b/examples/gowin/testbench.v
@@ -0,0 +1,40 @@
+module testbench;
+ reg clk;
+
+ initial begin
+ #5 clk = 0;
+ forever #5 clk = ~clk;
+ end
+
+ wire [15:0] leds;
+
+ initial begin
+ // $dumpfile("testbench.vcd");
+ // $dumpvars(0, testbench);
+ $monitor("%b", leds);
+ end
+
+ demo uut (
+ .clk (clk ),
+`ifdef POST_IMPL
+ .\leds[0] (leds[0]),
+ .\leds[1] (leds[1]),
+ .\leds[2] (leds[2]),
+ .\leds[3] (leds[3]),
+ .\leds[4] (leds[4]),
+ .\leds[5] (leds[5]),
+ .\leds[6] (leds[6]),
+ .\leds[7] (leds[7]),
+ .\leds[8] (leds[8]),
+ .\leds[9] (leds[9]),
+ .\leds[10] (leds[10]),
+ .\leds[11] (leds[11]),
+ .\leds[12] (leds[12]),
+ .\leds[13] (leds[13]),
+ .\leds[14] (leds[14]),
+ .\leds[15] (leds[15])
+`else
+ .leds(leds)
+`endif
+ );
+endmodule
diff --git a/examples/intel/DE2i-150/quartus_compile/de2i.qpf b/examples/intel/DE2i-150/quartus_compile/de2i.qpf
new file mode 100644
index 00000000..9fc734eb
--- /dev/null
+++ b/examples/intel/DE2i-150/quartus_compile/de2i.qpf
@@ -0,0 +1,4 @@
+QUARTUS_VERSION = "16.1"
+# Revisions
+
+PROJECT_REVISION = "de2i"
diff --git a/examples/intel/DE2i-150/quartus_compile/de2i.qsf b/examples/intel/DE2i-150/quartus_compile/de2i.qsf
new file mode 100644
index 00000000..5a230155
--- /dev/null
+++ b/examples/intel/DE2i-150/quartus_compile/de2i.qsf
@@ -0,0 +1,1099 @@
+set_global_assignment -name FAMILY "Cyclone IV GX"
+set_global_assignment -name DEVICE EP4CGX150DF31C7
+set_global_assignment -name TOP_LEVEL_ENTITY "top"
+set_global_assignment -name DEVICE_FILTER_PACKAGE FBGA
+
+
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLOCK2_50
+set_instance_assignment -name IO_STANDARD "2.5 V" -to CLOCK3_50
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLOCK_50
+
+#============================================================
+# DRAM
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[8]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[9]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[10]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[11]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[12]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_BA[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_BA[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_CAS_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_CKE
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_CLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_CS_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[8]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[9]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[10]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[11]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[12]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[13]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[14]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[15]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[16]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[17]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[18]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[19]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[20]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[21]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[22]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[23]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[24]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[25]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[26]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[27]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[28]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[29]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[30]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[31]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQM[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQM[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQM[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQM[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_RAS_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_WE_N
+
+#============================================================
+# EEP
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to EEP_I2C_SCLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to EEP_I2C_SDAT
+
+#============================================================
+# ENET
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_GTX_CLK
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_INT_N
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_LINK100
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_MDC
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_MDIO
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RST_N
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_CLK
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_COL
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_CRS
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DATA[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DATA[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DATA[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DATA[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DV
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_ER
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_CLK
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_DATA[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_DATA[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_DATA[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_DATA[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_EN
+set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_ER
+
+#============================================================
+# FAN
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to FAN_CTRL
+
+#============================================================
+# FLASH
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_RESET_N
+
+#============================================================
+# FS
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[8]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[9]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[10]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[11]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[12]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[13]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[14]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[15]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[16]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[17]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[18]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[19]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[20]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[21]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[22]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[23]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[24]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[25]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[26]
+
+#============================================================
+# FL
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_CE_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_OE_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_RY
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_WE_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_WP_N
+
+#============================================================
+# FS
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[8]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[9]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[10]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[11]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[12]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[13]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[14]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[15]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[16]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[17]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[18]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[19]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[20]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[21]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[22]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[23]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[24]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[25]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[26]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[27]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[28]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[29]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[30]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[31]
+
+#============================================================
+# GPIO
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[8]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[9]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[10]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[11]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[12]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[13]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[14]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[15]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[16]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[17]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[18]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[19]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[20]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[21]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[22]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[23]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[24]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[25]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[26]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[27]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[28]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[29]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[30]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[31]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[32]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[33]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[34]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[35]
+
+#============================================================
+# G
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to G_SENSOR_INT1
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to G_SENSOR_SCLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to G_SENSOR_SDAT
+
+#============================================================
+# HEX0
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[6]
+
+#============================================================
+# HEX1
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[6]
+
+#============================================================
+# HEX2
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[6]
+
+#============================================================
+# HEX3
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[6]
+
+#============================================================
+# HEX4
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[6]
+
+#============================================================
+# HEX5
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[6]
+
+#============================================================
+# HEX6
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[6]
+
+#============================================================
+# HEX7
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[6]
+
+#============================================================
+# HSMC
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN0
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN_N1
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN_N2
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN_P1
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN_P2
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT0
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT_N1
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT_N2
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT_P1
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT_P2
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_D[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_D[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_D[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_D[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_I2C_SCLK
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_I2C_SDAT
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[6]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[7]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[8]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[9]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[10]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[11]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[12]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[13]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[14]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[15]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[16]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[6]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[7]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[8]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[9]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[10]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[11]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[12]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[13]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[14]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[15]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[16]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[6]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[7]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[8]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[9]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[10]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[11]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[12]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[13]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[14]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[15]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[16]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[6]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[7]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[8]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[9]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[10]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[11]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[12]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[13]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[14]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[15]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[16]
+
+#============================================================
+# I2C
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to I2C_SCLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to I2C_SDAT
+
+#============================================================
+# IRDA
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to IRDA_RXD
+
+#============================================================
+# KEY
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to KEY[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to KEY[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to KEY[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to KEY[3]
+
+#============================================================
+# LCD
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_EN
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LCD_ON
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_RS
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_RW
+
+#============================================================
+# LEDG
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[6]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[7]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[8]
+
+#============================================================
+# LEDR
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[6]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[7]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[8]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[9]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[10]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[11]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[12]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[13]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[14]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[15]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[16]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[17]
+
+#============================================================
+# PCIE
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to PCIE_PERST_N
+set_instance_assignment -name IO_STANDARD HCSL -to PCIE_REFCLK_P
+set_instance_assignment -name IO_STANDARD "1.5-V PCML" -to PCIE_RX_P[0]
+set_instance_assignment -name IO_STANDARD "1.5-V PCML" -to PCIE_RX_P[1]
+set_instance_assignment -name IO_STANDARD "1.5-V PCML" -to PCIE_TX_P[0]
+set_instance_assignment -name IO_STANDARD "1.5-V PCML" -to PCIE_TX_P[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to PCIE_WAKE_N
+
+#============================================================
+# SD
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_CLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_CMD
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_DAT[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_DAT[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_DAT[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_DAT[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_WP_N
+
+#============================================================
+# SMA
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SMA_CLKIN
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SMA_CLKOUT
+
+#============================================================
+# SSRAM0
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM0_CE_N
+
+#============================================================
+# SSRAM1
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM1_CE_N
+
+#============================================================
+# SSRAM
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_ADSC_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_ADSP_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_ADV_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_BE[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_BE[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_BE[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_BE[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_CLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_GW_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_OE_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_WE_N
+
+#============================================================
+# SW
+#============================================================
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[4]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[5]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[6]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[7]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[8]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[9]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[10]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[11]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[12]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[13]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[14]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[15]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[16]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[17]
+
+#============================================================
+# TD
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_CLK27
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_HS
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_RESET_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_VS
+
+#============================================================
+# UART
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_CTS
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_RTS
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_RXD
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_TXD
+
+#============================================================
+# VGA
+#============================================================
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_BLANK_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_CLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_HS
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_SYNC_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_VS
+
+#============================================================
+# End of pin assignments by Terasic System Builder
+#============================================================
+
+
+
+set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO"
+set_location_assignment PIN_A15 -to CLOCK2_50
+set_location_assignment PIN_V11 -to CLOCK3_50
+set_location_assignment PIN_AJ16 -to CLOCK_50
+set_location_assignment PIN_AG7 -to DRAM_ADDR[0]
+set_location_assignment PIN_AJ7 -to DRAM_ADDR[1]
+set_location_assignment PIN_AG8 -to DRAM_ADDR[2]
+set_location_assignment PIN_AH8 -to DRAM_ADDR[3]
+set_location_assignment PIN_AE16 -to DRAM_ADDR[4]
+set_location_assignment PIN_AF16 -to DRAM_ADDR[5]
+set_location_assignment PIN_AE14 -to DRAM_ADDR[6]
+set_location_assignment PIN_AE15 -to DRAM_ADDR[7]
+set_location_assignment PIN_AE13 -to DRAM_ADDR[8]
+set_location_assignment PIN_AE12 -to DRAM_ADDR[9]
+set_location_assignment PIN_AH6 -to DRAM_ADDR[10]
+set_location_assignment PIN_AE11 -to DRAM_ADDR[11]
+set_location_assignment PIN_AE10 -to DRAM_ADDR[12]
+set_location_assignment PIN_AH5 -to DRAM_BA[0]
+set_location_assignment PIN_AG6 -to DRAM_BA[1]
+set_location_assignment PIN_AJ4 -to DRAM_CAS_N
+set_location_assignment PIN_AD6 -to DRAM_CKE
+set_location_assignment PIN_AE6 -to DRAM_CLK
+set_location_assignment PIN_AG5 -to DRAM_CS_N
+set_location_assignment PIN_AD10 -to DRAM_DQ[0]
+set_location_assignment PIN_AD9 -to DRAM_DQ[1]
+set_location_assignment PIN_AE9 -to DRAM_DQ[2]
+set_location_assignment PIN_AE8 -to DRAM_DQ[3]
+set_location_assignment PIN_AE7 -to DRAM_DQ[4]
+set_location_assignment PIN_AF7 -to DRAM_DQ[5]
+set_location_assignment PIN_AF6 -to DRAM_DQ[6]
+set_location_assignment PIN_AF9 -to DRAM_DQ[7]
+set_location_assignment PIN_AB13 -to DRAM_DQ[8]
+set_location_assignment PIN_AF13 -to DRAM_DQ[9]
+set_location_assignment PIN_AF12 -to DRAM_DQ[10]
+set_location_assignment PIN_AG9 -to DRAM_DQ[11]
+set_location_assignment PIN_AA13 -to DRAM_DQ[12]
+set_location_assignment PIN_AB11 -to DRAM_DQ[13]
+set_location_assignment PIN_AA12 -to DRAM_DQ[14]
+set_location_assignment PIN_AA15 -to DRAM_DQ[15]
+set_location_assignment PIN_AH11 -to DRAM_DQ[16]
+set_location_assignment PIN_AG11 -to DRAM_DQ[17]
+set_location_assignment PIN_AH12 -to DRAM_DQ[18]
+set_location_assignment PIN_AG12 -to DRAM_DQ[19]
+set_location_assignment PIN_AH13 -to DRAM_DQ[20]
+set_location_assignment PIN_AG13 -to DRAM_DQ[21]
+set_location_assignment PIN_AG14 -to DRAM_DQ[22]
+set_location_assignment PIN_AH14 -to DRAM_DQ[23]
+set_location_assignment PIN_AH9 -to DRAM_DQ[24]
+set_location_assignment PIN_AK8 -to DRAM_DQ[25]
+set_location_assignment PIN_AG10 -to DRAM_DQ[26]
+set_location_assignment PIN_AK7 -to DRAM_DQ[27]
+set_location_assignment PIN_AH7 -to DRAM_DQ[28]
+set_location_assignment PIN_AK6 -to DRAM_DQ[29]
+set_location_assignment PIN_AJ6 -to DRAM_DQ[30]
+set_location_assignment PIN_AK5 -to DRAM_DQ[31]
+set_location_assignment PIN_AF10 -to DRAM_DQM[0]
+set_location_assignment PIN_AB14 -to DRAM_DQM[1]
+set_location_assignment PIN_AH15 -to DRAM_DQM[2]
+set_location_assignment PIN_AH10 -to DRAM_DQM[3]
+set_location_assignment PIN_AK4 -to DRAM_RAS_N
+set_location_assignment PIN_AK3 -to DRAM_WE_N
+set_location_assignment PIN_AG27 -to EEP_I2C_SCLK
+set_location_assignment PIN_AG25 -to EEP_I2C_SDAT
+set_location_assignment PIN_A12 -to ENET_GTX_CLK
+set_location_assignment PIN_E16 -to ENET_INT_N
+set_location_assignment PIN_F5 -to ENET_LINK100
+set_location_assignment PIN_C16 -to ENET_MDC
+set_location_assignment PIN_C15 -to ENET_MDIO
+set_location_assignment PIN_C14 -to ENET_RST_N
+set_location_assignment PIN_L15 -to ENET_RX_CLK
+set_location_assignment PIN_G15 -to ENET_RX_COL
+set_location_assignment PIN_D6 -to ENET_RX_CRS
+set_location_assignment PIN_F15 -to ENET_RX_DATA[0]
+set_location_assignment PIN_E13 -to ENET_RX_DATA[1]
+set_location_assignment PIN_A5 -to ENET_RX_DATA[2]
+set_location_assignment PIN_B7 -to ENET_RX_DATA[3]
+set_location_assignment PIN_A8 -to ENET_RX_DV
+set_location_assignment PIN_D11 -to ENET_RX_ER
+set_location_assignment PIN_F13 -to ENET_TX_CLK
+set_location_assignment PIN_B12 -to ENET_TX_DATA[0]
+set_location_assignment PIN_E7 -to ENET_TX_DATA[1]
+set_location_assignment PIN_C13 -to ENET_TX_DATA[2]
+set_location_assignment PIN_D15 -to ENET_TX_DATA[3]
+set_location_assignment PIN_D14 -to ENET_TX_EN
+set_location_assignment PIN_D13 -to ENET_TX_ER
+set_location_assignment PIN_AF28 -to FAN_CTRL
+set_location_assignment PIN_AG18 -to FL_RESET_N
+set_location_assignment PIN_AB22 -to FS_ADDR[1]
+set_location_assignment PIN_AH19 -to FS_ADDR[2]
+set_location_assignment PIN_AK19 -to FS_ADDR[3]
+set_location_assignment PIN_AJ18 -to FS_ADDR[4]
+set_location_assignment PIN_AA18 -to FS_ADDR[5]
+set_location_assignment PIN_AH18 -to FS_ADDR[6]
+set_location_assignment PIN_AK17 -to FS_ADDR[7]
+set_location_assignment PIN_Y20 -to FS_ADDR[8]
+set_location_assignment PIN_AK21 -to FS_ADDR[9]
+set_location_assignment PIN_AH21 -to FS_ADDR[10]
+set_location_assignment PIN_AG21 -to FS_ADDR[11]
+set_location_assignment PIN_AG22 -to FS_ADDR[12]
+set_location_assignment PIN_AD22 -to FS_ADDR[13]
+set_location_assignment PIN_AE24 -to FS_ADDR[14]
+set_location_assignment PIN_AD23 -to FS_ADDR[15]
+set_location_assignment PIN_AB21 -to FS_ADDR[16]
+set_location_assignment PIN_AH17 -to FS_ADDR[17]
+set_location_assignment PIN_AE17 -to FS_ADDR[18]
+set_location_assignment PIN_AG20 -to FS_ADDR[19]
+set_location_assignment PIN_AK20 -to FS_ADDR[20]
+set_location_assignment PIN_AE19 -to FS_ADDR[21]
+set_location_assignment PIN_AA16 -to FS_ADDR[22]
+set_location_assignment PIN_AF15 -to FS_ADDR[23]
+set_location_assignment PIN_AG15 -to FS_ADDR[24]
+set_location_assignment PIN_Y17 -to FS_ADDR[25]
+set_location_assignment PIN_AB16 -to FS_ADDR[26]
+set_location_assignment PIN_AG19 -to FL_CE_N
+set_location_assignment PIN_AJ19 -to FL_OE_N
+set_location_assignment PIN_AF19 -to FL_RY
+set_location_assignment PIN_AG17 -to FL_WE_N
+set_location_assignment PIN_AK18 -to FL_WP_N
+set_location_assignment PIN_AK29 -to FS_DQ[0]
+set_location_assignment PIN_AE23 -to FS_DQ[1]
+set_location_assignment PIN_AH24 -to FS_DQ[2]
+set_location_assignment PIN_AH23 -to FS_DQ[3]
+set_location_assignment PIN_AA21 -to FS_DQ[4]
+set_location_assignment PIN_AE20 -to FS_DQ[5]
+set_location_assignment PIN_Y19 -to FS_DQ[6]
+set_location_assignment PIN_AA17 -to FS_DQ[7]
+set_location_assignment PIN_AB17 -to FS_DQ[8]
+set_location_assignment PIN_Y18 -to FS_DQ[9]
+set_location_assignment PIN_AA20 -to FS_DQ[10]
+set_location_assignment PIN_AE21 -to FS_DQ[11]
+set_location_assignment PIN_AH22 -to FS_DQ[12]
+set_location_assignment PIN_AJ24 -to FS_DQ[13]
+set_location_assignment PIN_AE22 -to FS_DQ[14]
+set_location_assignment PIN_AK28 -to FS_DQ[15]
+set_location_assignment PIN_AK9 -to FS_DQ[16]
+set_location_assignment PIN_AJ10 -to FS_DQ[17]
+set_location_assignment PIN_AK11 -to FS_DQ[18]
+set_location_assignment PIN_AK12 -to FS_DQ[19]
+set_location_assignment PIN_AJ13 -to FS_DQ[20]
+set_location_assignment PIN_AK15 -to FS_DQ[21]
+set_location_assignment PIN_AC16 -to FS_DQ[22]
+set_location_assignment PIN_AH16 -to FS_DQ[23]
+set_location_assignment PIN_AG16 -to FS_DQ[24]
+set_location_assignment PIN_AD16 -to FS_DQ[25]
+set_location_assignment PIN_AJ15 -to FS_DQ[26]
+set_location_assignment PIN_AK14 -to FS_DQ[27]
+set_location_assignment PIN_AK13 -to FS_DQ[28]
+set_location_assignment PIN_AJ12 -to FS_DQ[29]
+set_location_assignment PIN_AK10 -to FS_DQ[30]
+set_location_assignment PIN_AJ9 -to FS_DQ[31]
+set_location_assignment PIN_G16 -to GPIO[0]
+set_location_assignment PIN_F17 -to GPIO[1]
+set_location_assignment PIN_D18 -to GPIO[2]
+set_location_assignment PIN_F18 -to GPIO[3]
+set_location_assignment PIN_D19 -to GPIO[4]
+set_location_assignment PIN_K21 -to GPIO[5]
+set_location_assignment PIN_F19 -to GPIO[6]
+set_location_assignment PIN_K22 -to GPIO[7]
+set_location_assignment PIN_B21 -to GPIO[8]
+set_location_assignment PIN_C21 -to GPIO[9]
+set_location_assignment PIN_D22 -to GPIO[10]
+set_location_assignment PIN_D21 -to GPIO[11]
+set_location_assignment PIN_D23 -to GPIO[12]
+set_location_assignment PIN_D24 -to GPIO[13]
+set_location_assignment PIN_B28 -to GPIO[14]
+set_location_assignment PIN_C25 -to GPIO[15]
+set_location_assignment PIN_C26 -to GPIO[16]
+set_location_assignment PIN_D28 -to GPIO[17]
+set_location_assignment PIN_D25 -to GPIO[18]
+set_location_assignment PIN_F20 -to GPIO[19]
+set_location_assignment PIN_E21 -to GPIO[20]
+set_location_assignment PIN_F23 -to GPIO[21]
+set_location_assignment PIN_G20 -to GPIO[22]
+set_location_assignment PIN_F22 -to GPIO[23]
+set_location_assignment PIN_G22 -to GPIO[24]
+set_location_assignment PIN_G24 -to GPIO[25]
+set_location_assignment PIN_G23 -to GPIO[26]
+set_location_assignment PIN_A25 -to GPIO[27]
+set_location_assignment PIN_A26 -to GPIO[28]
+set_location_assignment PIN_A19 -to GPIO[29]
+set_location_assignment PIN_A28 -to GPIO[30]
+set_location_assignment PIN_A27 -to GPIO[31]
+set_location_assignment PIN_B30 -to GPIO[32]
+set_location_assignment PIN_AG28 -to GPIO[33]
+set_location_assignment PIN_AG26 -to GPIO[34]
+set_location_assignment PIN_Y21 -to GPIO[35]
+set_location_assignment PIN_AC30 -to G_SENSOR_INT1
+set_location_assignment PIN_AK27 -to G_SENSOR_SCLK
+set_location_assignment PIN_AK26 -to G_SENSOR_SDAT
+set_location_assignment PIN_E15 -to HEX0[0]
+set_location_assignment PIN_E12 -to HEX0[1]
+set_location_assignment PIN_G11 -to HEX0[2]
+set_location_assignment PIN_F11 -to HEX0[3]
+set_location_assignment PIN_F16 -to HEX0[4]
+set_location_assignment PIN_D16 -to HEX0[5]
+set_location_assignment PIN_F14 -to HEX0[6]
+set_location_assignment PIN_G14 -to HEX1[0]
+set_location_assignment PIN_B13 -to HEX1[1]
+set_location_assignment PIN_G13 -to HEX1[2]
+set_location_assignment PIN_F12 -to HEX1[3]
+set_location_assignment PIN_G12 -to HEX1[4]
+set_location_assignment PIN_J9 -to HEX1[5]
+set_location_assignment PIN_G10 -to HEX1[6]
+set_location_assignment PIN_G8 -to HEX2[0]
+set_location_assignment PIN_G7 -to HEX2[1]
+set_location_assignment PIN_F7 -to HEX2[2]
+set_location_assignment PIN_AG30 -to HEX2[3]
+set_location_assignment PIN_F6 -to HEX2[4]
+set_location_assignment PIN_F4 -to HEX2[5]
+set_location_assignment PIN_F10 -to HEX2[6]
+set_location_assignment PIN_D10 -to HEX3[0]
+set_location_assignment PIN_D7 -to HEX3[1]
+set_location_assignment PIN_E6 -to HEX3[2]
+set_location_assignment PIN_E4 -to HEX3[3]
+set_location_assignment PIN_E3 -to HEX3[4]
+set_location_assignment PIN_D5 -to HEX3[5]
+set_location_assignment PIN_D4 -to HEX3[6]
+set_location_assignment PIN_A14 -to HEX4[0]
+set_location_assignment PIN_A13 -to HEX4[1]
+set_location_assignment PIN_C7 -to HEX4[2]
+set_location_assignment PIN_C6 -to HEX4[3]
+set_location_assignment PIN_C5 -to HEX4[4]
+set_location_assignment PIN_C4 -to HEX4[5]
+set_location_assignment PIN_C3 -to HEX4[6]
+set_location_assignment PIN_D3 -to HEX5[0]
+set_location_assignment PIN_A10 -to HEX5[1]
+set_location_assignment PIN_A9 -to HEX5[2]
+set_location_assignment PIN_A7 -to HEX5[3]
+set_location_assignment PIN_A6 -to HEX5[4]
+set_location_assignment PIN_A11 -to HEX5[5]
+set_location_assignment PIN_B6 -to HEX5[6]
+set_location_assignment PIN_B9 -to HEX6[0]
+set_location_assignment PIN_B10 -to HEX6[1]
+set_location_assignment PIN_C8 -to HEX6[2]
+set_location_assignment PIN_C9 -to HEX6[3]
+set_location_assignment PIN_D8 -to HEX6[4]
+set_location_assignment PIN_D9 -to HEX6[5]
+set_location_assignment PIN_E9 -to HEX6[6]
+set_location_assignment PIN_E10 -to HEX7[0]
+set_location_assignment PIN_F8 -to HEX7[1]
+set_location_assignment PIN_F9 -to HEX7[2]
+set_location_assignment PIN_C10 -to HEX7[3]
+set_location_assignment PIN_C11 -to HEX7[4]
+set_location_assignment PIN_C12 -to HEX7[5]
+set_location_assignment PIN_D12 -to HEX7[6]
+set_location_assignment PIN_K15 -to HSMC_CLKIN0
+set_location_assignment PIN_V30 -to HSMC_CLKIN_N1
+set_location_assignment PIN_T30 -to HSMC_CLKIN_N2
+set_location_assignment PIN_V29 -to HSMC_CLKIN_P1
+set_location_assignment PIN_T29 -to HSMC_CLKIN_P2
+set_location_assignment PIN_G6 -to HSMC_CLKOUT0
+set_location_assignment PIN_AB28 -to HSMC_CLKOUT_N1
+set_location_assignment PIN_Y28 -to HSMC_CLKOUT_N2
+set_location_assignment PIN_AB27 -to HSMC_CLKOUT_P1
+set_location_assignment PIN_AA28 -to HSMC_CLKOUT_P2
+set_location_assignment PIN_AC25 -to HSMC_D[0]
+set_location_assignment PIN_E27 -to HSMC_D[1]
+set_location_assignment PIN_AB26 -to HSMC_D[2]
+set_location_assignment PIN_E28 -to HSMC_D[3]
+set_location_assignment PIN_AD26 -to HSMC_I2C_SCLK
+set_location_assignment PIN_AD25 -to HSMC_I2C_SDAT
+set_location_assignment PIN_G27 -to HSMC_RX_D_N[0]
+set_location_assignment PIN_G29 -to HSMC_RX_D_N[1]
+set_location_assignment PIN_H27 -to HSMC_RX_D_N[2]
+set_location_assignment PIN_K29 -to HSMC_RX_D_N[3]
+set_location_assignment PIN_L28 -to HSMC_RX_D_N[4]
+set_location_assignment PIN_M28 -to HSMC_RX_D_N[5]
+set_location_assignment PIN_N30 -to HSMC_RX_D_N[6]
+set_location_assignment PIN_P28 -to HSMC_RX_D_N[7]
+set_location_assignment PIN_R28 -to HSMC_RX_D_N[8]
+set_location_assignment PIN_U28 -to HSMC_RX_D_N[9]
+set_location_assignment PIN_W28 -to HSMC_RX_D_N[10]
+set_location_assignment PIN_W30 -to HSMC_RX_D_N[11]
+set_location_assignment PIN_M30 -to HSMC_RX_D_N[12]
+set_location_assignment PIN_Y27 -to HSMC_RX_D_N[13]
+set_location_assignment PIN_AA29 -to HSMC_RX_D_N[14]
+set_location_assignment PIN_AD28 -to HSMC_RX_D_N[15]
+set_location_assignment PIN_AE28 -to HSMC_RX_D_N[16]
+set_location_assignment PIN_G26 -to HSMC_RX_D_P[0]
+set_location_assignment PIN_G28 -to HSMC_RX_D_P[1]
+set_location_assignment PIN_J27 -to HSMC_RX_D_P[2]
+set_location_assignment PIN_K28 -to HSMC_RX_D_P[3]
+set_location_assignment PIN_L27 -to HSMC_RX_D_P[4]
+set_location_assignment PIN_M27 -to HSMC_RX_D_P[5]
+set_location_assignment PIN_N29 -to HSMC_RX_D_P[6]
+set_location_assignment PIN_P27 -to HSMC_RX_D_P[7]
+set_location_assignment PIN_R27 -to HSMC_RX_D_P[8]
+set_location_assignment PIN_U27 -to HSMC_RX_D_P[9]
+set_location_assignment PIN_W27 -to HSMC_RX_D_P[10]
+set_location_assignment PIN_W29 -to HSMC_RX_D_P[11]
+set_location_assignment PIN_M29 -to HSMC_RX_D_P[12]
+set_location_assignment PIN_AA27 -to HSMC_RX_D_P[13]
+set_location_assignment PIN_AB29 -to HSMC_RX_D_P[14]
+set_location_assignment PIN_AD27 -to HSMC_RX_D_P[15]
+set_location_assignment PIN_AE27 -to HSMC_RX_D_P[16]
+set_location_assignment PIN_H28 -to HSMC_TX_D_N[0]
+set_location_assignment PIN_F29 -to HSMC_TX_D_N[1]
+set_location_assignment PIN_D30 -to HSMC_TX_D_N[2]
+set_location_assignment PIN_E30 -to HSMC_TX_D_N[3]
+set_location_assignment PIN_G30 -to HSMC_TX_D_N[4]
+set_location_assignment PIN_J30 -to HSMC_TX_D_N[5]
+set_location_assignment PIN_K27 -to HSMC_TX_D_N[6]
+set_location_assignment PIN_K30 -to HSMC_TX_D_N[7]
+set_location_assignment PIN_T25 -to HSMC_TX_D_N[8]
+set_location_assignment PIN_N28 -to HSMC_TX_D_N[9]
+set_location_assignment PIN_V26 -to HSMC_TX_D_N[10]
+set_location_assignment PIN_Y30 -to HSMC_TX_D_N[11]
+set_location_assignment PIN_AC28 -to HSMC_TX_D_N[12]
+set_location_assignment PIN_AD30 -to HSMC_TX_D_N[13]
+set_location_assignment PIN_AE30 -to HSMC_TX_D_N[14]
+set_location_assignment PIN_AH30 -to HSMC_TX_D_N[15]
+set_location_assignment PIN_AG29 -to HSMC_TX_D_N[16]
+set_location_assignment PIN_J28 -to HSMC_TX_D_P[0]
+set_location_assignment PIN_F28 -to HSMC_TX_D_P[1]
+set_location_assignment PIN_D29 -to HSMC_TX_D_P[2]
+set_location_assignment PIN_F30 -to HSMC_TX_D_P[3]
+set_location_assignment PIN_H30 -to HSMC_TX_D_P[4]
+set_location_assignment PIN_J29 -to HSMC_TX_D_P[5]
+set_location_assignment PIN_K26 -to HSMC_TX_D_P[6]
+set_location_assignment PIN_L30 -to HSMC_TX_D_P[7]
+set_location_assignment PIN_U25 -to HSMC_TX_D_P[8]
+set_location_assignment PIN_N27 -to HSMC_TX_D_P[9]
+set_location_assignment PIN_V25 -to HSMC_TX_D_P[10]
+set_location_assignment PIN_AA30 -to HSMC_TX_D_P[11]
+set_location_assignment PIN_AC27 -to HSMC_TX_D_P[12]
+set_location_assignment PIN_AD29 -to HSMC_TX_D_P[13]
+set_location_assignment PIN_AE29 -to HSMC_TX_D_P[14]
+set_location_assignment PIN_AJ30 -to HSMC_TX_D_P[15]
+set_location_assignment PIN_AH29 -to HSMC_TX_D_P[16]
+set_location_assignment PIN_C27 -to I2C_SCLK
+set_location_assignment PIN_G21 -to I2C_SDAT
+set_location_assignment PIN_AH28 -to IRDA_RXD
+set_location_assignment PIN_AA26 -to KEY[0]
+set_location_assignment PIN_AE25 -to KEY[1]
+set_location_assignment PIN_AF30 -to KEY[2]
+set_location_assignment PIN_AE26 -to KEY[3]
+set_location_assignment PIN_AG4 -to LCD_DATA[0]
+set_location_assignment PIN_AF3 -to LCD_DATA[1]
+set_location_assignment PIN_AH3 -to LCD_DATA[2]
+set_location_assignment PIN_AE5 -to LCD_DATA[3]
+set_location_assignment PIN_AH2 -to LCD_DATA[4]
+set_location_assignment PIN_AE3 -to LCD_DATA[5]
+set_location_assignment PIN_AH4 -to LCD_DATA[6]
+set_location_assignment PIN_AE4 -to LCD_DATA[7]
+set_location_assignment PIN_AF4 -to LCD_EN
+set_location_assignment PIN_AF27 -to LCD_ON
+set_location_assignment PIN_AG3 -to LCD_RS
+set_location_assignment PIN_AJ3 -to LCD_RW
+set_location_assignment PIN_AA25 -to LEDG[0]
+set_location_assignment PIN_AB25 -to LEDG[1]
+set_location_assignment PIN_F27 -to LEDG[2]
+set_location_assignment PIN_F26 -to LEDG[3]
+set_location_assignment PIN_W26 -to LEDG[4]
+set_location_assignment PIN_Y22 -to LEDG[5]
+set_location_assignment PIN_Y25 -to LEDG[6]
+set_location_assignment PIN_AA22 -to LEDG[7]
+set_location_assignment PIN_J25 -to LEDG[8]
+set_location_assignment PIN_T23 -to LEDR[0]
+set_location_assignment PIN_T24 -to LEDR[1]
+set_location_assignment PIN_V27 -to LEDR[2]
+set_location_assignment PIN_W25 -to LEDR[3]
+set_location_assignment PIN_T21 -to LEDR[4]
+set_location_assignment PIN_T26 -to LEDR[5]
+set_location_assignment PIN_R25 -to LEDR[6]
+set_location_assignment PIN_T27 -to LEDR[7]
+set_location_assignment PIN_P25 -to LEDR[8]
+set_location_assignment PIN_R24 -to LEDR[9]
+set_location_assignment PIN_P21 -to LEDR[10]
+set_location_assignment PIN_N24 -to LEDR[11]
+set_location_assignment PIN_N21 -to LEDR[12]
+set_location_assignment PIN_M25 -to LEDR[13]
+set_location_assignment PIN_K24 -to LEDR[14]
+set_location_assignment PIN_L25 -to LEDR[15]
+set_location_assignment PIN_M21 -to LEDR[16]
+set_location_assignment PIN_M22 -to LEDR[17]
+set_location_assignment PIN_A4 -to PCIE_PERST_N
+set_location_assignment PIN_V15 -to PCIE_REFCLK_P
+set_location_assignment PIN_AC2 -to PCIE_RX_P[0]
+set_location_assignment PIN_AA2 -to PCIE_RX_P[1]
+set_location_assignment PIN_AB4 -to PCIE_TX_P[0]
+set_location_assignment PIN_Y4 -to PCIE_TX_P[1]
+set_location_assignment PIN_C29 -to PCIE_WAKE_N
+set_location_assignment PIN_AH25 -to SD_CLK
+set_location_assignment PIN_AF18 -to SD_CMD
+set_location_assignment PIN_AH27 -to SD_DAT[0]
+set_location_assignment PIN_AJ28 -to SD_DAT[1]
+set_location_assignment PIN_AD24 -to SD_DAT[2]
+set_location_assignment PIN_AE18 -to SD_DAT[3]
+set_location_assignment PIN_AJ27 -to SD_WP_N
+set_location_assignment PIN_AK16 -to SMA_CLKIN
+set_location_assignment PIN_AF25 -to SMA_CLKOUT
+set_location_assignment PIN_AJ21 -to SSRAM0_CE_N
+set_location_assignment PIN_AG23 -to SSRAM1_CE_N
+set_location_assignment PIN_AK25 -to SSRAM_ADSC_N
+set_location_assignment PIN_AJ25 -to SSRAM_ADSP_N
+set_location_assignment PIN_AH26 -to SSRAM_ADV_N
+set_location_assignment PIN_AF22 -to SSRAM_BE[0]
+set_location_assignment PIN_AK22 -to SSRAM_BE[1]
+set_location_assignment PIN_AJ22 -to SSRAM_BE[2]
+set_location_assignment PIN_AF21 -to SSRAM_BE[3]
+set_location_assignment PIN_AF24 -to SSRAM_CLK
+set_location_assignment PIN_AK23 -to SSRAM_GW_N
+set_location_assignment PIN_AG24 -to SSRAM_OE_N
+set_location_assignment PIN_AK24 -to SSRAM_WE_N
+set_location_assignment PIN_V28 -to SW[0]
+set_location_assignment PIN_U30 -to SW[1]
+set_location_assignment PIN_V21 -to SW[2]
+set_location_assignment PIN_C2 -to SW[3]
+set_location_assignment PIN_AB30 -to SW[4]
+set_location_assignment PIN_U21 -to SW[5]
+set_location_assignment PIN_T28 -to SW[6]
+set_location_assignment PIN_R30 -to SW[7]
+set_location_assignment PIN_P30 -to SW[8]
+set_location_assignment PIN_R29 -to SW[9]
+set_location_assignment PIN_R26 -to SW[10]
+set_location_assignment PIN_N26 -to SW[11]
+set_location_assignment PIN_M26 -to SW[12]
+set_location_assignment PIN_N25 -to SW[13]
+set_location_assignment PIN_J26 -to SW[14]
+set_location_assignment PIN_K25 -to SW[15]
+set_location_assignment PIN_C30 -to SW[16]
+set_location_assignment PIN_H25 -to SW[17]
+set_location_assignment PIN_B15 -to TD_CLK27
+set_location_assignment PIN_C17 -to TD_DATA[0]
+set_location_assignment PIN_D17 -to TD_DATA[1]
+set_location_assignment PIN_A16 -to TD_DATA[2]
+set_location_assignment PIN_B16 -to TD_DATA[3]
+set_location_assignment PIN_G18 -to TD_DATA[4]
+set_location_assignment PIN_G17 -to TD_DATA[5]
+set_location_assignment PIN_K18 -to TD_DATA[6]
+set_location_assignment PIN_K17 -to TD_DATA[7]
+set_location_assignment PIN_C28 -to TD_HS
+set_location_assignment PIN_E25 -to TD_RESET_N
+set_location_assignment PIN_E22 -to TD_VS
+set_location_assignment PIN_D26 -to UART_CTS
+set_location_assignment PIN_A29 -to UART_RTS
+set_location_assignment PIN_B27 -to UART_RXD
+set_location_assignment PIN_H24 -to UART_TXD
+set_location_assignment PIN_E24 -to VGA_B[0]
+set_location_assignment PIN_C24 -to VGA_B[1]
+set_location_assignment PIN_B25 -to VGA_B[2]
+set_location_assignment PIN_C23 -to VGA_B[3]
+set_location_assignment PIN_F24 -to VGA_B[4]
+set_location_assignment PIN_A23 -to VGA_B[5]
+set_location_assignment PIN_G25 -to VGA_B[6]
+set_location_assignment PIN_C22 -to VGA_B[7]
+set_location_assignment PIN_F25 -to VGA_BLANK_N
+set_location_assignment PIN_D27 -to VGA_CLK
+set_location_assignment PIN_D20 -to VGA_G[0]
+set_location_assignment PIN_C20 -to VGA_G[1]
+set_location_assignment PIN_A20 -to VGA_G[2]
+set_location_assignment PIN_K19 -to VGA_G[3]
+set_location_assignment PIN_A21 -to VGA_G[4]
+set_location_assignment PIN_F21 -to VGA_G[5]
+set_location_assignment PIN_A22 -to VGA_G[6]
+set_location_assignment PIN_B22 -to VGA_G[7]
+set_location_assignment PIN_B24 -to VGA_HS
+set_location_assignment PIN_A17 -to VGA_R[0]
+set_location_assignment PIN_C18 -to VGA_R[1]
+set_location_assignment PIN_B18 -to VGA_R[2]
+set_location_assignment PIN_A18 -to VGA_R[3]
+set_location_assignment PIN_E18 -to VGA_R[4]
+set_location_assignment PIN_E19 -to VGA_R[5]
+set_location_assignment PIN_B19 -to VGA_R[6]
+set_location_assignment PIN_C19 -to VGA_R[7]
+set_location_assignment PIN_AH20 -to VGA_SYNC_N
+set_location_assignment PIN_A24 -to VGA_VS
+set_instance_assignment -name VIRTUAL_PIN ON -to FS_ADDR[0]
+#============================================================
+set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
+set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
+set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
+set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
+set_global_assignment -name VQM_FILE ../top.vqm
+set_global_assignment -name SDC_FILE de2i_150_golden_top.sdc
+set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
+set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
+set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
+set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
+set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file
diff --git a/examples/intel/DE2i-150/quartus_compile/runme_quartus b/examples/intel/DE2i-150/quartus_compile/runme_quartus
new file mode 100644
index 00000000..83aa3b60
--- /dev/null
+++ b/examples/intel/DE2i-150/quartus_compile/runme_quartus
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+export REV="de2i"
+
+quartus_map -c $REV top && \
+ quartus_fit -c $REV top && \
+ quartus_asm -c $REV top
diff --git a/examples/intel/DE2i-150/run_cycloneiv b/examples/intel/DE2i-150/run_cycloneiv
new file mode 100644
index 00000000..518807b5
--- /dev/null
+++ b/examples/intel/DE2i-150/run_cycloneiv
@@ -0,0 +1,2 @@
+#/bin/env bash
+yosys -p "synth_intel -family cycloneiv -top top -vqm top.vqm" top.v sevenseg.v
diff --git a/examples/intel/DE2i-150/sevenseg.v b/examples/intel/DE2i-150/sevenseg.v
new file mode 100644
index 00000000..06cf7c14
--- /dev/null
+++ b/examples/intel/DE2i-150/sevenseg.v
@@ -0,0 +1,25 @@
+module sevenseg ( output reg [6:0] HEX0,
+ input [3:0] SW );
+
+ always @(*) begin
+ case(SW)
+ 4'h1: HEX0 = 7'b1111001;
+ 4'h2: HEX0 = 7'b0100100;
+ 4'h3: HEX0 = 7'b0110000;
+ 4'h4: HEX0 = 7'b0011001;
+ 4'h5: HEX0 = 7'b0010010;
+ 4'h6: HEX0 = 7'b0000010;
+ 4'h7: HEX0 = 7'b1111000;
+ 4'h8: HEX0 = 7'b0000000;
+ 4'h9: HEX0 = 7'b0011000;
+ 4'ha: HEX0 = 7'b0001000;
+ 4'hb: HEX0 = 7'b0000011;
+ 4'hc: HEX0 = 7'b1000110;
+ 4'hd: HEX0 = 7'b0100001;
+ 4'he: HEX0 = 7'b0000110;
+ 4'hf: HEX0 = 7'b0001110;
+ 4'h0: HEX0 = 7'b1000000;
+ endcase // case (SW)
+ end
+
+endmodule
diff --git a/examples/intel/DE2i-150/top.v b/examples/intel/DE2i-150/top.v
new file mode 100644
index 00000000..2bada0e2
--- /dev/null
+++ b/examples/intel/DE2i-150/top.v
@@ -0,0 +1,15 @@
+`default_nettype none
+module top ( output wire [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5, HEX6, HEX7,
+ input wire [15:0] SW );
+
+
+ sevenseg UUD0 (.HEX0(HEX0), .SW(4'h7));
+ sevenseg UUD1 (.HEX0(HEX1), .SW(4'h1));
+ sevenseg UUD2 (.HEX0(HEX2), .SW(4'h0));
+ sevenseg UUD3 (.HEX0(HEX3), .SW(4'h2));
+ sevenseg UUD4 (.HEX0(HEX4), .SW(SW[3:0]));
+ sevenseg UUD5 (.HEX0(HEX5), .SW(SW[7:4]));
+ sevenseg UUD6 (.HEX0(HEX6), .SW(SW[11:8]));
+ sevenseg UUD7 (.HEX0(HEX7), .SW(SW[15:12]));
+
+endmodule
diff --git a/examples/intel/MAX10/run_max10 b/examples/intel/MAX10/run_max10
new file mode 100644
index 00000000..0378e4fa
--- /dev/null
+++ b/examples/intel/MAX10/run_max10
@@ -0,0 +1 @@
+yosys -p "synth_intel -family max10 -top top -vqm top.vqm" top.v sevenseg.v
diff --git a/examples/intel/MAX10/runme_postsynth b/examples/intel/MAX10/runme_postsynth
new file mode 100644
index 00000000..f1621054
--- /dev/null
+++ b/examples/intel/MAX10/runme_postsynth
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+iverilog -D POST_IMPL -o verif_post -s tb_top tb_top.v top.vqm $(yosys-config --datdir/altera_intel/max10/cells_comb_max10.v)
+vvp -N verif_post
+
diff --git a/examples/intel/MAX10/sevenseg.v b/examples/intel/MAX10/sevenseg.v
new file mode 100644
index 00000000..06cf7c14
--- /dev/null
+++ b/examples/intel/MAX10/sevenseg.v
@@ -0,0 +1,25 @@
+module sevenseg ( output reg [6:0] HEX0,
+ input [3:0] SW );
+
+ always @(*) begin
+ case(SW)
+ 4'h1: HEX0 = 7'b1111001;
+ 4'h2: HEX0 = 7'b0100100;
+ 4'h3: HEX0 = 7'b0110000;
+ 4'h4: HEX0 = 7'b0011001;
+ 4'h5: HEX0 = 7'b0010010;
+ 4'h6: HEX0 = 7'b0000010;
+ 4'h7: HEX0 = 7'b1111000;
+ 4'h8: HEX0 = 7'b0000000;
+ 4'h9: HEX0 = 7'b0011000;
+ 4'ha: HEX0 = 7'b0001000;
+ 4'hb: HEX0 = 7'b0000011;
+ 4'hc: HEX0 = 7'b1000110;
+ 4'hd: HEX0 = 7'b0100001;
+ 4'he: HEX0 = 7'b0000110;
+ 4'hf: HEX0 = 7'b0001110;
+ 4'h0: HEX0 = 7'b1000000;
+ endcase // case (SW)
+ end
+
+endmodule
diff --git a/examples/intel/MAX10/top.v b/examples/intel/MAX10/top.v
new file mode 100644
index 00000000..2bada0e2
--- /dev/null
+++ b/examples/intel/MAX10/top.v
@@ -0,0 +1,15 @@
+`default_nettype none
+module top ( output wire [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5, HEX6, HEX7,
+ input wire [15:0] SW );
+
+
+ sevenseg UUD0 (.HEX0(HEX0), .SW(4'h7));
+ sevenseg UUD1 (.HEX0(HEX1), .SW(4'h1));
+ sevenseg UUD2 (.HEX0(HEX2), .SW(4'h0));
+ sevenseg UUD3 (.HEX0(HEX3), .SW(4'h2));
+ sevenseg UUD4 (.HEX0(HEX4), .SW(SW[3:0]));
+ sevenseg UUD5 (.HEX0(HEX5), .SW(SW[7:4]));
+ sevenseg UUD6 (.HEX0(HEX6), .SW(SW[11:8]));
+ sevenseg UUD7 (.HEX0(HEX7), .SW(SW[15:12]));
+
+endmodule
diff --git a/examples/intel/asicworld_lfsr/README b/examples/intel/asicworld_lfsr/README
new file mode 100644
index 00000000..ba365fab
--- /dev/null
+++ b/examples/intel/asicworld_lfsr/README
@@ -0,0 +1,6 @@
+Source of the files:
+http://www.asic-world.com/examples/verilog/lfsr.html
+
+Run first: runme_presynth
+Generate output netlist with run_max10 or run_cycloneiv
+Then, check with: runme_postsynth
diff --git a/examples/intel/asicworld_lfsr/lfsr_updown.v b/examples/intel/asicworld_lfsr/lfsr_updown.v
new file mode 100644
index 00000000..43db1606
--- /dev/null
+++ b/examples/intel/asicworld_lfsr/lfsr_updown.v
@@ -0,0 +1,35 @@
+`default_nettype none
+module lfsr_updown (
+clk , // Clock input
+reset , // Reset input
+enable , // Enable input
+up_down , // Up Down input
+count , // Count output
+overflow // Overflow output
+);
+
+ input clk;
+ input reset;
+ input enable;
+ input up_down;
+
+ output [7 : 0] count;
+ output overflow;
+
+ reg [7 : 0] count;
+
+ assign overflow = (up_down) ? (count == {{7{1'b0}}, 1'b1}) :
+ (count == {1'b1, {7{1'b0}}}) ;
+
+ always @(posedge clk)
+ if (reset)
+ count <= {7{1'b0}};
+ else if (enable) begin
+ if (up_down) begin
+ count <= {~(^(count & 8'b01100011)),count[7:1]};
+ end else begin
+ count <= {count[5:0],~(^(count & 8'b10110001))};
+ end
+ end
+
+endmodule
diff --git a/examples/intel/asicworld_lfsr/lfsr_updown_tb.v b/examples/intel/asicworld_lfsr/lfsr_updown_tb.v
new file mode 100644
index 00000000..db29e60f
--- /dev/null
+++ b/examples/intel/asicworld_lfsr/lfsr_updown_tb.v
@@ -0,0 +1,34 @@
+module tb();
+ reg clk;
+ reg reset;
+ reg enable;
+ reg up_down;
+
+ wire [7 : 0] count;
+ wire overflow;
+
+initial begin
+ $monitor("rst %b en %b updown %b cnt %b overflow %b",
+ reset,enable,up_down,count, overflow);
+ clk = 0;
+ reset = 1;
+ enable = 0;
+ up_down = 0;
+ #10 reset = 0;
+ #1 enable = 1;
+ #20 up_down = 1;
+ #30 $finish;
+end
+
+always #1 clk = ~clk;
+
+lfsr_updown U(
+.clk ( clk ),
+.reset ( reset ),
+.enable ( enable ),
+.up_down ( up_down ),
+.count ( count ),
+.overflow ( overflow )
+);
+
+endmodule
diff --git a/examples/intel/asicworld_lfsr/run_cycloneiv b/examples/intel/asicworld_lfsr/run_cycloneiv
new file mode 100755
index 00000000..c7498bde
--- /dev/null
+++ b/examples/intel/asicworld_lfsr/run_cycloneiv
@@ -0,0 +1,2 @@
+#!/bin/env bash
+yosys -p "synth_intel -family cycloneiv -top lfsr_updown -vqm top.vqm" lfsr_updown.v
diff --git a/examples/intel/asicworld_lfsr/run_max10 b/examples/intel/asicworld_lfsr/run_max10
new file mode 100755
index 00000000..b75d552b
--- /dev/null
+++ b/examples/intel/asicworld_lfsr/run_max10
@@ -0,0 +1,2 @@
+#!/bin/env bash
+yosys -p "synth_intel -family max10 -top lfsr_updown -vqm top.vqm" lfsr_updown.v
diff --git a/examples/intel/asicworld_lfsr/runme_postsynth b/examples/intel/asicworld_lfsr/runme_postsynth
new file mode 100755
index 00000000..c3b26b03
--- /dev/null
+++ b/examples/intel/asicworld_lfsr/runme_postsynth
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+iverilog -D POST_IMPL -o verif_post -s tb lfsr_updown_tb.v top.vqm $(yosys-config --datdir/altera_intel/max10/cells_comb_max10.v)
+vvp -N verif_post
+
diff --git a/examples/intel/asicworld_lfsr/runme_presynth b/examples/intel/asicworld_lfsr/runme_presynth
new file mode 100755
index 00000000..51118bb4
--- /dev/null
+++ b/examples/intel/asicworld_lfsr/runme_presynth
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+iverilog -o presynth lfsr_updown_tb.v lfsr_updown.v &&\
+
+vvp -N presynth \ No newline at end of file
diff --git a/examples/osu035/.gitignore b/examples/osu035/.gitignore
new file mode 100644
index 00000000..3abf340b
--- /dev/null
+++ b/examples/osu035/.gitignore
@@ -0,0 +1,3 @@
+osu035_stdcells.lib
+example.yslog
+example.edif
diff --git a/examples/osu035/Makefile b/examples/osu035/Makefile
new file mode 100644
index 00000000..2bb8162b
--- /dev/null
+++ b/examples/osu035/Makefile
@@ -0,0 +1,13 @@
+
+example.edif: example.ys example.v example.constr osu035_stdcells.lib
+ yosys -l example.yslog -q example.ys
+
+osu035_stdcells.lib:
+ rm -f osu035_stdcells.lib.part osu035_stdcells.lib
+ wget -O osu035_stdcells.lib.part https://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/ami035/signalstorm/osu035_stdcells.lib
+ mv osu035_stdcells.lib.part osu035_stdcells.lib
+
+clean:
+ rm -f osu035_stdcells.lib
+ rm -f example.yslog example.edif
+
diff --git a/examples/osu035/example.constr b/examples/osu035/example.constr
new file mode 100644
index 00000000..eb2c6e8d
--- /dev/null
+++ b/examples/osu035/example.constr
@@ -0,0 +1,2 @@
+set_driving_cell INVX1
+set_load 0.015
diff --git a/examples/osu035/example.v b/examples/osu035/example.v
new file mode 100644
index 00000000..0f043e5f
--- /dev/null
+++ b/examples/osu035/example.v
@@ -0,0 +1,3 @@
+module top (input clk, input [7:0] a, b, output reg [15:0] c);
+ always @(posedge clk) c <= a * b;
+endmodule
diff --git a/examples/osu035/example.ys b/examples/osu035/example.ys
new file mode 100644
index 00000000..6821ef42
--- /dev/null
+++ b/examples/osu035/example.ys
@@ -0,0 +1,11 @@
+read_verilog example.v
+read_liberty -lib osu035_stdcells.lib
+
+synth -top top
+
+dfflibmap -liberty osu035_stdcells.lib
+abc -D 10000 -constr example.constr -liberty osu035_stdcells.lib
+opt_clean
+
+stat -liberty osu035_stdcells.lib
+write_edif example.edif
diff --git a/examples/smtbmc/.gitignore b/examples/smtbmc/.gitignore
index a3f4f0f2..278f5ebf 100644
--- a/examples/smtbmc/.gitignore
+++ b/examples/smtbmc/.gitignore
@@ -20,3 +20,5 @@ demo6.smt2
demo6.yslog
demo7.smt2
demo7.yslog
+demo8.smt2
+demo8.yslog
diff --git a/examples/smtbmc/Makefile b/examples/smtbmc/Makefile
index 2f7060bd..96fa058d 100644
--- a/examples/smtbmc/Makefile
+++ b/examples/smtbmc/Makefile
@@ -1,5 +1,5 @@
-all: demo1 demo2 demo3 demo4 demo5 demo6 demo7
+all: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8
demo1: demo1.smt2
yosys-smtbmc --dump-vcd demo1.vcd demo1.smt2
@@ -25,6 +25,9 @@ demo6: demo6.smt2
demo7: demo7.smt2
yosys-smtbmc -t 10 demo7.smt2
+demo8: demo8.smt2
+ yosys-smtbmc -s z3 -t 1 -g demo8.smt2
+
demo1.smt2: demo1.v
yosys -ql demo1.yslog -p 'read_verilog -formal demo1.v; prep -top demo1 -nordff; write_smt2 -wires demo1.smt2'
@@ -46,6 +49,9 @@ demo6.smt2: demo6.v
demo7.smt2: demo7.v
yosys -ql demo7.yslog -p 'read_verilog -formal demo7.v; prep -top demo7 -nordff; write_smt2 -wires demo7.smt2'
+demo8.smt2: demo8.v
+ yosys -ql demo8.yslog -p 'read_verilog -formal demo8.v; prep -top demo8 -nordff; write_smt2 -stbv -wires demo8.smt2'
+
clean:
rm -f demo1.yslog demo1.smt2 demo1.vcd
rm -f demo2.yslog demo2.smt2 demo2.vcd demo2.smtc demo2_tb.v demo2_tb demo2_tb.vcd
@@ -54,6 +60,7 @@ clean:
rm -f demo5.yslog demo5.smt2 demo5.vcd
rm -f demo6.yslog demo6.smt2
rm -f demo7.yslog demo7.smt2
+ rm -f demo8.yslog demo8.smt2
-.PHONY: demo1 demo2 demo3 demo4 demo5 demo6 demo7 clean
+.PHONY: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8 clean
diff --git a/examples/smtbmc/demo2.v b/examples/smtbmc/demo2.v
index 34745e89..0cf529a4 100644
--- a/examples/smtbmc/demo2.v
+++ b/examples/smtbmc/demo2.v
@@ -9,7 +9,7 @@
module demo2(input clk, input [4:0] addr, output reg [31:0] data);
reg [31:0] mem [0:31];
- always @(posedge clk)
+ always @(negedge clk)
data <= mem[addr];
reg [31:0] used_addr = 0;
diff --git a/examples/smtbmc/demo8.v b/examples/smtbmc/demo8.v
new file mode 100644
index 00000000..c4c396cd
--- /dev/null
+++ b/examples/smtbmc/demo8.v
@@ -0,0 +1,12 @@
+// Simple exists-forall demo
+
+module demo8;
+ wire [7:0] prime = $anyconst;
+ wire [3:0] factor = $allconst;
+
+ always @* begin
+ if (1 < factor && factor < prime)
+ assume((prime % factor) != 0);
+ assume(prime > 1);
+ end
+endmodule
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 92513a24..e79be953 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -44,7 +44,7 @@ namespace AST {
// instanciate global variables (private API)
namespace AST_INTERNAL {
- bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
+ bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
@@ -84,6 +84,9 @@ std::string AST::type2str(AstNodeType type)
X(AST_PREFIX)
X(AST_ASSERT)
X(AST_ASSUME)
+ X(AST_LIVE)
+ X(AST_FAIR)
+ X(AST_COVER)
X(AST_FCALL)
X(AST_TO_BITS)
X(AST_TO_SIGNED)
@@ -168,8 +171,8 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
AstNode *attr = attributes.at(id);
if (attr->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- id.c_str(), attr->filename.c_str(), attr->linenum);
+ log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n",
+ id.c_str());
return attr->integer != 0;
}
@@ -188,8 +191,10 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
is_input = false;
is_output = false;
is_reg = false;
+ is_logic = false;
is_signed = false;
is_string = false;
+ was_checked = false;
range_valid = false;
range_swapped = false;
port_id = 0;
@@ -209,7 +214,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
}
// create a (deep recursive) copy of a node
-AstNode *AstNode::clone()
+AstNode *AstNode::clone() const
{
AstNode *that = new AstNode;
*that = *this;
@@ -221,7 +226,7 @@ AstNode *AstNode::clone()
}
// create a (deep recursive) copy of a node use 'other' as target root node
-void AstNode::cloneInto(AstNode *other)
+void AstNode::cloneInto(AstNode *other) const
{
AstNode *tmp = clone();
other->delete_children();
@@ -251,7 +256,7 @@ AstNode::~AstNode()
// create a nice text representation of the node
// (traverse tree by recursion, use 'other' pointer for diffing two AST trees)
-void AstNode::dumpAst(FILE *f, std::string indent)
+void AstNode::dumpAst(FILE *f, std::string indent) const
{
if (f == NULL) {
for (auto f : log_files)
@@ -262,10 +267,12 @@ void AstNode::dumpAst(FILE *f, std::string indent)
std::string type_name = type2str(type);
fprintf(f, "%s%s <%s:%d>", indent.c_str(), type_name.c_str(), filename.c_str(), linenum);
- if (id2ast)
- fprintf(f, " [%p -> %p]", this, id2ast);
- else
- fprintf(f, " [%p]", this);
+ if (!flag_no_dump_ptr) {
+ if (id2ast)
+ fprintf(f, " [%p -> %p]", this, id2ast);
+ else
+ fprintf(f, " [%p]", this);
+ }
if (!str.empty())
fprintf(f, " str='%s'", str.c_str());
@@ -282,7 +289,9 @@ void AstNode::dumpAst(FILE *f, std::string indent)
fprintf(f, " input");
if (is_output)
fprintf(f, " output");
- if (is_reg)
+ if (is_logic)
+ fprintf(f, " logic");
+ if (is_reg) // this is an AST dump, not Verilog - if we see "logic reg" that's fine.
fprintf(f, " reg");
if (is_signed)
fprintf(f, " signed");
@@ -330,7 +339,7 @@ static std::string id2vl(std::string txt)
}
// dump AST node as Verilog pseudo-code
-void AstNode::dumpVlog(FILE *f, std::string indent)
+void AstNode::dumpVlog(FILE *f, std::string indent) const
{
bool first = true;
std::string txt;
@@ -649,6 +658,8 @@ bool AstNode::operator==(const AstNode &other) const
return false;
if (is_output != other.is_output)
return false;
+ if (is_logic != other.is_logic)
+ return false;
if (is_reg != other.is_reg)
return false;
if (is_signed != other.is_signed)
@@ -752,7 +763,7 @@ AstNode *AstNode::mkconst_str(const std::string &str)
return node;
}
-bool AstNode::bits_only_01()
+bool AstNode::bits_only_01() const
{
for (auto bit : bits)
if (bit != RTLIL::S0 && bit != RTLIL::S1)
@@ -803,7 +814,7 @@ RTLIL::Const AstNode::asParaConst()
return val;
}
-bool AstNode::asBool()
+bool AstNode::asBool() const
{
log_assert(type == AST_CONSTANT);
for (auto &bit : bits)
@@ -812,7 +823,7 @@ bool AstNode::asBool()
return false;
}
-int AstNode::isConst()
+int AstNode::isConst() const
{
if (type == AST_CONSTANT)
return 1;
@@ -952,8 +963,8 @@ static AstModule* process_module(AstNode *ast, bool defer)
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), ast->filename.c_str(), ast->linenum);
+ log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
current_module->attributes[attr.first] = attr.second->asAttrConst();
}
for (size_t i = 0; i < ast->children.size(); i++) {
@@ -999,12 +1010,13 @@ 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 dump_rtlil,
- bool nolatches, bool nomeminit, 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 no_dump_ptr, bool dump_vlog, bool dump_rtlil,
+ bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
+ flag_no_dump_ptr = no_dump_ptr;
flag_dump_vlog = dump_vlog;
flag_dump_rtlil = dump_rtlil;
flag_nolatches = nolatches;
@@ -1016,14 +1028,12 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
flag_icells = icells;
flag_autowire = autowire;
- std::vector<AstNode*> global_decls;
-
log_assert(current_ast->type == AST_DESIGN);
for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)
{
if ((*it)->type == AST_MODULE)
{
- for (auto n : global_decls)
+ for (auto n : design->verilog_globals)
(*it)->children.push_back(n->clone());
for (auto n : design->verilog_packages){
@@ -1041,12 +1051,20 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
(*it)->str = "$abstract" + (*it)->str;
if (design->has((*it)->str)) {
- if (!ignore_redef)
- log_error("Re-definition of module `%s' at %s:%d!\n",
+ RTLIL::Module *existing_mod = design->module((*it)->str);
+ if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
+ log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n",
+ (*it)->str.c_str());
+ } else if (nooverwrite) {
+ log("Ignoring re-definition of module `%s' at %s:%d.\n",
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
- log("Ignoring re-definition of module `%s' at %s:%d!\n",
- (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
- continue;
+ continue;
+ } else {
+ log("Replacing existing%s module `%s' at %s:%d.\n",
+ existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "",
+ (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
+ design->remove(existing_mod);
+ }
}
design->add(process_module(*it, defer));
@@ -1054,7 +1072,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
else if ((*it)->type == AST_PACKAGE)
design->verilog_packages.push_back((*it)->clone());
else
- global_decls.push_back(*it);
+ design->verilog_globals.push_back((*it)->clone());
}
}
@@ -1066,7 +1084,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, dict<RTLIL::IdString, RTLIL::Const> parameters)
+RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool)
{
std::string stripped_name = name.str();
@@ -1105,7 +1123,10 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
rewrite_parameter:
para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
delete child->children.at(0);
- child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0);
+ if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0)
+ child->children[0] = AstNode::mkconst_str(parameters[para_id].decode_string());
+ else
+ child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0);
parameters.erase(para_id);
continue;
}
@@ -1115,8 +1136,16 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
goto rewrite_parameter;
}
}
- if (parameters.size() > 0)
- log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), stripped_name.c_str());
+
+ for (auto param : parameters) {
+ AstNode *defparam = new AstNode(AST_DEFPARAM, new AstNode(AST_IDENTIFIER));
+ defparam->children[0]->str = param.first.str();
+ if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0)
+ defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string()));
+ else
+ defparam->children.push_back(AstNode::mkconst_bits(param.second.bits, (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0));
+ new_ast->children.push_back(defparam);
+ }
std::string modname;
@@ -1177,4 +1206,3 @@ void AST::use_internal_line_num()
}
YOSYS_NAMESPACE_END
-
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index cd6e264e..7e97bdb3 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -1,4 +1,4 @@
-/*
+/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
@@ -65,6 +65,9 @@ namespace AST
AST_PREFIX,
AST_ASSERT,
AST_ASSUME,
+ AST_LIVE,
+ AST_FAIR,
+ AST_COVER,
AST_FCALL,
AST_TO_BITS,
@@ -165,7 +168,7 @@ namespace AST
// node content - most of it is unused in most node types
std::string str;
std::vector<RTLIL::State> bits;
- bool is_input, is_output, is_reg, is_signed, is_string, range_valid, range_swapped;
+ bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked;
int port_id, range_left, range_right;
uint32_t integer;
double realvalue;
@@ -187,8 +190,8 @@ namespace AST
// creating and deleting nodes
AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL, AstNode *child3 = NULL);
- AstNode *clone();
- void cloneInto(AstNode *other);
+ AstNode *clone() const;
+ void cloneInto(AstNode *other) const;
void delete_children();
~AstNode();
@@ -231,8 +234,8 @@ namespace AST
AstNode *eval_const_function(AstNode *fcall);
// create a human-readable text representation of the AST (for debugging)
- void dumpAst(FILE *f, std::string indent);
- void dumpVlog(FILE *f, std::string indent);
+ void dumpAst(FILE *f, std::string indent) const;
+ void dumpVlog(FILE *f, std::string indent) const;
// used by genRTLIL() for detecting expression width and sign
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);
@@ -261,27 +264,27 @@ namespace AST
RTLIL::Const asAttrConst();
RTLIL::Const asParaConst();
uint64_t asInt(bool is_signed);
- bool bits_only_01();
- bool asBool();
+ bool bits_only_01() const;
+ bool asBool() const;
// helper functions for real valued const eval
- int isConst(); // return '1' for AST_CONSTANT and '2' for AST_REALVALUE
+ int isConst() const; // return '1' for AST_CONSTANT and '2' for AST_REALVALUE
double asReal(bool is_signed);
RTLIL::Const realAsConst(int width);
};
// 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 dump_rtlil, bool nolatches, bool nomeminit,
- 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 no_dump_ptr, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit,
+ bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
- virtual ~AstModule();
- virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
- virtual RTLIL::Module *clone() const;
+ ~AstModule() YS_OVERRIDE;
+ RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
+ RTLIL::Module *clone() const YS_OVERRIDE;
};
// this must be set by the language frontend before parsing the sources
@@ -302,7 +305,7 @@ namespace AST
namespace AST_INTERNAL
{
// internal state variables
- extern bool flag_dump_ast1, flag_dump_ast2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
+ extern bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
extern bool 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;
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index db8d7409..0f7e910f 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -55,8 +55,8 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
if (gen_attributes)
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), that->filename.c_str(), that->linenum);
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -89,8 +89,8 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
if (that != NULL)
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), that->filename.c_str(), that->linenum);
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -117,8 +117,8 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_wi
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), that->filename.c_str(), that->linenum);
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -152,8 +152,8 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), that->filename.c_str(), that->linenum);
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -207,8 +207,8 @@ struct AST_INTERNAL::ProcessGenerator
proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, autoidx++);
for (auto &attr : always->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), always->filename.c_str(), always->linenum);
+ log_file_error(always->filename, always->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
proc->attributes[attr.first] = attr.second->asAttrConst();
}
current_module->processes[proc->name] = proc;
@@ -223,16 +223,22 @@ struct AST_INTERNAL::ProcessGenerator
bool found_global_syncs = false;
bool found_anyedge_syncs = false;
for (auto child : always->children)
+ {
+ if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER &&
+ child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute("\\gclk")) {
+ found_global_syncs = true;
+ }
if (child->type == AST_EDGE) {
if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->str == "\\$global_clock")
found_global_syncs = true;
else
found_anyedge_syncs = true;
}
+ }
if (found_anyedge_syncs) {
if (found_global_syncs)
- log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum);
+ log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n");
log("Note: Assuming pure combinatorial block at %s:%d in\n", always->filename.c_str(), always->linenum);
log("compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending\n");
log("use of @* instead of @(...) for better match of synthesis and simulation.\n");
@@ -242,14 +248,17 @@ struct AST_INTERNAL::ProcessGenerator
bool found_clocked_sync = false;
for (auto child : always->children)
if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) {
+ if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast &&
+ child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute("\\gclk"))
+ continue;
found_clocked_sync = true;
if (found_global_syncs || found_anyedge_syncs)
- log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum);
+ log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n");
RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn;
syncrule->signal = child->children[0]->genRTLIL();
if (GetSize(syncrule->signal) != 1)
- log_error("Found posedge/negedge event on a signal that is not 1 bit wide at %s:%d!\n", always->filename.c_str(), always->linenum);
+ log_file_error(always->filename, always->linenum, "Found posedge/negedge event on a signal that is not 1 bit wide!\n");
addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
proc->syncs.push_back(syncrule);
}
@@ -471,8 +480,8 @@ struct AST_INTERNAL::ProcessGenerator
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), ast->filename.c_str(), ast->linenum);
+ log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
sw->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -540,12 +549,12 @@ struct AST_INTERNAL::ProcessGenerator
break;
case AST_WIRE:
- log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
+ log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n");
break;
case AST_PARAMETER:
case AST_LOCALPARAM:
- log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
+ log_file_error(ast->filename, ast->linenum, "Found parameter declaration in block without label!\n");
break;
case AST_NONE:
@@ -554,6 +563,8 @@ struct AST_INTERNAL::ProcessGenerator
break;
default:
+ // ast->dumpAst(NULL, "ast> ");
+ // current_ast_mod->dumpAst(NULL, "mod> ");
log_abort();
}
}
@@ -591,7 +602,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (id_ast == NULL && current_scope.count(str))
id_ast = current_scope.at(str);
if (!id_ast)
- log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str());
if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) {
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;
@@ -601,7 +612,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (id_ast->children[0]->type == AST_CONSTANT)
this_width = id_ast->children[0]->bits.size();
else
- log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width for parameter %s!\n", str.c_str());
if (children.size() != 0)
range = children[0];
} else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) {
@@ -613,7 +624,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
// log("---\n");
// id_ast->dumpAst(NULL, "decl> ");
// dumpAst(NULL, "ref> ");
- log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of signal access `%s'!\n", str.c_str());
}
} else {
this_width = id_ast->range_left - id_ast->range_right + 1;
@@ -624,10 +635,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
this_width = 32;
} else if (id_ast->type == AST_MEMORY) {
if (!id_ast->children[0]->range_valid)
- log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
} else
- log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) {
if (range->children.size() == 1)
this_width = 1;
@@ -637,8 +648,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
+ str.c_str());
this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
delete left_at_zero_ast;
delete right_at_zero_ast;
@@ -654,7 +665,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_TO_BITS:
while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { }
if (children[0]->type != AST_CONSTANT)
- log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left operand of tobits expression is not constant!\n");
children[1]->detectSignWidthWorker(sub_width_hint, sign_hint);
width_hint = max(width_hint, children[0]->bitsAsConst().as_int());
break;
@@ -682,7 +693,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_REPLICATE:
while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
if (children[0]->type != AST_CONSTANT)
- log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n");
children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
sign_hint = false;
@@ -756,18 +767,18 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id2ast->is_signed)
sign_hint = false;
if (!id2ast->children[0]->range_valid)
- log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1;
width_hint = max(width_hint, this_width);
break;
case AST_FCALL:
- if (str == "\\$anyconst" || str == "\\$anyseq") {
+ if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") {
if (GetSize(children) == 1) {
while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
if (children[0]->type != AST_CONSTANT)
- log_error("System function %s called with non-const argument at %s:%d!\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
+ RTLIL::unescape_id(str).c_str());
width_hint = max(width_hint, int(children[0]->asInt(true)));
}
break;
@@ -788,8 +799,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
default:
for (auto f : log_files)
current_ast->dumpAst(f, "verilog-ast> ");
- log_error("Don't know how to detect sign and width for %s node at %s:%d!\n",
- type2str(type).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n",
+ type2str(type).c_str());
}
if (*found_real)
@@ -852,11 +863,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// create an RTLIL::Wire for an AST_WIRE node
case AST_WIRE: {
if (current_module->wires_.count(str) != 0)
- log_error("Re-definition of signal `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Re-definition of signal `%s'!\n",
+ str.c_str());
if (!range_valid)
- log_error("Signal `%s' with non-constant width at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n",
+ str.c_str());
log_assert(range_left >= range_right || (range_left == -1 && range_right == 0));
@@ -870,8 +881,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
wire->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -880,16 +891,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// create an RTLIL::Memory for an AST_MEMORY node
case AST_MEMORY: {
if (current_module->memories.count(str) != 0)
- log_error("Re-definition of memory `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Re-definition of memory `%s'!\n",
+ str.c_str());
log_assert(children.size() >= 2);
log_assert(children[0]->type == AST_RANGE);
log_assert(children[1]->type == AST_RANGE);
if (!children[0]->range_valid || !children[1]->range_valid)
- log_error("Memory `%s' with non-constant width or size at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n",
+ str.c_str());
RTLIL::Memory *memory = new RTLIL::Memory;
memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -906,8 +917,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
memory->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -926,8 +937,8 @@ 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",
- realvalue, log_signal(sig), filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "converting real value %e to binary %s.\n",
+ realvalue, log_signal(sig));
return sig;
}
@@ -947,25 +958,25 @@ 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_file_warning(filename, linenum, "Identifier `%s' is implicitly declared.\n", str.c_str());
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);
+ log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
}
else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) {
if (id2ast->children[0]->type != AST_CONSTANT)
- log_error("Parameter %s does not evaluate to constant value at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n",
+ str.c_str());
chunk = RTLIL::Const(id2ast->children[0]->bits);
goto use_const_chunk;
}
else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE &&
id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0)
- log_error("Identifier `%s' doesn't map to any signal at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n",
+ str.c_str());
if (id2ast->type == AST_MEMORY)
- log_error("Identifier `%s' does map to an unexpanded memory at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n",
+ str.c_str());
wire = current_module->wires_[str];
chunk.wire = wire;
@@ -983,8 +994,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
+ str.c_str());
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
children[0]->children[1]->clone() : children[0]->children[0]->clone());
@@ -1012,11 +1023,11 @@ 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",
- str.c_str(), filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
+ str.c_str());
else
- 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);
+ log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting all %d result bits to undef.\n",
+ str.c_str(), chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
if (chunk.width + chunk.offset > source_width) {
@@ -1029,11 +1040,11 @@ 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",
- str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb);
+ log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
+ str.c_str(), add_undef_bits_lsb);
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",
- str.c_str(), filename.c_str(), linenum, add_undef_bits_msb);
+ log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
+ str.c_str(), add_undef_bits_msb);
}
}
}
@@ -1072,7 +1083,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::SigSpec left = children[0]->genRTLIL();
RTLIL::SigSpec right = children[1]->genRTLIL();
if (!left.is_fully_const())
- log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n");
int count = left.as_int();
RTLIL::SigSpec sig;
for (int i = 0; i < count; i++)
@@ -1289,6 +1300,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0);
+ if (!sign_hint)
+ is_signed = false;
+
return RTLIL::SigSpec(wire);
}
@@ -1308,7 +1322,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
int num_words = 1;
if (type == AST_MEMINIT) {
if (children[2]->type != AST_CONSTANT)
- log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Memory init with non-constant word count!\n");
num_words = int(children[2]->asInt(false));
cell->parameters["\\WORDS"] = RTLIL::Const(num_words);
}
@@ -1336,9 +1350,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// generate $assert cells
case AST_ASSERT:
case AST_ASSUME:
+ case AST_LIVE:
+ case AST_FAIR:
+ case AST_COVER:
{
- const char *celltype = "$assert";
+ const char *celltype = nullptr;
+ if (type == AST_ASSERT) celltype = "$assert";
if (type == AST_ASSUME) celltype = "$assume";
+ if (type == AST_LIVE) celltype = "$live";
+ if (type == AST_FAIR) celltype = "$fair";
+ if (type == AST_COVER) celltype = "$cover";
log_assert(children.size() == 2);
@@ -1358,8 +1379,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -1380,10 +1401,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
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));
+ log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n"
+ " old assignment: %s = %s\n new assignment: %s = %s.\n",
+ log_signal(left), log_signal(right),
+ log_signal(new_left), log_signal(new_right));
left = new_left;
right = new_right;
}
@@ -1397,8 +1418,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
int port_counter = 0, para_counter = 0;
if (current_module->count_id(str) != 0)
- log_error("Re-definition of cell `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Re-definition of cell `%s'!\n", str.c_str());
RTLIL::Cell *cell = current_module->addCell(str, "");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -1414,16 +1434,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (child->type == AST_PARASET) {
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);
+ log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
+ log_id(cell), log_id(paraname), child->children[0]->realvalue);
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);
+ log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
+ log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst();
continue;
}
@@ -1444,8 +1463,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -1466,30 +1485,37 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
} break;
case AST_FCALL: {
- if (str == "\\$anyconst" || str == "\\$anyseq")
+ if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq")
{
string myid = stringf("%s$%d", str.c_str() + 1, autoidx++);
int width = width_hint;
if (GetSize(children) > 1)
- log_error("System function %s got %d arguments, expected 1 or 0 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), GetSize(children), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n",
+ RTLIL::unescape_id(str).c_str(), GetSize(children));
if (GetSize(children) == 1) {
if (children[0]->type != AST_CONSTANT)
- log_error("System function %s called with non-const argument at %s:%d!\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
+ RTLIL::unescape_id(str).c_str());
width = children[0]->asInt(true);
}
if (width <= 0)
- log_error("Failed to detect width of %s at %s:%d!\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of %s!\n",
+ RTLIL::unescape_id(str).c_str());
Cell *cell = current_module->addCell(myid, str.substr(1));
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
cell->parameters["\\WIDTH"] = width;
+ if (attributes.count("\\reg")) {
+ auto &attr = attributes.at("\\reg");
+ if (attr->type != AST_CONSTANT)
+ log_file_error(filename, linenum, "Attribute `reg' with non-constant value!\n");
+ cell->attributes["\\reg"] = attr->asAttrConst();
+ }
+
Wire *wire = current_module->addWire(myid + "_wire", width);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
cell->setPort("\\Y", wire);
@@ -1504,8 +1530,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto f : log_files)
current_ast->dumpAst(f, "verilog-ast> ");
type_name = type2str(type);
- log_error("Don't know how to generate RTLIL code for %s node at %s:%d!\n",
- type_name.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n",
+ type_name.c_str());
}
return RTLIL::SigSpec();
@@ -1535,4 +1561,3 @@ RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL
}
YOSYS_NAMESPACE_END
-
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 9d5c75fe..04c429f7 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -177,13 +177,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list
if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" ||
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);
+ log_file_warning(filename, linenum, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str());
delete_children();
str = std::string();
}
if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) {
- log_warning("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str());
delete_children();
str = std::string();
}
@@ -195,14 +195,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
int nargs = GetSize(children);
if (nargs < 1)
- log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n",
- str.c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' got %d arguments, expected >= 1.\n",
+ str.c_str(), int(children.size()));
// First argument is the format string
AstNode *node_string = children[0];
while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_string->type != AST_CONSTANT)
- log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str());
std::string sformat = node_string->bitsAsConst().decode_string();
// Other arguments are placeholders. Process the string as we go through it
@@ -215,7 +215,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
// If there's no next character, that's a problem
if (i+1 >= sformat.length())
- log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str());
char cformat = sformat[++i];
@@ -239,13 +239,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
case 'x':
case 'X':
if (next_arg >= GetSize(children))
- log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n",
- cformat, str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n",
+ cformat, str.c_str());
node_arg = children[next_arg++];
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_arg->type != AST_CONSTANT)
- log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str());
break;
case 'm':
@@ -253,7 +253,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
break;
default:
- log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str());
break;
}
@@ -327,6 +327,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (node->type == AST_WIRE) {
if (this_wire_scope.count(node->str) > 0) {
AstNode *first_node = this_wire_scope[node->str];
+ if (first_node->is_input && node->is_reg)
+ goto wires_are_incompatible;
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) {
@@ -361,6 +363,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
first_node->is_output = true;
if (node->is_reg)
first_node->is_reg = true;
+ if (node->is_logic)
+ first_node->is_logic = true;
if (node->is_signed)
first_node->is_signed = true;
for (auto &it : node->attributes) {
@@ -374,7 +378,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
continue;
wires_are_incompatible:
if (stage > 1)
- log_error("Incompatible re-declaration of wire %s at %s:%d.\n", node->str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", node->str.c_str());
continue;
}
this_wire_scope[node->str] = node;
@@ -387,7 +391,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i];
- if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE)
+ if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY)
while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM))
did_something = true;
}
@@ -401,13 +405,20 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_ALWAYS || type == AST_INITIAL)
{
+ if (current_always != nullptr)
+ log_file_error(filename, linenum, "Invalid nesting of always blocks and/or initializations.\n");
+
current_always = this;
current_always_clocked = false;
if (type == AST_ALWAYS)
- for (auto child : children)
+ for (auto child : children) {
if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE)
current_always_clocked = true;
+ if (child->type == AST_EDGE && GetSize(child->children) == 1 &&
+ child->children[0]->type == AST_IDENTIFIER && child->children[0]->str == "\\$global_clock")
+ current_always_clocked = true;
+ }
}
int backup_width_hint = width_hint;
@@ -433,6 +444,16 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
children[1]->detectSignWidth(width_hint, sign_hint);
width_hint = max(width_hint, backup_width_hint);
child_0_is_self_determined = true;
+ // test only once, before optimizations and memory mappings but after assignment LHS was mapped to an identifier
+ if (children[0]->id2ast && !children[0]->was_checked) {
+ if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->id2ast->is_logic)
+ children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment
+ if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg)
+ log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum);
+ if (type == AST_ASSIGN && children[0]->id2ast->is_reg)
+ log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum);
+ children[0]->was_checked = true;
+ }
break;
case AST_PARAMETER:
@@ -444,7 +465,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true)
did_something = true;
if (!children[1]->range_valid)
- log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n");
width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);
}
break;
@@ -685,26 +706,47 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
current_scope.clear();
// convert defparam nodes to cell parameters
- if (type == AST_DEFPARAM && !str.empty()) {
- size_t pos = str.rfind('.');
+ if (type == AST_DEFPARAM && !children.empty())
+ {
+ if (children[0]->type != AST_IDENTIFIER)
+ log_file_error(filename, linenum, "Module name in defparam contains non-constant expressions!\n");
+
+ string modname, paramname = children[0]->str;
+
+ size_t pos = paramname.rfind('.');
+
+ while (pos != 0 && pos != std::string::npos)
+ {
+ modname = paramname.substr(0, pos);
+
+ if (current_scope.count(modname))
+ break;
+
+ pos = paramname.rfind('.', pos - 1);
+ }
+
if (pos == std::string::npos)
- log_error("Defparam `%s' does not contain a dot (module/parameter separator) at %s:%d!\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
- std::string modname = str.substr(0, pos), paraname = "\\" + str.substr(pos+1);
- if (current_scope.count(modname) == 0 || current_scope.at(modname)->type != AST_CELL)
- log_error("Can't find cell for defparam `%s . %s` at %s:%d!\n", RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paraname).c_str(), filename.c_str(), linenum);
- AstNode *cell = current_scope.at(modname), *paraset = clone();
+ log_file_error(filename, linenum, "Can't find object for defparam `%s`!\n", RTLIL::unescape_id(paramname).c_str());
+
+ paramname = "\\" + paramname.substr(pos+1);
+
+ if (current_scope.at(modname)->type != AST_CELL)
+ log_file_error(filename, linenum, "Defparam argument `%s . %s` does not match a cell!\n",
+ RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str());
+
+ AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL);
+ paraset->str = paramname;
+
+ AstNode *cell = current_scope.at(modname);
cell->children.insert(cell->children.begin() + 1, paraset);
- paraset->type = AST_PARASET;
- paraset->str = paraname;
- str.clear();
+ delete_children();
}
// resolve constant prefixes
if (type == AST_PREFIX) {
if (children[0]->type != AST_CONSTANT) {
// dumpAst(NULL, "> ");
- log_error("Index in generate block prefix syntax at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Index in generate block prefix syntax is not constant!\n");
}
if (children[1]->type == AST_PREFIX)
children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param);
@@ -720,9 +762,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// evaluate TO_BITS nodes
if (type == AST_TO_BITS) {
if (children[0]->type != AST_CONSTANT)
- log_error("Left operand of to_bits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left operand of to_bits expression is not constant!\n");
if (children[1]->type != AST_CONSTANT)
- log_error("Right operand of to_bits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Right operand of to_bits expression is not constant!\n");
RTLIL::Const new_value = children[1]->bitsAsConst(children[0]->bitsAsConst().as_int(), children[1]->is_signed);
newNode = mkconst_bits(new_value.bits, children[1]->is_signed);
goto apply_newNode;
@@ -786,7 +828,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
multirange_dimensions.clear();
for (auto range : children[1]->children) {
if (!range->range_valid)
- log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant range on memory decl.\n");
multirange_dimensions.push_back(min(range->range_left, range->range_right));
multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);
total_size *= multirange_dimensions.back();
@@ -804,7 +846,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); 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);
+ log_file_error(filename, linenum, "Insufficient number of array indices for %s.\n", log_id(str));
AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone();
@@ -833,12 +875,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_PARAMETER || type == AST_LOCALPARAM) {
if (children.size() > 1 && children[1]->type == AST_RANGE) {
if (!children[1]->range_valid)
- log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n");
int width = std::abs(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",
- children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "converting real value %e to binary %s.\n",
+ children[0]->realvalue, log_signal(constvalue));
delete children[0];
children[0] = mkconst_bits(constvalue.bits, sign_hint);
did_something = true;
@@ -896,7 +938,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue)
{
if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1)
- log_error("Invalid bit-select on memory access at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Invalid bit-select on memory access!\n");
int mem_width, mem_size, addr_bits;
id2ast->meminfo(mem_width, mem_size, addr_bits);
@@ -921,6 +963,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data);
assign->children[0]->str = wire_id;
+ assign->children[0]->was_checked = true;
if (current_block)
{
@@ -945,10 +988,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
if (type == AST_WHILE)
- log_error("While loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n");
if (type == AST_REPEAT)
- log_error("Repeat loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Repeat loops are only allowed in constant functions!\n");
// unroll for loops and generate-for blocks
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
@@ -963,31 +1006,31 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
body_ast = body_ast->children.at(0);
if (init_ast->type != AST_ASSIGN_EQ)
- log_error("Unsupported 1st expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported 1st expression of generate for-loop!\n");
if (next_ast->type != AST_ASSIGN_EQ)
- log_error("Unsupported 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported 3rd expression of generate for-loop!\n");
if (type == AST_GENFOR) {
if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_GENVAR)
- log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a gen var!\n");
if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_GENVAR)
- log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a gen var!\n");
} else {
if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_WIRE)
- log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a register!\n");
if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_WIRE)
- log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a register!\n");
}
if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast)
- log_error("Incompatible left-hand sides in 1st and 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Incompatible left-hand sides in 1st and 3rd expression of generate for-loop!\n");
// eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone();
while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
if (varbuf->type != AST_CONSTANT)
- log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n");
varbuf = new AstNode(AST_LOCALPARAM, varbuf);
varbuf->str = init_ast->children[0]->str;
@@ -1009,7 +1052,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
- log_error("2nd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n");
if (buf->integer == 0) {
delete buf;
@@ -1050,7 +1093,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (buf->simplify(true, false, false, stage, 32, true, false)) { }
if (buf->type != AST_CONSTANT)
- log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n");
delete varbuf->children[0];
varbuf->children[0] = buf;
@@ -1062,6 +1105,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
}
+ // check for local objects in unnamed block
+ if (type == AST_BLOCK && str.empty())
+ {
+ for (size_t i = 0; i < children.size(); i++)
+ if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM)
+ log_file_error(children[i]->filename, children[i]->linenum, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n");
+ }
+
// transform block with name
if (type == AST_BLOCK && !str.empty())
{
@@ -1070,7 +1121,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::vector<AstNode*> new_children;
for (size_t i = 0; i < children.size(); i++)
- if (children[i]->type == AST_WIRE || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) {
+ if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) {
children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(children[i]);
current_scope[children[i]->str] = children[i];
@@ -1107,7 +1158,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
- log_error("Condition for generate if at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Condition for generate if is not constant!\n");
}
if (buf->asBool() != 0) {
delete buf;
@@ -1148,7 +1199,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
- log_error("Condition for generate case at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Condition for generate case is not constant!\n");
}
bool ref_signed = buf->is_signed;
@@ -1182,7 +1233,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
- log_error("Expression in generate case at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Expression in generate case is not constant!\n");
}
bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool();
@@ -1223,7 +1274,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_CELLARRAY)
{
if (!children.at(0)->range_valid)
- log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant array range on cell array.\n");
newNode = new AstNode(AST_GENBLOCK);
int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1;
@@ -1234,7 +1285,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
newNode->children.push_back(new_cell);
new_cell->str += stringf("[%d]", idx);
if (new_cell->type == AST_PRIMITIVE) {
- log_error("Cell arrays of primitives are currently not supported at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Cell arrays of primitives are currently not supported.\n");
} else {
log_assert(new_cell->children.at(0)->type == AST_CELLTYPE);
new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str());
@@ -1248,8 +1299,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_PRIMITIVE)
{
if (children.size() < 2)
- log_error("Insufficient number of arguments for primitive `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n",
+ str.c_str());
std::vector<AstNode*> children_list;
for (auto child : children) {
@@ -1264,8 +1315,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (str == "bufif0" || str == "bufif1" || str == "notif0" || str == "notif1")
{
if (children_list.size() != 3)
- log_error("Invalid number of arguments for primitive `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n",
+ str.c_str());
std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz);
@@ -1350,8 +1401,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
+ str.c_str());
result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
}
did_something = true;
@@ -1370,7 +1421,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 || type == AST_ASSUME) && current_block != NULL)
+ if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && current_block != NULL)
{
std::stringstream sstr;
sstr << "$formal$" << filename << ":" << linenum << "$" << (autoidx++);
@@ -1378,16 +1429,19 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *wire_check = new AstNode(AST_WIRE);
wire_check->str = id_check;
+ wire_check->was_checked = true;
current_ast_mod->children.push_back(wire_check);
current_scope[wire_check->str] = wire_check;
while (wire_check->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_en = new AstNode(AST_WIRE);
wire_en->str = id_en;
+ wire_en->was_checked = true;
current_ast_mod->children.push_back(wire_en);
if (current_always_clocked) {
current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)))));
current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en;
+ current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true;
}
current_scope[wire_en->str] = wire_en;
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
@@ -1397,9 +1451,11 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false));
assign_check->children[0]->str = id_check;
+ assign_check->children[0]->was_checked = true;
AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1));
assign_en->children[0]->str = id_en;
+ assign_en->children[0]->was_checked = true;
AstNode *default_signals = new AstNode(AST_BLOCK);
default_signals->children.push_back(assign_check);
@@ -1408,6 +1464,7 @@ skip_dynamic_range_lvalue_expansion:;
assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone()));
assign_check->children[0]->str = id_check;
+ assign_check->children[0]->was_checked = true;
if (current_always == nullptr || current_always->type != AST_INITIAL) {
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
@@ -1416,6 +1473,7 @@ skip_dynamic_range_lvalue_expansion:;
assign_en->children[1]->str = "\\$initstate";
}
assign_en->children[0]->str = id_en;
+ assign_en->children[0]->was_checked = true;
newNode = new AstNode(AST_BLOCK);
newNode->children.push_back(assign_check);
@@ -1432,7 +1490,7 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
- if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && children.size() == 1)
+ if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && children.size() == 1)
{
children.push_back(mkconst_int(1, false, 1));
did_something = true;
@@ -1524,12 +1582,14 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
wire_addr->str = id_addr;
+ wire_addr->was_checked = true;
current_ast_mod->children.push_back(wire_addr);
current_scope[wire_addr->str] = wire_addr;
while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_data->str = id_data;
+ wire_data->was_checked = true;
wire_data->is_signed = mem_signed;
current_ast_mod->children.push_back(wire_data);
current_scope[wire_data->str] = wire_data;
@@ -1539,6 +1599,7 @@ skip_dynamic_range_lvalue_expansion:;
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;
+ wire_en->was_checked = true;
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)) { }
@@ -1554,14 +1615,17 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false));
assign_addr->children[0]->str = id_addr;
+ assign_addr->children[0]->was_checked = true;
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;
+ assign_data->children[0]->was_checked = true;
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;
+ assign_en->children[0]->was_checked = true;
}
AstNode *default_signals = new AstNode(AST_BLOCK);
@@ -1573,6 +1637,7 @@ skip_dynamic_range_lvalue_expansion:;
assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
assign_addr->children[0]->str = id_addr;
+ assign_addr->children[0]->was_checked = true;
if (children[0]->children.size() == 2)
{
@@ -1587,12 +1652,14 @@ skip_dynamic_range_lvalue_expansion:;
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_data->children[0]->was_checked = true;
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;
+ assign_en->children[0]->was_checked = true;
}
}
else
@@ -1608,12 +1675,13 @@ skip_dynamic_range_lvalue_expansion:;
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
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_data->children[0]->was_checked = true;
if (current_always->type != AST_INITIAL) {
for (int i = 0; i < mem_width; i++)
@@ -1621,6 +1689,7 @@ skip_dynamic_range_lvalue_expansion:;
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;
+ assign_en->children[0]->was_checked = true;
}
delete left_at_zero_ast;
@@ -1632,10 +1701,12 @@ 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_data->children[0]->was_checked = true;
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;
+ assign_en->children[0]->was_checked = true;
}
}
@@ -1700,19 +1771,19 @@ skip_dynamic_range_lvalue_expansion:;
int num_steps = 1;
if (GetSize(children) != 1 && GetSize(children) != 2)
- log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (!current_always_clocked)
- log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n",
+ RTLIL::unescape_id(str).c_str());
if (GetSize(children) == 2)
{
AstNode *buf = children[1]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
- log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str());
num_steps = buf->asInt(true);
delete buf;
@@ -1768,12 +1839,12 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell")
{
if (GetSize(children) != 1)
- log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (!current_always_clocked)
- log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n",
+ RTLIL::unescape_id(str).c_str());
AstNode *present = children.at(0)->clone();
AstNode *past = clone();
@@ -1794,23 +1865,8 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
- if (str == "\\$rose" || str == "\\$fell")
- {
- if (GetSize(children) != 1)
- log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
-
- if (!current_always_clocked)
- log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
-
- newNode = new AstNode(AST_EQ, children.at(0)->clone(), clone());
- newNode->children.at(1)->str = "\\$past";
- goto apply_newNode;
- }
-
// $anyconst and $anyseq are mapped in AstNode::genRTLIL()
- if (str == "\\$anyconst" || str == "\\$anyseq") {
+ if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") {
recursion_counter--;
return false;
}
@@ -1818,13 +1874,13 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$clog2")
{
if (children.size() != 1)
- log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
AstNode *buf = children[0]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
- log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str());
RTLIL::Const arg_value = buf->bitsAsConst();
if (arg_value.as_bool())
@@ -1840,29 +1896,100 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
+ if (str == "\\$size" || str == "\\$bits")
+ {
+ if (str == "\\$bits" && children.size() != 1)
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
+
+ if (str == "\\$size" && children.size() != 1 && children.size() != 2)
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
+
+ int dim = 1;
+ if (str == "\\$size" && children.size() == 2) {
+ AstNode *buf = children[1]->clone();
+ // Evaluate constant expression
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ dim = buf->asInt(false);
+ delete buf;
+ }
+ AstNode *buf = children[0]->clone();
+ int mem_depth = 1;
+ AstNode *id_ast = NULL;
+
+ // Is this needed?
+ //while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ buf->detectSignWidth(width_hint, sign_hint);
+
+ if (buf->type == AST_IDENTIFIER) {
+ id_ast = buf->id2ast;
+ if (id_ast == NULL && current_scope.count(buf->str))
+ id_ast = current_scope.at(buf->str);
+ if (!id_ast)
+ log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str());
+ if (id_ast->type == AST_MEMORY) {
+ // We got here only if the argument is a memory
+ // Otherwise $size() and $bits() return the expression width
+ AstNode *mem_range = id_ast->children[1];
+ if (str == "\\$bits") {
+ if (mem_range->type == AST_RANGE) {
+ if (!mem_range->range_valid)
+ log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());
+ mem_depth = mem_range->range_left - mem_range->range_right + 1;
+ } else
+ log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());
+ } else {
+ // $size()
+ if (mem_range->type == AST_RANGE) {
+ if (!mem_range->range_valid)
+ log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());
+ int dims;
+ if (id_ast->multirange_dimensions.empty())
+ dims = 1;
+ else
+ dims = GetSize(id_ast->multirange_dimensions)/2;
+ if (dim == 1)
+ width_hint = (dims > 1) ? id_ast->multirange_dimensions[1] : (mem_range->range_left - mem_range->range_right + 1);
+ else if (dim <= dims) {
+ width_hint = id_ast->multirange_dimensions[2*dim-1];
+ } else if ((dim > dims+1) || (dim < 0))
+ log_file_error(filename, linenum, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1);
+ } else
+ log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());
+ }
+ }
+ }
+ delete buf;
+
+ newNode = mkconst_int(width_hint * mem_depth, false);
+ goto apply_newNode;
+ }
+
if (str == "\\$ln" || str == "\\$log10" || str == "\\$exp" || str == "\\$sqrt" || str == "\\$pow" ||
str == "\\$floor" || str == "\\$ceil" || str == "\\$sin" || str == "\\$cos" || str == "\\$tan" ||
str == "\\$asin" || str == "\\$acos" || str == "\\$atan" || str == "\\$atan2" || str == "\\$hypot" ||
- str == "\\$sinh" || str == "\\$cosh" || str == "\\$tanh" || str == "\\$asinh" || str == "\\$acosh" || str == "\\$atanh")
+ str == "\\$sinh" || str == "\\$cosh" || str == "\\$tanh" || str == "\\$asinh" || str == "\\$acosh" || str == "\\$atanh" ||
+ str == "\\$rtoi" || str == "\\$itor")
{
bool func_with_two_arguments = str == "\\$pow" || str == "\\$atan2" || str == "\\$hypot";
double x = 0, y = 0;
if (func_with_two_arguments) {
if (children.size() != 2)
- log_error("System function %s got %d arguments, expected 2 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 2.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
} else {
if (children.size() != 1)
- log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
}
if (children.size() >= 1) {
while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (!children[0]->isConst())
- log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n",
+ RTLIL::unescape_id(str).c_str());
int child_width_hint = width_hint;
bool child_sign_hint = sign_hint;
children[0]->detectSignWidth(child_width_hint, child_sign_hint);
@@ -1872,37 +1999,42 @@ skip_dynamic_range_lvalue_expansion:;
if (children.size() >= 2) {
while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (!children[1]->isConst())
- log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n",
+ RTLIL::unescape_id(str).c_str());
int child_width_hint = width_hint;
bool child_sign_hint = sign_hint;
children[1]->detectSignWidth(child_width_hint, child_sign_hint);
y = children[1]->asReal(child_sign_hint);
}
- newNode = new AstNode(AST_REALVALUE);
- if (str == "\\$ln") newNode->realvalue = ::log(x);
- else if (str == "\\$log10") newNode->realvalue = ::log10(x);
- else if (str == "\\$exp") newNode->realvalue = ::exp(x);
- else if (str == "\\$sqrt") newNode->realvalue = ::sqrt(x);
- else if (str == "\\$pow") newNode->realvalue = ::pow(x, y);
- else if (str == "\\$floor") newNode->realvalue = ::floor(x);
- else if (str == "\\$ceil") newNode->realvalue = ::ceil(x);
- else if (str == "\\$sin") newNode->realvalue = ::sin(x);
- else if (str == "\\$cos") newNode->realvalue = ::cos(x);
- else if (str == "\\$tan") newNode->realvalue = ::tan(x);
- else if (str == "\\$asin") newNode->realvalue = ::asin(x);
- else if (str == "\\$acos") newNode->realvalue = ::acos(x);
- else if (str == "\\$atan") newNode->realvalue = ::atan(x);
- else if (str == "\\$atan2") newNode->realvalue = ::atan2(x, y);
- else if (str == "\\$hypot") newNode->realvalue = ::hypot(x, y);
- else if (str == "\\$sinh") newNode->realvalue = ::sinh(x);
- else if (str == "\\$cosh") newNode->realvalue = ::cosh(x);
- else if (str == "\\$tanh") newNode->realvalue = ::tanh(x);
- else if (str == "\\$asinh") newNode->realvalue = ::asinh(x);
- else if (str == "\\$acosh") newNode->realvalue = ::acosh(x);
- else if (str == "\\$atanh") newNode->realvalue = ::atanh(x);
- else log_abort();
+ if (str == "\\$rtoi") {
+ newNode = AstNode::mkconst_int(x, true);
+ } else {
+ newNode = new AstNode(AST_REALVALUE);
+ if (str == "\\$ln") newNode->realvalue = ::log(x);
+ else if (str == "\\$log10") newNode->realvalue = ::log10(x);
+ else if (str == "\\$exp") newNode->realvalue = ::exp(x);
+ else if (str == "\\$sqrt") newNode->realvalue = ::sqrt(x);
+ else if (str == "\\$pow") newNode->realvalue = ::pow(x, y);
+ else if (str == "\\$floor") newNode->realvalue = ::floor(x);
+ else if (str == "\\$ceil") newNode->realvalue = ::ceil(x);
+ else if (str == "\\$sin") newNode->realvalue = ::sin(x);
+ else if (str == "\\$cos") newNode->realvalue = ::cos(x);
+ else if (str == "\\$tan") newNode->realvalue = ::tan(x);
+ else if (str == "\\$asin") newNode->realvalue = ::asin(x);
+ else if (str == "\\$acos") newNode->realvalue = ::acos(x);
+ else if (str == "\\$atan") newNode->realvalue = ::atan(x);
+ else if (str == "\\$atan2") newNode->realvalue = ::atan2(x, y);
+ else if (str == "\\$hypot") newNode->realvalue = ::hypot(x, y);
+ else if (str == "\\$sinh") newNode->realvalue = ::sinh(x);
+ else if (str == "\\$cosh") newNode->realvalue = ::cosh(x);
+ else if (str == "\\$tanh") newNode->realvalue = ::tanh(x);
+ else if (str == "\\$asinh") newNode->realvalue = ::asinh(x);
+ else if (str == "\\$acosh") newNode->realvalue = ::acosh(x);
+ else if (str == "\\$atanh") newNode->realvalue = ::atanh(x);
+ else if (str == "\\$itor") newNode->realvalue = x;
+ else log_abort();
+ }
goto apply_newNode;
}
@@ -1920,14 +2052,14 @@ skip_dynamic_range_lvalue_expansion:;
for (int i = 2; i < GetSize(dpi_decl->children); i++)
{
if (i-2 >= GetSize(children))
- log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Insufficient number of arguments in DPI function call.\n");
argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));
args.push_back(children.at(i-2)->clone());
while (args.back()->simplify(true, false, false, stage, -1, false, true)) { }
if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE)
- log_error("Failed to evaluate DPI function with non-constant argument at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate DPI function with non-constant argument.\n");
}
newNode = dpi_call(rtype, fname, argtypes, args);
@@ -1939,7 +2071,7 @@ skip_dynamic_range_lvalue_expansion:;
}
if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION)
- log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Can't resolve function name `%s'.\n", str.c_str());
}
if (type == AST_TCALL)
@@ -1947,26 +2079,26 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "$finish" || str == "$stop")
{
if (!current_always || current_always->type != AST_INITIAL)
- log_error("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str());
- log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' executed.\n", str.c_str());
}
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);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 2-4.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
AstNode *node_filename = children[0]->clone();
while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
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);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str());
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);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str());
int start_addr = -1, finish_addr = -1;
@@ -1974,7 +2106,7 @@ skip_dynamic_range_lvalue_expansion:;
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);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str());
start_addr = int(node_addr->asInt(false));
}
@@ -1982,7 +2114,7 @@ skip_dynamic_range_lvalue_expansion:;
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);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str());
finish_addr = int(node_addr->asInt(false));
}
@@ -2008,7 +2140,7 @@ skip_dynamic_range_lvalue_expansion:;
}
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);
+ log_file_error(filename, linenum, "Can't resolve task name `%s'.\n", str.c_str());
}
AstNode *decl = current_scope[str];
@@ -2036,9 +2168,9 @@ skip_dynamic_range_lvalue_expansion:;
}
if (in_param)
- log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant function call in constant expression.\n");
if (require_const_eval)
- log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Function %s can only be called with constant arguments.\n", str.c_str());
}
size_t arg_count = 0;
@@ -2137,7 +2269,7 @@ skip_dynamic_range_lvalue_expansion:;
}
for (auto child : decl->children)
- if (child->type == AST_WIRE || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
+ if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
{
AstNode *wire = nullptr;
@@ -2147,9 +2279,16 @@ skip_dynamic_range_lvalue_expansion:;
if (wire->children.empty()) {
for (auto c : child->children)
wire->children.push_back(c->clone());
- } else {
- if (!child->children.empty())
- log_error("Incompatible re-declaration of wire %s at %s:%d.\n", child->str.c_str(), filename.c_str(), linenum);
+ } else if (!child->children.empty()) {
+ while (child->simplify(true, false, false, stage, -1, false, false)) { }
+ if (GetSize(child->children) == GetSize(wire->children)) {
+ for (int i = 0; i < GetSize(child->children); i++)
+ if (*child->children.at(i) != *wire->children.at(i))
+ goto tcall_incompatible_wires;
+ } else {
+ tcall_incompatible_wires:
+ log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", child->str.c_str());
+ }
}
}
else
@@ -2197,7 +2336,7 @@ skip_dynamic_range_lvalue_expansion:;
}
for (auto child : decl->children)
- if (child->type != AST_WIRE && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM)
+ if (child->type != AST_WIRE && child->type != AST_MEMORY && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM)
{
AstNode *stmt = child->clone();
stmt->replace_ids(prefix, replace_rules);
@@ -2533,9 +2672,10 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
std::ifstream f;
f.open(mem_filename.c_str());
+ yosys_input_files.insert(mem_filename);
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_file_error(filename, linenum, "Can not open file `%s` for %s.\n", mem_filename.c_str(), str.c_str());
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;
@@ -2581,7 +2721,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
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);
+ log_file_error(filename, linenum, "Can not parse address `%s` for %s.\n", nptr, str.c_str());
continue;
}
@@ -2660,7 +2800,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
size_t pos = child->str.rfind('.');
if (pos == std::string::npos)
- pos = child->str[0] == '\\' ? 1 : 0;
+ pos = child->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0;
else
pos = pos + 1;
new_name = child->str.substr(0, pos) + new_name + child->str.substr(pos);
@@ -2837,7 +2977,7 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
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);
+ log_file_error(filename, linenum, "Invalid array access.\n");
return true;
}
@@ -2902,6 +3042,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
wire_addr->str = id_addr;
wire_addr->is_reg = true;
+ wire_addr->was_checked = true;
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_addr);
while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
@@ -2909,6 +3050,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_data->str = id_data;
wire_data->is_reg = true;
+ wire_data->was_checked = true;
wire_data->is_signed = mem_signed;
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_data);
@@ -2977,6 +3119,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
wire_addr->str = id_addr;
wire_addr->is_reg = true;
+ wire_addr->was_checked = true;
if (block)
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_addr);
@@ -2985,6 +3128,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_data->str = id_data;
wire_data->is_reg = true;
+ wire_data->was_checked = true;
wire_data->is_signed = mem_signed;
if (block)
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
@@ -2993,6 +3137,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone());
assign_addr->children[0]->str = id_addr;
+ assign_addr->children[0]->was_checked = true;
AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER));
case_node->children[0]->str = id_addr;
@@ -3003,6 +3148,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK));
AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER));
assign_reg->children[0]->str = id_data;
+ assign_reg->children[0]->was_checked = true;
assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i);
cond_node->children[1]->children.push_back(assign_reg);
case_node->children.push_back(cond_node);
@@ -3015,6 +3161,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
AstNode *cond_node = new AstNode(AST_COND, new AstNode(AST_DEFAULT), new AstNode(AST_BLOCK));
AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
assign_reg->children[0]->str = id_data;
+ assign_reg->children[0]->was_checked = true;
cond_node->children[1]->children.push_back(assign_reg);
case_node->children.push_back(cond_node);
@@ -3043,6 +3190,8 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
if (bit_part_sel)
children.push_back(bit_part_sel);
+
+ did_something = true;
}
log_assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
@@ -3094,13 +3243,13 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia
int offset = variables.at(str).offset, width = variables.at(str).val.bits.size();
if (!children.empty()) {
if (children.size() != 1 || children.at(0)->type != AST_RANGE)
- log_error("Memory access in constant function is not supported in %s:%d (called from %s:%d).\n",
- filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(filename, linenum, "Memory access in constant function is not supported\n%s:%d: ...called from here.\n",
+ fcall->filename.c_str(), fcall->linenum);
children.at(0)->replace_variables(variables, fcall);
while (simplify(true, false, false, 1, -1, false, true)) { }
if (!children.at(0)->range_valid)
- log_error("Non-constant range in %s:%d (called from %s:%d).\n",
- filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(filename, linenum, "Non-constant range\n%s:%d: ... called from here.\n",
+ fcall->filename.c_str(), fcall->linenum);
offset = min(children.at(0)->range_left, children.at(0)->range_right);
width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
}
@@ -3139,8 +3288,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
{
while (child->simplify(true, false, false, 1, -1, false, true)) { }
if (!child->range_valid)
- log_error("Can't determine size of variable %s in %s:%d (called from %s:%d).\n",
- child->str.c_str(), child->filename.c_str(), child->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(child->filename, child->linenum, "Can't determine size of variable %s\n%s:%d: ... called from here.\n",
+ child->str.c_str(), fcall->filename.c_str(), fcall->linenum);
variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1);
variables[child->str].offset = min(child->range_left, child->range_right);
variables[child->str].is_signed = child->is_signed;
@@ -3183,24 +3332,24 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
continue;
if (stmt->children.at(1)->type != AST_CONSTANT)
- log_error("Non-constant expression in constant function at %s:%d (called from %s:%d). X\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here. X\n",
+ fcall->filename.c_str(), fcall->linenum);
if (stmt->children.at(0)->type != AST_IDENTIFIER)
- log_error("Unsupported composite left hand side in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Unsupported composite left hand side in constant function\n%s:%d: ... called from here.\n",
+ fcall->filename.c_str(), fcall->linenum);
if (!variables.count(stmt->children.at(0)->str))
- log_error("Assignment to non-local variable in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Assignment to non-local variable in constant function\n%s:%d: ... called from here.\n",
+ fcall->filename.c_str(), fcall->linenum);
if (stmt->children.at(0)->children.empty()) {
variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
} else {
AstNode *range = stmt->children.at(0)->children.at(0);
if (!range->range_valid)
- log_error("Non-constant range in %s:%d (called from %s:%d).\n",
- range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(range->filename, range->linenum, "Non-constant range\n%s:%d: ... called from here.\n",
+ fcall->filename.c_str(), fcall->linenum);
int offset = min(range->range_left, range->range_right);
int width = std::abs(range->range_left - range->range_right) + 1;
varinfo_t &v = variables[stmt->children.at(0)->str];
@@ -3231,8 +3380,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
if (cond->type != AST_CONSTANT)
- log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n",
+ fcall->filename.c_str(), fcall->linenum);
if (cond->asBool()) {
block->children.insert(block->children.begin(), stmt->children.at(1)->clone());
@@ -3252,8 +3401,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
while (num->simplify(true, false, false, 1, -1, false, true)) { }
if (num->type != AST_CONSTANT)
- log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n",
+ fcall->filename.c_str(), fcall->linenum);
block->children.erase(block->children.begin());
for (int i = 0; i < num->bitsAsConst().as_int(); i++)
@@ -3290,8 +3439,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
if (cond->type != AST_CONSTANT)
- log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n",
+ fcall->filename.c_str(), fcall->linenum);
found_match = cond->asBool();
delete cond;
@@ -3320,8 +3469,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
continue;
}
- log_error("Unsupported language construct in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Unsupported language construct in constant function\n%s:%d: ... called from here.\n",
+ fcall->filename.c_str(), fcall->linenum);
log_abort();
}
@@ -3338,4 +3487,3 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
}
YOSYS_NAMESPACE_END
-
diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc
index 6d4d6087..034b3e70 100644
--- a/frontends/blif/blifparse.cc
+++ b/frontends/blif/blifparse.cc
@@ -55,12 +55,37 @@ static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count,
}
}
-void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode)
+static std::pair<RTLIL::IdString, int> wideports_split(std::string name)
+{
+ int pos = -1;
+
+ if (name.empty() || name.back() != ']')
+ goto failed;
+
+ for (int i = 0; i+1 < GetSize(name); i++) {
+ if (name[i] == '[')
+ pos = i;
+ else if (name[i] < '0' || name[i] > '9')
+ pos = -1;
+ else if (i == pos+1 && name[i] == '0' && name[i+1] != ']')
+ pos = -1;
+ }
+
+ if (pos >= 0)
+ return std::pair<RTLIL::IdString, int>("\\" + name.substr(0, pos), atoi(name.c_str() + pos+1)+1);
+
+failed:
+ return std::pair<RTLIL::IdString, int>("\\" + name, 0);
+}
+
+void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode, bool wideports)
{
RTLIL::Module *module = nullptr;
RTLIL::Const *lutptr = NULL;
RTLIL::Cell *sopcell = NULL;
+ RTLIL::Cell *lastcell = nullptr;
RTLIL::State lut_default_state = RTLIL::State::Sx;
+ std::string err_reason;
int blif_maxnum = 0, sopmode = -1;
auto blif_wire = [&](const std::string &wire_name) -> Wire*
@@ -96,6 +121,8 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
dict<RTLIL::IdString, RTLIL::Const> *obj_attributes = nullptr;
dict<RTLIL::IdString, RTLIL::Const> *obj_parameters = nullptr;
+ dict<RTLIL::IdString, std::pair<int, bool>> wideports_cache;
+
size_t buffer_size = 4096;
char *buffer = (char*)malloc(buffer_size);
int line_count = 0;
@@ -134,6 +161,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
if (module != nullptr)
goto error;
module = new RTLIL::Module;
+ lastcell = nullptr;
module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n"));
obj_attributes = &module->attributes;
obj_parameters = nullptr;
@@ -148,7 +176,32 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
if (!strcmp(cmd, ".end"))
{
+ for (auto &wp : wideports_cache)
+ {
+ auto name = wp.first;
+ int width = wp.second.first;
+ bool isinput = wp.second.second;
+
+ RTLIL::Wire *wire = module->addWire(name, width);
+ wire->port_input = isinput;
+ wire->port_output = !isinput;
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
+ RTLIL::Wire *other_wire = module->wire(other_name);
+ if (other_wire) {
+ other_wire->port_input = false;
+ other_wire->port_output = false;
+ if (isinput)
+ module->connect(other_wire, SigSpec(wire, i));
+ else
+ module->connect(SigSpec(wire, i), other_wire);
+ }
+ }
+ }
+
module->fixup_ports();
+ wideports_cache.clear();
if (run_clean)
{
@@ -182,14 +235,17 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
}
module = nullptr;
+ lastcell = nullptr;
obj_attributes = nullptr;
obj_parameters = nullptr;
continue;
}
- if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) {
+ if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs"))
+ {
char *p;
- while ((p = strtok(NULL, " \t\r\n")) != NULL) {
+ while ((p = strtok(NULL, " \t\r\n")) != NULL)
+ {
RTLIL::IdString wire_name(stringf("\\%s", p));
RTLIL::Wire *wire = module->wire(wire_name);
if (wire == nullptr)
@@ -198,12 +254,36 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
wire->port_input = true;
else
wire->port_output = true;
+
+ if (wideports) {
+ std::pair<RTLIL::IdString, int> wp = wideports_split(p);
+ if (wp.second > 0) {
+ wideports_cache[wp.first].first = std::max(wideports_cache[wp.first].first, wp.second);
+ wideports_cache[wp.first].second = !strcmp(cmd, ".inputs");
+ }
+ }
}
obj_attributes = nullptr;
obj_parameters = nullptr;
continue;
}
+ if (!strcmp(cmd, ".cname"))
+ {
+ char *p = strtok(NULL, " \t\r\n");
+ if (p == NULL)
+ goto error;
+
+ if(lastcell == nullptr || module == nullptr)
+ {
+ err_reason = stringf("No primative object to attach .cname %s.", p);
+ goto error_with_reason;
+ }
+
+ module->rename(lastcell, p);
+ continue;
+ }
+
if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) {
char *n = strtok(NULL, " \t\r\n");
char *v = strtok(NULL, "\r\n");
@@ -221,12 +301,16 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0;
}
if (!strcmp(cmd, ".attr")) {
- if (obj_attributes == nullptr)
- goto error;
+ if (obj_attributes == nullptr) {
+ err_reason = stringf("No object to attach .attr too.");
+ goto error_with_reason;
+ }
(*obj_attributes)[id_n] = const_v;
} else {
- if (obj_parameters == nullptr)
- goto error;
+ if (obj_parameters == nullptr) {
+ err_reason = stringf("No object to attach .param too.");
+ goto error_with_reason;
+ }
(*obj_parameters)[id_n] = const_v;
}
continue;
@@ -271,6 +355,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
}
}
+ lastcell = cell;
obj_attributes = &cell->attributes;
obj_parameters = &cell->parameters;
continue;
@@ -285,14 +370,45 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
IdString celltype = RTLIL::escape_id(p);
RTLIL::Cell *cell = module->addCell(NEW_ID, celltype);
- while ((p = strtok(NULL, " \t\r\n")) != NULL) {
+ dict<RTLIL::IdString, dict<int, SigBit>> cell_wideports_cache;
+
+ while ((p = strtok(NULL, " \t\r\n")) != NULL)
+ {
char *q = strchr(p, '=');
if (q == NULL || !q[0])
goto error;
*(q++) = 0;
- cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec());
+
+ if (wideports) {
+ std::pair<RTLIL::IdString, int> wp = wideports_split(p);
+ if (wp.second > 0)
+ cell_wideports_cache[wp.first][wp.second-1] = blif_wire(q);
+ else
+ cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec());
+ } else {
+ cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec());
+ }
+ }
+
+ for (auto &it : cell_wideports_cache)
+ {
+ int width = 0;
+ for (auto &b : it.second)
+ width = std::max(width, b.first + 1);
+
+ SigSpec sig;
+
+ for (int i = 0; i < width; i++) {
+ if (it.second.count(i))
+ sig.append(it.second.at(i));
+ else
+ sig.append(module->addWire(NEW_ID));
+ }
+
+ cell->setPort(it.first, sig);
}
+ lastcell = cell;
obj_attributes = &cell->attributes;
obj_parameters = &cell->parameters;
continue;
@@ -301,7 +417,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
obj_attributes = nullptr;
obj_parameters = nullptr;
- if (!strcmp(cmd, ".barbuf"))
+ if (!strcmp(cmd, ".barbuf") || !strcmp(cmd, ".conn"))
{
char *p = strtok(NULL, " \t\r\n");
if (p == NULL)
@@ -369,6 +485,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
sopcell->setPort("\\A", input_sig);
sopcell->setPort("\\Y", output_sig);
sopmode = -1;
+ lastcell = sopcell;
}
else
{
@@ -379,6 +496,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
cell->setPort("\\Y", output_sig);
lutptr = &cell->parameters.at("\\LUT");
lut_default_state = RTLIL::State::Sx;
+ lastcell = cell;
}
continue;
}
@@ -432,7 +550,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
if (lutptr)
{
- if (input_len > 8)
+ if (input_len > 12)
goto error;
for (int i = 0; i < (1 << input_len); i++) {
@@ -452,13 +570,17 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
}
}
+ return;
+
error:
log_error("Syntax error in line %d!\n", line_count);
+error_with_reason:
+ log_error("Syntax error in line %d: %s\n", line_count, err_reason.c_str());
}
struct BlifFrontend : public Frontend {
BlifFrontend() : Frontend("blif", "read BLIF file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -469,10 +591,15 @@ struct BlifFrontend : public Frontend {
log(" -sop\n");
log(" Create $sop cells instead of $lut cells\n");
log("\n");
+ log(" -wideports\n");
+ log(" Merge ports that match the pattern 'name[int]' into a single\n");
+ log(" multi-bit port 'name'.\n");
+ log("\n");
}
- virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool sop_mode = false;
+ bool wideports = false;
log_header(design, "Executing BLIF frontend.\n");
@@ -483,11 +610,15 @@ struct BlifFrontend : public Frontend {
sop_mode = true;
continue;
}
+ if (arg == "-wideports") {
+ wideports = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
- parse_blif(design, *f, "", true, sop_mode);
+ parse_blif(design, *f, "", true, sop_mode, wideports);
}
} BlifFrontend;
diff --git a/frontends/blif/blifparse.h b/frontends/blif/blifparse.h
index 058087d8..955b6aac 100644
--- a/frontends/blif/blifparse.h
+++ b/frontends/blif/blifparse.h
@@ -24,7 +24,8 @@
YOSYS_NAMESPACE_BEGIN
-extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean = false, bool sop_mode = false);
+extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name,
+ bool run_clean = false, bool sop_mode = false, bool wideports = false);
YOSYS_NAMESPACE_END
diff --git a/frontends/ilang/.gitignore b/frontends/ilang/.gitignore
index 43106a81..f586b33c 100644
--- a/frontends/ilang/.gitignore
+++ b/frontends/ilang/.gitignore
@@ -1,4 +1,4 @@
ilang_lexer.cc
ilang_parser.output
ilang_parser.tab.cc
-ilang_parser.tab.h
+ilang_parser.tab.hh
diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc
index e2a476c9..6f1f0e8f 100644
--- a/frontends/ilang/Makefile.inc
+++ b/frontends/ilang/Makefile.inc
@@ -1,15 +1,14 @@
GENFILES += frontends/ilang/ilang_parser.tab.cc
-GENFILES += frontends/ilang/ilang_parser.tab.h
+GENFILES += frontends/ilang/ilang_parser.tab.hh
GENFILES += frontends/ilang/ilang_parser.output
GENFILES += frontends/ilang/ilang_lexer.cc
frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y
$(Q) mkdir -p $(dir $@)
- $(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser $<
- $(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc
+ $(P) $(BISON) -o $@ -d -r all -b frontends/ilang/ilang_parser $<
-frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc
+frontends/ilang/ilang_parser.tab.hh: frontends/ilang/ilang_parser.tab.cc
frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l
$(Q) mkdir -p $(dir $@)
diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc
index ed678998..d8783ac1 100644
--- a/frontends/ilang/ilang_frontend.cc
+++ b/frontends/ilang/ilang_frontend.cc
@@ -35,7 +35,7 @@ YOSYS_NAMESPACE_BEGIN
struct IlangFrontend : public Frontend {
IlangFrontend() : Frontend("ilang", "read modules from ilang file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -45,7 +45,7 @@ struct IlangFrontend : public Frontend {
log("representation of a design in yosys's internal format.)\n");
log("\n");
}
- virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ILANG frontend.\n");
extra_args(f, filename, args, 1);
diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l
index 84238854..d8e01ae4 100644
--- a/frontends/ilang/ilang_lexer.l
+++ b/frontends/ilang/ilang_lexer.l
@@ -30,7 +30,7 @@
#endif
#include "frontends/ilang/ilang_frontend.h"
-#include "ilang_parser.tab.h"
+#include "ilang_parser.tab.hh"
USING_YOSYS_NAMESPACE
diff --git a/frontends/json/Makefile.inc b/frontends/json/Makefile.inc
new file mode 100644
index 00000000..0fe1b372
--- /dev/null
+++ b/frontends/json/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += frontends/json/jsonparse.o
+
diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc
new file mode 100644
index 00000000..82361ea9
--- /dev/null
+++ b/frontends/json/jsonparse.cc
@@ -0,0 +1,541 @@
+/*
+ * 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"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct JsonNode
+{
+ char type; // S=String, N=Number, A=Array, D=Dict
+ string data_string;
+ int data_number;
+ vector<JsonNode*> data_array;
+ dict<string, JsonNode*> data_dict;
+ vector<string> data_dict_keys;
+
+ JsonNode(std::istream &f)
+ {
+ type = 0;
+ data_number = 0;
+
+ while (1)
+ {
+ int ch = f.get();
+
+ if (ch == EOF)
+ log_error("Unexpected EOF in JSON file.\n");
+
+ if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
+ continue;
+
+ if (ch == '"')
+ {
+ type = 'S';
+
+ while (1)
+ {
+ ch = f.get();
+
+ if (ch == EOF)
+ log_error("Unexpected EOF in JSON string.\n");
+
+ if (ch == '"')
+ break;
+
+ if (ch == '\\') {
+ int ch = f.get();
+
+ if (ch == EOF)
+ log_error("Unexpected EOF in JSON string.\n");
+ }
+
+ data_string += ch;
+ }
+
+ break;
+ }
+
+ if ('0' <= ch && ch <= '9')
+ {
+ type = 'N';
+ data_number = ch - '0';
+ data_string += ch;
+
+ while (1)
+ {
+ ch = f.get();
+
+ if (ch == EOF)
+ break;
+
+ if (ch == '.')
+ goto parse_real;
+
+ if (ch < '0' || '9' < ch) {
+ f.unget();
+ break;
+ }
+
+ data_number = data_number*10 + (ch - '0');
+ data_string += ch;
+ }
+
+ data_string = "";
+ break;
+
+ parse_real:
+ type = 'S';
+ data_number = 0;
+ data_string += ch;
+
+ while (1)
+ {
+ ch = f.get();
+
+ if (ch == EOF)
+ break;
+
+ if (ch < '0' || '9' < ch) {
+ f.unget();
+ break;
+ }
+
+ data_string += ch;
+ }
+
+ break;
+ }
+
+ if (ch == '[')
+ {
+ type = 'A';
+
+ while (1)
+ {
+ ch = f.get();
+
+ if (ch == EOF)
+ log_error("Unexpected EOF in JSON file.\n");
+
+ if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
+ continue;
+
+ if (ch == ']')
+ break;
+
+ f.unget();
+ data_array.push_back(new JsonNode(f));
+ }
+
+ break;
+ }
+
+ if (ch == '{')
+ {
+ type = 'D';
+
+ while (1)
+ {
+ ch = f.get();
+
+ if (ch == EOF)
+ log_error("Unexpected EOF in JSON file.\n");
+
+ if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
+ continue;
+
+ if (ch == '}')
+ break;
+
+ f.unget();
+ JsonNode key(f);
+
+ while (1)
+ {
+ ch = f.get();
+
+ if (ch == EOF)
+ log_error("Unexpected EOF in JSON file.\n");
+
+ if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ':')
+ continue;
+
+ f.unget();
+ break;
+ }
+
+ JsonNode *value = new JsonNode(f);
+
+ if (key.type != 'S')
+ log_error("Unexpected non-string key in JSON dict.\n");
+
+ data_dict[key.data_string] = value;
+ data_dict_keys.push_back(key.data_string);
+ }
+
+ break;
+ }
+
+ log_error("Unexpected character in JSON file: '%c'\n", ch);
+ }
+ }
+
+ ~JsonNode()
+ {
+ for (auto it : data_array)
+ delete it;
+ for (auto &it : data_dict)
+ delete it.second;
+ }
+};
+
+void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
+{
+ if (node->type != 'D')
+ log_error("JSON attributes or parameters node is not a dictionary.\n");
+
+ for (auto it : node->data_dict)
+ {
+ IdString key = RTLIL::escape_id(it.first.c_str());
+ JsonNode *value_node = it.second;
+ Const value;
+
+ if (value_node->type == 'S') {
+ string &s = value_node->data_string;
+ if (s.find_first_not_of("01xz") == string::npos)
+ value = Const::from_string(s);
+ else
+ value = Const(s);
+ } else
+ if (value_node->type == 'N') {
+ value = Const(value_node->data_number, 32);
+ } else
+ if (value_node->type == 'A') {
+ log_error("JSON attribute or parameter value is an array.\n");
+ } else
+ if (value_node->type == 'D') {
+ log_error("JSON attribute or parameter value is a dict.\n");
+ } else {
+ log_abort();
+ }
+
+ results[key] = value;
+ }
+}
+
+void json_import(Design *design, string &modname, JsonNode *node)
+{
+ log("Importing module %s from JSON tree.\n", modname.c_str());
+
+ Module *module = new RTLIL::Module;
+ module->name = RTLIL::escape_id(modname.c_str());
+
+ if (design->module(module->name))
+ log_error("Re-definition of module %s.\n", log_id(module->name));
+
+ design->add(module);
+
+ if (node->data_dict.count("attributes"))
+ json_parse_attr_param(module->attributes, node->data_dict.at("attributes"));
+
+ dict<int, SigBit> signal_bits;
+
+ if (node->data_dict.count("ports"))
+ {
+ JsonNode *ports_node = node->data_dict.at("ports");
+
+ if (ports_node->type != 'D')
+ log_error("JSON ports node is not a dictionary.\n");
+
+ for (int port_id = 1; port_id <= GetSize(ports_node->data_dict_keys); port_id++)
+ {
+ IdString port_name = RTLIL::escape_id(ports_node->data_dict_keys[port_id-1].c_str());
+ JsonNode *port_node = ports_node->data_dict.at(ports_node->data_dict_keys[port_id-1]);
+
+ if (port_node->type != 'D')
+ log_error("JSON port node '%s' is not a dictionary.\n", log_id(port_name));
+
+ if (port_node->data_dict.count("direction") == 0)
+ log_error("JSON port node '%s' has no direction attribute.\n", log_id(port_name));
+
+ if (port_node->data_dict.count("bits") == 0)
+ log_error("JSON port node '%s' has no bits attribute.\n", log_id(port_name));
+
+ JsonNode *port_direction_node = port_node->data_dict.at("direction");
+ JsonNode *port_bits_node = port_node->data_dict.at("bits");
+
+ if (port_direction_node->type != 'S')
+ log_error("JSON port node '%s' has non-string direction attribute.\n", log_id(port_name));
+
+ if (port_bits_node->type != 'A')
+ log_error("JSON port node '%s' has non-array bits attribute.\n", log_id(port_name));
+
+ Wire *port_wire = module->wire(port_name);
+
+ if (port_wire == nullptr)
+ port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array));
+
+ if (port_direction_node->data_string == "input") {
+ port_wire->port_input = true;
+ } else
+ if (port_direction_node->data_string == "output") {
+ port_wire->port_output = true;
+ } else
+ if (port_direction_node->data_string == "inout") {
+ port_wire->port_input = true;
+ port_wire->port_output = true;
+ } else
+ log_error("JSON port node '%s' has invalid '%s' direction attribute.\n", log_id(port_name), port_direction_node->data_string.c_str());
+
+ port_wire->port_id = port_id;
+
+ for (int i = 0; i < GetSize(port_bits_node->data_array); i++)
+ {
+ JsonNode *bitval_node = port_bits_node->data_array.at(i);
+ SigBit sigbit(port_wire, i);
+
+ if (bitval_node->type == 'S') {
+ if (bitval_node->data_string == "0")
+ module->connect(sigbit, State::S0);
+ else if (bitval_node->data_string == "1")
+ module->connect(sigbit, State::S1);
+ else if (bitval_node->data_string == "x")
+ module->connect(sigbit, State::Sx);
+ else if (bitval_node->data_string == "z")
+ module->connect(sigbit, State::Sz);
+ else
+ log_error("JSON port node '%s' has invalid '%s' bit string value on bit %d.\n",
+ log_id(port_name), bitval_node->data_string.c_str(), i);
+ } else
+ if (bitval_node->type == 'N') {
+ int bitidx = bitval_node->data_number;
+ if (signal_bits.count(bitidx)) {
+ if (port_wire->port_output) {
+ module->connect(sigbit, signal_bits.at(bitidx));
+ } else {
+ module->connect(signal_bits.at(bitidx), sigbit);
+ signal_bits[bitidx] = sigbit;
+ }
+ } else {
+ signal_bits[bitidx] = sigbit;
+ }
+ } else
+ log_error("JSON port node '%s' has invalid bit value on bit %d.\n", log_id(port_name), i);
+ }
+ }
+
+ module->fixup_ports();
+ }
+
+ if (node->data_dict.count("netnames"))
+ {
+ JsonNode *netnames_node = node->data_dict.at("netnames");
+
+ if (netnames_node->type != 'D')
+ log_error("JSON netnames node is not a dictionary.\n");
+
+ for (auto &net : netnames_node->data_dict)
+ {
+ IdString net_name = RTLIL::escape_id(net.first.c_str());
+ JsonNode *net_node = net.second;
+
+ if (net_node->type != 'D')
+ log_error("JSON netname node '%s' is not a dictionary.\n", log_id(net_name));
+
+ if (net_node->data_dict.count("bits") == 0)
+ log_error("JSON netname node '%s' has no bits attribute.\n", log_id(net_name));
+
+ JsonNode *bits_node = net_node->data_dict.at("bits");
+
+ if (bits_node->type != 'A')
+ log_error("JSON netname node '%s' has non-array bits attribute.\n", log_id(net_name));
+
+ Wire *wire = module->wire(net_name);
+
+ if (wire == nullptr)
+ wire = module->addWire(net_name, GetSize(bits_node->data_array));
+
+ for (int i = 0; i < GetSize(bits_node->data_array); i++)
+ {
+ JsonNode *bitval_node = bits_node->data_array.at(i);
+ SigBit sigbit(wire, i);
+
+ if (bitval_node->type == 'S') {
+ if (bitval_node->data_string == "0")
+ module->connect(sigbit, State::S0);
+ else if (bitval_node->data_string == "1")
+ module->connect(sigbit, State::S1);
+ else if (bitval_node->data_string == "x")
+ module->connect(sigbit, State::Sx);
+ else if (bitval_node->data_string == "z")
+ module->connect(sigbit, State::Sz);
+ else
+ log_error("JSON netname node '%s' has invalid '%s' bit string value on bit %d.\n",
+ log_id(net_name), bitval_node->data_string.c_str(), i);
+ } else
+ if (bitval_node->type == 'N') {
+ int bitidx = bitval_node->data_number;
+ if (signal_bits.count(bitidx)) {
+ if (sigbit != signal_bits.at(bitidx))
+ module->connect(sigbit, signal_bits.at(bitidx));
+ } else {
+ signal_bits[bitidx] = sigbit;
+ }
+ } else
+ log_error("JSON netname node '%s' has invalid bit value on bit %d.\n", log_id(net_name), i);
+ }
+
+ if (net_node->data_dict.count("attributes"))
+ json_parse_attr_param(wire->attributes, net_node->data_dict.at("attributes"));
+ }
+ }
+
+ if (node->data_dict.count("cells"))
+ {
+ JsonNode *cells_node = node->data_dict.at("cells");
+
+ if (cells_node->type != 'D')
+ log_error("JSON cells node is not a dictionary.\n");
+
+ for (auto &cell_node_it : cells_node->data_dict)
+ {
+ IdString cell_name = RTLIL::escape_id(cell_node_it.first.c_str());
+ JsonNode *cell_node = cell_node_it.second;
+
+ if (cell_node->type != 'D')
+ log_error("JSON cells node '%s' is not a dictionary.\n", log_id(cell_name));
+
+ if (cell_node->data_dict.count("type") == 0)
+ log_error("JSON cells node '%s' has no type attribute.\n", log_id(cell_name));
+
+ JsonNode *type_node = cell_node->data_dict.at("type");
+
+ if (type_node->type != 'S')
+ log_error("JSON cells node '%s' has a non-string type.\n", log_id(cell_name));
+
+ IdString cell_type = RTLIL::escape_id(type_node->data_string.c_str());
+
+ Cell *cell = module->addCell(cell_name, cell_type);
+
+ if (cell_node->data_dict.count("connections") == 0)
+ log_error("JSON cells node '%s' has no connections attribute.\n", log_id(cell_name));
+
+ JsonNode *connections_node = cell_node->data_dict.at("connections");
+
+ if (connections_node->type != 'D')
+ log_error("JSON cells node '%s' has non-dictionary connections attribute.\n", log_id(cell_name));
+
+ for (auto &conn_it : connections_node->data_dict)
+ {
+ IdString conn_name = RTLIL::escape_id(conn_it.first.c_str());
+ JsonNode *conn_node = conn_it.second;
+
+ if (conn_node->type != 'A')
+ log_error("JSON cells node '%s' connection '%s' is not an array.\n", log_id(cell_name), log_id(conn_name));
+
+ SigSpec sig;
+
+ for (int i = 0; i < GetSize(conn_node->data_array); i++)
+ {
+ JsonNode *bitval_node = conn_node->data_array.at(i);
+
+ if (bitval_node->type == 'S') {
+ if (bitval_node->data_string == "0")
+ sig.append(State::S0);
+ else if (bitval_node->data_string == "1")
+ sig.append(State::S1);
+ else if (bitval_node->data_string == "x")
+ sig.append(State::Sx);
+ else if (bitval_node->data_string == "z")
+ sig.append(State::Sz);
+ else
+ log_error("JSON cells node '%s' connection '%s' has invalid '%s' bit string value on bit %d.\n",
+ log_id(cell_name), log_id(conn_name), bitval_node->data_string.c_str(), i);
+ } else
+ if (bitval_node->type == 'N') {
+ int bitidx = bitval_node->data_number;
+ if (signal_bits.count(bitidx) == 0)
+ signal_bits[bitidx] = module->addWire(NEW_ID);
+ sig.append(signal_bits.at(bitidx));
+ } else
+ log_error("JSON cells node '%s' connection '%s' has invalid bit value on bit %d.\n",
+ log_id(cell_name), log_id(conn_name), i);
+
+ }
+
+ cell->setPort(conn_name, sig);
+ }
+
+ if (cell_node->data_dict.count("attributes"))
+ json_parse_attr_param(cell->attributes, cell_node->data_dict.at("attributes"));
+
+ if (cell_node->data_dict.count("parameters"))
+ json_parse_attr_param(cell->parameters, cell_node->data_dict.at("parameters"));
+ }
+ }
+}
+
+struct JsonFrontend : public Frontend {
+ JsonFrontend() : Frontend("json", "read JSON file") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" read_json [filename]\n");
+ log("\n");
+ log("Load modules from a JSON file into the current design See \"help write_json\"\n");
+ log("for a description of the file format.\n");
+ log("\n");
+ }
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing JSON frontend.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ // std::string arg = args[argidx];
+ // if (arg == "-sop") {
+ // sop_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ JsonNode root(*f);
+
+ if (root.type != 'D')
+ log_error("JSON root node is not a dictionary.\n");
+
+ if (root.data_dict.count("modules") != 0)
+ {
+ JsonNode *modules = root.data_dict.at("modules");
+
+ if (modules->type != 'D')
+ log_error("JSON modules node is not a dictionary.\n");
+
+ for (auto &it : modules->data_dict)
+ json_import(design, it.first, it.second);
+ }
+ }
+} JsonFrontend;
+
+YOSYS_NAMESPACE_END
+
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index 4666c818..0a5bd84d 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -148,7 +148,7 @@ static bool parse_func_reduce(RTLIL::Module *module, std::vector<token_t> &stack
}
if (0 <= top && stack[top].type == 2) {
- if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(')
+ if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(' || next_token.type == '!')
return false;
stack[top].type = 3;
return true;
@@ -188,7 +188,7 @@ static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr)
}
token_t next_token(0);
- if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|')
+ if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|' || *expr == '&')
next_token = token_t(*(expr++));
else
next_token = token_t(0, parse_func_identifier(module, expr));
@@ -290,7 +290,7 @@ static void create_ff(RTLIL::Module *module, LibertyAst *node)
log_assert(!cell->type.empty());
}
-static void create_latch(RTLIL::Module *module, LibertyAst *node)
+static bool create_latch(RTLIL::Module *module, LibertyAst *node, bool flag_ignore_miss_data_latch)
{
RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
@@ -309,8 +309,14 @@ static void create_latch(RTLIL::Module *module, LibertyAst *node)
preset_sig = parse_func_expr(module, child->value.c_str());
}
- if (enable_sig.size() == 0 || data_sig.size() == 0)
- log_error("Latch cell %s has no data_in and/or enable attribute.\n", log_id(module->name));
+ if (enable_sig.size() == 0 || data_sig.size() == 0) {
+ if (!flag_ignore_miss_data_latch)
+ log_error("Latch cell %s has no data_in and/or enable attribute.\n", log_id(module->name));
+ else
+ log("Ignored latch cell %s with no data_in and/or enable attribute.\n", log_id(module->name));
+
+ return false;
+ }
for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
{
@@ -399,6 +405,8 @@ static void create_latch(RTLIL::Module *module, LibertyAst *node)
cell->setPort("\\D", data_sig);
cell->setPort("\\Q", iq_sig);
cell->setPort("\\E", enable_sig);
+
+ return true;
}
void parse_type_map(std::map<std::string, std::tuple<int, int, bool>> &type_map, LibertyAst *ast)
@@ -444,7 +452,7 @@ void parse_type_map(std::map<std::string, std::tuple<int, int, bool>> &type_map,
struct LibertyFrontend : public Frontend {
LibertyFrontend() : Frontend("liberty", "read cells from liberty file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -455,9 +463,13 @@ struct LibertyFrontend : public Frontend {
log(" -lib\n");
log(" only create empty blackbox modules\n");
log("\n");
- log(" -ignore_redef\n");
+ log(" -nooverwrite\n");
log(" ignore re-definitions of modules. (the default behavior is to\n");
- log(" create an error message.)\n");
+ log(" create an error message if the existing module is not a blackbox\n");
+ log(" module, and overwrite the existing module if it is a blackbox module.)\n");
+ log("\n");
+ log(" -overwrite\n");
+ log(" overwrite existing modules with the same name\n");
log("\n");
log(" -ignore_miss_func\n");
log(" ignore cells with missing function specification of outputs\n");
@@ -466,16 +478,21 @@ struct LibertyFrontend : public Frontend {
log(" ignore cells with a missing or invalid direction\n");
log(" specification on a pin\n");
log("\n");
+ log(" -ignore_miss_data_latch\n");
+ log(" ignore latches with missing data and/or enable pins\n");
+ log("\n");
log(" -setattr <attribute_name>\n");
log(" set the specified attribute (to the value 1) on all loaded modules\n");
log("\n");
}
- virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_lib = false;
- bool flag_ignore_redef = false;
+ bool flag_nooverwrite = false;
+ bool flag_overwrite = false;
bool flag_ignore_miss_func = false;
bool flag_ignore_miss_dir = false;
+ bool flag_ignore_miss_data_latch = false;
std::vector<std::string> attributes;
log_header(design, "Executing Liberty frontend.\n");
@@ -487,8 +504,14 @@ struct LibertyFrontend : public Frontend {
flag_lib = true;
continue;
}
- if (arg == "-ignore_redef") {
- flag_ignore_redef = true;
+ if (arg == "-ignore_redef" || arg == "-nooverwrite") {
+ flag_nooverwrite = true;
+ flag_overwrite = false;
+ continue;
+ }
+ if (arg == "-overwrite") {
+ flag_nooverwrite = false;
+ flag_overwrite = true;
continue;
}
if (arg == "-ignore_miss_func") {
@@ -499,6 +522,10 @@ struct LibertyFrontend : public Frontend {
flag_ignore_miss_dir = true;
continue;
}
+ if (arg == "-ignore_miss_data_latch") {
+ flag_ignore_miss_data_latch = true;
+ continue;
+ }
if (arg == "-setattr" && argidx+1 < args.size()) {
attributes.push_back(RTLIL::escape_id(args[++argidx]));
continue;
@@ -521,9 +548,16 @@ struct LibertyFrontend : public Frontend {
std::string cell_name = RTLIL::escape_id(cell->args.at(0));
if (design->has(cell_name)) {
- if (flag_ignore_redef)
+ Module *existing_mod = design->module(cell_name);
+ if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
+ log_error("Re-definition of of cell/module %s!\n", log_id(cell_name));
+ } else if (flag_nooverwrite) {
+ log("Ignoring re-definition of module %s.\n", log_id(cell_name));
continue;
- log_error("Duplicate definition of cell/module %s.\n", RTLIL::unescape_id(cell_name).c_str());
+ } else {
+ log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", log_id(cell_name));
+ design->remove(existing_mod);
+ }
}
// log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str());
@@ -566,6 +600,12 @@ struct LibertyFrontend : public Frontend {
LibertyAst *dir = node->find("direction");
+ if (dir == nullptr) {
+ LibertyAst *pin = node->find("pin");
+ if (pin != nullptr)
+ dir = pin->find("direction");
+ }
+
if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
@@ -600,7 +640,10 @@ struct LibertyFrontend : public Frontend {
if (node->id == "ff" && node->args.size() == 2)
create_ff(module, node);
if (node->id == "latch" && node->args.size() == 2)
- create_latch(module, node);
+ if (!create_latch(module, node, flag_ignore_miss_data_latch)) {
+ delete module;
+ goto skip_cell;
+ }
}
if (node->id == "pin" && node->args.size() == 1)
diff --git a/frontends/verific/Makefile.inc b/frontends/verific/Makefile.inc
index 68ef9aed..972f4f9f 100644
--- a/frontends/verific/Makefile.inc
+++ b/frontends/verific/Makefile.inc
@@ -3,6 +3,8 @@ OBJS += frontends/verific/verific.o
ifeq ($(ENABLE_VERIFIC),1)
+OBJS += frontends/verific/verificsva.o
+
EXTRA_TARGETS += share/verific
share/verific:
@@ -11,6 +13,7 @@ share/verific:
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1987/. share/verific.new/vhdl_vdbs_1987
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1993/. share/verific.new/vhdl_vdbs_1993
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008/. share/verific.new/vhdl_vdbs_2008
+ $(Q) chmod -R a+rX share/verific.new
$(Q) mv share/verific.new share/verific
endif
diff --git a/frontends/verific/README b/frontends/verific/README
new file mode 100644
index 00000000..b4c436a3
--- /dev/null
+++ b/frontends/verific/README
@@ -0,0 +1,62 @@
+
+
+This directory contains Verific bindings for Yosys.
+See http://www.verific.com/ for details.
+
+
+Building Yosys with the 32 bit Verific eval library on amd64:
+=============================================================
+
+1.) Use a Makefile.conf like the following one:
+
+--snip--
+CONFIG := gcc
+ENABLE_TCL := 0
+ENABLE_PLUGINS := 0
+ENABLE_VERIFIC := 1
+CXXFLAGS += -m32
+LDFLAGS += -m32
+VERIFIC_DIR = /usr/local/src/verific_lib_eval
+--snap--
+
+
+2.) Install the necessary multilib packages
+
+Hint: On debian/ubuntu the multilib packages have names such as
+libreadline-dev:i386 or lib32readline6-dev, depending on the
+exact version of debian/ubuntu you are working with.
+
+
+3.) Build and test
+
+make -j8
+./yosys -p 'verific -sv frontends/verific/example.sv; verific -import top'
+
+
+Verific Features that should be enabled in your Verific library
+===============================================================
+
+database/DBCompileFlags.h:
+ DB_PRESERVE_INITIAL_VALUE
+
+
+Testing Verific+Yosys+SymbiYosys for formal verification
+========================================================
+
+Install Yosys+Verific, SymbiYosys, and Yices2. Install instructions:
+http://symbiyosys.readthedocs.io/en/latest/quickstart.html#installing
+
+Then run in the following command in this directory:
+
+ sby -f example.sby
+
+This will generate approximately one page of text outpout. The last lines
+should be something like this:
+
+ SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)
+ SBY [example] summary: Elapsed process time [H:MM:SS (secs)]: 0:00:00 (0)
+ SBY [example] summary: engine_0 (smtbmc yices) returned PASS for basecase
+ SBY [example] summary: engine_0 (smtbmc yices) returned PASS for induction
+ SBY [example] summary: successful proof by k-induction.
+ SBY [example] DONE (PASS, rc=0)
+
diff --git a/frontends/verific/build_amd64.txt b/frontends/verific/build_amd64.txt
deleted file mode 100644
index d6952820..00000000
--- a/frontends/verific/build_amd64.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-
-Notes on building yosys with verific support on amd64 when you
-only have the i386 eval version of Verific:
-
-
-1.) Use a Makefile.conf like the following one:
-
---snip--
-CONFIG := clang
-ENABLE_TCL := 0
-ENABLE_PLUGINS := 0
-ENABLE_VERIFIC := 1
-CXXFLAGS += -m32
-LDFLAGS += -m32
-VERIFIC_DIR = /usr/local/src/verific_lib_eval
---snap--
-
-
-2.) Install the necessary multilib packages
-
-Hint: On debian/ubuntu the multilib packages have names such as
-libreadline-dev:i386 or lib32readline6-dev, depending on the
-exact version of debian/ubuntu you are working with.
-
-
-3.) Build and test
-
-make -j8
-./yosys frontends/verific/test_navre.ys
-
diff --git a/frontends/verific/example.sby b/frontends/verific/example.sby
new file mode 100644
index 00000000..ffbf33ca
--- /dev/null
+++ b/frontends/verific/example.sby
@@ -0,0 +1,16 @@
+# Simple SymbiYosys example job utilizing Verific
+
+[options]
+mode prove
+depth 10
+
+[engines]
+smtbmc yices
+
+[script]
+verific -sv example.sv
+verific -import top
+prep -top top
+
+[files]
+example.sv
diff --git a/frontends/verific/example.sv b/frontends/verific/example.sv
new file mode 100644
index 00000000..21a5d42c
--- /dev/null
+++ b/frontends/verific/example.sv
@@ -0,0 +1,18 @@
+module top (
+ input clk, rst,
+ output reg [3:0] cnt
+);
+ initial cnt = 0;
+
+ always @(posedge clk) begin
+ if (rst)
+ cnt <= 0;
+ else
+ cnt <= cnt + 4'd 1;
+ end
+
+ always @(posedge clk) begin
+ assume (cnt != 10);
+ assert (cnt != 15);
+ end
+endmodule
diff --git a/frontends/verific/test_navre.ys b/frontends/verific/test_navre.ys
deleted file mode 100644
index a56b725a..00000000
--- a/frontends/verific/test_navre.ys
+++ /dev/null
@@ -1,18 +0,0 @@
-verific -vlog2k ../yosys-bigsim/softusb_navre/rtl/softusb_navre.v
-verific -import softusb_navre
-
-memory softusb_navre
-flatten softusb_navre
-rename softusb_navre gate
-
-read_verilog ../yosys-bigsim/softusb_navre/rtl/softusb_navre.v
-cd softusb_navre; proc; opt; memory; opt; cd ..
-rename softusb_navre gold
-
-expose -dff -shared gold gate
-miter -equiv -ignore_gold_x -make_assert -make_outputs -make_outcmp gold gate miter
-
-cd miter
-flatten; opt -undriven
-sat -verify -maxsteps 5 -set-init-undef -set-def-inputs -prove-asserts -tempinduct-def \
- -seq 1 -set-at 1 in_rst 1 # -show-inputs -show-outputs
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 7dd36a74..1dd6d7e2 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -29,29 +29,47 @@
# include <dirent.h>
#endif
+#include "frontends/verific/verific.h"
+
USING_YOSYS_NAMESPACE
#ifdef YOSYS_ENABLE_VERIFIC
+#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
+#endif
#include "veri_file.h"
#include "vhdl_file.h"
+#include "hier_tree.h"
#include "VeriModule.h"
+#include "VeriWrite.h"
#include "VhdlUnits.h"
-#include "DataBase.h"
#include "Message.h"
+#ifdef __clang__
#pragma clang diagnostic pop
+#endif
#ifdef VERIFIC_NAMESPACE
-using namespace Verific ;
+using namespace Verific;
+#endif
+
#endif
-static void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args)
+#ifdef YOSYS_ENABLE_VERIFIC
+YOSYS_NAMESPACE_BEGIN
+
+int verific_verbose;
+bool verific_import_pending;
+string verific_error_msg;
+
+vector<string> verific_incdirs, verific_libdirs;
+
+void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args)
{
- log("VERIFIC-%s [%s] ",
+ string message_prefix = stringf("VERIFIC-%s [%s] ",
msg_type == VERIFIC_NONE ? "NONE" :
msg_type == VERIFIC_ERROR ? "ERROR" :
msg_type == VERIFIC_WARNING ? "WARNING" :
@@ -59,13 +77,47 @@ static void msg_func(msg_type_t msg_type, const char *message_id, linefile_type
msg_type == VERIFIC_INFO ? "INFO" :
msg_type == VERIFIC_COMMENT ? "COMMENT" :
msg_type == VERIFIC_PROGRAM_ERROR ? "PROGRAM_ERROR" : "UNKNOWN", message_id);
- if (linefile)
- log("%s:%d: ", LineFile::GetFileName(linefile), LineFile::GetLineNo(linefile));
- logv(msg, args);
- log("\n");
+
+ string message = linefile ? stringf("%s:%d: ", LineFile::GetFileName(linefile), LineFile::GetLineNo(linefile)) : "";
+ message += vstringf(msg, args);
+
+ if (msg_type == VERIFIC_ERROR || msg_type == VERIFIC_WARNING || msg_type == VERIFIC_PROGRAM_ERROR)
+ log_warning_noprefix("%s%s\n", message_prefix.c_str(), message.c_str());
+ else
+ log("%s%s\n", message_prefix.c_str(), message.c_str());
+
+ if (verific_error_msg.empty() && (msg_type == VERIFIC_ERROR || msg_type == VERIFIC_PROGRAM_ERROR))
+ verific_error_msg = message;
}
-static void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj)
+string get_full_netlist_name(Netlist *nl)
+{
+ if (nl->NumOfRefs() == 1) {
+ Instance *inst = (Instance*)nl->GetReferences()->GetLast();
+ return get_full_netlist_name(inst->Owner()) + "." + inst->Name();
+ }
+
+ return nl->CellBaseName();
+}
+
+// ==================================================================
+
+VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover) :
+ mode_gates(mode_gates), mode_keep(mode_keep), mode_nosva(mode_nosva),
+ mode_names(mode_names), mode_verific(mode_verific), mode_autocover(mode_autocover)
+{
+}
+
+RTLIL::SigBit VerificImporter::net_map_at(Net *net)
+{
+ if (net->IsExternalTo(netlist))
+ log_error("Found external reference to '%s.%s' in netlist '%s', please use -flatten or -extnets.\n",
+ get_full_netlist_name(net->Owner()).c_str(), net->Name(), get_full_netlist_name(netlist).c_str());
+
+ return net_map.at(net);
+}
+
+void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj)
{
MapIter mi;
Att *attr;
@@ -74,44 +126,47 @@ static void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, D
attributes["\\src"] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile()));
// FIXME: Parse numeric attributes
- FOREACH_ATTRIBUTE(obj, mi, attr)
+ FOREACH_ATTRIBUTE(obj, mi, attr) {
+ if (attr->Key()[0] == ' ' || attr->Value() == nullptr)
+ continue;
attributes[RTLIL::escape_id(attr->Key())] = RTLIL::Const(std::string(attr->Value()));
+ }
}
-static RTLIL::SigSpec operatorInput(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map)
+RTLIL::SigSpec VerificImporter::operatorInput(Instance *inst)
{
RTLIL::SigSpec sig;
for (int i = int(inst->InputSize())-1; i >= 0; i--)
if (inst->GetInputBit(i))
- sig.append(net_map.at(inst->GetInputBit(i)));
+ sig.append(net_map_at(inst->GetInputBit(i)));
else
sig.append(RTLIL::State::Sz);
return sig;
}
-static RTLIL::SigSpec operatorInput1(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map)
+RTLIL::SigSpec VerificImporter::operatorInput1(Instance *inst)
{
RTLIL::SigSpec sig;
for (int i = int(inst->Input1Size())-1; i >= 0; i--)
if (inst->GetInput1Bit(i))
- sig.append(net_map.at(inst->GetInput1Bit(i)));
+ sig.append(net_map_at(inst->GetInput1Bit(i)));
else
sig.append(RTLIL::State::Sz);
return sig;
}
-static RTLIL::SigSpec operatorInput2(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map)
+RTLIL::SigSpec VerificImporter::operatorInput2(Instance *inst)
{
RTLIL::SigSpec sig;
for (int i = int(inst->Input2Size())-1; i >= 0; i--)
if (inst->GetInput2Bit(i))
- sig.append(net_map.at(inst->GetInput2Bit(i)));
+ sig.append(net_map_at(inst->GetInput2Bit(i)));
else
sig.append(RTLIL::State::Sz);
return sig;
}
-static RTLIL::SigSpec operatorInport(Instance *inst, const char *portname, std::map<Net*, RTLIL::SigBit> &net_map)
+RTLIL::SigSpec VerificImporter::operatorInport(Instance *inst, const char *portname)
{
PortBus *portbus = inst->View()->GetPortBus(portname);
if (portbus) {
@@ -124,7 +179,7 @@ static RTLIL::SigSpec operatorInport(Instance *inst, const char *portname, std::
else if (net->IsPwr())
sig.append(RTLIL::State::S1);
else
- sig.append(net_map.at(net));
+ sig.append(net_map_at(net));
} else
sig.append(RTLIL::State::Sz);
}
@@ -133,17 +188,17 @@ static RTLIL::SigSpec operatorInport(Instance *inst, const char *portname, std::
Port *port = inst->View()->GetPort(portname);
log_assert(port != NULL);
Net *net = inst->GetNet(port);
- return net_map.at(net);
+ return net_map_at(net);
}
}
-static RTLIL::SigSpec operatorOutput(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map, RTLIL::Module *module)
+RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*, hash_ptr_ops> *any_all_nets)
{
RTLIL::SigSpec sig;
RTLIL::Wire *dummy_wire = NULL;
for (int i = int(inst->OutputSize())-1; i >= 0; i--)
- if (inst->GetOutputBit(i)) {
- sig.append(net_map.at(inst->GetOutputBit(i)));
+ if (inst->GetOutputBit(i) && (!any_all_nets || !any_all_nets->count(inst->GetOutputBit(i)))) {
+ sig.append(net_map_at(inst->GetOutputBit(i)));
dummy_wire = NULL;
} else {
if (dummy_wire == NULL)
@@ -155,72 +210,74 @@ static RTLIL::SigSpec operatorOutput(Instance *inst, std::map<Net*, RTLIL::SigBi
return sig;
}
-static bool import_netlist_instance_gates(RTLIL::Module *module, std::map<Net*, RTLIL::SigBit> &net_map, Instance *inst)
+bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdString inst_name)
{
if (inst->Type() == PRIM_AND) {
- module->addAndGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ module->addAndGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_NAND) {
RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addAndGate(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
- module->addNotGate(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
+ module->addAndGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_OR) {
- module->addOrGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ module->addOrGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_NOR) {
RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addOrGate(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
- module->addNotGate(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
+ module->addOrGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_XOR) {
- module->addXorGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ module->addXorGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_XNOR) {
- module->addXnorGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ module->addXnorGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_BUF) {
- module->addBufGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ auto outnet = inst->GetOutput();
+ if (!any_all_nets.count(outnet))
+ module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(outnet));
return true;
}
if (inst->Type() == PRIM_INV) {
- module->addNotGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ module->addNotGate(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_MUX) {
- module->addMuxGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
+ module->addMuxGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_TRI) {
- module->addMuxGate(RTLIL::escape_id(inst->Name()), RTLIL::State::Sz, net_map.at(inst->GetInput()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
+ module->addMuxGate(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_FADD)
{
- RTLIL::SigSpec a = net_map.at(inst->GetInput1()), b = net_map.at(inst->GetInput2()), c = net_map.at(inst->GetCin());
- RTLIL::SigSpec x = inst->GetCout() ? net_map.at(inst->GetCout()) : module->addWire(NEW_ID);
- RTLIL::SigSpec y = inst->GetOutput() ? net_map.at(inst->GetOutput()) : module->addWire(NEW_ID);
+ RTLIL::SigSpec a = net_map_at(inst->GetInput1()), b = net_map_at(inst->GetInput2()), c = net_map_at(inst->GetCin());
+ RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(NEW_ID);
+ RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID);
RTLIL::SigSpec tmp1 = module->addWire(NEW_ID);
RTLIL::SigSpec tmp2 = module->addWire(NEW_ID);
RTLIL::SigSpec tmp3 = module->addWire(NEW_ID);
module->addXorGate(NEW_ID, a, b, tmp1);
- module->addXorGate(RTLIL::escape_id(inst->Name()), tmp1, c, y);
+ module->addXorGate(inst_name, tmp1, c, y);
module->addAndGate(NEW_ID, tmp1, c, tmp2);
module->addAndGate(NEW_ID, a, b, tmp3);
module->addOrGate(NEW_ID, tmp2, tmp3, x);
@@ -229,163 +286,168 @@ static bool import_netlist_instance_gates(RTLIL::Module *module, std::map<Net*,
if (inst->Type() == PRIM_DFFRS)
{
+ VerificClocking clocking(this, inst->GetClock());
+ log_assert(clocking.disable_sig == State::S0);
+ log_assert(clocking.body_net == nullptr);
+
if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
- module->addDffGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
else if (inst->GetSet()->IsGnd())
- module->addAdffGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetReset()),
- net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), false);
+ clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), State::S0);
else if (inst->GetReset()->IsGnd())
- module->addAdffGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()),
- net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), true);
+ clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), State::S1);
else
- module->addDffsrGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()),
- net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
+ net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
return true;
}
return false;
}
-static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*, RTLIL::SigBit> &net_map, Instance *inst)
+bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdString inst_name)
{
if (inst->Type() == PRIM_AND) {
- module->addAnd(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_NAND) {
RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addAnd(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
- module->addNot(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
+ module->addAnd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_OR) {
- module->addOr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_NOR) {
RTLIL::SigSpec tmp = module->addWire(NEW_ID);
- module->addOr(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
- module->addNot(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
+ module->addOr(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp);
+ module->addNot(inst_name, tmp, net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_XOR) {
- module->addXor(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_XNOR) {
- module->addXnor(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
+ module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_INV) {
- module->addNot(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_MUX) {
- module->addMux(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
+ module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_TRI) {
- module->addMux(RTLIL::escape_id(inst->Name()), RTLIL::State::Sz, net_map.at(inst->GetInput()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
+ module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_FADD)
{
RTLIL::SigSpec a_plus_b = module->addWire(NEW_ID, 2);
- RTLIL::SigSpec y = inst->GetOutput() ? net_map.at(inst->GetOutput()) : module->addWire(NEW_ID);
+ RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID);
if (inst->GetCout())
- y.append(net_map.at(inst->GetCout()));
- module->addAdd(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), a_plus_b);
- module->addAdd(RTLIL::escape_id(inst->Name()), a_plus_b, net_map.at(inst->GetCin()), y);
+ y.append(net_map_at(inst->GetCout()));
+ module->addAdd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b);
+ module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y);
return true;
}
if (inst->Type() == PRIM_DFFRS)
{
+ VerificClocking clocking(this, inst->GetClock());
+ log_assert(clocking.disable_sig == State::S0);
+ log_assert(clocking.body_net == nullptr);
+
if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
- module->addDff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
else if (inst->GetSet()->IsGnd())
- module->addAdff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetReset()),
- net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), RTLIL::State::S0);
+ clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0);
else if (inst->GetReset()->IsGnd())
- module->addAdff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()),
- net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), RTLIL::State::S1);
+ clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1);
else
- module->addDffsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()),
- net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
+ net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_DLATCHRS)
{
if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
- module->addDlatch(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetControl()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
else
- module->addDlatchsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetControl()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()),
- net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()),
+ net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
return true;
}
- #define IN operatorInput(inst, net_map)
- #define IN1 operatorInput1(inst, net_map)
- #define IN2 operatorInput2(inst, net_map)
- #define OUT operatorOutput(inst, net_map, module)
+ #define IN operatorInput(inst)
+ #define IN1 operatorInput1(inst)
+ #define IN2 operatorInput2(inst)
+ #define OUT operatorOutput(inst)
+ #define FILTERED_OUT operatorOutput(inst, &any_all_nets)
#define SIGNED inst->View()->IsSigned()
if (inst->Type() == OPER_ADDER) {
RTLIL::SigSpec out = OUT;
if (inst->GetCout() != NULL)
- out.append(net_map.at(inst->GetCout()));
+ out.append(net_map_at(inst->GetCout()));
if (inst->GetCin()->IsGnd()) {
- module->addAdd(RTLIL::escape_id(inst->Name()), IN1, IN2, out, SIGNED);
+ module->addAdd(inst_name, IN1, IN2, out, SIGNED);
} else {
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);
+ module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false);
}
return true;
}
if (inst->Type() == OPER_MULTIPLIER) {
- module->addMul(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ module->addMul(inst_name, IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_DIVIDER) {
- module->addDiv(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ module->addDiv(inst_name, IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_MODULO) {
- module->addMod(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_REMAINDER) {
- module->addMod(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ module->addMod(inst_name, IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_SHIFT_LEFT) {
- module->addShl(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, false);
+ module->addShl(inst_name, IN1, IN2, OUT, false);
return true;
}
if (inst->Type() == OPER_ENABLED_DECODER) {
RTLIL::SigSpec vec;
- vec.append(net_map.at(inst->GetControl()));
+ vec.append(net_map_at(inst->GetControl()));
for (unsigned i = 1; i < inst->OutputSize(); i++) {
vec.append(RTLIL::State::S0);
}
- module->addShl(RTLIL::escape_id(inst->Name()), vec, IN, OUT, false);
+ module->addShl(inst_name, vec, IN, OUT, false);
return true;
}
@@ -395,7 +457,7 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
for (unsigned i = 1; i < inst->OutputSize(); i++) {
vec.append(RTLIL::State::S0);
}
- module->addShl(RTLIL::escape_id(inst->Name()), vec, IN, OUT, false);
+ module->addShl(inst_name, vec, IN, OUT, false);
return true;
}
@@ -403,112 +465,163 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
Net *net_cin = inst->GetCin();
Net *net_a_msb = inst->GetInput1Bit(0);
if (net_cin->IsGnd())
- module->addShr(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, false);
+ module->addShr(inst_name, IN1, IN2, OUT, false);
else if (net_cin == net_a_msb)
- module->addSshr(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, true);
+ module->addSshr(inst_name, IN1, IN2, OUT, true);
else
log_error("Can't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", inst->Name());
return true;
}
if (inst->Type() == OPER_REDUCE_AND) {
- module->addReduceAnd(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
+ module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_REDUCE_OR) {
- module->addReduceOr(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
+ module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_REDUCE_XOR) {
- module->addReduceXor(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
+ module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_REDUCE_XNOR) {
- module->addReduceXnor(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
+ module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED);
+ return true;
+ }
+
+ if (inst->Type() == OPER_REDUCE_NOR) {
+ SigSpec t = module->ReduceOr(NEW_ID, IN, SIGNED);
+ module->addNot(inst_name, t, net_map_at(inst->GetOutput()));
return true;
}
if (inst->Type() == OPER_LESSTHAN) {
Net *net_cin = inst->GetCin();
if (net_cin->IsGnd())
- module->addLt(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
+ module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
else if (net_cin->IsPwr())
- module->addLe(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
+ module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
else
log_error("Can't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", inst->Name());
return true;
}
if (inst->Type() == OPER_WIDE_AND) {
- module->addAnd(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ module->addAnd(inst_name, IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_OR) {
- module->addOr(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ module->addOr(inst_name, IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_XOR) {
- module->addXor(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ module->addXor(inst_name, IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_XNOR) {
- module->addXnor(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ module->addXnor(inst_name, IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_BUF) {
- module->addPos(RTLIL::escape_id(inst->Name()), IN, OUT, SIGNED);
+ module->addPos(inst_name, IN, FILTERED_OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_INV) {
- module->addNot(RTLIL::escape_id(inst->Name()), IN, OUT, SIGNED);
+ module->addNot(inst_name, IN, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_MINUS) {
- module->addSub(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
+ module->addSub(inst_name, IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_UMINUS) {
- module->addNeg(RTLIL::escape_id(inst->Name()), IN, OUT, SIGNED);
+ module->addNeg(inst_name, IN, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_EQUAL) {
- module->addEq(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
+ module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_NEQUAL) {
- module->addNe(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
+ module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_MUX) {
- module->addMux(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetControl()), OUT);
+ module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT);
+ return true;
+ }
+
+ if (inst->Type() == OPER_NTO1MUX) {
+ module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_NTO1MUX)
+ {
+ SigSpec data = IN2, out = OUT;
+
+ int wordsize_bits = ceil_log2(GetSize(out));
+ int wordsize = 1 << wordsize_bits;
+
+ SigSpec sel = {IN1, SigSpec(State::S0, wordsize_bits)};
+
+ SigSpec padded_data;
+ for (int i = 0; i < GetSize(data); i += GetSize(out)) {
+ SigSpec d = data.extract(i, GetSize(out));
+ d.extend_u0(wordsize);
+ padded_data.append(d);
+ }
+
+ module->addShr(inst_name, padded_data, sel, out);
+ return true;
+ }
+
+ if (inst->Type() == OPER_SELECTOR)
+ {
+ module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput()));
+ return true;
+ }
+
+ if (inst->Type() == OPER_WIDE_SELECTOR)
+ {
+ SigSpec out = OUT;
+ module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out);
return true;
}
if (inst->Type() == OPER_WIDE_TRI) {
- module->addMux(RTLIL::escape_id(inst->Name()), RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map.at(inst->GetControl()), OUT);
+ module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT);
return true;
}
- if (inst->Type() == OPER_WIDE_DFFRS) {
- RTLIL::SigSpec sig_set = operatorInport(inst, "set", net_map);
- RTLIL::SigSpec sig_reset = operatorInport(inst, "reset", net_map);
+ if (inst->Type() == OPER_WIDE_DFFRS)
+ {
+ VerificClocking clocking(this, inst->GetClock());
+ log_assert(clocking.disable_sig == State::S0);
+ log_assert(clocking.body_net == nullptr);
+
+ RTLIL::SigSpec sig_set = operatorInport(inst, "set");
+ RTLIL::SigSpec sig_reset = operatorInport(inst, "reset");
+
if (sig_set.is_fully_const() && !sig_set.as_bool() && sig_reset.is_fully_const() && !sig_reset.as_bool())
- module->addDff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), IN, OUT);
+ clocking.addDff(inst_name, IN, OUT);
else
- module->addDffsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), sig_set, sig_reset, IN, OUT);
+ clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT);
+
return true;
}
@@ -521,23 +634,95 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
return false;
}
-static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo, bool mode_gates)
+void VerificImporter::merge_past_ffs_clock(pool<RTLIL::Cell*> &candidates, SigBit clock, bool clock_pol)
+{
+ bool keep_running = true;
+ SigMap sigmap;
+
+ while (keep_running)
+ {
+ keep_running = false;
+
+ dict<SigBit, pool<RTLIL::Cell*>> dbits_db;
+ SigSpec dbits;
+
+ for (auto cell : candidates) {
+ SigBit bit = sigmap(cell->getPort("\\D"));
+ dbits_db[bit].insert(cell);
+ dbits.append(bit);
+ }
+
+ dbits.sort_and_unify();
+
+ for (auto chunk : dbits.chunks())
+ {
+ SigSpec sig_d = chunk;
+
+ if (chunk.wire == nullptr || GetSize(sig_d) == 1)
+ continue;
+
+ SigSpec sig_q = module->addWire(NEW_ID, GetSize(sig_d));
+ RTLIL::Cell *new_ff = module->addDff(NEW_ID, clock, sig_d, sig_q, clock_pol);
+
+ if (verific_verbose)
+ log(" merging single-bit past_ffs into new %d-bit ff %s.\n", GetSize(sig_d), log_id(new_ff));
+
+ for (int i = 0; i < GetSize(sig_d); i++)
+ for (auto old_ff : dbits_db[sig_d[i]])
+ {
+ if (verific_verbose)
+ log(" replacing old ff %s on bit %d.\n", log_id(old_ff), i);
+
+ SigBit old_q = old_ff->getPort("\\Q");
+ SigBit new_q = sig_q[i];
+
+ sigmap.add(old_q, new_q);
+ module->connect(old_q, new_q);
+ candidates.erase(old_ff);
+ module->remove(old_ff);
+ keep_running = true;
+ }
+ }
+ }
+}
+
+void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates)
+{
+ dict<pair<SigBit, int>, pool<RTLIL::Cell*>> database;
+
+ for (auto cell : candidates)
+ {
+ SigBit clock = cell->getPort("\\CLK");
+ bool clock_pol = cell->getParam("\\CLK_POLARITY").as_bool();
+ database[make_pair(clock, int(clock_pol))].insert(cell);
+ }
+
+ for (auto it : database)
+ merge_past_ffs_clock(it.second, it.first.first, it.first.second);
+}
+
+void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo)
{
std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name());
+ netlist = nl;
+
if (design->has(module_name)) {
if (!nl->IsOperator())
log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name());
return;
}
- RTLIL::Module *module = new RTLIL::Module;
+ module = new RTLIL::Module;
module->name = module_name;
design->add(module);
- log("Importing module %s.\n", RTLIL::id2cstr(module->name));
-
- std::map<Net*, RTLIL::SigBit> net_map;
+ if (nl->IsBlackBox()) {
+ log("Importing blackbox module %s.\n", RTLIL::id2cstr(module->name));
+ module->set_bool_attribute("\\blackbox");
+ } else {
+ log("Importing module %s.\n", RTLIL::id2cstr(module->name));
+ }
SetIter si;
MapIter mi, mi2;
@@ -553,7 +738,8 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
if (port->Bus())
continue;
- // log(" importing port %s.\n", port->Name());
+ if (verific_verbose)
+ log(" importing port %s.\n", port->Name());
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(port->Name()));
import_attributes(wire->attributes, port);
@@ -570,15 +756,16 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
if (net_map.count(net) == 0)
net_map[net] = wire;
else if (wire->port_input)
- module->connect(net_map.at(net), wire);
+ module->connect(net_map_at(net), wire);
else
- module->connect(wire, net_map.at(net));
+ module->connect(wire, net_map_at(net));
}
}
FOREACH_PORTBUS_OF_NETLIST(nl, mi, portbus)
{
- // log(" importing portbus %s.\n", portbus->Name());
+ if (verific_verbose)
+ log(" importing portbus %s.\n", portbus->Name());
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size());
wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
@@ -596,9 +783,9 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
if (net_map.count(net) == 0)
net_map[net] = bit;
else if (wire->port_input)
- module->connect(net_map.at(net), bit);
+ module->connect(net_map_at(net), bit);
else
- module->connect(bit, net_map.at(net));
+ module->connect(bit, net_map_at(net));
}
if (i == portbus->RightIndex())
break;
@@ -607,6 +794,11 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
module->fixup_ports();
+ dict<Net*, char, hash_ptr_ops> init_nets;
+ pool<Net*, hash_ptr_ops> anyconst_nets, anyseq_nets;
+ pool<Net*, hash_ptr_ops> allconst_nets, allseq_nets;
+ any_all_nets.clear();
+
FOREACH_NET_OF_NETLIST(nl, mi, net)
{
if (net->IsRamNet())
@@ -633,20 +825,98 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
memory->width = bits_in_word;
memory->size = number_of_bits / bits_in_word;
+
+ const char *ascii_initdata = net->GetWideInitialValue();
+ if (ascii_initdata) {
+ while (*ascii_initdata != 0 && *ascii_initdata != '\'')
+ ascii_initdata++;
+ if (*ascii_initdata == '\'')
+ ascii_initdata++;
+ if (*ascii_initdata != 0) {
+ log_assert(*ascii_initdata == 'b');
+ ascii_initdata++;
+ }
+ for (int word_idx = 0; word_idx < memory->size; word_idx++) {
+ Const initval = Const(State::Sx, memory->width);
+ bool initval_valid = false;
+ for (int bit_idx = memory->width-1; bit_idx >= 0; bit_idx--) {
+ if (*ascii_initdata == 0)
+ break;
+ if (*ascii_initdata == '0' || *ascii_initdata == '1') {
+ initval[bit_idx] = (*ascii_initdata == '0') ? State::S0 : State::S1;
+ initval_valid = true;
+ }
+ ascii_initdata++;
+ }
+ if (initval_valid) {
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$meminit");
+ cell->parameters["\\WORDS"] = 1;
+ if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound())
+ cell->setPort("\\ADDR", word_idx);
+ else
+ cell->setPort("\\ADDR", memory->size - word_idx - 1);
+ cell->setPort("\\DATA", initval);
+ cell->parameters["\\MEMID"] = RTLIL::Const(memory->name.str());
+ cell->parameters["\\ABITS"] = 32;
+ cell->parameters["\\WIDTH"] = memory->width;
+ cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1);
+ }
+ }
+ }
continue;
}
+ if (net->GetInitialValue())
+ init_nets[net] = net->GetInitialValue();
+
+ const char *rand_const_attr = net->GetAttValue(" rand_const");
+ const char *rand_attr = net->GetAttValue(" rand");
+
+ const char *anyconst_attr = net->GetAttValue("anyconst");
+ const char *anyseq_attr = net->GetAttValue("anyseq");
+
+ const char *allconst_attr = net->GetAttValue("allconst");
+ const char *allseq_attr = net->GetAttValue("allseq");
+
+ if (rand_const_attr != nullptr && (!strcmp(rand_const_attr, "1") || !strcmp(rand_const_attr, "'1'"))) {
+ anyconst_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (rand_attr != nullptr && (!strcmp(rand_attr, "1") || !strcmp(rand_attr, "'1'"))) {
+ anyseq_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (anyconst_attr != nullptr && (!strcmp(anyconst_attr, "1") || !strcmp(anyconst_attr, "'1'"))) {
+ anyconst_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (anyseq_attr != nullptr && (!strcmp(anyseq_attr, "1") || !strcmp(anyseq_attr, "'1'"))) {
+ anyseq_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (allconst_attr != nullptr && (!strcmp(allconst_attr, "1") || !strcmp(allconst_attr, "'1'"))) {
+ allconst_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (allseq_attr != nullptr && (!strcmp(allseq_attr, "1") || !strcmp(allseq_attr, "'1'"))) {
+ allseq_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+
if (net_map.count(net)) {
- // log(" skipping net %s.\n", net->Name());
+ if (verific_verbose)
+ log(" skipping net %s.\n", net->Name());
continue;
}
if (net->Bus())
continue;
- // log(" importing net %s.\n", net->Name());
+ RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : NEW_ID);
+
+ if (verific_verbose)
+ log(" importing net %s as %s.\n", net->Name(), log_id(wire_name));
- RTLIL::IdString wire_name = module->uniquify(RTLIL::escape_id(net->Name()));
RTLIL::Wire *wire = module->addWire(wire_name);
import_attributes(wire->attributes, net);
@@ -666,81 +936,191 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
if (found_new_net)
{
- // log(" importing netbus %s.\n", netbus->Name());
+ RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : NEW_ID);
+
+ if (verific_verbose)
+ log(" importing netbus %s as %s.\n", netbus->Name(), log_id(wire_name));
- RTLIL::IdString wire_name = module->uniquify(RTLIL::escape_id(netbus->Name()));
RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size());
wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex());
import_attributes(wire->attributes, netbus);
- for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) {
- if (netbus->ElementAtIndex(i)) {
+ RTLIL::Const initval = Const(State::Sx, GetSize(wire));
+ bool initval_valid = false;
+
+ for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1)
+ {
+ if (netbus->ElementAtIndex(i))
+ {
+ int bitidx = i - wire->start_offset;
net = netbus->ElementAtIndex(i);
- RTLIL::SigBit bit(wire, i - wire->start_offset);
+ RTLIL::SigBit bit(wire, bitidx);
+
+ if (init_nets.count(net)) {
+ if (init_nets.at(net) == '0')
+ initval.bits.at(bitidx) = State::S0;
+ if (init_nets.at(net) == '1')
+ initval.bits.at(bitidx) = State::S1;
+ initval_valid = true;
+ init_nets.erase(net);
+ }
+
if (net_map.count(net) == 0)
net_map[net] = bit;
else
- module->connect(bit, net_map.at(net));
+ module->connect(bit, net_map_at(net));
}
+
if (i == netbus->RightIndex())
break;
}
+
+ if (initval_valid)
+ wire->attributes["\\init"] = initval;
}
else
{
- // log(" skipping netbus %s.\n", netbus->Name());
+ if (verific_verbose)
+ log(" skipping netbus %s.\n", netbus->Name());
+ }
+
+ SigSpec anyconst_sig;
+ SigSpec anyseq_sig;
+ SigSpec allconst_sig;
+ SigSpec allseq_sig;
+
+ for (int i = netbus->RightIndex();; i += netbus->IsUp() ? -1 : +1) {
+ net = netbus->ElementAtIndex(i);
+ if (net != nullptr && anyconst_nets.count(net)) {
+ anyconst_sig.append(net_map_at(net));
+ anyconst_nets.erase(net);
+ }
+ if (net != nullptr && anyseq_nets.count(net)) {
+ anyseq_sig.append(net_map_at(net));
+ anyseq_nets.erase(net);
+ }
+ if (net != nullptr && allconst_nets.count(net)) {
+ allconst_sig.append(net_map_at(net));
+ allconst_nets.erase(net);
+ }
+ if (net != nullptr && allseq_nets.count(net)) {
+ allseq_sig.append(net_map_at(net));
+ allseq_nets.erase(net);
+ }
+ if (i == netbus->LeftIndex())
+ break;
}
+
+ if (GetSize(anyconst_sig))
+ module->connect(anyconst_sig, module->Anyconst(NEW_ID, GetSize(anyconst_sig)));
+
+ if (GetSize(anyseq_sig))
+ module->connect(anyseq_sig, module->Anyseq(NEW_ID, GetSize(anyseq_sig)));
+
+ if (GetSize(allconst_sig))
+ module->connect(allconst_sig, module->Allconst(NEW_ID, GetSize(allconst_sig)));
+
+ if (GetSize(allseq_sig))
+ module->connect(allseq_sig, module->Allseq(NEW_ID, GetSize(allseq_sig)));
}
+ for (auto it : init_nets)
+ {
+ Const initval;
+ SigBit bit = net_map_at(it.first);
+ log_assert(bit.wire);
+
+ if (bit.wire->attributes.count("\\init"))
+ initval = bit.wire->attributes.at("\\init");
+
+ while (GetSize(initval) < GetSize(bit.wire))
+ initval.bits.push_back(State::Sx);
+
+ if (it.second == '0')
+ initval.bits.at(bit.offset) = State::S0;
+ if (it.second == '1')
+ initval.bits.at(bit.offset) = State::S1;
+
+ bit.wire->attributes["\\init"] = initval;
+ }
+
+ for (auto net : anyconst_nets)
+ module->connect(net_map_at(net), module->Anyconst(NEW_ID));
+
+ for (auto net : anyseq_nets)
+ module->connect(net_map_at(net), module->Anyseq(NEW_ID));
+
+ pool<Instance*, hash_ptr_ops> sva_asserts;
+ pool<Instance*, hash_ptr_ops> sva_assumes;
+ pool<Instance*, hash_ptr_ops> sva_covers;
+ pool<Instance*, hash_ptr_ops> sva_triggers;
+
+ pool<RTLIL::Cell*> past_ffs;
+
FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst)
{
- // log(" importing cell %s (%s).\n", inst->Name(), inst->View()->Owner()->Name());
+ RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : NEW_ID);
+
+ if (verific_verbose)
+ log(" importing cell %s (%s) as %s.\n", inst->Name(), inst->View()->Owner()->Name(), log_id(inst_name));
+
+ if (mode_verific)
+ goto import_verific_cells;
if (inst->Type() == PRIM_PWR) {
- module->connect(net_map.at(inst->GetOutput()), RTLIL::State::S1);
+ module->connect(net_map_at(inst->GetOutput()), RTLIL::State::S1);
continue;
}
if (inst->Type() == PRIM_GND) {
- module->connect(net_map.at(inst->GetOutput()), RTLIL::State::S0);
+ module->connect(net_map_at(inst->GetOutput()), RTLIL::State::S0);
continue;
}
if (inst->Type() == PRIM_BUF) {
- module->addBufGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
+ auto outnet = inst->GetOutput();
+ if (!any_all_nets.count(outnet))
+ module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(outnet));
continue;
}
if (inst->Type() == PRIM_X) {
- module->connect(net_map.at(inst->GetOutput()), RTLIL::State::Sx);
+ module->connect(net_map_at(inst->GetOutput()), RTLIL::State::Sx);
continue;
}
if (inst->Type() == PRIM_Z) {
- module->connect(net_map.at(inst->GetOutput()), RTLIL::State::Sz);
+ module->connect(net_map_at(inst->GetOutput()), RTLIL::State::Sz);
continue;
}
if (inst->Type() == OPER_READ_PORT)
{
RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetInput()->Name()));
- if (memory->width != int(inst->OutputSize()))
- log_error("Import of asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
+ int numchunks = int(inst->OutputSize()) / memory->width;
+ int chunksbits = ceil_log2(numchunks);
- RTLIL::SigSpec addr = operatorInput1(inst, net_map);
- RTLIL::SigSpec data = operatorOutput(inst, net_map, module);
+ if ((numchunks * memory->width) != int(inst->OutputSize()) || (numchunks & (numchunks - 1)) != 0)
+ log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
- RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), "$memrd");
- cell->parameters["\\MEMID"] = memory->name.str();
- cell->parameters["\\CLK_ENABLE"] = false;
- cell->parameters["\\CLK_POLARITY"] = true;
- cell->parameters["\\TRANSPARENT"] = false;
- cell->parameters["\\ABITS"] = GetSize(addr);
- cell->parameters["\\WIDTH"] = GetSize(data);
- cell->setPort("\\CLK", RTLIL::State::Sx);
- cell->setPort("\\EN", RTLIL::State::Sx);
- cell->setPort("\\ADDR", addr);
- cell->setPort("\\DATA", data);
+ for (int i = 0; i < numchunks; i++)
+ {
+ RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)};
+ RTLIL::SigSpec data = operatorOutput(inst).extract(i * memory->width, memory->width);
+
+ RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name :
+ RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), "$memrd");
+ cell->parameters["\\MEMID"] = memory->name.str();
+ cell->parameters["\\CLK_ENABLE"] = false;
+ cell->parameters["\\CLK_POLARITY"] = true;
+ cell->parameters["\\TRANSPARENT"] = false;
+ cell->parameters["\\ABITS"] = GetSize(addr);
+ cell->parameters["\\WIDTH"] = GetSize(data);
+ cell->setPort("\\CLK", RTLIL::State::Sx);
+ cell->setPort("\\EN", RTLIL::State::Sx);
+ cell->setPort("\\ADDR", addr);
+ cell->setPort("\\DATA", data);
+ }
continue;
}
@@ -748,52 +1128,197 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
{
RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name()));
if (memory->width != int(inst->Input2Size()))
- log_error("Import of asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
+ log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
- RTLIL::SigSpec addr = operatorInput1(inst, net_map);
- RTLIL::SigSpec data = operatorInput2(inst, net_map);
+ RTLIL::SigSpec addr = operatorInput1(inst);
+ RTLIL::SigSpec data = operatorInput2(inst);
- RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), "$memwr");
+ RTLIL::Cell *cell = module->addCell(inst_name, "$memwr");
cell->parameters["\\MEMID"] = memory->name.str();
cell->parameters["\\CLK_ENABLE"] = false;
cell->parameters["\\CLK_POLARITY"] = true;
cell->parameters["\\PRIORITY"] = 0;
cell->parameters["\\ABITS"] = GetSize(addr);
cell->parameters["\\WIDTH"] = GetSize(data);
- cell->setPort("\\EN", RTLIL::SigSpec(net_map.at(inst->GetControl())).repeat(GetSize(data)));
+ cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data)));
cell->setPort("\\CLK", RTLIL::State::S0);
cell->setPort("\\ADDR", addr);
cell->setPort("\\DATA", data);
if (inst->Type() == OPER_CLOCKED_WRITE_PORT) {
cell->parameters["\\CLK_ENABLE"] = true;
- cell->setPort("\\CLK", net_map.at(inst->GetClock()));
+ cell->setPort("\\CLK", net_map_at(inst->GetClock()));
}
continue;
}
if (!mode_gates) {
- if (import_netlist_instance_cells(module, net_map, inst))
+ if (import_netlist_instance_cells(inst, inst_name))
continue;
- if (inst->IsOperator())
+ if (inst->IsOperator() && !verific_sva_prims.count(inst->Type()))
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))
+ if (import_netlist_instance_gates(inst, inst_name))
continue;
}
+ if (inst->Type() == PRIM_SVA_ASSERT || inst->Type() == PRIM_SVA_IMMEDIATE_ASSERT)
+ sva_asserts.insert(inst);
+
+ if (inst->Type() == PRIM_SVA_ASSUME || inst->Type() == PRIM_SVA_IMMEDIATE_ASSUME)
+ sva_assumes.insert(inst);
+
+ if (inst->Type() == PRIM_SVA_COVER || inst->Type() == PRIM_SVA_IMMEDIATE_COVER)
+ sva_covers.insert(inst);
+
+ if (inst->Type() == PRIM_SVA_TRIGGERED)
+ sva_triggers.insert(inst);
+
+ if (inst->Type() == OPER_SVA_STABLE)
+ {
+ VerificClocking clocking(this, inst->GetInput2Bit(0));
+ log_assert(clocking.disable_sig == State::S0);
+ log_assert(clocking.body_net == nullptr);
+
+ log_assert(inst->Input1Size() == inst->OutputSize());
+
+ SigSpec sig_d, sig_q, sig_o;
+ sig_q = module->addWire(NEW_ID, inst->Input1Size());
+
+ for (int i = int(inst->Input1Size())-1; i >= 0; i--){
+ sig_d.append(net_map_at(inst->GetInput1Bit(i)));
+ sig_o.append(net_map_at(inst->GetOutputBit(i)));
+ }
+
+ if (verific_verbose) {
+ log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
+ log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
+ log(" XNOR with A=%s, B=%s, Y=%s.\n",
+ log_signal(sig_d), log_signal(sig_q), log_signal(sig_o));
+ }
+
+ clocking.addDff(NEW_ID, sig_d, sig_q);
+ module->addXnor(NEW_ID, sig_d, sig_q, sig_o);
+
+ if (!mode_keep)
+ continue;
+ }
+
+ if (inst->Type() == PRIM_SVA_STABLE)
+ {
+ VerificClocking clocking(this, inst->GetInput2());
+ log_assert(clocking.disable_sig == State::S0);
+ log_assert(clocking.body_net == nullptr);
+
+ SigSpec sig_d = net_map_at(inst->GetInput1());
+ SigSpec sig_o = net_map_at(inst->GetOutput());
+ SigSpec sig_q = module->addWire(NEW_ID);
+
+ if (verific_verbose) {
+ log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
+ log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
+ log(" XNOR with A=%s, B=%s, Y=%s.\n",
+ log_signal(sig_d), log_signal(sig_q), log_signal(sig_o));
+ }
+
+ clocking.addDff(NEW_ID, sig_d, sig_q);
+ module->addXnor(NEW_ID, sig_d, sig_q, sig_o);
+
+ if (!mode_keep)
+ continue;
+ }
+
+ if (inst->Type() == PRIM_SVA_PAST)
+ {
+ VerificClocking clocking(this, inst->GetInput2());
+ log_assert(clocking.disable_sig == State::S0);
+ log_assert(clocking.body_net == nullptr);
+
+ SigBit sig_d = net_map_at(inst->GetInput1());
+ SigBit sig_q = net_map_at(inst->GetOutput());
+
+ if (verific_verbose)
+ log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
+ log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
+
+ past_ffs.insert(clocking.addDff(NEW_ID, sig_d, sig_q));
+
+ if (!mode_keep)
+ continue;
+ }
+
+ if ((inst->Type() == PRIM_SVA_ROSE || inst->Type() == PRIM_SVA_FELL))
+ {
+ VerificClocking clocking(this, inst->GetInput2());
+ log_assert(clocking.disable_sig == State::S0);
+ log_assert(clocking.body_net == nullptr);
+
+ SigBit sig_d = net_map_at(inst->GetInput1());
+ SigBit sig_o = net_map_at(inst->GetOutput());
+ SigBit sig_q = module->addWire(NEW_ID);
+
+ if (verific_verbose)
+ log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
+ log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
+
+ clocking.addDff(NEW_ID, sig_d, sig_q);
+ module->addEq(NEW_ID, {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o);
+
+ if (!mode_keep)
+ continue;
+ }
+
+ if (!mode_keep && verific_sva_prims.count(inst->Type())) {
+ if (verific_verbose)
+ log(" skipping SVA cell in non k-mode\n");
+ continue;
+ }
+
+ if (inst->Type() == PRIM_HDL_ASSERTION)
+ {
+ SigBit cond = net_map_at(inst->GetInput());
+
+ if (verific_verbose)
+ log(" assert condition %s.\n", log_signal(cond));
+
+ const char *assume_attr = nullptr; // inst->GetAttValue("assume");
+
+ Cell *cell = nullptr;
+ if (assume_attr != nullptr && !strcmp(assume_attr, "1"))
+ cell = module->addAssume(NEW_ID, cond, State::S1);
+ else
+ cell = module->addAssert(NEW_ID, cond, State::S1);
+
+ import_attributes(cell->attributes, inst);
+ continue;
+ }
+
if (inst->IsPrimitive())
- log_error("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name());
+ {
+ if (!mode_keep)
+ log_error("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name());
+
+ if (!verific_sva_prims.count(inst->Type()))
+ log_warning("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name());
+ }
+ import_verific_cells:
nl_todo.insert(inst->View());
- RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), inst->IsOperator() ?
+ RTLIL::Cell *cell = module->addCell(inst_name, inst->IsOperator() ?
std::string("$verific$") + inst->View()->Owner()->Name() : RTLIL::escape_id(inst->View()->Owner()->Name()));
+ if (inst->IsPrimitive() && mode_keep)
+ cell->attributes["\\keep"] = 1;
+
dict<IdString, vector<SigBit>> cell_port_conns;
+ if (verific_verbose)
+ log(" ports in verific db:\n");
+
FOREACH_PORTREF_OF_INST(inst, mi2, pr) {
- // log(" .%s(%s)\n", pr->GetPort()->Name(), pr->GetNet()->Name());
+ if (verific_verbose)
+ log(" .%s(%s)\n", pr->GetPort()->Name(), pr->GetNet()->Name());
const char *port_name = pr->GetPort()->Name();
int port_offset = 0;
if (pr->GetPort()->Bus()) {
@@ -808,127 +1333,685 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
for (auto bit : zwires)
sigvec.push_back(bit);
}
- sigvec[port_offset] = net_map.at(pr->GetNet());
+ sigvec[port_offset] = net_map_at(pr->GetNet());
}
+ if (verific_verbose)
+ log(" ports in yosys db:\n");
+
for (auto &it : cell_port_conns) {
- // log(" .%s(%s)\n", log_id(it.first), log_signal(it.second));
+ if (verific_verbose)
+ log(" .%s(%s)\n", log_id(it.first), log_signal(it.second));
cell->setPort(it.first, it.second);
}
}
+
+ if (!mode_nosva)
+ {
+ for (auto inst : sva_asserts) {
+ if (mode_autocover)
+ verific_import_sva_cover(this, inst);
+ verific_import_sva_assert(this, inst);
+ }
+
+ for (auto inst : sva_assumes)
+ verific_import_sva_assume(this, inst);
+
+ for (auto inst : sva_covers)
+ verific_import_sva_cover(this, inst);
+
+ for (auto inst : sva_triggers)
+ verific_import_sva_trigger(this, inst);
+
+ merge_past_ffs(past_ffs);
+ }
+}
+
+// ==================================================================
+
+VerificClocking::VerificClocking(VerificImporter *importer, Net *net, bool sva_at_only)
+{
+ module = importer->module;
+
+ log_assert(importer != nullptr);
+ log_assert(net != nullptr);
+
+ Instance *inst = net->Driver();
+
+ if (inst != nullptr && inst->Type() == PRIM_SVA_AT)
+ {
+ net = inst->GetInput1();
+ body_net = inst->GetInput2();
+
+ inst = net->Driver();
+
+ Instance *body_inst = body_net->Driver();
+ if (body_inst != nullptr && body_inst->Type() == PRIM_SVA_DISABLE_IFF) {
+ disable_net = body_inst->GetInput1();
+ disable_sig = importer->net_map_at(disable_net);
+ body_net = body_inst->GetInput2();
+ }
+ }
+ else
+ {
+ if (sva_at_only)
+ return;
+ }
+
+ // Use while() instead of if() to work around VIPER #13453
+ while (inst != nullptr && inst->Type() == PRIM_SVA_POSEDGE)
+ {
+ net = inst->GetInput();
+ inst = net->Driver();;
+ }
+
+ if (inst != nullptr && inst->Type() == PRIM_INV)
+ {
+ net = inst->GetInput();
+ inst = net->Driver();;
+ posedge = false;
+ }
+
+ // Detect clock-enable circuit
+ do {
+ if (inst == nullptr || inst->Type() != PRIM_AND)
+ break;
+
+ Net *net_dlatch = inst->GetInput1();
+ Instance *inst_dlatch = net_dlatch->Driver();
+
+ if (inst_dlatch == nullptr || inst_dlatch->Type() != PRIM_DLATCHRS)
+ break;
+
+ if (!inst_dlatch->GetSet()->IsGnd() || !inst_dlatch->GetReset()->IsGnd())
+ break;
+
+ Net *net_enable = inst_dlatch->GetInput();
+ Net *net_not_clock = inst_dlatch->GetControl();
+
+ if (net_enable == nullptr || net_not_clock == nullptr)
+ break;
+
+ Instance *inst_not_clock = net_not_clock->Driver();
+
+ if (inst_not_clock == nullptr || inst_not_clock->Type() != PRIM_INV)
+ break;
+
+ Net *net_clock1 = inst_not_clock->GetInput();
+ Net *net_clock2 = inst->GetInput2();
+
+ if (net_clock1 == nullptr || net_clock1 != net_clock2)
+ break;
+
+ enable_net = net_enable;
+ enable_sig = importer->net_map_at(enable_net);
+
+ net = net_clock1;
+ inst = net->Driver();;
+ } while (0);
+
+ // Detect condition expression
+ do {
+ if (body_net == nullptr)
+ break;
+
+ Instance *inst_mux = body_net->Driver();
+
+ if (inst_mux == nullptr || inst_mux->Type() != PRIM_MUX)
+ break;
+
+ if (!inst_mux->GetInput1()->IsPwr())
+ break;
+
+ Net *sva_net = inst_mux->GetInput2();
+ if (!verific_is_sva_net(importer, sva_net))
+ break;
+
+ body_net = sva_net;
+ cond_net = inst_mux->GetControl();
+ } while (0);
+
+ clock_net = net;
+ clock_sig = importer->net_map_at(clock_net);
+
+ const char *gclk_attr = clock_net->GetAttValue("gclk");
+ if (gclk_attr != nullptr && (!strcmp(gclk_attr, "1") || !strcmp(gclk_attr, "'1'")))
+ gclk = true;
}
+Cell *VerificClocking::addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value)
+{
+ log_assert(GetSize(sig_d) == GetSize(sig_q));
+
+ if (GetSize(init_value) != 0) {
+ log_assert(GetSize(sig_q) == GetSize(init_value));
+ if (sig_q.is_wire()) {
+ sig_q.as_wire()->attributes["\\init"] = init_value;
+ } else {
+ Wire *w = module->addWire(NEW_ID, GetSize(sig_q));
+ w->attributes["\\init"] = init_value;
+ module->connect(sig_q, w);
+ sig_q = w;
+ }
+ }
+
+ if (enable_sig != State::S1)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig);
+
+ if (disable_sig != State::S0) {
+ log_assert(gclk == false);
+ log_assert(GetSize(sig_q) == GetSize(init_value));
+ return module->addAdff(name, clock_sig, disable_sig, sig_d, sig_q, init_value, posedge);
+ }
+
+ if (gclk)
+ return module->addFf(name, sig_d, sig_q);
+
+ return module->addDff(name, clock_sig, sig_d, sig_q, posedge);
+}
+
+Cell *VerificClocking::addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value)
+{
+ log_assert(gclk == false);
+ log_assert(disable_sig == State::S0);
+
+ if (enable_sig != State::S1)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig);
+
+ return module->addAdff(name, clock_sig, sig_arst, sig_d, sig_q, arst_value, posedge);
+}
+
+Cell *VerificClocking::addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q)
+{
+ log_assert(gclk == false);
+ log_assert(disable_sig == State::S0);
+
+ if (enable_sig != State::S1)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig);
+
+ return module->addDffsr(name, clock_sig, sig_set, sig_clr, sig_d, sig_q, posedge);
+}
+
+// ==================================================================
+
+struct VerificExtNets
+{
+ int portname_cnt = 0;
+
+ // a map from Net to the same Net one level up in the design hierarchy
+ std::map<Net*, Net*> net_level_up;
+
+ Net *get_net_level_up(Net *net)
+ {
+ if (net_level_up.count(net) == 0)
+ {
+ Netlist *nl = net->Owner();
+
+ // Simply return if Netlist is not unique
+ if (nl->NumOfRefs() != 1)
+ return net;
+
+ Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
+ Netlist *up_nl = up_inst->Owner();
+
+ // create new Port
+ string name = stringf("___extnets_%d", portname_cnt++);
+ Port *new_port = new Port(name.c_str(), DIR_OUT);
+ nl->Add(new_port);
+ net->Connect(new_port);
+
+ // create new Net in up Netlist
+ Net *new_net = new Net(name.c_str());
+ up_nl->Add(new_net);
+ up_inst->Connect(new_port, new_net);
+
+ net_level_up[net] = new_net;
+ }
+
+ return net_level_up.at(net);
+ }
+
+ void run(Netlist *nl)
+ {
+ MapIter mi, mi2;
+ Instance *inst;
+ PortRef *pr;
+
+ vector<tuple<Instance*, Port*, Net*>> todo_connect;
+
+ FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst)
+ run(inst->View());
+
+ FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst)
+ FOREACH_PORTREF_OF_INST(inst, mi2, pr)
+ {
+ Port *port = pr->GetPort();
+ Net *net = pr->GetNet();
+
+ if (!net->IsExternalTo(nl))
+ continue;
+
+ if (verific_verbose)
+ log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
+
+ while (net->IsExternalTo(nl))
+ {
+ Net *newnet = get_net_level_up(net);
+ if (newnet == net) break;
+
+ if (verific_verbose)
+ log(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name());
+ net = newnet;
+ }
+
+ if (verific_verbose)
+ log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : "");
+ todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net));
+ }
+
+ for (auto it : todo_connect) {
+ get<0>(it)->Disconnect(get<1>(it));
+ get<0>(it)->Connect(get<1>(it), get<2>(it));
+ }
+ }
+};
+
+void verific_import(Design *design, std::string top)
+{
+ std::set<Netlist*> nl_todo, nl_done;
+
+ {
+ VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
+ VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
+
+ Array veri_libs, vhdl_libs;
+ if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
+ if (veri_lib) veri_libs.InsertLast(veri_lib);
+
+ Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
+ Netlist *nl;
+ int i;
+
+ FOREACH_ARRAY_ITEM(netlists, i, nl) {
+ if (top.empty() || nl->Owner()->Name() == top)
+ nl_todo.insert(nl);
+ }
+
+ delete netlists;
+ }
+
+ if (!verific_error_msg.empty())
+ log_error("%s\n", verific_error_msg.c_str());
+
+ VerificExtNets worker;
+ for (auto nl : nl_todo)
+ worker.run(nl);
+
+ while (!nl_todo.empty()) {
+ Netlist *nl = *nl_todo.begin();
+ if (nl_done.count(nl) == 0) {
+ VerificImporter importer(false, false, false, false, false, false);
+ importer.import_netlist(design, nl, nl_todo);
+ }
+ nl_todo.erase(nl);
+ nl_done.insert(nl);
+ }
+
+ veri_file::Reset();
+ vhdl_file::Reset();
+ Libset::Reset();
+ verific_incdirs.clear();
+ verific_libdirs.clear();
+ verific_import_pending = false;
+
+ if (!verific_error_msg.empty())
+ log_error("%s\n", verific_error_msg.c_str());
+}
+
+YOSYS_NAMESPACE_END
#endif /* YOSYS_ENABLE_VERIFIC */
-YOSYS_NAMESPACE_BEGIN
+PRIVATE_NAMESPACE_BEGIN
+
+bool check_noverific_env()
+{
+ const char *e = getenv("YOSYS_NOVERIFIC");
+ if (e == nullptr)
+ return false;
+ if (atoi(e) == 0)
+ return false;
+ return true;
+}
struct VerificPass : public Pass {
VerificPass() : Pass("verific", "load Verilog and VHDL designs using Verific") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv} <verilog-file>..\n");
+ log(" verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv} <verilog-file>..\n");
log("\n");
log("Load the specified Verilog/SystemVerilog files into Verific.\n");
log("\n");
+ log("All files specified in one call to this command are one compilation unit.\n");
+ log("Files passed to different calls to this command are treated as belonging to\n");
+ log("different compilation units.\n");
log("\n");
- log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008} <vhdl-file>..\n");
+ log("Additional -D<macro>[=<value>] options may be added after the option indicating\n");
+ log("the language version (and before file names) to set additional verilog defines.\n");
+ log("The macros SYNTHESIS and VERIFIC are defined implicitly.\n");
+ log("\n");
+ log("\n");
+ log(" verific -formal <verilog-file>..\n");
+ log("\n");
+ log("Like -sv, but define FORMAL instead of SYNTHESIS.\n");
+ log("\n");
+ log("\n");
+ log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n");
log("\n");
log("Load the specified VHDL files into Verific.\n");
log("\n");
log("\n");
- log(" verific -import [-gates] {-all | <top-module>..}\n");
+ log(" verific -work <libname> {-sv|-vhdl|...} <hdl-file>\n");
+ log("\n");
+ log("Load the specified Verilog/SystemVerilog/VHDL file into the specified library.\n");
+ log("(default library when -work is not present: \"work\")\n");
+ log("\n");
+ log("\n");
+ log(" verific -vlog-incdir <directory>..\n");
+ log("\n");
+ log("Add Verilog include directories.\n");
+ log("\n");
+ log("\n");
+ log(" verific -vlog-libdir <directory>..\n");
+ log("\n");
+ log("Add Verilog library directories. Verific will search in this directories to\n");
+ log("find undefined modules.\n");
+ log("\n");
+ log("\n");
+ log(" verific -vlog-define <macro>[=<value>]..\n");
+ log("\n");
+ log("Add Verilog defines.\n");
+ log("\n");
+ log("\n");
+ log(" verific -vlog-undef <macro>..\n");
+ log("\n");
+ log("Remove Verilog defines previously set with -vlog-define.\n");
+ log("\n");
+ log("\n");
+ log(" verific -set-error <msg_id>..\n");
+ log(" verific -set-warning <msg_id>..\n");
+ log(" verific -set-info <msg_id>..\n");
+ log(" verific -set-ignore <msg_id>..\n");
+ log("\n");
+ log("Set message severity. <msg_id> is the string in square brackets when a message\n");
+ log("is printed, such as VERI-1209.\n");
+ log("\n");
+ log("\n");
+ log(" verific -import [options] <top-module>..\n");
log("\n");
log("Elaborate the design for the specified top modules, import to Yosys and\n");
- log("reset the internal state of Verific. A gate-level netlist is created\n");
- log("when called with -gates.\n");
+ log("reset the internal state of Verific.\n");
+ log("\n");
+ log("Import options:\n");
+ log("\n");
+ log(" -all\n");
+ log(" Elaborate all modules, not just the hierarchy below the given top\n");
+ log(" modules. With this option the list of modules to import is optional.\n");
+ log("\n");
+ log(" -gates\n");
+ log(" Create a gate-level netlist.\n");
+ log("\n");
+ log(" -flatten\n");
+ log(" Flatten the design in Verific before importing.\n");
+ log("\n");
+ log(" -extnets\n");
+ log(" Resolve references to external nets by adding module ports as needed.\n");
+ log("\n");
+ log(" -autocover\n");
+ log(" Generate automatic cover statements for all asserts\n");
+ log("\n");
+ log(" -v, -vv\n");
+ log(" Verbose log messages. (-vv is even more verbose than -v.)\n");
+ log("\n");
+ log("The following additional import options are useful for debugging the Verific\n");
+ log("bindings (for Yosys and/or Verific developers):\n");
+ log("\n");
+ log(" -k\n");
+ log(" Keep going after an unsupported verific primitive is found. The\n");
+ log(" unsupported primitive is added as blockbox module to the design.\n");
+ log(" This will also add all SVA related cells to the design parallel to\n");
+ log(" the checker logic inferred by it.\n");
+ log("\n");
+ log(" -V\n");
+ log(" Import Verific netlist as-is without translating to Yosys cell types. \n");
+ log("\n");
+ log(" -nosva\n");
+ log(" Ignore SVA properties, do not infer checker logic.\n");
+ log("\n");
+ log(" -n\n");
+ log(" Keep all Verific names on instances and nets. By default only\n");
+ log(" user-declared names are preserved.\n");
+ log("\n");
+ log(" -d <dump_file>\n");
+ log(" Dump the Verific netlist as a verilog file.\n");
log("\n");
log("Visit http://verific.com/ for more information on Verific.\n");
log("\n");
}
#ifdef YOSYS_ENABLE_VERIFIC
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- log_header(design, "Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n");
+ static bool set_verific_global_flags = true;
- Message::SetConsoleOutput(0);
- Message::RegisterCallBackMsg(msg_func);
+ if (check_noverific_env())
+ log_cmd_error("This version of Yosys is built without Verific support.\n");
- if (args.size() > 1 && args[1] == "-vlog95") {
- for (size_t argidx = 2; argidx < args.size(); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_95))
- log_cmd_error("Reading `%s' in VERILOG_95 mode failed.\n", args[argidx].c_str());
- return;
+ log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n");
+
+ if (set_verific_global_flags)
+ {
+ Message::SetConsoleOutput(0);
+ Message::RegisterCallBackMsg(msg_func);
+ RuntimeFlags::SetVar("db_preserve_user_nets", 1);
+ RuntimeFlags::SetVar("db_allow_external_nets", 1);
+ RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0);
+ RuntimeFlags::SetVar("veri_extract_dualport_rams", 0);
+ RuntimeFlags::SetVar("veri_extract_multiport_rams", 1);
+ RuntimeFlags::SetVar("db_infer_wide_operators", 1);
+
+ // Workaround for VIPER #13851
+ RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1);
+
+ // WARNING: instantiating unknown module 'XYZ' (VERI-1063)
+ Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
+
+ set_verific_global_flags = false;
}
- if (args.size() > 1 && args[1] == "-vlog2k") {
- for (size_t argidx = 2; argidx < args.size(); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_2K))
- log_cmd_error("Reading `%s' in VERILOG_2K mode failed.\n", args[argidx].c_str());
- return;
+ verific_verbose = 0;
+
+ const char *release_str = Message::ReleaseString();
+ time_t release_time = Message::ReleaseDate();
+ char *release_tmstr = ctime(&release_time);
+
+ if (release_str == nullptr)
+ release_str = "(no release string)";
+
+ for (char *p = release_tmstr; *p; p++)
+ if (*p == '\n') *p = 0;
+
+ log("Built with Verific %s, released at %s.\n", release_str, release_tmstr);
+
+ int argidx = 1;
+ std::string work = "work";
+
+ if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" ||
+ args[argidx] == "-set-info" || args[argidx] == "-set-ignore"))
+ {
+ msg_type_t new_type;
+
+ if (args[argidx] == "-set-error")
+ new_type = VERIFIC_ERROR;
+ else if (args[argidx] == "-set-warning")
+ new_type = VERIFIC_WARNING;
+ else if (args[argidx] == "-set-info")
+ new_type = VERIFIC_INFO;
+ else if (args[argidx] == "-set-ignore")
+ new_type = VERIFIC_IGNORE;
+ else
+ log_abort();
+
+ for (argidx++; argidx < GetSize(args); argidx++)
+ Message::SetMessageType(args[argidx].c_str(), new_type);
+
+ goto check_error;
}
- if (args.size() > 1 && args[1] == "-sv2005") {
- for (size_t argidx = 2; argidx < args.size(); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2005))
- log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2005 mode failed.\n", args[argidx].c_str());
- return;
+ if (GetSize(args) > argidx && args[argidx] == "-vlog-incdir") {
+ for (argidx++; argidx < GetSize(args); argidx++)
+ verific_incdirs.push_back(args[argidx]);
+ goto check_error;
}
- if (args.size() > 1 && args[1] == "-sv2009") {
- for (size_t argidx = 2; argidx < args.size(); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2009))
- log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2009 mode failed.\n", args[argidx].c_str());
- return;
+ if (GetSize(args) > argidx && args[argidx] == "-vlog-libdir") {
+ for (argidx++; argidx < GetSize(args); argidx++)
+ verific_libdirs.push_back(args[argidx]);
+ goto check_error;
}
- if (args.size() > 1 && args[1] == "-sv") {
- for (size_t argidx = 2; argidx < args.size(); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG))
- log_cmd_error("Reading `%s' in SYSTEM_VERILOG mode failed.\n", args[argidx].c_str());
- return;
+ if (GetSize(args) > argidx && args[argidx] == "-vlog-define") {
+ for (argidx++; argidx < GetSize(args); argidx++) {
+ string name = args[argidx];
+ size_t equal = name.find('=');
+ if (equal != std::string::npos) {
+ string value = name.substr(equal+1);
+ name = name.substr(0, equal);
+ veri_file::DefineCmdLineMacro(name.c_str(), value.c_str());
+ } else {
+ veri_file::DefineCmdLineMacro(name.c_str());
+ }
+ }
+ goto check_error;
}
- if (args.size() > 1 && args[1] == "-vhdl87") {
+ if (GetSize(args) > argidx && args[argidx] == "-vlog-undef") {
+ for (argidx++; argidx < GetSize(args); argidx++) {
+ string name = args[argidx];
+ veri_file::UndefineMacro(name.c_str());
+ }
+ goto check_error;
+ }
+
+ for (; argidx < GetSize(args); argidx++)
+ {
+ if (args[argidx] == "-work" && argidx+1 < GetSize(args)) {
+ work = args[++argidx];
+ continue;
+ }
+ break;
+ }
+
+ if (GetSize(args) > argidx && (args[argidx] == "-vlog95" || args[argidx] == "-vlog2k" || args[argidx] == "-sv2005" ||
+ args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal"))
+ {
+ Array file_names;
+ unsigned verilog_mode;
+
+ if (args[argidx] == "-vlog95")
+ verilog_mode = veri_file::VERILOG_95;
+ else if (args[argidx] == "-vlog2k")
+ verilog_mode = veri_file::VERILOG_2K;
+ else if (args[argidx] == "-sv2005")
+ verilog_mode = veri_file::SYSTEM_VERILOG_2005;
+ else if (args[argidx] == "-sv2009")
+ verilog_mode = veri_file::SYSTEM_VERILOG_2009;
+ else if (args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal")
+ verilog_mode = veri_file::SYSTEM_VERILOG;
+ else
+ log_abort();
+
+ veri_file::DefineMacro("VERIFIC");
+ veri_file::DefineMacro(args[argidx] == "-formal" ? "FORMAL" : "SYNTHESIS");
+
+ for (argidx++; argidx < GetSize(args) && GetSize(args[argidx]) >= 2 && args[argidx].substr(0, 2) == "-D"; argidx++) {
+ std::string name = args[argidx].substr(2);
+ if (args[argidx] == "-D") {
+ if (++argidx >= GetSize(args))
+ break;
+ name = args[argidx];
+ }
+ size_t equal = name.find('=');
+ if (equal != std::string::npos) {
+ string value = name.substr(equal+1);
+ name = name.substr(0, equal);
+ veri_file::DefineMacro(name.c_str(), value.c_str());
+ } else {
+ veri_file::DefineMacro(name.c_str());
+ }
+ }
+
+ for (auto &dir : verific_incdirs)
+ veri_file::AddIncludeDir(dir.c_str());
+ for (auto &dir : verific_libdirs)
+ veri_file::AddYDir(dir.c_str());
+
+ while (argidx < GetSize(args))
+ file_names.Insert(args[argidx++].c_str());
+
+ if (!veri_file::AnalyzeMultipleFiles(&file_names, verilog_mode, work.c_str(), veri_file::MFCU))
+ log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n");
+
+ verific_import_pending = true;
+ goto check_error;
+ }
+
+ if (GetSize(args) > argidx && args[argidx] == "-vhdl87") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str());
- for (size_t argidx = 2; argidx < args.size(); argidx++)
- if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_87))
+ for (argidx++; argidx < GetSize(args); argidx++)
+ if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_87))
log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str());
- return;
+ verific_import_pending = true;
+ goto check_error;
}
- if (args.size() > 1 && args[1] == "-vhdl93") {
+ if (GetSize(args) > argidx && args[argidx] == "-vhdl93") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
- for (size_t argidx = 2; argidx < args.size(); argidx++)
- if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_93))
+ for (argidx++; argidx < GetSize(args); argidx++)
+ if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_93))
log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", args[argidx].c_str());
- return;
+ verific_import_pending = true;
+ goto check_error;
}
- if (args.size() > 1 && args[1] == "-vhdl2k") {
+ if (GetSize(args) > argidx && args[argidx] == "-vhdl2k") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
- for (size_t argidx = 2; argidx < args.size(); argidx++)
- if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2K))
+ for (argidx++; argidx < GetSize(args); argidx++)
+ if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2K))
log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", args[argidx].c_str());
- return;
+ verific_import_pending = true;
+ goto check_error;
}
- if (args.size() > 1 && args[1] == "-vhdl2008") {
+ if (GetSize(args) > argidx && (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl")) {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str());
- for (size_t argidx = 2; argidx < args.size(); argidx++)
- if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2008))
+ for (argidx++; argidx < GetSize(args); argidx++)
+ if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2008))
log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", args[argidx].c_str());
- return;
+ verific_import_pending = true;
+ goto check_error;
}
- if (args.size() > 1 && args[1] == "-import")
+ if (GetSize(args) > argidx && args[argidx] == "-import")
{
std::set<Netlist*> nl_todo, nl_done;
- bool mode_all = false, mode_gates = false;
+ bool mode_all = false, mode_gates = false, mode_keep = false;
+ bool mode_nosva = false, mode_names = false, mode_verific = false;
+ bool mode_autocover = false;
+ bool flatten = false, extnets = false;
+ string dumpfile;
- size_t argidx = 2;
- for (; argidx < args.size(); argidx++) {
+ for (argidx++; argidx < GetSize(args); argidx++) {
if (args[argidx] == "-all") {
mode_all = true;
continue;
@@ -937,69 +2020,342 @@ struct VerificPass : public Pass {
mode_gates = true;
continue;
}
+ if (args[argidx] == "-flatten") {
+ flatten = true;
+ continue;
+ }
+ if (args[argidx] == "-extnets") {
+ extnets = true;
+ continue;
+ }
+ if (args[argidx] == "-k") {
+ mode_keep = true;
+ continue;
+ }
+ if (args[argidx] == "-nosva") {
+ mode_nosva = true;
+ continue;
+ }
+ if (args[argidx] == "-n") {
+ mode_names = true;
+ continue;
+ }
+ if (args[argidx] == "-autocover") {
+ mode_autocover = true;
+ continue;
+ }
+ if (args[argidx] == "-V") {
+ mode_verific = true;
+ continue;
+ }
+ if (args[argidx] == "-v") {
+ verific_verbose = 1;
+ continue;
+ }
+ if (args[argidx] == "-vv") {
+ verific_verbose = 2;
+ continue;
+ }
+ if (args[argidx] == "-d" && argidx+1 < GetSize(args)) {
+ dumpfile = args[++argidx];
+ continue;
+ }
break;
}
- if (argidx > args.size() && args[argidx].substr(0, 1) == "-")
+ if (argidx > GetSize(args) && args[argidx].substr(0, 1) == "-")
cmd_error(args, argidx, "unknown option");
if (mode_all)
{
- if (argidx != args.size())
- log_cmd_error("Got -all and an explicit list of top modules.\n");
-
- MapIter m1, m2, m3;
- VeriModule *mod;
- FOREACH_VERILOG_MODULE(m1, mod)
- args.push_back(mod->Name());
-
- VhdlLibrary *lib;
- VhdlPrimaryUnit *primunit;
- FOREACH_VHDL_LIBRARY(m1, lib)
- FOREACH_VHDL_PRIMARY_UNIT(lib, m2, primunit) {
- if (primunit->IsPackageDecl())
- continue;
- args.push_back(primunit->Name());
+#if 0
+ log("Running veri_file::ElaborateAll().\n");
+ if (!veri_file::ElaborateAll())
+ log_cmd_error("Elaboration of Verilog modules failed.\n");
+
+ log("Running vhdl_file::ElaborateAll().\n");
+ if (!vhdl_file::ElaborateAll())
+ log_cmd_error("Elaboration of VHDL modules failed.\n");
+
+ Library *lib = Netlist::PresentDesign()->Owner()->Owner();
+
+ if (argidx == GetSize(args))
+ {
+ MapIter iter;
+ char *iter_name;
+ Verific::Cell *iter_cell;
+
+ FOREACH_MAP_ITEM(lib->GetCells(), iter, &iter_name, &iter_cell) {
+ if (*iter_name != '$')
+ nl_todo.insert(iter_cell->GetFirstNetlist());
+ }
+ }
+ else
+ {
+ for (; argidx < GetSize(args); argidx++)
+ {
+ Verific::Cell *cell = lib->GetCell(args[argidx].c_str());
+
+ if (cell == nullptr)
+ log_cmd_error("Module not found: %s\n", args[argidx].c_str());
+
+ nl_todo.insert(cell->GetFirstNetlist());
+ cell->GetFirstNetlist()->SetPresentDesign();
+ }
}
+#else
+ log("Running hier_tree::ElaborateAll().\n");
+
+ VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
+ VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1);
+
+ Array veri_libs, vhdl_libs;
+ if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
+ if (veri_lib) veri_libs.InsertLast(veri_lib);
+
+ Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
+ Netlist *nl;
+ int i;
+
+ FOREACH_ARRAY_ITEM(netlists, i, nl)
+ nl_todo.insert(nl);
+ delete netlists;
+#endif
}
else
- if (argidx == args.size())
+ {
+ if (argidx == GetSize(args))
log_cmd_error("No top module specified.\n");
- for (; argidx < args.size(); argidx++) {
- if (veri_file::GetModule(args[argidx].c_str())) {
- log("Running veri_file::Elaborate(\"%s\").\n", args[argidx].c_str());
- if (!veri_file::Elaborate(args[argidx].c_str()))
- log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
- nl_todo.insert(Netlist::PresentDesign());
- } else {
- log("Running vhdl_file::Elaborate(\"%s\").\n", args[argidx].c_str());
- if (!vhdl_file::Elaborate(args[argidx].c_str()))
- log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
- nl_todo.insert(Netlist::PresentDesign());
+#if 0
+ for (; argidx < GetSize(args); argidx++) {
+ if (veri_file::GetModule(args[argidx].c_str())) {
+ log("Running veri_file::Elaborate(\"%s\").\n", args[argidx].c_str());
+ if (!veri_file::Elaborate(args[argidx].c_str()))
+ log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
+ nl_todo.insert(Netlist::PresentDesign());
+ } else {
+ log("Running vhdl_file::Elaborate(\"%s\").\n", args[argidx].c_str());
+ if (!vhdl_file::Elaborate(args[argidx].c_str()))
+ log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
+ nl_todo.insert(Netlist::PresentDesign());
+ }
+ }
+#else
+ Array veri_modules, vhdl_units;
+ for (; argidx < GetSize(args); argidx++)
+ {
+ const char *name = args[argidx].c_str();
+
+ VeriModule *veri_module = veri_file::GetModule(name);
+ if (veri_module) {
+ log("Adding Verilog module '%s' to elaboration queue.\n", name);
+ veri_modules.InsertLast(veri_module);
+ continue;
+ }
+
+ VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
+ VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(name);
+ if (vhdl_unit) {
+ log("Adding VHDL unit '%s' to elaboration queue.\n", name);
+ vhdl_units.InsertLast(vhdl_unit);
+ continue;
+ }
+
+ log_error("Can't find module/unit '%s'.\n", name);
}
+
+ log("Running hier_tree::Elaborate().\n");
+ Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units);
+ Netlist *nl;
+ int i;
+
+ FOREACH_ARRAY_ITEM(netlists, i, nl)
+ nl_todo.insert(nl);
+ delete netlists;
+#endif
+ }
+
+ if (!verific_error_msg.empty())
+ goto check_error;
+
+ if (flatten) {
+ for (auto nl : nl_todo)
+ nl->Flatten();
+ }
+
+ if (extnets) {
+ VerificExtNets worker;
+ for (auto nl : nl_todo)
+ worker.run(nl);
+ }
+
+ if (!dumpfile.empty()) {
+ VeriWrite veri_writer;
+ veri_writer.WriteFile(dumpfile.c_str(), Netlist::PresentDesign());
}
while (!nl_todo.empty()) {
Netlist *nl = *nl_todo.begin();
- if (nl_done.count(nl) == 0)
- import_netlist(design, nl, nl_todo, mode_gates);
+ if (nl_done.count(nl) == 0) {
+ VerificImporter importer(mode_gates, mode_keep, mode_nosva,
+ mode_names, mode_verific, mode_autocover);
+ importer.import_netlist(design, nl, nl_todo);
+ }
nl_todo.erase(nl);
nl_done.insert(nl);
}
+ veri_file::Reset();
+ vhdl_file::Reset();
Libset::Reset();
- return;
+ verific_incdirs.clear();
+ verific_libdirs.clear();
+ verific_import_pending = false;
+ goto check_error;
}
log_cmd_error("Missing or unsupported mode parameter.\n");
+
+ check_error:
+ if (!verific_error_msg.empty())
+ log_error("%s\n", verific_error_msg.c_str());
+
}
#else /* YOSYS_ENABLE_VERIFIC */
- virtual void execute(std::vector<std::string>, RTLIL::Design *) {
+ void execute(std::vector<std::string>, RTLIL::Design *) YS_OVERRIDE {
log_cmd_error("This version of Yosys is built without Verific support.\n");
}
#endif
} VerificPass;
-YOSYS_NAMESPACE_END
+struct ReadPass : public Pass {
+ ReadPass() : Pass("read", "load HDL designs") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" read {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv|-formal} <verilog-file>..\n");
+ log("\n");
+ log("Load the specified Verilog/SystemVerilog files. (Full SystemVerilog support\n");
+ log("is only available via Verific.)\n");
+ log("\n");
+ log("Additional -D<macro>[=<value>] options may be added after the option indicating\n");
+ log("the language version (and before file names) to set additional verilog defines.\n");
+ log("\n");
+ log("\n");
+ log(" read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n");
+ log("\n");
+ log("Load the specified VHDL files. (Requires Verific.)\n");
+ log("\n");
+ log("\n");
+ log(" read -define <macro>[=<value>]..\n");
+ log("\n");
+ log("Set global Verilog/SystemVerilog defines.\n");
+ log("\n");
+ log("\n");
+ log(" read -undef <macro>..\n");
+ log("\n");
+ log("Unset global Verilog/SystemVerilog defines.\n");
+ log("\n");
+ log("\n");
+ log(" read -incdir <directory>\n");
+ log("\n");
+ log("Add directory to global Verilog/SystemVerilog include directories.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ if (args.size() < 2)
+ log_cmd_error("Missing mode parameter.\n");
+
+ if (args.size() < 3)
+ log_cmd_error("Missing file name parameter.\n");
+
+#ifdef YOSYS_ENABLE_VERIFIC
+ bool use_verific = !check_noverific_env();
+#else
+ bool use_verific = false;
+#endif
+
+ if (args[1] == "-vlog95" || args[1] == "-vlog2k") {
+ if (use_verific) {
+ args[0] = "verific";
+ } else {
+ args[0] = "read_verilog";
+ args.erase(args.begin()+1, args.begin()+2);
+ }
+ Pass::call(design, args);
+ return;
+ }
+
+ if (args[1] == "-sv2005" || args[1] == "-sv2009" || args[1] == "-sv2012" || args[1] == "-sv" || args[1] == "-formal") {
+ if (use_verific) {
+ args[0] = "verific";
+ } else {
+ args[0] = "read_verilog";
+ if (args[1] == "-formal")
+ args.insert(args.begin()+1, std::string());
+ args[1] = "-sv";
+ }
+ Pass::call(design, args);
+ return;
+ }
+
+ if (args[1] == "-vhdl87" || args[1] == "-vhdl93" || args[1] == "-vhdl2k" || args[1] == "-vhdl2008" || args[1] == "-vhdl") {
+ if (use_verific) {
+ args[0] = "verific";
+ Pass::call(design, args);
+ } else {
+ log_cmd_error("This version of Yosys is built without Verific support.\n");
+ }
+ return;
+ }
+
+ if (args[1] == "-define") {
+ if (use_verific) {
+ args[0] = "verific";
+ args[1] = "-vlog-define";
+ Pass::call(design, args);
+ }
+ args[0] = "verilog_defines";
+ args.erase(args.begin()+1, args.begin()+2);
+ for (int i = 1; i < GetSize(args); i++)
+ args[i] = "-D" + args[i];
+ Pass::call(design, args);
+ return;
+ }
+
+ if (args[1] == "-undef") {
+ if (use_verific) {
+ args[0] = "verific";
+ args[1] = "-vlog-undef";
+ Pass::call(design, args);
+ }
+ args[0] = "verilog_defines";
+ args.erase(args.begin()+1, args.begin()+2);
+ for (int i = 1; i < GetSize(args); i++)
+ args[i] = "-U" + args[i];
+ Pass::call(design, args);
+ return;
+ }
+
+ if (args[1] == "-incdir") {
+ if (use_verific) {
+ args[0] = "verific";
+ args[1] = "-vlog-incdir";
+ Pass::call(design, args);
+ }
+ args[0] = "verilog_defaults";
+ args[1] = "-add";
+ for (int i = 2; i < GetSize(args); i++)
+ args[i] = "-I" + args[i];
+ Pass::call(design, args);
+ return;
+ }
+
+ log_cmd_error("Missing or unsupported mode parameter.\n");
+ }
+} ReadPass;
+PRIVATE_NAMESPACE_END
diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h
new file mode 100644
index 00000000..cbd9314d
--- /dev/null
+++ b/frontends/verific/verific.h
@@ -0,0 +1,106 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifdef YOSYS_ENABLE_VERIFIC
+
+#include "DataBase.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+extern int verific_verbose;
+
+extern bool verific_import_pending;
+extern void verific_import(Design *design, std::string top = std::string());
+
+extern pool<int> verific_sva_prims;
+
+struct VerificImporter;
+
+struct VerificClocking {
+ RTLIL::Module *module = nullptr;
+ Verific::Net *clock_net = nullptr;
+ Verific::Net *enable_net = nullptr;
+ Verific::Net *disable_net = nullptr;
+ Verific::Net *body_net = nullptr;
+ Verific::Net *cond_net = nullptr;
+ SigBit clock_sig = State::Sx;
+ SigBit enable_sig = State::S1;
+ SigBit disable_sig = State::S0;
+ bool posedge = true;
+ bool gclk = false;
+
+ VerificClocking() { }
+ VerificClocking(VerificImporter *importer, Verific::Net *net, bool sva_at_only = false);
+ RTLIL::Cell *addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value = Const());
+ RTLIL::Cell *addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value);
+ RTLIL::Cell *addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q);
+
+ bool property_matches_sequence(const VerificClocking &seq) const {
+ if (clock_net != seq.clock_net)
+ return false;
+ if (enable_net != seq.enable_net)
+ return false;
+ if (posedge != seq.posedge)
+ return false;
+ return true;
+ }
+};
+
+struct VerificImporter
+{
+ RTLIL::Module *module;
+ Verific::Netlist *netlist;
+
+ std::map<Verific::Net*, RTLIL::SigBit> net_map;
+ std::map<Verific::Net*, Verific::Net*> sva_posedge_map;
+ pool<Verific::Net*, hash_ptr_ops> any_all_nets;
+
+ bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific;
+ bool mode_autocover;
+
+ VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover);
+
+ RTLIL::SigBit net_map_at(Verific::Net *net);
+
+ void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj);
+
+ RTLIL::SigSpec operatorInput(Verific::Instance *inst);
+ RTLIL::SigSpec operatorInput1(Verific::Instance *inst);
+ RTLIL::SigSpec operatorInput2(Verific::Instance *inst);
+ RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname);
+ RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool<Verific::Net*, hash_ptr_ops> *any_all_nets = nullptr);
+
+ bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name);
+ bool import_netlist_instance_cells(Verific::Instance *inst, RTLIL::IdString inst_name);
+
+ void merge_past_ffs_clock(pool<RTLIL::Cell*> &candidates, SigBit clock, bool clock_pol);
+ void merge_past_ffs(pool<RTLIL::Cell*> &candidates);
+
+ void import_netlist(RTLIL::Design *design, Verific::Netlist *nl, std::set<Verific::Netlist*> &nl_todo);
+};
+
+void verific_import_sva_assert(VerificImporter *importer, Verific::Instance *inst);
+void verific_import_sva_assume(VerificImporter *importer, Verific::Instance *inst);
+void verific_import_sva_cover(VerificImporter *importer, Verific::Instance *inst);
+void verific_import_sva_trigger(VerificImporter *importer, Verific::Instance *inst);
+bool verific_is_sva_net(VerificImporter *importer, Verific::Net *net);
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc
new file mode 100644
index 00000000..85b84218
--- /dev/null
+++ b/frontends/verific/verificsva.cc
@@ -0,0 +1,1814 @@
+/*
+ * 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.
+ *
+ */
+
+
+// Currently supported SVA sequence and property syntax:
+// http://symbiyosys.readthedocs.io/en/latest/verific.html
+//
+// Next gen property syntax:
+// basic_property
+// [antecedent_condition] property
+// [antecedent_condition] always.. property
+// [antecedent_condition] eventually.. basic_property
+// [antecedent_condition] property until.. expression
+// [antecedent_condition] basic_property until.. basic_property (assert/assume only)
+//
+// antecedent_condition:
+// sequence |->
+// sequence |=>
+//
+// basic_property:
+// sequence
+// not basic_property
+// sequence #-# basic_property
+// sequence #=# basic_property
+// basic_property or basic_property (cover only)
+// basic_property and basic_property (assert/assume only)
+// basic_property implies basic_property
+// basic_property iff basic_property
+//
+// sequence:
+// expression
+// sequence ##N sequence
+// sequence ##[*] sequence
+// sequence ##[+] sequence
+// sequence ##[N:M] sequence
+// sequence ##[N:$] sequence
+// expression [*]
+// expression [+]
+// expression [*N]
+// expression [*N:M]
+// expression [*N:$]
+// sequence or sequence
+// sequence and sequence
+// expression throughout sequence
+// sequence intersect sequence
+// sequence within sequence
+// first_match( sequence )
+// expression [=N]
+// expression [=N:M]
+// expression [=N:$]
+// expression [->N]
+// expression [->N:M]
+// expression [->N:$]
+
+
+#include "kernel/yosys.h"
+#include "frontends/verific/verific.h"
+
+USING_YOSYS_NAMESPACE
+
+#ifdef VERIFIC_NAMESPACE
+using namespace Verific;
+#endif
+
+PRIVATE_NAMESPACE_BEGIN
+
+// Non-deterministic FSM
+struct SvaNFsmNode
+{
+ // Edge: Activate the target node if ctrl signal is true, consumes clock cycle
+ // Link: Activate the target node if ctrl signal is true, doesn't consume clock cycle
+ vector<pair<int, SigBit>> edges, links;
+ bool is_cond_node;
+};
+
+// Non-deterministic FSM after resolving links
+struct SvaUFsmNode
+{
+ // Edge: Activate the target node if all bits in ctrl signal are true, consumes clock cycle
+ // Accept: This node functions as an accept node if all bits in ctrl signal are true
+ vector<pair<int, SigSpec>> edges;
+ vector<SigSpec> accept, cond;
+ bool reachable;
+};
+
+// Deterministic FSM
+struct SvaDFsmNode
+{
+ // A DFSM state corresponds to a set of NFSM states. We represent DFSM states as sorted vectors
+ // of NFSM state node ids. Edge/accept controls are constants matched against the ctrl sigspec.
+ SigSpec ctrl;
+ vector<pair<vector<int>, Const>> edges;
+ vector<Const> accept, reject;
+
+ // additional temp data for getReject()
+ Wire *ffoutwire;
+ SigBit statesig;
+ SigSpec nextstate;
+
+ // additional temp data for getDFsm()
+ int outnode;
+};
+
+struct SvaFsm
+{
+ Module *module;
+ VerificClocking clocking;
+
+ SigBit trigger_sig = State::S1, disable_sig;
+ SigBit throughout_sig = State::S1;
+ bool in_cond_mode = false;
+
+ vector<SigBit> disable_stack;
+ vector<SigBit> throughout_stack;
+
+ int startNode, acceptNode, condNode;
+ vector<SvaNFsmNode> nodes;
+
+ vector<SvaUFsmNode> unodes;
+ dict<vector<int>, SvaDFsmNode> dnodes;
+ dict<pair<SigSpec, SigSpec>, SigBit> cond_eq_cache;
+ bool materialized = false;
+
+ SigBit final_accept_sig = State::Sx;
+ SigBit final_reject_sig = State::Sx;
+
+ SvaFsm(const VerificClocking &clking, SigBit trig = State::S1)
+ {
+ module = clking.module;
+ clocking = clking;
+ trigger_sig = trig;
+
+ startNode = createNode();
+ acceptNode = createNode();
+
+ in_cond_mode = true;
+ condNode = createNode();
+ in_cond_mode = false;
+ }
+
+ void pushDisable(SigBit sig)
+ {
+ log_assert(!materialized);
+
+ disable_stack.push_back(disable_sig);
+
+ if (disable_sig == State::S0)
+ disable_sig = sig;
+ else
+ disable_sig = module->Or(NEW_ID, disable_sig, sig);
+ }
+
+ void popDisable()
+ {
+ log_assert(!materialized);
+ log_assert(!disable_stack.empty());
+
+ disable_sig = disable_stack.back();
+ disable_stack.pop_back();
+ }
+
+ void pushThroughout(SigBit sig)
+ {
+ log_assert(!materialized);
+
+ throughout_stack.push_back(throughout_sig);
+
+ if (throughout_sig == State::S1)
+ throughout_sig = sig;
+ else
+ throughout_sig = module->And(NEW_ID, throughout_sig, sig);
+ }
+
+ void popThroughout()
+ {
+ log_assert(!materialized);
+ log_assert(!throughout_stack.empty());
+
+ throughout_sig = throughout_stack.back();
+ throughout_stack.pop_back();
+ }
+
+ int createNode(int link_node = -1)
+ {
+ log_assert(!materialized);
+
+ int idx = GetSize(nodes);
+ nodes.push_back(SvaNFsmNode());
+ nodes.back().is_cond_node = in_cond_mode;
+ if (link_node >= 0)
+ createLink(link_node, idx);
+ return idx;
+ }
+
+ int createStartNode()
+ {
+ return createNode(startNode);
+ }
+
+ void createEdge(int from_node, int to_node, SigBit ctrl = State::S1)
+ {
+ log_assert(!materialized);
+ log_assert(0 <= from_node && from_node < GetSize(nodes));
+ log_assert(0 <= to_node && to_node < GetSize(nodes));
+ log_assert(from_node != acceptNode);
+ log_assert(to_node != acceptNode);
+ log_assert(from_node != condNode);
+ log_assert(to_node != condNode);
+ log_assert(to_node != startNode);
+
+ if (from_node != startNode)
+ log_assert(nodes.at(from_node).is_cond_node == nodes.at(to_node).is_cond_node);
+
+ if (throughout_sig != State::S1) {
+ if (ctrl != State::S1)
+ ctrl = module->And(NEW_ID, throughout_sig, ctrl);
+ else
+ ctrl = throughout_sig;
+ }
+
+ nodes[from_node].edges.push_back(make_pair(to_node, ctrl));
+ }
+
+ void createLink(int from_node, int to_node, SigBit ctrl = State::S1)
+ {
+ log_assert(!materialized);
+ log_assert(0 <= from_node && from_node < GetSize(nodes));
+ log_assert(0 <= to_node && to_node < GetSize(nodes));
+ log_assert(from_node != acceptNode);
+ log_assert(from_node != condNode);
+ log_assert(to_node != startNode);
+
+ if (from_node != startNode)
+ log_assert(nodes.at(from_node).is_cond_node == nodes.at(to_node).is_cond_node);
+
+ if (throughout_sig != State::S1) {
+ if (ctrl != State::S1)
+ ctrl = module->And(NEW_ID, throughout_sig, ctrl);
+ else
+ ctrl = throughout_sig;
+ }
+
+ nodes[from_node].links.push_back(make_pair(to_node, ctrl));
+ }
+
+ void make_link_order(vector<int> &order, int node, int min)
+ {
+ order[node] = std::max(order[node], min);
+ for (auto &it : nodes[node].links)
+ make_link_order(order, it.first, order[node]+1);
+ }
+
+ // ----------------------------------------------------
+ // Generating NFSM circuit to acquire accept signal
+
+ SigBit getAccept()
+ {
+ log_assert(!materialized);
+ materialized = true;
+
+ vector<Wire*> state_wire(GetSize(nodes));
+ vector<SigBit> state_sig(GetSize(nodes));
+ vector<SigBit> next_state_sig(GetSize(nodes));
+
+ // Create state signals
+
+ {
+ SigBit not_disable = State::S1;
+
+ if (disable_sig != State::S0)
+ not_disable = module->Not(NEW_ID, disable_sig);
+
+ for (int i = 0; i < GetSize(nodes); i++)
+ {
+ Wire *w = module->addWire(NEW_ID);
+ state_wire[i] = w;
+ state_sig[i] = w;
+
+ if (i == startNode)
+ state_sig[i] = module->Or(NEW_ID, state_sig[i], trigger_sig);
+
+ if (disable_sig != State::S0)
+ state_sig[i] = module->And(NEW_ID, state_sig[i], not_disable);
+ }
+ }
+
+ // Follow Links
+
+ {
+ vector<int> node_order(GetSize(nodes));
+ vector<vector<int>> order_to_nodes;
+
+ for (int i = 0; i < GetSize(nodes); i++)
+ make_link_order(node_order, i, 0);
+
+ for (int i = 0; i < GetSize(nodes); i++) {
+ if (node_order[i] >= GetSize(order_to_nodes))
+ order_to_nodes.resize(node_order[i]+1);
+ order_to_nodes[node_order[i]].push_back(i);
+ }
+
+ for (int order = 0; order < GetSize(order_to_nodes); order++)
+ for (int node : order_to_nodes[order])
+ {
+ for (auto &it : nodes[node].links)
+ {
+ int target = it.first;
+ SigBit ctrl = state_sig[node];
+
+ if (it.second != State::S1)
+ ctrl = module->And(NEW_ID, ctrl, it.second);
+
+ state_sig[target] = module->Or(NEW_ID, state_sig[target], ctrl);
+ }
+ }
+ }
+
+ // Construct activations
+
+ {
+ vector<SigSpec> activate_sig(GetSize(nodes));
+ vector<SigBit> activate_bit(GetSize(nodes));
+
+ for (int i = 0; i < GetSize(nodes); i++) {
+ for (auto &it : nodes[i].edges)
+ activate_sig[it.first].append(module->And(NEW_ID, state_sig[i], it.second));
+ }
+
+ for (int i = 0; i < GetSize(nodes); i++) {
+ if (GetSize(activate_sig[i]) == 0)
+ next_state_sig[i] = State::S0;
+ else if (GetSize(activate_sig[i]) == 1)
+ next_state_sig[i] = activate_sig[i];
+ else
+ next_state_sig[i] = module->ReduceOr(NEW_ID, activate_sig[i]);
+ }
+ }
+
+ // Create state FFs
+
+ for (int i = 0; i < GetSize(nodes); i++)
+ {
+ if (next_state_sig[i] != State::S0) {
+ clocking.addDff(NEW_ID, next_state_sig[i], state_wire[i], Const(0, 1));
+ } else {
+ module->connect(state_wire[i], State::S0);
+ }
+ }
+
+ final_accept_sig = state_sig[acceptNode];
+ return final_accept_sig;
+ }
+
+ // ----------------------------------------------------
+ // Generating quantifier-based NFSM circuit to acquire reject signal
+
+ SigBit getAnyAllRejectWorker(bool /* allMode */)
+ {
+ // FIXME
+ log_abort();
+ }
+
+ SigBit getAnyReject()
+ {
+ return getAnyAllRejectWorker(false);
+ }
+
+ SigBit getAllReject()
+ {
+ return getAnyAllRejectWorker(true);
+ }
+
+ // ----------------------------------------------------
+ // Generating DFSM circuit to acquire reject signal
+
+ void node_to_unode(int node, int unode, SigSpec ctrl)
+ {
+ if (node == acceptNode)
+ unodes[unode].accept.push_back(ctrl);
+
+ if (node == condNode)
+ unodes[unode].cond.push_back(ctrl);
+
+ for (auto &it : nodes[node].edges) {
+ if (it.second != State::S1) {
+ SigSpec s = {ctrl, it.second};
+ s.sort_and_unify();
+ unodes[unode].edges.push_back(make_pair(it.first, s));
+ } else {
+ unodes[unode].edges.push_back(make_pair(it.first, ctrl));
+ }
+ }
+
+ for (auto &it : nodes[node].links) {
+ if (it.second != State::S1) {
+ SigSpec s = {ctrl, it.second};
+ s.sort_and_unify();
+ node_to_unode(it.first, unode, s);
+ } else {
+ node_to_unode(it.first, unode, ctrl);
+ }
+ }
+ }
+
+ void mark_reachable_unode(int unode)
+ {
+ if (unodes[unode].reachable)
+ return;
+
+ unodes[unode].reachable = true;
+ for (auto &it : unodes[unode].edges)
+ mark_reachable_unode(it.first);
+ }
+
+ void usortint(vector<int> &vec)
+ {
+ vector<int> newvec;
+ std::sort(vec.begin(), vec.end());
+ for (int i = 0; i < GetSize(vec); i++)
+ if (i == GetSize(vec)-1 || vec[i] != vec[i+1])
+ newvec.push_back(vec[i]);
+ vec.swap(newvec);
+ }
+
+ bool cmp_ctrl(const pool<SigBit> &ctrl_bits, const SigSpec &ctrl)
+ {
+ for (int i = 0; i < GetSize(ctrl); i++)
+ if (ctrl_bits.count(ctrl[i]) == 0)
+ return false;
+ return true;
+ }
+
+ void create_dnode(const vector<int> &state, bool firstmatch, bool condaccept)
+ {
+ if (dnodes.count(state) != 0)
+ return;
+
+ SvaDFsmNode dnode;
+ dnodes[state] = SvaDFsmNode();
+
+ for (int unode : state) {
+ log_assert(unodes[unode].reachable);
+ for (auto &it : unodes[unode].edges)
+ dnode.ctrl.append(it.second);
+ for (auto &it : unodes[unode].accept)
+ dnode.ctrl.append(it);
+ for (auto &it : unodes[unode].cond)
+ dnode.ctrl.append(it);
+ }
+
+ dnode.ctrl.sort_and_unify();
+
+ if (GetSize(dnode.ctrl) > 16) {
+ if (verific_verbose >= 2) {
+ log(" detected state explosion in DFSM generation:\n");
+ dump();
+ log(" ctrl signal: %s\n", log_signal(dnode.ctrl));
+ }
+ log_error("SVA DFSM state ctrl signal has %d (>16) bits. Stopping to prevent exponential design size explosion.\n", GetSize(dnode.ctrl));
+ }
+
+ for (int i = 0; i < (1 << GetSize(dnode.ctrl)); i++)
+ {
+ Const ctrl_val(i, GetSize(dnode.ctrl));
+ pool<SigBit> ctrl_bits;
+
+ for (int i = 0; i < GetSize(dnode.ctrl); i++)
+ if (ctrl_val[i] == State::S1)
+ ctrl_bits.insert(dnode.ctrl[i]);
+
+ vector<int> new_state;
+ bool accept = false, cond = false;
+
+ for (int unode : state) {
+ for (auto &it : unodes[unode].accept)
+ if (cmp_ctrl(ctrl_bits, it))
+ accept = true;
+ for (auto &it : unodes[unode].cond)
+ if (cmp_ctrl(ctrl_bits, it))
+ cond = true;
+ }
+
+ bool new_state_cond = false;
+ bool new_state_noncond = false;
+
+ if (accept && condaccept)
+ accept = cond;
+
+ if (!accept || !firstmatch) {
+ for (int unode : state)
+ for (auto &it : unodes[unode].edges)
+ if (cmp_ctrl(ctrl_bits, it.second)) {
+ if (nodes.at(it.first).is_cond_node)
+ new_state_cond = true;
+ else
+ new_state_noncond = true;
+ new_state.push_back(it.first);
+ }
+ }
+
+ if (accept)
+ dnode.accept.push_back(ctrl_val);
+
+ if (condaccept && (!new_state_cond || !new_state_noncond))
+ new_state.clear();
+
+ if (new_state.empty()) {
+ if (!accept)
+ dnode.reject.push_back(ctrl_val);
+ } else {
+ usortint(new_state);
+ dnode.edges.push_back(make_pair(new_state, ctrl_val));
+ create_dnode(new_state, firstmatch, condaccept);
+ }
+ }
+
+ dnodes[state] = dnode;
+ }
+
+ void optimize_cond(vector<Const> &values)
+ {
+ bool did_something = true;
+
+ while (did_something)
+ {
+ did_something = false;
+
+ for (int i = 0; i < GetSize(values); i++)
+ for (int j = 0; j < GetSize(values); j++)
+ {
+ if (i == j)
+ continue;
+
+ log_assert(GetSize(values[i]) == GetSize(values[j]));
+
+ int delta_pos = -1;
+ bool i_within_j = true;
+ bool j_within_i = true;
+
+ for (int k = 0; k < GetSize(values[i]); k++) {
+ if (values[i][k] == State::Sa && values[j][k] != State::Sa) {
+ i_within_j = false;
+ continue;
+ }
+ if (values[i][k] != State::Sa && values[j][k] == State::Sa) {
+ j_within_i = false;
+ continue;
+ }
+ if (values[i][k] == values[j][k])
+ continue;
+ if (delta_pos >= 0)
+ goto next_pair;
+ delta_pos = k;
+ }
+
+ if (delta_pos >= 0 && i_within_j && j_within_i) {
+ did_something = true;
+ values[i][delta_pos] = State::Sa;
+ values[j] = values.back();
+ values.pop_back();
+ goto next_pair;
+ }
+
+ if (delta_pos < 0 && i_within_j) {
+ did_something = true;
+ values[i] = values.back();
+ values.pop_back();
+ goto next_pair;
+ }
+
+ if (delta_pos < 0 && j_within_i) {
+ did_something = true;
+ values[j] = values.back();
+ values.pop_back();
+ goto next_pair;
+ }
+ next_pair:;
+ }
+ }
+ }
+
+ SigBit make_cond_eq(const SigSpec &ctrl, const Const &value, SigBit enable = State::S1)
+ {
+ SigSpec sig_a, sig_b;
+
+ log_assert(GetSize(ctrl) == GetSize(value));
+
+ for (int i = 0; i < GetSize(ctrl); i++)
+ if (value[i] != State::Sa) {
+ sig_a.append(ctrl[i]);
+ sig_b.append(value[i]);
+ }
+
+ if (GetSize(sig_a) == 0)
+ return enable;
+
+ if (enable != State::S1) {
+ sig_a.append(enable);
+ sig_b.append(State::S1);
+ }
+
+ auto key = make_pair(sig_a, sig_b);
+
+ if (cond_eq_cache.count(key) == 0)
+ {
+ if (sig_b == State::S1)
+ cond_eq_cache[key] = sig_a;
+ else if (sig_b == State::S0)
+ cond_eq_cache[key] = module->Not(NEW_ID, sig_a);
+ else
+ cond_eq_cache[key] = module->Eq(NEW_ID, sig_a, sig_b);
+
+ if (verific_verbose >= 2) {
+ log(" Cond: %s := %s == %s\n", log_signal(cond_eq_cache[key]),
+ log_signal(sig_a), log_signal(sig_b));
+ }
+ }
+
+ return cond_eq_cache.at(key);
+ }
+
+ void getFirstAcceptReject(SigBit *accept_p, SigBit *reject_p)
+ {
+ log_assert(!materialized);
+ materialized = true;
+
+ // Create unlinked NFSM
+
+ unodes.resize(GetSize(nodes));
+
+ for (int node = 0; node < GetSize(nodes); node++)
+ node_to_unode(node, node, SigSpec());
+
+ mark_reachable_unode(startNode);
+
+ // Create DFSM
+
+ create_dnode(vector<int>{startNode}, true, false);
+ dnodes.sort();
+
+ // Create DFSM Circuit
+
+ SigSpec accept_sig, reject_sig;
+
+ for (auto &it : dnodes)
+ {
+ SvaDFsmNode &dnode = it.second;
+ dnode.ffoutwire = module->addWire(NEW_ID);
+ dnode.statesig = dnode.ffoutwire;
+
+ if (it.first == vector<int>{startNode})
+ dnode.statesig = module->Or(NEW_ID, dnode.statesig, trigger_sig);
+ }
+
+ for (auto &it : dnodes)
+ {
+ SvaDFsmNode &dnode = it.second;
+ dict<vector<int>, vector<Const>> edge_cond;
+
+ for (auto &edge : dnode.edges)
+ edge_cond[edge.first].push_back(edge.second);
+
+ for (auto &it : edge_cond) {
+ optimize_cond(it.second);
+ for (auto &value : it.second)
+ dnodes.at(it.first).nextstate.append(make_cond_eq(dnode.ctrl, value, dnode.statesig));
+ }
+
+ if (accept_p) {
+ vector<Const> accept_cond = dnode.accept;
+ optimize_cond(accept_cond);
+ for (auto &value : accept_cond)
+ accept_sig.append(make_cond_eq(dnode.ctrl, value, dnode.statesig));
+ }
+
+ if (reject_p) {
+ vector<Const> reject_cond = dnode.reject;
+ optimize_cond(reject_cond);
+ for (auto &value : reject_cond)
+ reject_sig.append(make_cond_eq(dnode.ctrl, value, dnode.statesig));
+ }
+ }
+
+ for (auto &it : dnodes)
+ {
+ SvaDFsmNode &dnode = it.second;
+ if (GetSize(dnode.nextstate) == 0) {
+ module->connect(dnode.ffoutwire, State::S0);
+ } else
+ if (GetSize(dnode.nextstate) == 1) {
+ clocking.addDff(NEW_ID, dnode.nextstate, dnode.ffoutwire, State::S0);
+ } else {
+ SigSpec nextstate = module->ReduceOr(NEW_ID, dnode.nextstate);
+ clocking.addDff(NEW_ID, nextstate, dnode.ffoutwire, State::S0);
+ }
+ }
+
+ if (accept_p)
+ {
+ if (GetSize(accept_sig) == 0)
+ final_accept_sig = State::S0;
+ else if (GetSize(accept_sig) == 1)
+ final_accept_sig = accept_sig;
+ else
+ final_accept_sig = module->ReduceOr(NEW_ID, accept_sig);
+ *accept_p = final_accept_sig;
+ }
+
+ if (reject_p)
+ {
+ if (GetSize(reject_sig) == 0)
+ final_reject_sig = State::S0;
+ else if (GetSize(reject_sig) == 1)
+ final_reject_sig = reject_sig;
+ else
+ final_reject_sig = module->ReduceOr(NEW_ID, reject_sig);
+ *reject_p = final_reject_sig;
+ }
+ }
+
+ SigBit getFirstAccept()
+ {
+ SigBit accept;
+ getFirstAcceptReject(&accept, nullptr);
+ return accept;
+ }
+
+ SigBit getReject()
+ {
+ SigBit reject;
+ getFirstAcceptReject(nullptr, &reject);
+ return reject;
+ }
+
+ void getDFsm(SvaFsm &output_fsm, int output_start_node, int output_accept_node, int output_reject_node = -1, bool firstmatch = true, bool condaccept = false)
+ {
+ log_assert(!materialized);
+ materialized = true;
+
+ // Create unlinked NFSM
+
+ unodes.resize(GetSize(nodes));
+
+ for (int node = 0; node < GetSize(nodes); node++)
+ node_to_unode(node, node, SigSpec());
+
+ mark_reachable_unode(startNode);
+
+ // Create DFSM
+
+ create_dnode(vector<int>{startNode}, firstmatch, condaccept);
+ dnodes.sort();
+
+ // Create DFSM Graph
+
+ for (auto &it : dnodes)
+ {
+ SvaDFsmNode &dnode = it.second;
+ dnode.outnode = output_fsm.createNode();
+
+ if (it.first == vector<int>{startNode})
+ output_fsm.createLink(output_start_node, dnode.outnode);
+
+ if (output_accept_node >= 0) {
+ vector<Const> accept_cond = dnode.accept;
+ optimize_cond(accept_cond);
+ for (auto &value : accept_cond)
+ output_fsm.createLink(it.second.outnode, output_accept_node, make_cond_eq(dnode.ctrl, value));
+ }
+
+ if (output_reject_node >= 0) {
+ vector<Const> reject_cond = dnode.reject;
+ optimize_cond(reject_cond);
+ for (auto &value : reject_cond)
+ output_fsm.createLink(it.second.outnode, output_reject_node, make_cond_eq(dnode.ctrl, value));
+ }
+ }
+
+ for (auto &it : dnodes)
+ {
+ SvaDFsmNode &dnode = it.second;
+ dict<vector<int>, vector<Const>> edge_cond;
+
+ for (auto &edge : dnode.edges)
+ edge_cond[edge.first].push_back(edge.second);
+
+ for (auto &it : edge_cond) {
+ optimize_cond(it.second);
+ for (auto &value : it.second)
+ output_fsm.createEdge(dnode.outnode, dnodes.at(it.first).outnode, make_cond_eq(dnode.ctrl, value));
+ }
+ }
+ }
+
+ // ----------------------------------------------------
+ // State dump for verbose log messages
+
+ void dump_nodes()
+ {
+ if (nodes.empty())
+ return;
+
+ log(" non-deterministic encoding:\n");
+ for (int i = 0; i < GetSize(nodes); i++)
+ {
+ log(" node %d:%s\n", i,
+ i == startNode ? " [start]" :
+ i == acceptNode ? " [accept]" :
+ i == condNode ? " [cond]" : "");
+
+ for (auto &it : nodes[i].edges) {
+ if (it.second != State::S1)
+ log(" egde %s -> %d\n", log_signal(it.second), it.first);
+ else
+ log(" egde -> %d\n", it.first);
+ }
+
+ for (auto &it : nodes[i].links) {
+ if (it.second != State::S1)
+ log(" link %s -> %d\n", log_signal(it.second), it.first);
+ else
+ log(" link -> %d\n", it.first);
+ }
+ }
+ }
+
+ void dump_unodes()
+ {
+ if (unodes.empty())
+ return;
+
+ log(" unlinked non-deterministic encoding:\n");
+ for (int i = 0; i < GetSize(unodes); i++)
+ {
+ if (!unodes[i].reachable)
+ continue;
+
+ log(" unode %d:%s\n", i, i == startNode ? " [start]" : "");
+
+ for (auto &it : unodes[i].edges) {
+ if (!it.second.empty())
+ log(" egde %s -> %d\n", log_signal(it.second), it.first);
+ else
+ log(" egde -> %d\n", it.first);
+ }
+
+ for (auto &ctrl : unodes[i].accept) {
+ if (!ctrl.empty())
+ log(" accept %s\n", log_signal(ctrl));
+ else
+ log(" accept\n");
+ }
+
+ for (auto &ctrl : unodes[i].cond) {
+ if (!ctrl.empty())
+ log(" cond %s\n", log_signal(ctrl));
+ else
+ log(" cond\n");
+ }
+ }
+ }
+
+ void dump_dnodes()
+ {
+ if (dnodes.empty())
+ return;
+
+ log(" deterministic encoding:\n");
+ for (auto &it : dnodes)
+ {
+ log(" dnode {");
+ for (int i = 0; i < GetSize(it.first); i++)
+ log("%s%d", i ? "," : "", it.first[i]);
+ log("}:%s\n", GetSize(it.first) == 1 && it.first[0] == startNode ? " [start]" : "");
+
+ log(" ctrl %s\n", log_signal(it.second.ctrl));
+
+ for (auto &edge : it.second.edges) {
+ log(" edge %s -> {", log_signal(edge.second));
+ for (int i = 0; i < GetSize(edge.first); i++)
+ log("%s%d", i ? "," : "", edge.first[i]);
+ log("}\n");
+ }
+
+ for (auto &value : it.second.accept)
+ log(" accept %s\n", log_signal(value));
+
+ for (auto &value : it.second.reject)
+ log(" reject %s\n", log_signal(value));
+ }
+ }
+
+ void dump()
+ {
+ if (!nodes.empty())
+ log(" number of NFSM states: %d\n", GetSize(nodes));
+
+ if (!unodes.empty()) {
+ int count = 0;
+ for (auto &unode : unodes)
+ if (unode.reachable)
+ count++;
+ log(" number of reachable UFSM states: %d\n", count);
+ }
+
+ if (!dnodes.empty())
+ log(" number of DFSM states: %d\n", GetSize(dnodes));
+
+ if (verific_verbose >= 2) {
+ dump_nodes();
+ dump_unodes();
+ dump_dnodes();
+ }
+
+ if (trigger_sig != State::S1)
+ log(" trigger signal: %s\n", log_signal(trigger_sig));
+
+ if (final_accept_sig != State::Sx)
+ log(" accept signal: %s\n", log_signal(final_accept_sig));
+
+ if (final_reject_sig != State::Sx)
+ log(" reject signal: %s\n", log_signal(final_reject_sig));
+ }
+};
+
+PRIVATE_NAMESPACE_END
+
+YOSYS_NAMESPACE_BEGIN
+
+pool<int> verific_sva_prims = {
+ // Copy&paste from Verific 3.16_484_32_170630 Netlist.h
+ PRIM_SVA_IMMEDIATE_ASSERT, PRIM_SVA_ASSERT, PRIM_SVA_COVER, PRIM_SVA_ASSUME,
+ PRIM_SVA_EXPECT, PRIM_SVA_POSEDGE, PRIM_SVA_NOT, PRIM_SVA_FIRST_MATCH,
+ PRIM_SVA_ENDED, PRIM_SVA_MATCHED, PRIM_SVA_CONSECUTIVE_REPEAT,
+ PRIM_SVA_NON_CONSECUTIVE_REPEAT, PRIM_SVA_GOTO_REPEAT,
+ PRIM_SVA_MATCH_ITEM_TRIGGER, PRIM_SVA_AND, PRIM_SVA_OR, PRIM_SVA_SEQ_AND,
+ PRIM_SVA_SEQ_OR, PRIM_SVA_EVENT_OR, PRIM_SVA_OVERLAPPED_IMPLICATION,
+ PRIM_SVA_NON_OVERLAPPED_IMPLICATION, PRIM_SVA_OVERLAPPED_FOLLOWED_BY,
+ PRIM_SVA_NON_OVERLAPPED_FOLLOWED_BY, PRIM_SVA_INTERSECT, PRIM_SVA_THROUGHOUT,
+ PRIM_SVA_WITHIN, PRIM_SVA_AT, PRIM_SVA_DISABLE_IFF, PRIM_SVA_SAMPLED,
+ PRIM_SVA_ROSE, PRIM_SVA_FELL, PRIM_SVA_STABLE, PRIM_SVA_PAST,
+ PRIM_SVA_MATCH_ITEM_ASSIGN, PRIM_SVA_SEQ_CONCAT, PRIM_SVA_IF,
+ PRIM_SVA_RESTRICT, PRIM_SVA_TRIGGERED, PRIM_SVA_STRONG, PRIM_SVA_WEAK,
+ PRIM_SVA_NEXTTIME, PRIM_SVA_S_NEXTTIME, PRIM_SVA_ALWAYS, PRIM_SVA_S_ALWAYS,
+ PRIM_SVA_S_EVENTUALLY, PRIM_SVA_EVENTUALLY, PRIM_SVA_UNTIL, PRIM_SVA_S_UNTIL,
+ PRIM_SVA_UNTIL_WITH, PRIM_SVA_S_UNTIL_WITH, PRIM_SVA_IMPLIES, PRIM_SVA_IFF,
+ PRIM_SVA_ACCEPT_ON, PRIM_SVA_REJECT_ON, PRIM_SVA_SYNC_ACCEPT_ON,
+ PRIM_SVA_SYNC_REJECT_ON, PRIM_SVA_GLOBAL_CLOCKING_DEF,
+ PRIM_SVA_GLOBAL_CLOCKING_REF, PRIM_SVA_IMMEDIATE_ASSUME,
+ PRIM_SVA_IMMEDIATE_COVER, OPER_SVA_SAMPLED, OPER_SVA_STABLE
+};
+
+struct VerificSvaImporter
+{
+ VerificImporter *importer = nullptr;
+ Module *module = nullptr;
+
+ Netlist *netlist = nullptr;
+ Instance *root = nullptr;
+
+ VerificClocking clocking;
+
+ bool mode_assert = false;
+ bool mode_assume = false;
+ bool mode_cover = false;
+ bool mode_trigger = false;
+
+ Instance *net_to_ast_driver(Net *n)
+ {
+ if (n == nullptr)
+ return nullptr;
+
+ if (n->IsMultipleDriven())
+ return nullptr;
+
+ Instance *inst = n->Driver();
+
+ if (inst == nullptr)
+ return nullptr;
+
+ if (!verific_sva_prims.count(inst->Type()))
+ return nullptr;
+
+ if (inst->Type() == PRIM_SVA_ROSE || inst->Type() == PRIM_SVA_FELL ||
+ inst->Type() == PRIM_SVA_STABLE || inst->Type() == OPER_SVA_STABLE ||
+ inst->Type() == PRIM_SVA_PAST || inst->Type() == PRIM_SVA_TRIGGERED)
+ return nullptr;
+
+ return inst;
+ }
+
+ Instance *get_ast_input(Instance *inst) { return net_to_ast_driver(inst->GetInput()); }
+ Instance *get_ast_input1(Instance *inst) { return net_to_ast_driver(inst->GetInput1()); }
+ Instance *get_ast_input2(Instance *inst) { return net_to_ast_driver(inst->GetInput2()); }
+ Instance *get_ast_input3(Instance *inst) { return net_to_ast_driver(inst->GetInput3()); }
+ Instance *get_ast_control(Instance *inst) { return net_to_ast_driver(inst->GetControl()); }
+
+ // ----------------------------------------------------------
+ // SVA Importer
+
+ struct ParserErrorException {
+ };
+
+ [[noreturn]] void parser_error(std::string errmsg)
+ {
+ if (!importer->mode_keep)
+ log_error("%s", errmsg.c_str());
+ log_warning("%s", errmsg.c_str());
+ throw ParserErrorException();
+ }
+
+ [[noreturn]] void parser_error(std::string errmsg, linefile_type loc)
+ {
+ parser_error(stringf("%s at %s:%d.\n", errmsg.c_str(), LineFile::GetFileName(loc), LineFile::GetLineNo(loc)));
+ }
+
+ [[noreturn]] void parser_error(std::string errmsg, Instance *inst)
+ {
+ parser_error(stringf("%s at %s (%s)", errmsg.c_str(), inst->View()->Owner()->Name(), inst->Name()), inst->Linefile());
+ }
+
+ [[noreturn]] void parser_error(Instance *inst)
+ {
+ parser_error(stringf("Verific SVA primitive %s (%s) is currently unsupported in this context",
+ inst->View()->Owner()->Name(), inst->Name()), inst->Linefile());
+ }
+
+ dict<Net*, bool, hash_ptr_ops> check_expression_cache;
+
+ bool check_expression(Net *net, bool raise_error = false)
+ {
+ while (!check_expression_cache.count(net))
+ {
+ Instance *inst = net_to_ast_driver(net);
+
+ if (inst == nullptr) {
+ check_expression_cache[net] = true;
+ break;
+ }
+
+ if (inst->Type() == PRIM_SVA_AT)
+ {
+ VerificClocking new_clocking(importer, net);
+ log_assert(new_clocking.cond_net == nullptr);
+ if (!clocking.property_matches_sequence(new_clocking))
+ parser_error("Mixed clocking is currently not supported", inst);
+ check_expression_cache[net] = check_expression(new_clocking.body_net, raise_error);
+ break;
+ }
+
+ if (inst->Type() == PRIM_SVA_FIRST_MATCH || inst->Type() == PRIM_SVA_NOT)
+ {
+ check_expression_cache[net] = check_expression(inst->GetInput(), raise_error);
+ break;
+ }
+
+ if (inst->Type() == PRIM_SVA_SEQ_OR || inst->Type() == PRIM_SVA_SEQ_AND || inst->Type() == PRIM_SVA_INTERSECT ||
+ inst->Type() == PRIM_SVA_WITHIN || inst->Type() == PRIM_SVA_THROUGHOUT ||
+ inst->Type() == PRIM_SVA_OR || inst->Type() == PRIM_SVA_AND)
+ {
+ check_expression_cache[net] = check_expression(inst->GetInput1(), raise_error) && check_expression(inst->GetInput2(), raise_error);
+ break;
+ }
+
+ if (inst->Type() == PRIM_SVA_SEQ_CONCAT)
+ {
+ const char *sva_low_s = inst->GetAttValue("sva:low");
+ const char *sva_high_s = inst->GetAttValue("sva:high");
+
+ int sva_low = atoi(sva_low_s);
+ int sva_high = atoi(sva_high_s);
+ bool sva_inf = !strcmp(sva_high_s, "$");
+
+ if (sva_low == 0 && sva_high == 0 && !sva_inf)
+ check_expression_cache[net] = check_expression(inst->GetInput1(), raise_error) && check_expression(inst->GetInput2(), raise_error);
+ else
+ check_expression_cache[net] = false;
+ break;
+ }
+
+ check_expression_cache[net] = false;
+ }
+
+ if (raise_error && !check_expression_cache.at(net))
+ parser_error(net_to_ast_driver(net));
+ return check_expression_cache.at(net);
+ }
+
+ SigBit parse_expression(Net *net)
+ {
+ check_expression(net, true);
+
+ Instance *inst = net_to_ast_driver(net);
+
+ if (inst == nullptr) {
+ return importer->net_map_at(net);
+ }
+
+ if (inst->Type() == PRIM_SVA_AT)
+ {
+ VerificClocking new_clocking(importer, net);
+ log_assert(new_clocking.cond_net == nullptr);
+ if (!clocking.property_matches_sequence(new_clocking))
+ parser_error("Mixed clocking is currently not supported", inst);
+ return parse_expression(new_clocking.body_net);
+ }
+
+ if (inst->Type() == PRIM_SVA_FIRST_MATCH)
+ return parse_expression(inst->GetInput());
+
+ if (inst->Type() == PRIM_SVA_NOT)
+ return module->Not(NEW_ID, parse_expression(inst->GetInput()));
+
+ if (inst->Type() == PRIM_SVA_SEQ_OR || inst->Type() == PRIM_SVA_OR)
+ return module->Or(NEW_ID, parse_expression(inst->GetInput1()), parse_expression(inst->GetInput2()));
+
+ if (inst->Type() == PRIM_SVA_SEQ_AND || inst->Type() == PRIM_SVA_AND || inst->Type() == PRIM_SVA_INTERSECT ||
+ inst->Type() == PRIM_SVA_WITHIN || inst->Type() == PRIM_SVA_THROUGHOUT || inst->Type() == PRIM_SVA_SEQ_CONCAT)
+ return module->And(NEW_ID, parse_expression(inst->GetInput1()), parse_expression(inst->GetInput2()));
+
+ log_abort();
+ }
+
+ bool check_zero_consecutive_repeat(Net *net)
+ {
+ Instance *inst = net_to_ast_driver(net);
+
+ if (inst == nullptr)
+ return false;
+
+ if (inst->Type() != PRIM_SVA_CONSECUTIVE_REPEAT)
+ return false;
+
+ const char *sva_low_s = inst->GetAttValue("sva:low");
+ int sva_low = atoi(sva_low_s);
+
+ return sva_low == 0;
+ }
+
+ int parse_consecutive_repeat(SvaFsm &fsm, int start_node, Net *net, bool add_pre_delay, bool add_post_delay)
+ {
+ Instance *inst = net_to_ast_driver(net);
+
+ log_assert(inst->Type() == PRIM_SVA_CONSECUTIVE_REPEAT);
+
+ const char *sva_low_s = inst->GetAttValue("sva:low");
+ const char *sva_high_s = inst->GetAttValue("sva:high");
+
+ int sva_low = atoi(sva_low_s);
+ int sva_high = atoi(sva_high_s);
+ bool sva_inf = !strcmp(sva_high_s, "$");
+
+ Net *body_net = inst->GetInput();
+
+ if (add_pre_delay || add_post_delay)
+ log_assert(sva_low == 0);
+
+ if (sva_low == 0) {
+ if (!add_pre_delay && !add_post_delay)
+ parser_error("Possibly zero-length consecutive repeat must follow or precede a delay of at least one cycle", inst);
+ sva_low++;
+ }
+
+ int node = fsm.createNode(start_node);
+ start_node = node;
+
+ if (add_pre_delay) {
+ node = fsm.createNode(start_node);
+ fsm.createEdge(start_node, node);
+ }
+
+ int prev_node = node;
+ node = parse_sequence(fsm, node, body_net);
+
+ for (int i = 1; i < sva_low; i++)
+ {
+ int next_node = fsm.createNode();
+ fsm.createEdge(node, next_node);
+
+ prev_node = node;
+ node = parse_sequence(fsm, next_node, body_net);
+ }
+
+ if (sva_inf)
+ {
+ log_assert(prev_node >= 0);
+ fsm.createEdge(node, prev_node);
+ }
+ else
+ {
+ for (int i = sva_low; i < sva_high; i++)
+ {
+ int next_node = fsm.createNode();
+ fsm.createEdge(node, next_node);
+
+ prev_node = node;
+ node = parse_sequence(fsm, next_node, body_net);
+
+ fsm.createLink(prev_node, node);
+ }
+ }
+
+ if (add_post_delay) {
+ int next_node = fsm.createNode();
+ fsm.createEdge(node, next_node);
+ node = next_node;
+ }
+
+ if (add_pre_delay || add_post_delay)
+ fsm.createLink(start_node, node);
+
+ return node;
+ }
+
+ int parse_sequence(SvaFsm &fsm, int start_node, Net *net)
+ {
+ if (check_expression(net)) {
+ int node = fsm.createNode();
+ fsm.createLink(start_node, node, parse_expression(net));
+ return node;
+ }
+
+ Instance *inst = net_to_ast_driver(net);
+
+ if (inst->Type() == PRIM_SVA_AT)
+ {
+ VerificClocking new_clocking(importer, net);
+ log_assert(new_clocking.cond_net == nullptr);
+ if (!clocking.property_matches_sequence(new_clocking))
+ parser_error("Mixed clocking is currently not supported", inst);
+ return parse_sequence(fsm, start_node, new_clocking.body_net);
+ }
+
+ if (inst->Type() == PRIM_SVA_FIRST_MATCH)
+ {
+ SvaFsm match_fsm(clocking);
+ match_fsm.createLink(parse_sequence(match_fsm, match_fsm.createStartNode(), inst->GetInput()), match_fsm.acceptNode);
+
+ int node = fsm.createNode();
+ match_fsm.getDFsm(fsm, start_node, node);
+
+ if (verific_verbose) {
+ log(" First Match FSM:\n");
+ match_fsm.dump();
+ }
+
+ return node;
+ }
+
+ if (inst->Type() == PRIM_SVA_SEQ_CONCAT)
+ {
+ const char *sva_low_s = inst->GetAttValue("sva:low");
+ const char *sva_high_s = inst->GetAttValue("sva:high");
+
+ int sva_low = atoi(sva_low_s);
+ int sva_high = atoi(sva_high_s);
+ bool sva_inf = !strcmp(sva_high_s, "$");
+
+ int node = -1;
+ bool past_add_delay = false;
+
+ if (check_zero_consecutive_repeat(inst->GetInput1()) && sva_low > 0) {
+ node = parse_consecutive_repeat(fsm, start_node, inst->GetInput1(), false, true);
+ sva_low--, sva_high--;
+ } else {
+ node = parse_sequence(fsm, start_node, inst->GetInput1());
+ }
+
+ if (check_zero_consecutive_repeat(inst->GetInput2()) && sva_low > 0) {
+ past_add_delay = true;
+ sva_low--, sva_high--;
+ }
+
+ for (int i = 0; i < sva_low; i++) {
+ int next_node = fsm.createNode();
+ fsm.createEdge(node, next_node);
+ node = next_node;
+ }
+
+ if (sva_inf)
+ {
+ fsm.createEdge(node, node);
+ }
+ else
+ {
+ for (int i = sva_low; i < sva_high; i++)
+ {
+ int next_node = fsm.createNode();
+ fsm.createEdge(node, next_node);
+ fsm.createLink(node, next_node);
+ node = next_node;
+ }
+ }
+
+ if (past_add_delay)
+ node = parse_consecutive_repeat(fsm, node, inst->GetInput2(), true, false);
+ else
+ node = parse_sequence(fsm, node, inst->GetInput2());
+
+ return node;
+ }
+
+ if (inst->Type() == PRIM_SVA_CONSECUTIVE_REPEAT)
+ {
+ return parse_consecutive_repeat(fsm, start_node, net, false, false);
+ }
+
+ if (inst->Type() == PRIM_SVA_NON_CONSECUTIVE_REPEAT || inst->Type() == PRIM_SVA_GOTO_REPEAT)
+ {
+ const char *sva_low_s = inst->GetAttValue("sva:low");
+ const char *sva_high_s = inst->GetAttValue("sva:high");
+
+ int sva_low = atoi(sva_low_s);
+ int sva_high = atoi(sva_high_s);
+ bool sva_inf = !strcmp(sva_high_s, "$");
+
+ Net *body_net = inst->GetInput();
+ int node = fsm.createNode(start_node);
+
+ SigBit cond = parse_expression(body_net);
+ SigBit not_cond = module->Not(NEW_ID, cond);
+
+ for (int i = 0; i < sva_low; i++)
+ {
+ int wait_node = fsm.createNode();
+ fsm.createEdge(wait_node, wait_node, not_cond);
+
+ if (i == 0)
+ fsm.createLink(node, wait_node);
+ else
+ fsm.createEdge(node, wait_node);
+
+ int next_node = fsm.createNode();
+ fsm.createLink(wait_node, next_node, cond);
+
+ node = next_node;
+ }
+
+ if (sva_inf)
+ {
+ int wait_node = fsm.createNode();
+ fsm.createEdge(wait_node, wait_node, not_cond);
+ fsm.createEdge(node, wait_node);
+ fsm.createLink(wait_node, node, cond);
+ }
+ else
+ {
+ for (int i = sva_low; i < sva_high; i++)
+ {
+ int wait_node = fsm.createNode();
+ fsm.createEdge(wait_node, wait_node, not_cond);
+
+ if (i == 0)
+ fsm.createLink(node, wait_node);
+ else
+ fsm.createEdge(node, wait_node);
+
+ int next_node = fsm.createNode();
+ fsm.createLink(wait_node, next_node, cond);
+
+ fsm.createLink(node, next_node);
+ node = next_node;
+ }
+ }
+
+ if (inst->Type() == PRIM_SVA_NON_CONSECUTIVE_REPEAT)
+ fsm.createEdge(node, node);
+
+ return node;
+ }
+
+ if (inst->Type() == PRIM_SVA_SEQ_OR || inst->Type() == PRIM_SVA_OR)
+ {
+ int node = parse_sequence(fsm, start_node, inst->GetInput1());
+ int node2 = parse_sequence(fsm, start_node, inst->GetInput2());
+ fsm.createLink(node2, node);
+ return node;
+ }
+
+ if (inst->Type() == PRIM_SVA_SEQ_AND || inst->Type() == PRIM_SVA_AND)
+ {
+ SvaFsm fsm1(clocking);
+ fsm1.createLink(parse_sequence(fsm1, fsm1.createStartNode(), inst->GetInput1()), fsm1.acceptNode);
+
+ SvaFsm fsm2(clocking);
+ fsm2.createLink(parse_sequence(fsm2, fsm2.createStartNode(), inst->GetInput2()), fsm2.acceptNode);
+
+ SvaFsm combined_fsm(clocking);
+ fsm1.getDFsm(combined_fsm, combined_fsm.createStartNode(), -1, combined_fsm.acceptNode);
+ fsm2.getDFsm(combined_fsm, combined_fsm.createStartNode(), -1, combined_fsm.acceptNode);
+
+ int node = fsm.createNode();
+ combined_fsm.getDFsm(fsm, start_node, -1, node);
+
+ if (verific_verbose)
+ {
+ log(" Left And FSM:\n");
+ fsm1.dump();
+
+ log(" Right And FSM:\n");
+ fsm1.dump();
+
+ log(" Combined And FSM:\n");
+ combined_fsm.dump();
+ }
+
+ return node;
+ }
+
+ if (inst->Type() == PRIM_SVA_INTERSECT || inst->Type() == PRIM_SVA_WITHIN)
+ {
+ SvaFsm intersect_fsm(clocking);
+
+ if (inst->Type() == PRIM_SVA_INTERSECT)
+ {
+ intersect_fsm.createLink(parse_sequence(intersect_fsm, intersect_fsm.createStartNode(), inst->GetInput1()), intersect_fsm.acceptNode);
+ }
+ else
+ {
+ int n = intersect_fsm.createNode();
+ intersect_fsm.createLink(intersect_fsm.createStartNode(), n);
+ intersect_fsm.createEdge(n, n);
+
+ n = parse_sequence(intersect_fsm, n, inst->GetInput1());
+
+ intersect_fsm.createLink(n, intersect_fsm.acceptNode);
+ intersect_fsm.createEdge(n, n);
+ }
+
+ intersect_fsm.in_cond_mode = true;
+ intersect_fsm.createLink(parse_sequence(intersect_fsm, intersect_fsm.createStartNode(), inst->GetInput2()), intersect_fsm.condNode);
+ intersect_fsm.in_cond_mode = false;
+
+ int node = fsm.createNode();
+ intersect_fsm.getDFsm(fsm, start_node, node, -1, false, true);
+
+ if (verific_verbose) {
+ log(" Intersect FSM:\n");
+ intersect_fsm.dump();
+ }
+
+ return node;
+ }
+
+ if (inst->Type() == PRIM_SVA_THROUGHOUT)
+ {
+ SigBit expr = parse_expression(inst->GetInput1());
+
+ fsm.pushThroughout(expr);
+ int node = parse_sequence(fsm, start_node, inst->GetInput2());
+ fsm.popThroughout();
+
+ return node;
+ }
+
+ parser_error(inst);
+ }
+
+ void get_fsm_accept_reject(SvaFsm &fsm, SigBit *accept_p, SigBit *reject_p, bool swap_accept_reject = false)
+ {
+ log_assert(accept_p != nullptr || reject_p != nullptr);
+
+ if (swap_accept_reject)
+ get_fsm_accept_reject(fsm, reject_p, accept_p);
+ else if (reject_p == nullptr)
+ *accept_p = fsm.getAccept();
+ else if (accept_p == nullptr)
+ *reject_p = fsm.getReject();
+ else
+ fsm.getFirstAcceptReject(accept_p, reject_p);
+ }
+
+ bool eventually_property(Net *&net, SigBit &trig)
+ {
+ Instance *inst = net_to_ast_driver(net);
+
+ if (inst == nullptr)
+ return false;
+
+ if (clocking.cond_net != nullptr)
+ trig = importer->net_map_at(clocking.cond_net);
+ else
+ trig = State::S1;
+
+ if (inst->Type() == PRIM_SVA_S_EVENTUALLY || inst->Type() == PRIM_SVA_EVENTUALLY)
+ {
+ if (mode_cover || mode_trigger)
+ parser_error(inst);
+
+ net = inst->GetInput();
+ clocking.cond_net = nullptr;
+
+ return true;
+ }
+
+ if (inst->Type() == PRIM_SVA_OVERLAPPED_IMPLICATION ||
+ inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION)
+ {
+ Net *antecedent_net = inst->GetInput1();
+ Net *consequent_net = inst->GetInput2();
+
+ Instance *consequent_inst = net_to_ast_driver(consequent_net);
+
+ if (consequent_inst == nullptr)
+ return false;
+
+ if (consequent_inst->Type() != PRIM_SVA_S_EVENTUALLY && consequent_inst->Type() != PRIM_SVA_EVENTUALLY)
+ return false;
+
+ if (mode_cover || mode_trigger)
+ parser_error(consequent_inst);
+
+ int node;
+
+ SvaFsm antecedent_fsm(clocking, trig);
+ node = parse_sequence(antecedent_fsm, antecedent_fsm.createStartNode(), antecedent_net);
+ if (inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) {
+ int next_node = antecedent_fsm.createNode();
+ antecedent_fsm.createEdge(node, next_node);
+ node = next_node;
+ }
+ antecedent_fsm.createLink(node, antecedent_fsm.acceptNode);
+
+ trig = antecedent_fsm.getAccept();
+ net = consequent_inst->GetInput();
+ clocking.cond_net = nullptr;
+
+ if (verific_verbose) {
+ log(" Eventually Antecedent FSM:\n");
+ antecedent_fsm.dump();
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ void parse_property(Net *net, SigBit *accept_p, SigBit *reject_p)
+ {
+ Instance *inst = net_to_ast_driver(net);
+
+ SigBit trig = State::S1;
+
+ if (clocking.cond_net != nullptr)
+ trig = importer->net_map_at(clocking.cond_net);
+
+ if (inst == nullptr)
+ {
+ log_assert(trig == State::S1);
+
+ if (accept_p != nullptr)
+ *accept_p = importer->net_map_at(net);
+ if (reject_p != nullptr)
+ *reject_p = module->Not(NEW_ID, importer->net_map_at(net));
+ }
+ else
+ if (inst->Type() == PRIM_SVA_OVERLAPPED_IMPLICATION ||
+ inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION)
+ {
+ Net *antecedent_net = inst->GetInput1();
+ Net *consequent_net = inst->GetInput2();
+ int node;
+
+ SvaFsm antecedent_fsm(clocking, trig);
+ node = parse_sequence(antecedent_fsm, antecedent_fsm.createStartNode(), antecedent_net);
+ if (inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) {
+ int next_node = antecedent_fsm.createNode();
+ antecedent_fsm.createEdge(node, next_node);
+ node = next_node;
+ }
+
+ Instance *consequent_inst = net_to_ast_driver(consequent_net);
+
+ if (consequent_inst && (consequent_inst->Type() == PRIM_SVA_UNTIL || consequent_inst->Type() == PRIM_SVA_S_UNTIL ||
+ consequent_inst->Type() == PRIM_SVA_UNTIL_WITH || consequent_inst->Type() == PRIM_SVA_S_UNTIL_WITH))
+ {
+ bool until_with = consequent_inst->Type() == PRIM_SVA_UNTIL_WITH || consequent_inst->Type() == PRIM_SVA_S_UNTIL_WITH;
+
+ Net *until_net = consequent_inst->GetInput2();
+ consequent_net = consequent_inst->GetInput1();
+ consequent_inst = net_to_ast_driver(consequent_net);
+
+ SigBit until_sig = parse_expression(until_net);
+ SigBit not_until_sig = module->Not(NEW_ID, until_sig);
+ antecedent_fsm.createEdge(node, node, not_until_sig);
+
+ antecedent_fsm.createLink(node, antecedent_fsm.acceptNode, until_with ? State::S1 : not_until_sig);
+ }
+ else
+ {
+ antecedent_fsm.createLink(node, antecedent_fsm.acceptNode);
+ }
+
+ SigBit antecedent_match = antecedent_fsm.getAccept();
+
+ if (verific_verbose) {
+ log(" Antecedent FSM:\n");
+ antecedent_fsm.dump();
+ }
+
+ bool consequent_not = false;
+ if (consequent_inst && consequent_inst->Type() == PRIM_SVA_NOT) {
+ consequent_not = true;
+ consequent_net = consequent_inst->GetInput();
+ consequent_inst = net_to_ast_driver(consequent_net);
+ }
+
+ SvaFsm consequent_fsm(clocking, antecedent_match);
+ node = parse_sequence(consequent_fsm, consequent_fsm.createStartNode(), consequent_net);
+ consequent_fsm.createLink(node, consequent_fsm.acceptNode);
+
+ get_fsm_accept_reject(consequent_fsm, accept_p, reject_p, consequent_not);
+
+ if (verific_verbose) {
+ log(" Consequent FSM:\n");
+ consequent_fsm.dump();
+ }
+ }
+ else
+ {
+ bool prop_not = inst->Type() == PRIM_SVA_NOT;
+ if (prop_not) {
+ net = inst->GetInput();
+ inst = net_to_ast_driver(net);
+ }
+
+ SvaFsm fsm(clocking, trig);
+ int node = parse_sequence(fsm, fsm.createStartNode(), net);
+ fsm.createLink(node, fsm.acceptNode);
+
+ get_fsm_accept_reject(fsm, accept_p, reject_p, prop_not);
+
+ if (verific_verbose) {
+ log(" Sequence FSM:\n");
+ fsm.dump();
+ }
+ }
+ }
+
+ void import()
+ {
+ try
+ {
+ module = importer->module;
+ netlist = root->Owner();
+
+ if (verific_verbose)
+ log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
+ LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
+
+ RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID);
+
+ // parse SVA sequence into trigger signal
+
+ clocking = VerificClocking(importer, root->GetInput(), true);
+ SigBit accept_bit = State::S0, reject_bit = State::S0;
+
+ if (clocking.body_net == nullptr)
+ {
+ if (clocking.clock_net != nullptr || clocking.enable_net != nullptr || clocking.disable_net != nullptr || clocking.cond_net != nullptr)
+ parser_error(stringf("Failed to parse SVA clocking"), root);
+
+ if (mode_assert || mode_assume) {
+ reject_bit = module->Not(NEW_ID, parse_expression(root->GetInput()));
+ } else {
+ accept_bit = parse_expression(root->GetInput());
+ }
+ }
+ else
+ {
+ Net *net = clocking.body_net;
+ SigBit trig;
+
+ if (eventually_property(net, trig))
+ {
+ SigBit sig_a, sig_en = trig;
+ parse_property(net, &sig_a, nullptr);
+
+ // add final FF stage
+
+ SigBit sig_a_q, sig_en_q;
+
+ if (clocking.body_net == nullptr) {
+ sig_a_q = sig_a;
+ sig_en_q = sig_en;
+ } else {
+ sig_a_q = module->addWire(NEW_ID);
+ sig_en_q = module->addWire(NEW_ID);
+ clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0);
+ clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0);
+ }
+
+ // generate fair/live cell
+
+ RTLIL::Cell *c = nullptr;
+
+ if (mode_assert) c = module->addLive(root_name, sig_a_q, sig_en_q);
+ if (mode_assume) c = module->addFair(root_name, sig_a_q, sig_en_q);
+
+ importer->import_attributes(c->attributes, root);
+
+ return;
+ }
+ else
+ {
+ if (mode_assert || mode_assume) {
+ parse_property(net, nullptr, &reject_bit);
+ } else {
+ parse_property(net, &accept_bit, nullptr);
+ }
+ }
+ }
+
+ if (mode_trigger)
+ {
+ module->connect(importer->net_map_at(root->GetOutput()), accept_bit);
+ }
+ else
+ {
+ SigBit sig_a = module->Not(NEW_ID, reject_bit);
+ SigBit sig_en = module->Or(NEW_ID, accept_bit, reject_bit);
+
+ // add final FF stage
+
+ SigBit sig_a_q, sig_en_q;
+
+ if (clocking.body_net == nullptr) {
+ sig_a_q = sig_a;
+ sig_en_q = sig_en;
+ } else {
+ sig_a_q = module->addWire(NEW_ID);
+ sig_en_q = module->addWire(NEW_ID);
+ clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0);
+ clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0);
+ }
+
+ // generate assert/assume/cover cell
+
+ RTLIL::Cell *c = nullptr;
+
+ if (mode_assert) c = module->addAssert(root_name, sig_a_q, sig_en_q);
+ if (mode_assume) c = module->addAssume(root_name, sig_a_q, sig_en_q);
+ if (mode_cover) c = module->addCover(root_name, sig_a_q, sig_en_q);
+
+ importer->import_attributes(c->attributes, root);
+ }
+ }
+ catch (ParserErrorException)
+ {
+ }
+ }
+};
+
+void verific_import_sva_assert(VerificImporter *importer, Instance *inst)
+{
+ VerificSvaImporter worker;
+ worker.importer = importer;
+ worker.root = inst;
+ worker.mode_assert = true;
+ worker.import();
+}
+
+void verific_import_sva_assume(VerificImporter *importer, Instance *inst)
+{
+ VerificSvaImporter worker;
+ worker.importer = importer;
+ worker.root = inst;
+ worker.mode_assume = true;
+ worker.import();
+}
+
+void verific_import_sva_cover(VerificImporter *importer, Instance *inst)
+{
+ VerificSvaImporter worker;
+ worker.importer = importer;
+ worker.root = inst;
+ worker.mode_cover = true;
+ worker.import();
+}
+
+void verific_import_sva_trigger(VerificImporter *importer, Instance *inst)
+{
+ VerificSvaImporter worker;
+ worker.importer = importer;
+ worker.root = inst;
+ worker.mode_trigger = true;
+ worker.import();
+}
+
+bool verific_is_sva_net(VerificImporter *importer, Verific::Net *net)
+{
+ VerificSvaImporter worker;
+ worker.importer = importer;
+ return worker.net_to_ast_driver(net) != nullptr;
+}
+
+YOSYS_NAMESPACE_END
diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore
index 1d4ae9e5..aadbcdcd 100644
--- a/frontends/verilog/.gitignore
+++ b/frontends/verilog/.gitignore
@@ -1,4 +1,4 @@
verilog_lexer.cc
verilog_parser.output
verilog_parser.tab.cc
-verilog_parser.tab.h
+verilog_parser.tab.hh
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index a06c1d5a..dbaace58 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -1,15 +1,14 @@
GENFILES += frontends/verilog/verilog_parser.tab.cc
-GENFILES += frontends/verilog/verilog_parser.tab.h
+GENFILES += frontends/verilog/verilog_parser.tab.hh
GENFILES += frontends/verilog/verilog_parser.output
GENFILES += frontends/verilog/verilog_lexer.cc
frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
$(Q) mkdir -p $(dir $@)
- $(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser $<
- $(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc
+ $(P) $(BISON) -o $@ -d -r all -b frontends/verilog/verilog_parser $<
-frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc
+frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@)
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index 4a58357b..7848c626 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -49,8 +49,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
int carry = 0;
for (size_t i = 0; i < digits.size(); i++) {
if (digits[i] >= 10)
- log_error("Invalid use of [a-fxz?] in decimal constant at %s:%d.\n",
- current_filename.c_str(), get_line_num());
+ log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n");
digits[i] += carry * 10;
carry = digits[i] % 2;
digits[i] /= 2;
@@ -105,8 +104,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
int bits_per_digit = my_ilog2(base-1);
for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
if (*it > (base-1) && *it < 0xf0)
- log_error("Digit larger than %d used in in base-%d constant at %s:%d.\n",
- base-1, base, current_filename.c_str(), get_line_num());
+ log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n",
+ base-1, base);
for (int i = 0; i < bits_per_digit; i++) {
int bitmask = 1 << i;
if (*it == 0xf0)
@@ -238,4 +237,3 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
}
YOSYS_NAMESPACE_END
-
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
index 997920b8..dea22ee8 100644
--- a/frontends/verilog/preproc.cc
+++ b/frontends/verilog/preproc.cc
@@ -182,15 +182,20 @@ static std::string next_token(bool pass_newline = false)
{
const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789";
if (ch == '`' || strchr(ok, ch) != NULL)
- while ((ch = next_char()) != 0) {
- if (strchr(ok, ch) == NULL) {
- return_char(ch);
- break;
- }
+ {
+ char first = ch;
+ ch = next_char();
+ if (first == '`' && (ch == '"' || ch == '`')) {
token += ch;
- }
+ } else do {
+ if (strchr(ok, ch) == NULL) {
+ return_char(ch);
+ break;
+ }
+ token += ch;
+ } while ((ch = next_char()) != 0);
+ }
}
-
return token;
}
@@ -210,10 +215,69 @@ static void input_file(std::istream &f, std::string filename)
input_buffer.insert(it, "\n`file_pop\n");
}
-std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs)
+
+static bool try_expand_macro(std::set<std::string> &defines_with_args,
+ std::map<std::string, std::string> &defines_map,
+ std::string &tok
+ )
+{
+ if (tok == "`\"") {
+ std::string literal("\"");
+ // Expand string literal
+ while (!input_buffer.empty()) {
+ std::string ntok = next_token();
+ if (ntok == "`\"") {
+ insert_input(literal+"\"");
+ return true;
+ } else if (!try_expand_macro(defines_with_args, defines_map, ntok)) {
+ literal += ntok;
+ }
+ }
+ return false; // error - unmatched `"
+ } else if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) {
+ std::string name = tok.substr(1);
+ // printf("expand: >>%s<< -> >>%s<<\n", name.c_str(), defines_map[name].c_str());
+ std::string skipped_spaces = skip_spaces();
+ tok = next_token(false);
+ if (tok == "(" && defines_with_args.count(name) > 0) {
+ int level = 1;
+ std::vector<std::string> args;
+ args.push_back(std::string());
+ while (1)
+ {
+ skip_spaces();
+ tok = next_token(true);
+ if (tok == ")" || tok == "}" || tok == "]")
+ level--;
+ if (level == 0)
+ break;
+ if (level == 1 && tok == ",")
+ args.push_back(std::string());
+ else
+ args.back() += tok;
+ if (tok == "(" || tok == "{" || tok == "[")
+ level++;
+ }
+ 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);
+ insert_input(skipped_spaces);
+ }
+ insert_input(defines_map[name]);
+ return true;
+ } else if (tok == "``") {
+ // Swallow `` in macro expansion
+ return true;
+ } else return false;
+}
+
+std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> &pre_defines_map,
+ dict<std::string, std::pair<std::string, bool>> &global_defines_cache, const std::list<std::string> &include_dirs)
{
std::set<std::string> defines_with_args;
std::map<std::string, std::string> defines_map(pre_defines_map);
+ std::vector<std::string> filename_stack;
int ifdef_fail_level = 0;
bool in_elseif = false;
@@ -222,9 +286,19 @@ 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[formal_mode ? "FORMAL" : "SYNTHESIS"] = "1";
+ for (auto &it : pre_defines_map)
+ defines_map[it.first] = it.second;
+
+ for (auto &it : global_defines_cache) {
+ if (it.second.second)
+ defines_with_args.insert(it.first);
+ defines_map[it.first] = it.second.first;
+ }
+
while (!input_buffer.empty())
{
std::string tok = next_token();
@@ -281,6 +355,9 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
if (tok == "`include") {
skip_spaces();
std::string fn = next_token(true);
+ while (try_expand_macro(defines_with_args, defines_map, fn)) {
+ fn = next_token();
+ }
while (1) {
size_t pos = fn.find('"');
if (pos == std::string::npos)
@@ -292,26 +369,66 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
}
std::ifstream ff;
ff.clear();
- ff.open(fn.c_str());
- if (ff.fail() && fn.size() > 0 && fn[0] != '/' && filename.find('/') != std::string::npos) {
+ std::string fixed_fn = fn;
+ ff.open(fixed_fn.c_str());
+
+ bool filename_path_sep_found;
+ bool fn_relative;
+#ifdef _WIN32
+ // Both forward and backslash are acceptable separators on Windows.
+ filename_path_sep_found = (filename.find_first_of("/\\") != std::string::npos);
+ // Easier just to invert the check for an absolute path (e.g. C:\ or C:/)
+ fn_relative = !(fn[1] == ':' && (fn[2] == '/' || fn[2] == '\\'));
+#else
+ filename_path_sep_found = (filename.find('/') != std::string::npos);
+ fn_relative = (fn[0] != '/');
+#endif
+
+ if (ff.fail() && fn.size() > 0 && fn_relative && filename_path_sep_found) {
// if the include file was not found, it is not given with an absolute path, and the
// currently read file is given with a path, then try again relative to its directory
ff.clear();
- ff.open(filename.substr(0, filename.rfind('/')+1) + fn);
+#ifdef _WIN32
+ fixed_fn = filename.substr(0, filename.find_last_of("/\\")+1) + fn;
+#else
+ fixed_fn = filename.substr(0, filename.rfind('/')+1) + fn;
+#endif
+ ff.open(fixed_fn);
}
- if (ff.fail() && fn.size() > 0 && fn[0] != '/') {
+ if (ff.fail() && fn.size() > 0 && fn_relative) {
// if the include file was not found and it is not given with an absolute path, then
// search it in the include path
for (auto incdir : include_dirs) {
ff.clear();
- ff.open(incdir + '/' + fn);
+ fixed_fn = incdir + '/' + fn;
+ ff.open(fixed_fn);
if (!ff.fail()) break;
}
}
- if (ff.fail())
+ if (ff.fail()) {
output_code.push_back("`file_notfound " + fn);
- else
- input_file(ff, fn);
+ } else {
+ input_file(ff, fixed_fn);
+ yosys_input_files.insert(fixed_fn);
+ }
+ continue;
+ }
+
+ if (tok == "`file_push") {
+ skip_spaces();
+ std::string fn = next_token(true);
+ if (!fn.empty() && fn.front() == '"' && fn.back() == '"')
+ fn = fn.substr(1, fn.size()-2);
+ output_code.push_back(tok + " \"" + fn + "\"");
+ filename_stack.push_back(filename);
+ filename = fn;
+ continue;
+ }
+
+ if (tok == "`file_pop") {
+ output_code.push_back(tok);
+ filename = filename_stack.back();
+ filename_stack.pop_back();
continue;
}
@@ -379,6 +496,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
defines_with_args.insert(name);
else
defines_with_args.erase(name);
+ global_defines_cache[name] = std::pair<std::string, bool>(value, state == 2);
continue;
}
@@ -389,6 +507,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
// printf("undef: >>%s<<\n", name.c_str());
defines_map.erase(name);
defines_with_args.erase(name);
+ global_defines_cache.erase(name);
continue;
}
@@ -401,39 +520,16 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
continue;
}
- if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) {
- std::string name = tok.substr(1);
- // printf("expand: >>%s<< -> >>%s<<\n", name.c_str(), defines_map[name].c_str());
- std::string skipped_spaces = skip_spaces();
- tok = next_token(false);
- if (tok == "(" && defines_with_args.count(name) > 0) {
- int level = 1;
- std::vector<std::string> args;
- args.push_back(std::string());
- while (1)
- {
- tok = next_token(true);
- if (tok == ")" || tok == "}" || tok == "]")
- level--;
- if (level == 0)
- break;
- if (level == 1 && tok == ",")
- args.push_back(std::string());
- else
- args.back() += tok;
- if (tok == "(" || tok == "{" || tok == "[")
- level++;
- }
- 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);
- insert_input(skipped_spaces);
- }
- insert_input(defines_map[name]);
+ if (tok == "`resetall") {
+ defines_map.clear();
+ defines_with_args.clear();
+ global_defines_cache.clear();
continue;
}
+ if (try_expand_macro(defines_with_args, defines_map, tok))
+ continue;
+
output_code.push_back(tok);
}
@@ -449,4 +545,3 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
}
YOSYS_NAMESPACE_END
-
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index 894723c8..8dcc7c5a 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -42,14 +42,14 @@ static std::list<std::vector<std::string>> verilog_defaults_stack;
static void error_on_dpi_function(AST::AstNode *node)
{
if (node->type == AST::AST_DPI_FUNCTION)
- log_error("Found DPI function %s at %s:%d.\n", node->str.c_str(), node->filename.c_str(), node->linenum);
+ log_file_error(node->filename, node->linenum, "Found DPI function %s.\n", node->str.c_str());
for (auto child : node->children)
error_on_dpi_function(child);
}
struct VerilogFrontend : public Frontend {
VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -78,6 +78,9 @@ struct VerilogFrontend : public Frontend {
log(" -dump_ast2\n");
log(" dump abstract syntax tree (after simplification)\n");
log("\n");
+ log(" -no_dump_ptr\n");
+ log(" do not include hex memory addresses in dump (easier to diff dumps)\n");
+ log("\n");
log(" -dump_vlog\n");
log(" dump ast as Verilog code (after simplification)\n");
log("\n");
@@ -137,9 +140,13 @@ struct VerilogFrontend : public Frontend {
log(" -icells\n");
log(" interpret cell types starting with '$' as internal cell types\n");
log("\n");
- log(" -ignore_redef\n");
+ log(" -nooverwrite\n");
log(" ignore re-definitions of modules. (the default behavior is to\n");
- log(" create an error message.)\n");
+ log(" create an error message if the existing module is not a black box\n");
+ log(" module, and overwrite the existing module otherwise.)\n");
+ log("\n");
+ log(" -overwrite\n");
+ log(" overwrite existing modules with the same name\n");
log("\n");
log(" -defer\n");
log(" only read the abstract syntax tree and defer actual compilation\n");
@@ -168,14 +175,19 @@ struct VerilogFrontend : public Frontend {
log("recommended to use a simulator (for example Icarus Verilog) for checking\n");
log("the syntax of the code, rather than to rely on read_verilog for that.\n");
log("\n");
+ log("Depending on if read_verilog is run in -formal mode, either the macro\n");
+ log("SYNTHESIS or FORMAL is defined automatically. In addition, read_verilog\n");
+ log("always defines the macro YOSYS.\n");
+ log("\n");
log("See the Yosys README file for a list of non-standard Verilog features\n");
log("supported by the Yosys Verilog front-end.\n");
log("\n");
}
- virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_dump_ast1 = false;
bool flag_dump_ast2 = false;
+ bool flag_no_dump_ptr = false;
bool flag_dump_vlog = false;
bool flag_dump_rtlil = false;
bool flag_nolatches = false;
@@ -187,7 +199,8 @@ struct VerilogFrontend : public Frontend {
bool flag_nodpi = false;
bool flag_noopt = false;
bool flag_icells = false;
- bool flag_ignore_redef = false;
+ bool flag_nooverwrite = false;
+ bool flag_overwrite = false;
bool flag_defer = false;
std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs;
@@ -232,6 +245,10 @@ struct VerilogFrontend : public Frontend {
flag_dump_ast2 = true;
continue;
}
+ if (arg == "-no_dump_ptr") {
+ flag_no_dump_ptr = true;
+ continue;
+ }
if (arg == "-dump_vlog") {
flag_dump_vlog = true;
continue;
@@ -285,8 +302,14 @@ struct VerilogFrontend : public Frontend {
flag_icells = true;
continue;
}
- if (arg == "-ignore_redef") {
- flag_ignore_redef = true;
+ if (arg == "-ignore_redef" || arg == "-nooverwrite") {
+ flag_nooverwrite = true;
+ flag_overwrite = false;
+ continue;
+ }
+ if (arg == "-overwrite") {
+ flag_nooverwrite = false;
+ flag_overwrite = true;
continue;
}
if (arg == "-defer") {
@@ -303,10 +326,10 @@ struct VerilogFrontend : public Frontend {
}
if (arg == "-D" && argidx+1 < args.size()) {
std::string name = args[++argidx], value;
- size_t equal = name.find('=', 2);
+ size_t equal = name.find('=');
if (equal != std::string::npos) {
- value = arg.substr(equal+1);
- name = arg.substr(0, equal);
+ value = name.substr(equal+1);
+ name = name.substr(0, equal);
}
defines_map[name] = value;
continue;
@@ -345,7 +368,7 @@ struct VerilogFrontend : public Frontend {
std::string code_after_preproc;
if (!flag_nopp) {
- code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, include_dirs);
+ code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, design->verilog_defines, include_dirs);
if (flag_ppdump)
log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str());
lexin = new std::istringstream(code_after_preproc);
@@ -366,7 +389,7 @@ struct VerilogFrontend : public Frontend {
if (flag_nodpi)
error_on_dpi_function(current_ast);
- AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
+ AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
@@ -380,7 +403,7 @@ struct VerilogFrontend : public Frontend {
struct VerilogDefaults : public Pass {
VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -401,9 +424,9 @@ struct VerilogDefaults : public Pass {
log("not imply -clear.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
- if (args.size() == 0)
+ if (args.size() < 2)
cmd_error(args, 1, "Missing argument.");
if (args[1] == "-add") {
@@ -436,6 +459,66 @@ struct VerilogDefaults : public Pass {
}
} VerilogDefaults;
+struct VerilogDefines : public Pass {
+ VerilogDefines() : Pass("verilog_defines", "define and undefine verilog defines") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" verilog_defines [options]\n");
+ log("\n");
+ log("Define and undefine verilog preprocessor macros.\n");
+ log("\n");
+ log(" -Dname[=definition]\n");
+ log(" define the preprocessor symbol 'name' and set its optional value\n");
+ log(" 'definition'\n");
+ log("\n");
+ log(" -Uname[=definition]\n");
+ log(" undefine the preprocessor symbol 'name'\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ std::string arg = args[argidx];
+ if (arg == "-D" && argidx+1 < args.size()) {
+ std::string name = args[++argidx], value;
+ size_t equal = name.find('=');
+ if (equal != std::string::npos) {
+ value = name.substr(equal+1);
+ name = name.substr(0, equal);
+ }
+ design->verilog_defines[name] = std::pair<std::string, bool>(value, false);
+ continue;
+ }
+ if (arg.compare(0, 2, "-D") == 0) {
+ size_t equal = arg.find('=', 2);
+ std::string name = arg.substr(2, equal-2);
+ std::string value;
+ if (equal != std::string::npos)
+ value = arg.substr(equal+1);
+ design->verilog_defines[name] = std::pair<std::string, bool>(value, false);
+ continue;
+ }
+ if (arg == "-U" && argidx+1 < args.size()) {
+ std::string name = args[++argidx];
+ design->verilog_defines.erase(name);
+ continue;
+ }
+ if (arg.compare(0, 2, "-U") == 0) {
+ std::string name = arg.substr(2);
+ design->verilog_defines.erase(name);
+ continue;
+ }
+ break;
+ }
+
+ if (args.size() != argidx)
+ cmd_error(args, argidx, "Extra argument.");
+ }
+} VerilogDefines;
+
YOSYS_NAMESPACE_END
// the yyerror function used by bison to report parser errors
@@ -444,13 +527,11 @@ 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);
+ YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(),
+ "%s", buffer);
exit(1);
}
-
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index 606ec20a..16edc798 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -68,7 +68,8 @@ namespace VERILOG_FRONTEND
}
// the pre-processor
-std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs);
+std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> &pre_defines_map,
+ dict<std::string, std::pair<std::string, bool>> &global_defines_cache, const std::list<std::string> &include_dirs);
YOSYS_NAMESPACE_END
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 405aeb97..83921bf0 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -42,7 +42,7 @@
#include "kernel/log.h"
#include "frontends/verilog/verilog_frontend.h"
#include "frontends/ast/ast.h"
-#include "verilog_parser.tab.h"
+#include "verilog_parser.tab.hh"
USING_YOSYS_NAMESPACE
using namespace AST;
@@ -145,6 +145,9 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
+"specify" { return TOK_SPECIFY; }
+"endspecify" { return TOK_ENDSPECIFY; }
+"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
"parameter" { return TOK_PARAMETER; }
@@ -170,17 +173,30 @@ YOSYS_NAMESPACE_END
"endgenerate" { return TOK_ENDGENERATE; }
"while" { return TOK_WHILE; }
"repeat" { return TOK_REPEAT; }
+"automatic" { return TOK_AUTOMATIC; }
+
+"unique" { SV_KEYWORD(TOK_UNIQUE); }
+"unique0" { SV_KEYWORD(TOK_UNIQUE); }
+"priority" { SV_KEYWORD(TOK_PRIORITY); }
"always_comb" { SV_KEYWORD(TOK_ALWAYS); }
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
-"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
-"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
-"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
-"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
-"logic" { SV_KEYWORD(TOK_REG); }
-"bit" { SV_KEYWORD(TOK_REG); }
+"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
+"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
+"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
+"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
+"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
+"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); }
+"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
+"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
+"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
+"logic" { SV_KEYWORD(TOK_LOGIC); }
+"bit" { SV_KEYWORD(TOK_REG); }
+
+"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
+"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
"input" { return TOK_INPUT; }
"output" { return TOK_OUTPUT; }
@@ -192,14 +208,17 @@ YOSYS_NAMESPACE_END
"genvar" { return TOK_GENVAR; }
"real" { return TOK_REAL; }
+"enum" { SV_KEYWORD(TOK_ENUM); }
+"typedef" { SV_KEYWORD(TOK_TYPEDEF); }
+
[0-9][0-9_]* {
frontend_verilog_yylval.string = new std::string(yytext);
- return TOK_CONST;
+ return TOK_CONSTVAL;
}
[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext);
- return TOK_CONST;
+ return TOK_CONSTVAL;
}
[0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? {
@@ -222,10 +241,18 @@ YOSYS_NAMESPACE_END
while (yystr[i]) {
if (yystr[i] == '\\' && yystr[i + 1]) {
i++;
- if (yystr[i] == 'n')
+ if (yystr[i] == 'a')
+ yystr[i] = '\a';
+ else if (yystr[i] == 'f')
+ yystr[i] = '\f';
+ else if (yystr[i] == 'n')
yystr[i] = '\n';
+ else if (yystr[i] == 'r')
+ yystr[i] = '\r';
else if (yystr[i] == 't')
yystr[i] = '\t';
+ else if (yystr[i] == 'v')
+ yystr[i] = '\v';
else if ('0' <= yystr[i] && yystr[i] <= '7') {
yystr[i] = yystr[i] - '0';
if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
@@ -358,7 +385,9 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"<<<" { return OP_SSHL; }
">>>" { return OP_SSHR; }
-"::" { SV_KEYWORD(TOK_PACKAGESEP); }
+"::" { return TOK_PACKAGESEP; }
+"++" { return TOK_INCREMENT; }
+"--" { return TOK_DECREMENT; }
"+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; }
@@ -372,10 +401,6 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
\\[\r\n] /* ignore continuation sequence */
"//"[^\r\n]* /* ignore one-line comments */
-"#"\ *[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/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 5bbda535..2389d7d3 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -59,6 +59,7 @@ namespace VERILOG_FRONTEND {
bool default_nettype_wire;
bool sv_mode, formal_mode, lib_mode;
bool norestrict_mode, assume_asserts_mode;
+ bool current_wire_rand, current_wire_const;
std::istream *lexin;
}
YOSYS_NAMESPACE_END
@@ -100,27 +101,29 @@ static void free_attr(std::map<std::string, AstNode*> *al)
bool boolean;
}
-%token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE
+%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
-%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG
+%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
-%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR
+%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
-%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK
+%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
-%token TOK_RESTRICT TOK_PROPERTY
+%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
+%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
+%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <string> opt_label tok_prim_wrapper hierarchical_id
-%type <boolean> opt_signed
-%type <al> attr
+%type <boolean> opt_signed unique_case_attr
+%type <al> attr case_attr
// operator precedence from low to high
%left OP_LOR
@@ -139,7 +142,9 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%define parse.error verbose
%define parse.lac full
-%expect 2
+%nonassoc FAKE_THEN
+%nonassoc TOK_ELSE
+
%debug
%%
@@ -269,7 +274,13 @@ single_module_para:
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 | single_param_decl;
+ } param_signed param_integer param_range single_param_decl |
+ TOK_LOCALPARAM {
+ if (astbuf1) delete astbuf1;
+ astbuf1 = new AstNode(AST_LOCALPARAM);
+ astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ } param_signed param_integer param_range single_param_decl |
+ single_param_decl;
module_args_opt:
'(' ')' | /* empty */ | '(' module_args optional_comma ')';
@@ -346,6 +357,9 @@ package_body_stmt:
localparam_decl;
non_opt_delay:
+ '#' TOK_ID { delete $2; } |
+ '#' TOK_CONSTVAL { delete $2; } |
+ '#' TOK_REALVAL { delete $2; } |
'#' '(' expr ')' { delete $3; } |
'#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; };
@@ -355,14 +369,17 @@ delay:
wire_type:
{
astbuf3 = new AstNode(AST_WIRE);
+ current_wire_rand = false;
+ current_wire_const = false;
} wire_type_token_list delay {
$$ = astbuf3;
};
wire_type_token_list:
- wire_type_token | wire_type_token_list wire_type_token;
+ wire_type_token | wire_type_token_list wire_type_token |
+ wire_type_token_io ;
-wire_type_token:
+wire_type_token_io:
TOK_INPUT {
astbuf3->is_input = true;
} |
@@ -372,12 +389,17 @@ wire_type_token:
TOK_INOUT {
astbuf3->is_input = true;
astbuf3->is_output = true;
- } |
+ };
+
+wire_type_token:
TOK_WIRE {
} |
TOK_REG {
astbuf3->is_reg = true;
} |
+ TOK_LOGIC {
+ astbuf3->is_logic = true;
+ } |
TOK_INTEGER {
astbuf3->is_reg = true;
astbuf3->range_left = 31;
@@ -392,6 +414,12 @@ wire_type_token:
} |
TOK_SIGNED {
astbuf3->is_signed = true;
+ } |
+ TOK_RAND {
+ current_wire_rand = true;
+ } |
+ TOK_CONST {
+ current_wire_const = true;
};
non_opt_range:
@@ -454,8 +482,19 @@ module_body:
/* empty */;
module_body_stmt:
- task_func_decl | param_decl | localparam_decl | defparam_decl | wire_decl | assign_stmt | cell_stmt |
- always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property;
+ task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
+ always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl;
+
+checker_decl:
+ TOK_CHECKER TOK_ID ';' {
+ AstNode *node = new AstNode(AST_GENBLOCK);
+ node->str = *$2;
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ } module_body TOK_ENDCHECKER {
+ delete $2;
+ ast_stack.pop_back();
+ };
task_func_decl:
attr TOK_DPI_FUNCTION TOK_ID TOK_ID {
@@ -491,35 +530,36 @@ task_func_decl:
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
- attr TOK_TASK TOK_ID {
+ attr TOK_TASK opt_automatic TOK_ID {
current_function_or_task = new AstNode(AST_TASK);
- current_function_or_task->str = *$3;
+ current_function_or_task->str = *$4;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
ast_stack.push_back(current_function_or_task);
current_function_or_task_port_id = 1;
- delete $3;
+ delete $4;
} 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_automatic opt_signed range_or_signed_int TOK_ID {
current_function_or_task = new AstNode(AST_FUNCTION);
- current_function_or_task->str = *$5;
+ current_function_or_task->str = *$6;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
ast_stack.push_back(current_function_or_task);
AstNode *outreg = new AstNode(AST_WIRE);
- outreg->str = *$5;
- outreg->is_signed = $3;
- if ($4 != NULL) {
- outreg->children.push_back($4);
- outreg->is_signed = $3 || $4->is_signed;
- $4->is_signed = false;
+ outreg->str = *$6;
+ outreg->is_signed = $4;
+ outreg->is_reg = true;
+ if ($5 != NULL) {
+ outreg->children.push_back($5);
+ outreg->is_signed = $4 || $5->is_signed;
+ $5->is_signed = false;
}
current_function_or_task->children.push_back(outreg);
current_function_or_task_port_id = 1;
- delete $5;
+ delete $6;
} task_func_args_opt ';' task_func_body TOK_ENDFUNCTION {
current_function_or_task = NULL;
ast_stack.pop_back();
@@ -546,6 +586,10 @@ dpi_function_args:
dpi_function_arg |
/* empty */;
+opt_automatic:
+ TOK_AUTOMATIC |
+ /* empty */;
+
opt_signed:
TOK_SIGNED {
$$ = true;
@@ -597,6 +641,194 @@ task_func_body:
task_func_body behavioral_stmt |
/* empty */;
+specify_block:
+ TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
+ TOK_SPECIFY TOK_ENDSPECIFY ;
+
+specify_item_opt:
+ specify_item_opt specify_item |
+ specify_item ;
+
+specify_item:
+ specparam_declaration
+ // | pulsestyle_declaration
+ // | showcancelled_declaration
+ | path_declaration
+ | system_timing_declaration
+ ;
+
+specparam_declaration:
+ TOK_SPECPARAM list_of_specparam_assignments ';' |
+ TOK_SPECPARAM specparam_range list_of_specparam_assignments ';' ;
+
+// IEEE 1364-2005 calls this sinmply 'range' but the current 'range' rule allows empty match
+// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
+// exxxxtending this for SV specparam would change this anyhow
+specparam_range:
+ '[' constant_expression ':' constant_expression ']' ;
+
+list_of_specparam_assignments:
+ specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
+
+specparam_assignment:
+ TOK_ID '=' constant_mintypmax_expression ;
+
+/*
+pulsestyle_declaration :
+ ;
+
+showcancelled_declaration :
+ ;
+*/
+
+path_declaration :
+ simple_path_declaration ';'
+ // | edge_sensitive_path_declaration
+ // | state_dependent_path_declaration
+ ;
+
+simple_path_declaration :
+ parallel_path_description '=' path_delay_value |
+ full_path_description '=' path_delay_value
+ ;
+
+path_delay_value :
+ '(' path_delay_expression list_of_path_delay_extra_expressions ')'
+ | path_delay_expression
+ | path_delay_expression list_of_path_delay_extra_expressions
+ ;
+
+list_of_path_delay_extra_expressions :
+/*
+ t_path_delay_expression
+ | trise_path_delay_expression ',' tfall_path_delay_expression
+ | trise_path_delay_expression ',' tfall_path_delay_expression ',' tz_path_delay_expression
+ | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
+ tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression
+ | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
+ tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression ','
+ t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ','
+ tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression
+*/
+ ',' path_delay_expression
+ | ',' path_delay_expression ',' path_delay_expression
+ | ',' path_delay_expression ',' path_delay_expression ','
+ path_delay_expression ',' path_delay_expression ',' path_delay_expression
+ | ',' path_delay_expression ',' path_delay_expression ','
+ path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
+ path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
+ path_delay_expression ',' path_delay_expression ',' path_delay_expression
+ ;
+
+parallel_path_description :
+ '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ;
+
+full_path_description :
+ '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' ;
+
+// This was broken into 2 rules to solve shift/reduce conflicts
+list_of_path_inputs :
+ specify_input_terminal_descriptor opt_polarity_operator |
+ specify_input_terminal_descriptor more_path_inputs opt_polarity_operator ;
+
+more_path_inputs :
+ ',' specify_input_terminal_descriptor |
+ more_path_inputs ',' specify_input_terminal_descriptor ;
+
+list_of_path_outputs :
+ specify_output_terminal_descriptor |
+ list_of_path_outputs ',' specify_output_terminal_descriptor ;
+
+opt_polarity_operator :
+ '+'
+ | '-'
+ | ;
+
+// Good enough for the time being
+specify_input_terminal_descriptor :
+ TOK_ID ;
+
+// Good enough for the time being
+specify_output_terminal_descriptor :
+ TOK_ID ;
+
+system_timing_declaration :
+ TOK_ID '(' system_timing_args ')' ';' ;
+
+system_timing_arg :
+ TOK_POSEDGE TOK_ID |
+ TOK_NEGEDGE TOK_ID |
+ expr ;
+
+system_timing_args :
+ system_timing_arg |
+ system_timing_args ',' system_timing_arg ;
+
+/*
+t_path_delay_expression :
+ path_delay_expression;
+
+trise_path_delay_expression :
+ path_delay_expression;
+
+tfall_path_delay_expression :
+ path_delay_expression;
+
+tz_path_delay_expression :
+ path_delay_expression;
+
+t01_path_delay_expression :
+ path_delay_expression;
+
+t10_path_delay_expression :
+ path_delay_expression;
+
+t0z_path_delay_expression :
+ path_delay_expression;
+
+tz1_path_delay_expression :
+ path_delay_expression;
+
+t1z_path_delay_expression :
+ path_delay_expression;
+
+tz0_path_delay_expression :
+ path_delay_expression;
+
+t0x_path_delay_expression :
+ path_delay_expression;
+
+tx1_path_delay_expression :
+ path_delay_expression;
+
+t1x_path_delay_expression :
+ path_delay_expression;
+
+tx0_path_delay_expression :
+ path_delay_expression;
+
+txz_path_delay_expression :
+ path_delay_expression;
+
+tzx_path_delay_expression :
+ path_delay_expression;
+*/
+
+path_delay_expression :
+ constant_expression;
+
+constant_mintypmax_expression :
+ constant_expression
+ | constant_expression ':' constant_expression ':' constant_expression
+ ;
+
+// for the time being this is OK, but we may write our own expr here.
+// as I'm not sure it is legal to use a full expr here (probably not)
+// On the other hand, other rules requiring constant expressions also use 'expr'
+// (such as param assignment), so we may leave this as-is, perhaps assing runtime checks for constant-ness
+constant_expression:
+ expr ;
+
param_signed:
TOK_SIGNED {
astbuf1->is_signed = true;
@@ -666,14 +898,13 @@ defparam_decl_list:
single_defparam_decl | defparam_decl_list ',' single_defparam_decl;
single_defparam_decl:
- range hierarchical_id '=' expr {
+ range rvalue '=' expr {
AstNode *node = new AstNode(AST_DEFPARAM);
- node->str = *$2;
+ node->children.push_back($2);
node->children.push_back($4);
if ($1 != NULL)
node->children.push_back($1);
ast_stack.back()->children.push_back(node);
- delete $2;
};
wire_decl:
@@ -731,7 +962,48 @@ wire_name_list:
wire_name_and_opt_assign | wire_name_list ',' wire_name_and_opt_assign;
wire_name_and_opt_assign:
- wire_name |
+ wire_name {
+ bool attr_anyconst = false;
+ bool attr_anyseq = false;
+ bool attr_allconst = false;
+ bool attr_allseq = false;
+ if (ast_stack.back()->children.back()->get_bool_attribute("\\anyconst")) {
+ delete ast_stack.back()->children.back()->attributes.at("\\anyconst");
+ ast_stack.back()->children.back()->attributes.erase("\\anyconst");
+ attr_anyconst = true;
+ }
+ if (ast_stack.back()->children.back()->get_bool_attribute("\\anyseq")) {
+ delete ast_stack.back()->children.back()->attributes.at("\\anyseq");
+ ast_stack.back()->children.back()->attributes.erase("\\anyseq");
+ attr_anyseq = true;
+ }
+ if (ast_stack.back()->children.back()->get_bool_attribute("\\allconst")) {
+ delete ast_stack.back()->children.back()->attributes.at("\\allconst");
+ ast_stack.back()->children.back()->attributes.erase("\\allconst");
+ attr_allconst = true;
+ }
+ if (ast_stack.back()->children.back()->get_bool_attribute("\\allseq")) {
+ delete ast_stack.back()->children.back()->attributes.at("\\allseq");
+ ast_stack.back()->children.back()->attributes.erase("\\allseq");
+ attr_allseq = true;
+ }
+ if (current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) {
+ AstNode *wire = new AstNode(AST_IDENTIFIER);
+ AstNode *fcall = new AstNode(AST_FCALL);
+ wire->str = ast_stack.back()->children.back()->str;
+ fcall->str = current_wire_const ? "\\$anyconst" : "\\$anyseq";
+ if (attr_anyconst)
+ fcall->str = "\\$anyconst";
+ if (attr_anyseq)
+ fcall->str = "\\$anyseq";
+ if (attr_allconst)
+ fcall->str = "\\$allconst";
+ if (attr_allseq)
+ fcall->str = "\\$allseq";
+ fcall->attributes["\\reg"] = AstNode::mkconst_str(RTLIL::unescape_id(wire->str));
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, fcall));
+ }
+ } |
wire_name '=' expr {
AstNode *wire = new AstNode(AST_IDENTIFIER);
wire->str = ast_stack.back()->children.back()->str;
@@ -782,6 +1054,7 @@ wire_name:
node->port_id = current_function_or_task_port_id++;
}
ast_stack.back()->children.push_back(node);
+
delete $1;
};
@@ -994,18 +1267,45 @@ opt_label:
$$ = NULL;
};
+opt_property:
+ TOK_PROPERTY | /* empty */;
+
+opt_stmt_label:
+ TOK_ID ':' | /* empty */;
+
assert:
- TOK_ASSERT '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $3));
+ opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
+ } |
+ opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ } |
+ opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
+ } |
+ opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
} |
- TOK_ASSUME '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
+ opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
} |
- TOK_RESTRICT '(' expr ')' ';' {
+ opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
+ } |
+ opt_stmt_label TOK_COVER ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
+ } |
+ opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
if (norestrict_mode)
- delete $3;
+ delete $5;
+ else
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ } |
+ opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ if (norestrict_mode)
+ delete $6;
else
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
};
assert_property:
@@ -1015,11 +1315,26 @@ assert_property:
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
} |
+ TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5));
+ } |
+ TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
+ } |
+ TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
+ } |
TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
if (norestrict_mode)
delete $4;
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
+ } |
+ TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
+ if (norestrict_mode)
+ delete $5;
+ else
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
};
simple_behavioral_stmt:
@@ -1027,6 +1342,14 @@ simple_behavioral_stmt:
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4);
ast_stack.back()->children.push_back(node);
} |
+ lvalue TOK_INCREMENT {
+ AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_ADD, $1->clone(), AstNode::mkconst_int(1, true)));
+ ast_stack.back()->children.push_back(node);
+ } |
+ lvalue TOK_DECREMENT {
+ AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_SUB, $1->clone(), AstNode::mkconst_int(1, true)));
+ ast_stack.back()->children.push_back(node);
+ } |
lvalue OP_LE delay expr {
AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4);
ast_stack.back()->children.push_back(node);
@@ -1118,7 +1441,7 @@ behavioral_stmt:
ast_stack.pop_back();
ast_stack.pop_back();
} |
- attr case_type '(' expr ')' {
+ case_attr case_type '(' expr ')' {
AstNode *node = new AstNode(AST_CASE, $4);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
@@ -1128,6 +1451,23 @@ behavioral_stmt:
ast_stack.pop_back();
};
+unique_case_attr:
+ /* empty */ {
+ $$ = false;
+ } |
+ TOK_PRIORITY case_attr {
+ $$ = $2;
+ } |
+ TOK_UNIQUE case_attr {
+ $$ = true;
+ };
+
+case_attr:
+ attr unique_case_attr {
+ if ($2) (*$1)["\\parallel_case"] = AstNode::mkconst_int(1, false);
+ $$ = $1;
+ };
+
case_type:
TOK_CASE {
case_type_stack.push_back(0);
@@ -1162,7 +1502,7 @@ optional_else:
ast_stack.back()->children.push_back(cond);
ast_stack.push_back(block);
} behavioral_stmt |
- /* empty */;
+ /* empty */ %prec FAKE_THEN;
case_body:
case_body case_item |
@@ -1229,7 +1569,9 @@ rvalue:
$$ = new AstNode(AST_IDENTIFIER, $2);
$$->str = *$1;
delete $1;
- if ($2 == nullptr && formal_mode && ($$->str == "\\$initstate" || $$->str == "\\$anyconst" || $$->str == "\\$anyseq"))
+ if ($2 == nullptr && ($$->str == "\\$initstate" ||
+ $$->str == "\\$anyconst" || $$->str == "\\$anyseq" ||
+ $$->str == "\\$allconst" || $$->str == "\\$allseq"))
$$->type = AST_FCALL;
} |
hierarchical_id non_opt_multirange {
@@ -1333,7 +1675,7 @@ gen_stmt_or_null:
gen_stmt_block | ';';
opt_gen_else:
- TOK_ELSE gen_stmt_or_null | /* empty */;
+ TOK_ELSE gen_stmt_or_null | /* empty */ %prec FAKE_THEN;
expr:
basic_expr {
@@ -1351,7 +1693,7 @@ basic_expr:
rvalue {
$$ = $1;
} |
- '(' expr ')' TOK_CONST {
+ '(' expr ')' TOK_CONSTVAL {
if ($4->substr(0, 1) != "'")
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = $2;
@@ -1361,7 +1703,7 @@ basic_expr:
$$ = new AstNode(AST_TO_BITS, bits, val);
delete $4;
} |
- hierarchical_id TOK_CONST {
+ hierarchical_id TOK_CONSTVAL {
if ($2->substr(0, 1) != "'")
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = new AstNode(AST_IDENTIFIER);
@@ -1373,14 +1715,14 @@ basic_expr:
delete $1;
delete $2;
} |
- TOK_CONST TOK_CONST {
+ TOK_CONSTVAL TOK_CONSTVAL {
$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
if ($$ == NULL || (*$2)[0] != '\'')
log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
delete $1;
delete $2;
} |
- TOK_CONST {
+ TOK_CONSTVAL {
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
if ($$ == NULL)
log_error("Value conversion failed: `%s'\n", $1->c_str());
@@ -1441,10 +1783,18 @@ basic_expr:
$$ = new AstNode(AST_BIT_AND, $1, $4);
append_attr($$, $3);
} |
+ basic_expr OP_NAND attr basic_expr {
+ $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_AND, $1, $4));
+ append_attr($$, $3);
+ } |
basic_expr '|' attr basic_expr {
$$ = new AstNode(AST_BIT_OR, $1, $4);
append_attr($$, $3);
} |
+ basic_expr OP_NOR attr basic_expr {
+ $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_OR, $1, $4));
+ append_attr($$, $3);
+ } |
basic_expr '^' attr basic_expr {
$$ = new AstNode(AST_BIT_XOR, $1, $4);
append_attr($$, $3);
diff --git a/frontends/vhdl2verilog/Makefile.inc b/frontends/vhdl2verilog/Makefile.inc
deleted file mode 100644
index 003d89c4..00000000
--- a/frontends/vhdl2verilog/Makefile.inc
+++ /dev/null
@@ -1 +0,0 @@
-OBJS += frontends/vhdl2verilog/vhdl2verilog.o
diff --git a/frontends/vhdl2verilog/vhdl2verilog.cc b/frontends/vhdl2verilog/vhdl2verilog.cc
deleted file mode 100644
index 6f9c0e3f..00000000
--- a/frontends/vhdl2verilog/vhdl2verilog.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#include "kernel/register.h"
-#include "kernel/sigtools.h"
-#include "kernel/log.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-
-#ifndef _WIN32
-# include <unistd.h>
-# include <dirent.h>
-#endif
-
-YOSYS_NAMESPACE_BEGIN
-
-struct Vhdl2verilogPass : public Pass {
- Vhdl2verilogPass() : Pass("vhdl2verilog", "importing VHDL designs using vhdl2verilog") { }
- virtual void help()
- {
- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
- log("\n");
- log(" vhdl2verilog [options] <vhdl-file>..\n");
- log("\n");
- log("This command reads VHDL source files using the 'vhdl2verilog' tool and the\n");
- log("Yosys Verilog frontend.\n");
- log("\n");
- log(" -out <out_file>\n");
- log(" do not import the vhdl2verilog output. instead write it to the\n");
- log(" specified file.\n");
- log("\n");
- log(" -vhdl2verilog_dir <directory>\n");
- log(" do use the specified vhdl2verilog installation. this is the directory\n");
- log(" that contains the setup_env.sh file. when this option is not present,\n");
- log(" it is assumed that vhdl2verilog is in the PATH environment variable.\n");
- log("\n");
- log(" -top <top-entity-name>\n");
- log(" The name of the top entity. This option is mandatory.\n");
- log("\n");
- log("The following options are passed as-is to vhdl2verilog:\n");
- log("\n");
- log(" -arch <architecture_name>\n");
- log(" -unroll_generate\n");
- log(" -nogenericeval\n");
- log(" -nouniquify\n");
- log(" -oldparser\n");
- log(" -suppress <list>\n");
- log(" -quiet\n");
- log(" -nobanner\n");
- log(" -mapfile <file>\n");
- log("\n");
- log("vhdl2verilog can be obtained from:\n");
- log("http://www.edautils.com/vhdl2verilog.html\n");
- log("\n");
- }
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
- {
- log_header(design, "Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n");
- log_push();
-
- std::string out_file, top_entity;
- std::string vhdl2verilog_dir;
- std::string extra_opts;
-
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++) {
- if (args[argidx] == "-out" && argidx+1 < args.size()) {
- out_file = args[++argidx];
- continue;
- }
- if (args[argidx] == "-top" && argidx+1 < args.size()) {
- top_entity = args[++argidx];
- continue;
- }
- if (args[argidx] == "-vhdl2verilog_dir" && argidx+1 < args.size()) {
- vhdl2verilog_dir = args[++argidx];
- continue;
- }
- if ((args[argidx] == "-arch" || args[argidx] == "-suppress" || args[argidx] == "-mapfile") && argidx+1 < args.size()) {
- if (args[argidx] == "-mapfile" && !args[argidx+1].empty() && args[argidx+1][0] != '/') {
- char pwd[PATH_MAX];
- if (!getcwd(pwd, sizeof(pwd))) {
- log_cmd_error("getcwd failed: %s", strerror(errno));
- log_abort();
- }
- args[argidx+1] = pwd + ("/" + args[argidx+1]);
- }
- extra_opts += std::string(" ") + args[argidx];
- extra_opts += std::string(" '") + args[++argidx] + std::string("'");
- continue;
- }
- if (args[argidx] == "-unroll_generate" || args[argidx] == "-nogenericeval" || args[argidx] == "-nouniquify" ||
- args[argidx] == "-oldparser" || args[argidx] == "-quiet" || args[argidx] == "-nobanner") {
- extra_opts += std::string(" ") + args[argidx];
- continue;
- }
- break;
- }
-
- if (argidx == args.size())
- cmd_error(args, argidx, "Missing filenames.");
- if (args[argidx].substr(0, 1) == "-")
- cmd_error(args, argidx, "Unknown option.");
- if (top_entity.empty())
- log_cmd_error("Missing -top option.\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];
- if (!getcwd(pwd, sizeof(pwd))) {
- log_cmd_error("getcwd failed: %s", strerror(errno));
- log_abort();
- }
- out_file = pwd + ("/" + out_file);
- }
-
- 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())
- continue;
- if (file[0] != '/') {
- char pwd[PATH_MAX];
- if (!getcwd(pwd, sizeof(pwd))) {
- log_cmd_error("getcwd failed: %s", strerror(errno));
- log_abort();
- }
- file = pwd + ("/" + file);
- }
- fprintf(f, "%s\n", file.c_str());
- log("Adding '%s' to the file list.\n", file.c_str());
- }
- fclose(f);
-
- 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.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());
-
- 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()).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.c_str()), "verilog");
- }
-
- log_header(design, "Removing temp directory `%s':\n", tempdir_name.c_str());
- remove_directory(tempdir_name);
- log_pop();
- }
-} Vhdl2verilogPass;
-
-YOSYS_NAMESPACE_END
-
diff --git a/kernel/calc.cc b/kernel/calc.cc
index a24fa2ab..4a484077 100644
--- a/kernel/calc.cc
+++ b/kernel/calc.cc
@@ -291,7 +291,7 @@ static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Co
BigInteger pos = BigInteger(i) + offset;
if (pos < 0)
result.bits[i] = RTLIL::State::S0;
- else if (pos >= arg1.bits.size())
+ else if (pos >= BigInteger(int(arg1.bits.size())))
result.bits[i] = sign_ext ? arg1.bits.back() : RTLIL::State::S0;
else
result.bits[i] = arg1.bits[pos.toInt()];
@@ -342,7 +342,7 @@ static RTLIL::Const const_shift_shiftx(const RTLIL::Const &arg1, const RTLIL::Co
for (int i = 0; i < result_len; i++) {
BigInteger pos = BigInteger(i) + offset;
- if (pos < 0 || pos >= arg1.bits.size())
+ if (pos < 0 || pos >= BigInteger(int(arg1.bits.size())))
result.bits[i] = other_bits;
else
result.bits[i] = arg1.bits[pos.toInt()];
diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc
index 41f81355..5fd76afe 100644
--- a/kernel/cellaigs.cc
+++ b/kernel/cellaigs.cc
@@ -202,6 +202,16 @@ struct AigMaker
return or_gate(and_gate(A, B), nor_gate(A, B));
}
+ int andnot_gate(int A, int B)
+ {
+ return and_gate(A, not_gate(B));
+ }
+
+ int ornot_gate(int A, int B)
+ {
+ return or_gate(A, not_gate(B));
+ }
+
int mux_gate(int A, int B, int S)
{
return or_gate(and_gate(A, not_gate(S)), and_gate(B, S));
@@ -290,7 +300,7 @@ Aig::Aig(Cell *cell)
goto optimize;
}
- if (cell->type.in("$and", "$_AND_", "$_NAND_", "$or", "$_OR_", "$_NOR_", "$xor", "$xnor", "$_XOR_", "$_XNOR_"))
+ if (cell->type.in("$and", "$_AND_", "$_NAND_", "$or", "$_OR_", "$_NOR_", "$xor", "$xnor", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
{
for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) {
int A = mk.inport("\\A", i);
@@ -300,7 +310,9 @@ Aig::Aig(Cell *cell)
cell->type.in("$or", "$_OR_") ? mk.or_gate(A, B) :
cell->type.in("$_NOR_") ? mk.nor_gate(A, B) :
cell->type.in("$xor", "$_XOR_") ? mk.xor_gate(A, B) :
- cell->type.in("$xnor", "$_XNOR_") ? mk.xnor_gate(A, B) : -1;
+ cell->type.in("$xnor", "$_XNOR_") ? mk.xnor_gate(A, B) :
+ cell->type.in("$_ANDNOT_") ? mk.andnot_gate(A, B) :
+ cell->type.in("$_ORNOT_") ? mk.ornot_gate(A, B) : -1;
mk.outport(Y, "\\Y", i);
}
goto optimize;
diff --git a/kernel/celledges.h b/kernel/celledges.h
index 6aab9ed4..2cc297cb 100644
--- a/kernel/celledges.h
+++ b/kernel/celledges.h
@@ -1,4 +1,4 @@
-/*
+/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
@@ -38,7 +38,7 @@ struct FwdCellEdgesDatabase : AbstractCellEdgesDatabase
dict<SigBit, pool<SigBit>> db;
FwdCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { }
- virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override {
+ void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) YS_OVERRIDE {
SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]);
SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]);
db[from_sigbit].insert(to_sigbit);
@@ -51,7 +51,7 @@ struct RevCellEdgesDatabase : AbstractCellEdgesDatabase
dict<SigBit, pool<SigBit>> db;
RevCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { }
- virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override {
+ void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) YS_OVERRIDE {
SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]);
SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]);
db[to_sigbit].insert(from_sigbit);
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index f0ead1e8..fcc4fcc4 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -20,7 +20,7 @@
#ifndef CELLTYPES_H
#define CELLTYPES_H
-#include <kernel/yosys.h>
+#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
@@ -116,9 +116,14 @@ struct CellTypes
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
+ setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
+ setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$equiv", {A, B}, {Y}, true);
}
@@ -164,6 +169,8 @@ struct CellTypes
setup_type("$_NOR_", {A, B}, {Y}, true);
setup_type("$_XOR_", {A, B}, {Y}, true);
setup_type("$_XNOR_", {A, B}, {Y}, true);
+ setup_type("$_ANDNOT_", {A, B}, {Y}, true);
+ setup_type("$_ORNOT_", {A, B}, {Y}, true);
setup_type("$_MUX_", {A, B, S}, {Y}, true);
setup_type("$_MUX4_", {A, B, C, D, S, T}, {Y}, true);
setup_type("$_MUX8_", {A, B, C, D, E, F, G, H, S, T, U}, {Y}, true);
@@ -312,11 +319,15 @@ struct CellTypes
if (type == "$_OR_")
return const_or(arg1, arg2, false, false, 1);
if (type == "$_NOR_")
- return eval_not(const_and(arg1, arg2, false, false, 1));
+ return eval_not(const_or(arg1, arg2, false, false, 1));
if (type == "$_XOR_")
return const_xor(arg1, arg2, false, false, 1);
if (type == "$_XNOR_")
return const_xnor(arg1, arg2, false, false, 1);
+ if (type == "$_ANDNOT_")
+ return const_and(arg1, eval_not(arg2), false, false, 1);
+ if (type == "$_ORNOT_")
+ return const_or(arg1, eval_not(arg2), false, false, 1);
log_abort();
}
diff --git a/kernel/consteval.h b/kernel/consteval.h
index 4d48b45e..0229f504 100644
--- a/kernel/consteval.h
+++ b/kernel/consteval.h
@@ -36,8 +36,9 @@ struct ConstEval
SigSet<RTLIL::Cell*> sig2driver;
std::set<RTLIL::Cell*> busy;
std::vector<SigMap> stack;
+ RTLIL::State defaultval;
- ConstEval(RTLIL::Module *module) : module(module), assign_map(module)
+ ConstEval(RTLIL::Module *module, RTLIL::State defaultval = RTLIL::State::Sm) : module(module), assign_map(module), defaultval(defaultval)
{
CellTypes ct;
ct.setup_internals();
@@ -365,6 +366,12 @@ struct ConstEval
if (sig.is_fully_const())
return true;
+ if (defaultval != RTLIL::State::Sm) {
+ for (auto &bit : sig)
+ if (bit.wire) bit = defaultval;
+ return true;
+ }
+
for (auto &c : sig.chunks())
if (c.wire != NULL)
undef.append(c);
diff --git a/kernel/cost.h b/kernel/cost.h
index 4f12889f..e795b571 100644
--- a/kernel/cost.h
+++ b/kernel/cost.h
@@ -20,7 +20,7 @@
#ifndef COST_H
#define COST_H
-#include <kernel/yosys.h>
+#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
@@ -30,19 +30,21 @@ int get_cell_cost(RTLIL::IdString type, const 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 }
+ { "$_BUF_", 1 },
+ { "$_NOT_", 2 },
+ { "$_AND_", 4 },
+ { "$_NAND_", 4 },
+ { "$_OR_", 4 },
+ { "$_NOR_", 4 },
+ { "$_ANDNOT_", 4 },
+ { "$_ORNOT_", 4 },
+ { "$_XOR_", 8 },
+ { "$_XNOR_", 8 },
+ { "$_AOI3_", 6 },
+ { "$_OAI3_", 6 },
+ { "$_AOI4_", 8 },
+ { "$_OAI4_", 8 },
+ { "$_MUX_", 4 }
};
if (gate_cost.count(type))
diff --git a/kernel/driver.cc b/kernel/driver.cc
index f8d00c38..17864110 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -25,16 +25,26 @@
# include <readline/history.h>
#endif
+#ifdef YOSYS_ENABLE_EDITLINE
+# include <editline/readline.h>
+#endif
+
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
-#ifdef __linux__
+#if defined (__linux__) || defined(__FreeBSD__)
+# include <sys/resource.h>
# include <sys/types.h>
# include <unistd.h>
#endif
+#ifdef __FreeBSD__
+# include <sys/sysctl.h>
+# include <sys/user.h>
+#endif
+
#if !defined(_WIN32) || defined(__MINGW32__)
# include <unistd.h>
#else
@@ -75,20 +85,37 @@ USING_YOSYS_NAMESPACE
#ifdef EMSCRIPTEN
# include <sys/stat.h>
# include <sys/types.h>
+# include <emscripten.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**)
+int main(int argc, char **argv)
{
+ EM_ASM(
+ if (ENVIRONMENT_IS_NODE)
+ {
+ FS.mkdir('/hostcwd');
+ FS.mount(NODEFS, { root: '.' }, '/hostcwd');
+ FS.mkdir('/hostfs');
+ FS.mount(NODEFS, { root: '/' }, '/hostfs');
+ }
+ );
+
mkdir("/work", 0777);
chdir("/work");
log_files.push_back(stdout);
log_error_stderr = true;
yosys_banner();
yosys_setup();
+
+ if (argc == 2)
+ {
+ // Run the first argument as a script file
+ run_frontend(argv[1], "script", 0, 0, 0);
+ }
}
void run(const char *command)
@@ -119,6 +146,35 @@ const char *prompt()
#else /* EMSCRIPTEN */
+#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
+int yosys_history_offset = 0;
+std::string yosys_history_file;
+#endif
+
+void yosys_atexit()
+{
+#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
+ if (!yosys_history_file.empty()) {
+#if defined(YOSYS_ENABLE_READLINE)
+ if (yosys_history_offset > 0) {
+ history_truncate_file(yosys_history_file.c_str(), 100);
+ append_history(where_history() - yosys_history_offset, yosys_history_file.c_str());
+ } else
+ write_history(yosys_history_file.c_str());
+#else
+ write_history(yosys_history_file.c_str());
+#endif
+ }
+
+ clear_history();
+#if defined(YOSYS_ENABLE_READLINE)
+ HIST_ENTRY **hist_list = history_list();
+ if (hist_list != NULL)
+ free(hist_list);
+#endif
+#endif
+}
+
int main(int argc, char **argv)
{
std::string frontend_command = "auto";
@@ -127,6 +183,7 @@ int main(int argc, char **argv)
std::vector<std::string> plugin_filenames;
std::string output_filename = "";
std::string scriptfile = "";
+ std::string depsfile = "";
bool scriptfile_tcl = false;
bool got_output_filename = false;
bool print_banner = true;
@@ -136,13 +193,11 @@ int main(int argc, char **argv)
bool mode_v = false;
bool mode_q = false;
-#ifdef YOSYS_ENABLE_READLINE
- int history_offset = 0;
- std::string history_file;
+#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
if (getenv("HOME") != NULL) {
- history_file = stringf("%s/.yosys_history", getenv("HOME"));
- read_history(history_file.c_str());
- history_offset = where_history();
+ yosys_history_file = stringf("%s/.yosys_history", getenv("HOME"));
+ read_history(yosys_history_file.c_str());
+ yosys_history_offset = where_history();
}
#endif
@@ -218,6 +273,20 @@ int main(int argc, char **argv)
printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n");
printf(" Use 'ALL' as <header_id> to dump at every header.\n");
printf("\n");
+ printf(" -W regex\n");
+ printf(" print a warning for all log messages matching the regex.\n");
+ printf("\n");
+ printf(" -w regex\n");
+ printf(" if a warning message matches the regex, it is printed as regular\n");
+ printf(" message instead.\n");
+ printf("\n");
+ printf(" -e regex\n");
+ printf(" if a warning message matches the regex, it is printed as error\n");
+ printf(" message instead and the tool terminates with a nonzero return code.\n");
+ printf("\n");
+ printf(" -E <depsfile>\n");
+ printf(" write a Makefile dependencies file with in- and output file names\n");
+ printf("\n");
printf(" -V\n");
printf(" print version information and exit\n");
printf("\n");
@@ -238,7 +307,7 @@ int main(int argc, char **argv)
}
int opt;
- while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:D:")) != -1)
+ while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:E:")) != -1)
{
switch (opt)
{
@@ -320,6 +389,24 @@ int main(int argc, char **argv)
scriptfile = optarg;
scriptfile_tcl = true;
break;
+ case 'W':
+ log_warn_regexes.push_back(std::regex(optarg,
+ std::regex_constants::nosubs |
+ std::regex_constants::optimize |
+ std::regex_constants::egrep));
+ break;
+ case 'w':
+ log_nowarn_regexes.push_back(std::regex(optarg,
+ std::regex_constants::nosubs |
+ std::regex_constants::optimize |
+ std::regex_constants::egrep));
+ break;
+ case 'e':
+ log_werror_regexes.push_back(std::regex(optarg,
+ std::regex_constants::nosubs |
+ std::regex_constants::optimize |
+ std::regex_constants::egrep));
+ break;
case 'D':
{
auto args = split_tokens(optarg, ":");
@@ -342,6 +429,9 @@ int main(int argc, char **argv)
}
}
break;
+ case 'E':
+ depsfile = optarg;
+ break;
default:
fprintf(stderr, "Run '%s -h' for help.\n", argv[0]);
exit(1);
@@ -359,7 +449,20 @@ int main(int argc, char **argv)
if (print_stats)
log_hasher = new SHA1;
+#if defined(__linux__)
+ // set stack size to >= 128 MB
+ {
+ struct rlimit rl;
+ const rlim_t stack_size = 128L * 1024L * 1024L;
+ if (getrlimit(RLIMIT_STACK, &rl) == 0 && rl.rlim_cur < stack_size) {
+ rl.rlim_cur = stack_size;
+ setrlimit(RLIMIT_STACK, &rl);
+ }
+ }
+#endif
+
yosys_setup();
+ log_error_atexit = yosys_atexit;
for (auto &fn : plugin_filenames)
load_plugin(fn, {});
@@ -391,6 +494,24 @@ int main(int argc, char **argv)
if (!backend_command.empty())
run_backend(output_filename, backend_command);
+ if (!depsfile.empty())
+ {
+ FILE *f = fopen(depsfile.c_str(), "wt");
+ if (f == nullptr)
+ log_error("Can't open dependencies file for writing: %s\n", strerror(errno));
+ bool first = true;
+ for (auto fn : yosys_output_files) {
+ fprintf(f, "%s%s", first ? "" : " ", fn.c_str());
+ first = false;
+ }
+ fprintf(f, ":");
+ for (auto fn : yosys_input_files) {
+ if (yosys_output_files.count(fn) == 0)
+ fprintf(f, " %s", fn.c_str());
+ }
+ fprintf(f, "\n");
+ }
+
if (print_stats)
{
std::string hash = log_hasher->final().substr(0, 10);
@@ -404,12 +525,14 @@ int main(int argc, char **argv)
if (mode_v && !mode_q)
log_files.push_back(stderr);
+ if (log_warnings_count)
+ log("Warnings: %d unique messages, %d total\n", GetSize(log_warnings), log_warnings_count);
#ifdef _WIN32
log("End of script. Logfile hash: %s\n", hash.c_str());
#else
std::string meminfo;
std::string stats_divider = ", ";
-# ifdef __linux__
+# if defined(__linux__)
std::ifstream statm;
statm.open(stringf("/proc/%lld/statm", (long long)getpid()));
if (statm.is_open()) {
@@ -420,6 +543,19 @@ int main(int argc, char **argv)
sz_resident * (getpagesize() / 1024.0 / 1024.0));
stats_divider = "\n";
}
+# elif defined(__FreeBSD__)
+ pid_t pid = getpid();
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid};
+ struct kinfo_proc kip;
+ size_t kip_len = sizeof(kip);
+ if (sysctl(mib, 4, &kip, &kip_len, NULL, 0) == 0) {
+ vm_size_t sz_total = kip.ki_size;
+ segsz_t sz_resident = kip.ki_rssize;
+ meminfo = stringf(", MEM: %.2f MB total, %.2f MB resident",
+ (int)sz_total / 1024.0 / 1024.0,
+ (int)sz_resident * (getpagesize() / 1024.0 / 1024.0));
+ stats_divider = "\n";
+ }
# endif
struct rusage ru_buffer;
@@ -463,7 +599,7 @@ int main(int argc, char **argv)
}
}
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE"))
{
string filename;
@@ -490,25 +626,12 @@ int main(int argc, char **argv)
}
#endif
+ yosys_atexit();
+
memhasher_off();
if (call_abort)
abort();
-#ifdef YOSYS_ENABLE_READLINE
- if (!history_file.empty()) {
- if (history_offset > 0) {
- history_truncate_file(history_file.c_str(), 100);
- append_history(where_history() - history_offset, history_file.c_str());
- } else
- write_history(history_file.c_str());
- }
-
- clear_history();
- HIST_ENTRY **hist_list = history_list();
- if (hist_list != NULL)
- free(hist_list);
-#endif
-
log_flush();
#if defined(_MSC_VER)
_exit(0);
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
index 3c824b8c..df534ec1 100644
--- a/kernel/hashlib.h
+++ b/kernel/hashlib.h
@@ -147,7 +147,7 @@ struct hash_ptr_ops {
return a == b;
}
static inline unsigned int hash(const void *a) {
- return (unsigned long)a;
+ return (uintptr_t)a;
}
};
@@ -868,6 +868,13 @@ public:
return !operator==(other);
}
+ bool hash() const {
+ unsigned int hashval = mkhash_init;
+ for (auto &it : entries)
+ hashval ^= ops.hash(it.udata);
+ return hashval;
+ }
+
void reserve(size_t n) { entries.reserve(n); }
size_t size() const { return entries.size(); }
bool empty() const { return entries.empty(); }
diff --git a/kernel/log.cc b/kernel/log.cc
index abc401f5..0ee2170a 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -25,7 +25,7 @@
# include <sys/time.h>
#endif
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
# include <dlfcn.h>
#endif
@@ -41,6 +41,9 @@ YOSYS_NAMESPACE_BEGIN
std::vector<FILE*> log_files;
std::vector<std::ostream*> log_streams;
std::map<std::string, std::set<std::string>> log_hdump;
+std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
+std::set<std::string> log_warnings;
+int log_warnings_count = 0;
bool log_hdump_all = false;
FILE *log_errfile = NULL;
SHA1 *log_hasher = NULL;
@@ -51,6 +54,7 @@ bool log_cmd_error_throw = false;
bool log_quiet_warnings = false;
int log_verbose_level;
string log_last_error;
+void (*log_error_atexit)() = NULL;
vector<int> header_count;
pool<RTLIL::IdString> log_id_cache;
@@ -136,6 +140,32 @@ void logv(const char *format, va_list ap)
for (auto f : log_streams)
*f << str;
+
+ static std::string linebuffer;
+ static bool log_warn_regex_recusion_guard = false;
+
+ if (!log_warn_regex_recusion_guard)
+ {
+ log_warn_regex_recusion_guard = true;
+
+ if (log_warn_regexes.empty())
+ {
+ linebuffer.clear();
+ }
+ else
+ {
+ linebuffer += str;
+
+ if (!linebuffer.empty() && linebuffer.back() == '\n') {
+ for (auto &re : log_warn_regexes)
+ if (std::regex_search(linebuffer, re))
+ log_warning("Found log message matching -W regex:\n%s", str.c_str());
+ linebuffer.clear();
+ }
+ }
+
+ log_warn_regex_recusion_guard = false;
+ }
}
void logv_header(RTLIL::Design *design, const char *format, va_list ap)
@@ -173,20 +203,73 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap)
log_files.pop_back();
}
+static void logv_warning_with_prefix(const char *prefix,
+ const char *format, va_list ap)
+{
+ std::string message = vstringf(format, ap);
+ bool suppressed = false;
+
+ for (auto &re : log_nowarn_regexes)
+ if (std::regex_search(message, re))
+ suppressed = true;
+
+ if (suppressed)
+ {
+ log("Suppressed %s%s", prefix, message.c_str());
+ }
+ else
+ {
+ for (auto &re : log_werror_regexes)
+ if (std::regex_search(message, re))
+ log_error("%s", message.c_str());
+
+ if (log_warnings.count(message))
+ {
+ log("%s%s", prefix, message.c_str());
+ log_flush();
+ }
+ else
+ {
+ if (log_errfile != NULL && !log_quiet_warnings)
+ log_files.push_back(log_errfile);
+
+ log("%s%s", prefix, message.c_str());
+ log_flush();
+
+ if (log_errfile != NULL && !log_quiet_warnings)
+ log_files.pop_back();
+
+ log_warnings.insert(message);
+ }
+
+ log_warnings_count++;
+ }
+}
+
void logv_warning(const char *format, va_list ap)
{
- if (log_errfile != NULL && !log_quiet_warnings)
- log_files.push_back(log_errfile);
+ logv_warning_with_prefix("Warning: ", format, ap);
+}
- log("Warning: ");
- logv(format, ap);
- log_flush();
+void logv_warning_noprefix(const char *format, va_list ap)
+{
+ logv_warning_with_prefix("", format, ap);
+}
- if (log_errfile != NULL && !log_quiet_warnings)
- log_files.pop_back();
+void log_file_warning(const std::string &filename, int lineno,
+ const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ std::string prefix = stringf("%s:%d: Warning: ",
+ filename.c_str(), lineno);
+ logv_warning_with_prefix(prefix.c_str(), format, ap);
+ va_end(ap);
}
-void logv_error(const char *format, va_list ap)
+YS_ATTRIBUTE(noreturn)
+static void logv_error_with_prefix(const char *prefix,
+ const char *format, va_list ap)
{
#ifdef EMSCRIPTEN
auto backup_log_files = log_files;
@@ -201,9 +284,12 @@ void logv_error(const char *format, va_list ap)
f = stderr;
log_last_error = vstringf(format, ap);
- log("ERROR: %s", log_last_error.c_str());
+ log("%s%s", prefix, log_last_error.c_str());
log_flush();
+ if (log_error_atexit)
+ log_error_atexit();
+
#ifdef EMSCRIPTEN
log_files = backup_log_files;
throw 0;
@@ -214,6 +300,21 @@ void logv_error(const char *format, va_list ap)
#endif
}
+void logv_error(const char *format, va_list ap)
+{
+ logv_error_with_prefix("ERROR: ", format, ap);
+}
+
+void log_file_error(const string &filename, int lineno,
+ const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ std::string prefix = stringf("%s:%d: ERROR: ",
+ filename.c_str(), lineno);
+ logv_error_with_prefix(prefix.c_str(), format, ap);
+}
+
void log(const char *format, ...)
{
va_list ap;
@@ -238,6 +339,14 @@ void log_warning(const char *format, ...)
va_end(ap);
}
+void log_warning_noprefix(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ logv_warning_noprefix(format, ap);
+ va_end(ap);
+}
+
void log_error(const char *format, ...)
{
va_list ap;
@@ -262,8 +371,8 @@ void log_cmd_error(const char *format, ...)
void log_spacer()
{
- while (log_newline_count < 2)
- log("\n");
+ if (log_newline_count < 2) log("\n");
+ if (log_newline_count < 2) log("\n");
}
void log_push()
@@ -280,7 +389,7 @@ void log_pop()
log_flush();
}
-#if defined(__linux__) && defined(YOSYS_ENABLE_PLUGINS)
+#if (defined(__linux__) || defined(__FreeBSD__)) && defined(YOSYS_ENABLE_PLUGINS)
void log_backtrace(const char *prefix, int levels)
{
if (levels <= 0) return;
@@ -297,6 +406,9 @@ void log_backtrace(const char *prefix, int levels)
if (levels <= 1) return;
+#ifndef DEBUG
+ log("%sframe #2: [build Yosys with ENABLE_DEBUG for deeper backtraces]\n", prefix);
+#else
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 {
@@ -368,6 +480,7 @@ void log_backtrace(const char *prefix, int levels)
}
if (levels <= 9) return;
+#endif
}
#else
void log_backtrace(const char*, int) { }
@@ -461,10 +574,17 @@ void log_cell(RTLIL::Cell *cell, std::string indent)
log("%s", buf.str().c_str());
}
+void log_wire(RTLIL::Wire *wire, std::string indent)
+{
+ std::stringstream buf;
+ ILANG_BACKEND::dump_wire(buf, indent, wire);
+ log("%s", buf.str().c_str());
+}
+
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
dict<std::string, std::pair<std::string, int>> extra_coverage_data;
@@ -513,4 +633,3 @@ dict<std::string, std::pair<std::string, int>> get_coverage_data()
#endif
YOSYS_NAMESPACE_END
-
diff --git a/kernel/log.h b/kernel/log.h
index 53480db3..0b4905c3 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -23,6 +23,7 @@
#define LOG_H
#include <time.h>
+#include <regex>
#ifndef _WIN32
# include <sys/time.h>
@@ -48,6 +49,9 @@ struct log_cmd_error_exception { };
extern std::vector<FILE*> log_files;
extern std::vector<std::ostream*> log_streams;
extern std::map<std::string, std::set<std::string>> log_hdump;
+extern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
+extern std::set<std::string> log_warnings;
+extern int log_warnings_count;
extern bool log_hdump_all;
extern FILE *log_errfile;
extern SHA1 *log_hasher;
@@ -58,16 +62,24 @@ extern bool log_cmd_error_throw;
extern bool log_quiet_warnings;
extern int log_verbose_level;
extern string log_last_error;
+extern void (*log_error_atexit)();
void logv(const char *format, va_list ap);
void logv_header(RTLIL::Design *design, const char *format, va_list ap);
void logv_warning(const char *format, va_list ap);
+void logv_warning_noprefix(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, ...) YS_ATTRIBUTE(format(printf, 1, 2));
void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3));
void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
+
+// Log with filename to report a problem in a source file.
+void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
+
+void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
+void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn);
YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
void log_spacer();
@@ -88,6 +100,7 @@ template<typename T> static inline const char *log_id(T *obj) {
void log_module(RTLIL::Module *module, std::string indent = "");
void log_cell(RTLIL::Cell *cell, std::string indent = "");
+void log_wire(RTLIL::Wire *wire, std::string indent = "");
#ifndef NDEBUG
static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) {
@@ -106,7 +119,7 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi
// This is the magic behind the code coverage counters
// ---------------------------------------------------
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
#define cover(_id) do { \
static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
@@ -165,7 +178,7 @@ struct PerformanceTimer
}
static int64_t query() {
-# if _WIN32
+# ifdef _WIN32
return 0;
# elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
struct timespec ts;
diff --git a/kernel/modtools.h b/kernel/modtools.h
index ffcb48d4..409562eb 100644
--- a/kernel/modtools.h
+++ b/kernel/modtools.h
@@ -1,4 +1,4 @@
-/*
+/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
@@ -158,7 +158,7 @@ struct ModIndex : public RTLIL::Monitor
#endif
}
- virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
+ 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);
@@ -169,7 +169,7 @@ struct ModIndex : public RTLIL::Monitor
port_add(cell, port, sig);
}
- virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE
+ void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE
{
log_assert(module == mod);
@@ -214,13 +214,13 @@ struct ModIndex : public RTLIL::Monitor
}
}
- virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector<RTLIL::SigSig>&) YS_OVERRIDE
+ 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 YS_ATTRIBUTE(unused)) YS_OVERRIDE
+ void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE
{
log_assert(module == mod);
auto_reload_module = true;
diff --git a/kernel/register.cc b/kernel/register.cc
index 7a1d0b44..402a5b3e 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -173,7 +173,7 @@ void Pass::call(RTLIL::Design *design, std::string command)
}
while (!tok.empty()) {
- if (tok == "#") {
+ if (tok[0] == '#') {
int stop;
for (stop = 0; stop < GetSize(cmd_buf); stop++)
if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n')
@@ -428,6 +428,7 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
}
std::ifstream *ff = new std::ifstream;
ff->open(filename.c_str());
+ yosys_input_files.insert(filename);
if (ff->fail())
delete ff;
else
@@ -543,6 +544,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
filename = arg;
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), std::ofstream::trunc);
+ yosys_output_files.insert(filename);
if (ff->fail()) {
delete ff;
log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
@@ -613,7 +615,7 @@ static struct CellHelpMessages {
struct HelpPass : public Pass {
HelpPass() : Pass("help", "display help messages") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" help ................ list all commands\n");
@@ -682,7 +684,7 @@ struct HelpPass : public Pass {
fclose(f);
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
if (args.size() == 1) {
log("\n");
@@ -766,7 +768,7 @@ struct HelpPass : public Pass {
struct EchoPass : public Pass {
EchoPass() : Pass("echo", "turning echoing back of commands on and off") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" echo on\n");
@@ -779,7 +781,7 @@ struct EchoPass : public Pass {
log("Do not print all commands to log before executing them. (default)\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
if (args.size() > 2)
cmd_error(args, 2, "Unexpected argument.");
@@ -804,10 +806,9 @@ struct MinisatSatSolver : public SatSolver {
MinisatSatSolver() : SatSolver("minisat") {
yosys_satsolver = this;
}
- virtual ezSAT *create() YS_OVERRIDE {
+ ezSAT *create() YS_OVERRIDE {
return new ezMiniSAT();
}
} MinisatSatSolver;
YOSYS_NAMESPACE_END
-
diff --git a/kernel/register.h b/kernel/register.h
index 8024c56a..c7402982 100644
--- a/kernel/register.h
+++ b/kernel/register.h
@@ -1,4 +1,4 @@
-/*
+/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
@@ -88,9 +88,9 @@ struct Frontend : Pass
std::string frontend_name;
Frontend(std::string name, std::string short_help = "** document me **");
- virtual void run_register() YS_OVERRIDE;
- virtual ~Frontend();
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
+ void run_register() YS_OVERRIDE;
+ ~Frontend() YS_OVERRIDE;
+ 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;
@@ -104,9 +104,9 @@ struct Backend : Pass
{
std::string backend_name;
Backend(std::string name, std::string short_help = "** document me **");
- virtual void run_register() YS_OVERRIDE;
- virtual ~Backend();
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
+ void run_register() YS_OVERRIDE;
+ ~Backend() YS_OVERRIDE;
+ 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);
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 66bbf042..a4fa2cf0 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -161,6 +161,50 @@ std::string RTLIL::Const::decode_string() const
return string;
}
+bool RTLIL::Const::is_fully_zero() const
+{
+ cover("kernel.rtlil.const.is_fully_zero");
+
+ for (auto bit : bits)
+ if (bit != RTLIL::State::S0)
+ return false;
+
+ return true;
+}
+
+bool RTLIL::Const::is_fully_ones() const
+{
+ cover("kernel.rtlil.const.is_fully_ones");
+
+ for (auto bit : bits)
+ if (bit != RTLIL::State::S1)
+ return false;
+
+ return true;
+}
+
+bool RTLIL::Const::is_fully_def() const
+{
+ cover("kernel.rtlil.const.is_fully_def");
+
+ for (auto bit : bits)
+ if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
+ return false;
+
+ return true;
+}
+
+bool RTLIL::Const::is_fully_undef() const
+{
+ cover("kernel.rtlil.const.is_fully_undef");
+
+ for (auto bit : bits)
+ if (bit != RTLIL::State::Sx && bit != RTLIL::State::Sz)
+ return false;
+
+ return true;
+}
+
void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id)
{
attributes[id] = RTLIL::Const(1);
@@ -201,6 +245,22 @@ pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const
return data;
}
+void RTLIL::AttrObject::set_src_attribute(const std::string &src)
+{
+ if (src.empty())
+ attributes.erase("\\src");
+ else
+ attributes["\\src"] = src;
+}
+
+std::string RTLIL::AttrObject::get_src_attribute() const
+{
+ std::string src;
+ if (attributes.count("\\src"))
+ src = attributes.at("\\src").decode_string();
+ return src;
+}
+
bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
{
if (full_selection)
@@ -306,6 +366,8 @@ RTLIL::Design::~Design()
delete it->second;
for (auto n : verilog_packages)
delete n;
+ for (auto n : verilog_globals)
+ delete n;
}
RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
@@ -577,8 +639,10 @@ RTLIL::Module::~Module()
delete it->second;
}
-RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>)
+RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, bool mayfail)
{
+ if (mayfail)
+ return RTLIL::IdString();
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
}
@@ -1024,7 +1088,7 @@ namespace {
return;
}
- if (cell->type.in("$assert", "$assume")) {
+ if (cell->type.in("$assert", "$assume", "$live", "$fair", "$cover")) {
port("\\A", 1);
port("\\EN", 1);
check_expected();
@@ -1037,7 +1101,7 @@ namespace {
return;
}
- if (cell->type.in("$anyconst", "$anyseq")) {
+ if (cell->type.in("$anyconst", "$anyseq", "$allconst", "$allseq")) {
port("\\Y", param("\\WIDTH"));
check_expected();
return;
@@ -1051,19 +1115,21 @@ namespace {
return;
}
- if (cell->type == "$_BUF_") { check_gate("AY"); return; }
- if (cell->type == "$_NOT_") { check_gate("AY"); return; }
- if (cell->type == "$_AND_") { check_gate("ABY"); return; }
- if (cell->type == "$_NAND_") { check_gate("ABY"); return; }
- if (cell->type == "$_OR_") { check_gate("ABY"); return; }
- if (cell->type == "$_NOR_") { check_gate("ABY"); return; }
- if (cell->type == "$_XOR_") { check_gate("ABY"); return; }
- if (cell->type == "$_XNOR_") { check_gate("ABY"); return; }
- if (cell->type == "$_MUX_") { check_gate("ABSY"); return; }
- if (cell->type == "$_AOI3_") { check_gate("ABCY"); return; }
- if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; }
- if (cell->type == "$_AOI4_") { check_gate("ABCDY"); return; }
- if (cell->type == "$_OAI4_") { check_gate("ABCDY"); return; }
+ if (cell->type == "$_BUF_") { check_gate("AY"); return; }
+ if (cell->type == "$_NOT_") { check_gate("AY"); return; }
+ if (cell->type == "$_AND_") { check_gate("ABY"); return; }
+ if (cell->type == "$_NAND_") { check_gate("ABY"); return; }
+ if (cell->type == "$_OR_") { check_gate("ABY"); return; }
+ if (cell->type == "$_NOR_") { check_gate("ABY"); return; }
+ if (cell->type == "$_XOR_") { check_gate("ABY"); return; }
+ if (cell->type == "$_XNOR_") { check_gate("ABY"); return; }
+ if (cell->type == "$_ANDNOT_") { check_gate("ABY"); return; }
+ if (cell->type == "$_ORNOT_") { check_gate("ABY"); return; }
+ if (cell->type == "$_MUX_") { check_gate("ABSY"); return; }
+ if (cell->type == "$_AOI3_") { check_gate("ABCY"); return; }
+ if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; }
+ if (cell->type == "$_AOI4_") { check_gate("ABCDY"); return; }
+ if (cell->type == "$_OAI4_") { check_gate("ABCDY"); return; }
if (cell->type == "$_TBUF_") { check_gate("AYE"); return; }
@@ -1583,18 +1649,19 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth
}
#define DEF_METHOD(_func, _y_size, _type) \
- RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed) { \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
cell->parameters["\\A_SIGNED"] = is_signed; \
cell->parameters["\\A_WIDTH"] = sig_a.size(); \
cell->parameters["\\Y_WIDTH"] = sig_y.size(); \
cell->setPort("\\A", sig_a); \
cell->setPort("\\Y", sig_y); \
+ cell->set_src_attribute(src); \
return cell; \
} \
- RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed) { \
+ RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed, const std::string &src) { \
RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \
- add ## _func(name, sig_a, sig_y, is_signed); \
+ add ## _func(name, sig_a, sig_y, is_signed, src); \
return sig_y; \
}
DEF_METHOD(Not, sig_a.size(), "$not")
@@ -1609,7 +1676,7 @@ DEF_METHOD(LogicNot, 1, "$logic_not")
#undef DEF_METHOD
#define DEF_METHOD(_func, _y_size, _type) \
- RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed) { \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
cell->parameters["\\A_SIGNED"] = is_signed; \
cell->parameters["\\B_SIGNED"] = is_signed; \
@@ -1619,12 +1686,13 @@ DEF_METHOD(LogicNot, 1, "$logic_not")
cell->setPort("\\A", sig_a); \
cell->setPort("\\B", sig_b); \
cell->setPort("\\Y", sig_y); \
+ cell->set_src_attribute(src); \
return cell; \
} \
- RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed) { \
- RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \
- add ## _func(name, sig_a, sig_b, sig_y, is_signed); \
- return sig_y; \
+ RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed, const std::string &src) { \
+ RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \
+ add ## _func(name, sig_a, sig_b, sig_y, is_signed, src); \
+ return sig_y; \
}
DEF_METHOD(And, max(sig_a.size(), sig_b.size()), "$and")
DEF_METHOD(Or, max(sig_a.size(), sig_b.size()), "$or")
@@ -1654,7 +1722,7 @@ DEF_METHOD(LogicOr, 1, "$logic_or")
#undef DEF_METHOD
#define DEF_METHOD(_func, _type, _pmux) \
- RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y) { \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
cell->parameters["\\WIDTH"] = sig_a.size(); \
if (_pmux) cell->parameters["\\S_WIDTH"] = sig_s.size(); \
@@ -1662,11 +1730,12 @@ DEF_METHOD(LogicOr, 1, "$logic_or")
cell->setPort("\\B", sig_b); \
cell->setPort("\\S", sig_s); \
cell->setPort("\\Y", sig_y); \
+ cell->set_src_attribute(src); \
return cell; \
} \
- RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s) { \
+ RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, const std::string &src) { \
RTLIL::SigSpec sig_y = addWire(NEW_ID, sig_a.size()); \
- add ## _func(name, sig_a, sig_b, sig_s, sig_y); \
+ add ## _func(name, sig_a, sig_b, sig_s, sig_y, src); \
return sig_y; \
}
DEF_METHOD(Mux, "$mux", 0)
@@ -1674,78 +1743,84 @@ DEF_METHOD(Pmux, "$pmux", 1)
#undef DEF_METHOD
#define DEF_METHOD_2(_func, _type, _P1, _P2) \
- RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2) { \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
cell->setPort("\\" #_P1, sig1); \
cell->setPort("\\" #_P2, sig2); \
+ cell->set_src_attribute(src); \
return cell; \
} \
- RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1) { \
- RTLIL::SigBit sig2 = addWire(NEW_ID); \
- add ## _func(name, sig1, sig2); \
+ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, const std::string &src) { \
+ RTLIL::SigBit sig2 = addWire(NEW_ID); \
+ add ## _func(name, sig1, sig2, src); \
return sig2; \
}
#define DEF_METHOD_3(_func, _type, _P1, _P2, _P3) \
- RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3) { \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
cell->setPort("\\" #_P1, sig1); \
cell->setPort("\\" #_P2, sig2); \
cell->setPort("\\" #_P3, sig3); \
+ cell->set_src_attribute(src); \
return cell; \
} \
- RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2) { \
- RTLIL::SigBit sig3 = addWire(NEW_ID); \
- add ## _func(name, sig1, sig2, sig3); \
+ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, const std::string &src) { \
+ RTLIL::SigBit sig3 = addWire(NEW_ID); \
+ add ## _func(name, sig1, sig2, sig3, src); \
return sig3; \
}
#define DEF_METHOD_4(_func, _type, _P1, _P2, _P3, _P4) \
- RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4) { \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
cell->setPort("\\" #_P1, sig1); \
cell->setPort("\\" #_P2, sig2); \
cell->setPort("\\" #_P3, sig3); \
cell->setPort("\\" #_P4, sig4); \
+ cell->set_src_attribute(src); \
return cell; \
} \
- RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3) { \
- RTLIL::SigBit sig4 = addWire(NEW_ID); \
- add ## _func(name, sig1, sig2, sig3, sig4); \
+ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, const std::string &src) { \
+ RTLIL::SigBit sig4 = addWire(NEW_ID); \
+ add ## _func(name, sig1, sig2, sig3, sig4, src); \
return sig4; \
}
#define DEF_METHOD_5(_func, _type, _P1, _P2, _P3, _P4, _P5) \
- RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4, RTLIL::SigBit sig5) { \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4, RTLIL::SigBit sig5, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
cell->setPort("\\" #_P1, sig1); \
cell->setPort("\\" #_P2, sig2); \
cell->setPort("\\" #_P3, sig3); \
cell->setPort("\\" #_P4, sig4); \
cell->setPort("\\" #_P5, sig5); \
+ cell->set_src_attribute(src); \
return cell; \
} \
- RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4) { \
- RTLIL::SigBit sig5 = addWire(NEW_ID); \
- add ## _func(name, sig1, sig2, sig3, sig4, sig5); \
- return sig5; \
- }
-DEF_METHOD_2(BufGate, "$_BUF_", A, Y)
-DEF_METHOD_2(NotGate, "$_NOT_", A, Y)
-DEF_METHOD_3(AndGate, "$_AND_", A, B, Y)
-DEF_METHOD_3(NandGate, "$_NAND_", A, B, Y)
-DEF_METHOD_3(OrGate, "$_OR_", A, B, Y)
-DEF_METHOD_3(NorGate, "$_NOR_", A, B, Y)
-DEF_METHOD_3(XorGate, "$_XOR_", A, B, Y)
-DEF_METHOD_3(XnorGate, "$_XNOR_", A, B, Y)
-DEF_METHOD_4(MuxGate, "$_MUX_", A, B, S, Y)
-DEF_METHOD_4(Aoi3Gate, "$_AOI3_", A, B, C, Y)
-DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y)
-DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y)
-DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y)
+ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4, const std::string &src) { \
+ RTLIL::SigBit sig5 = addWire(NEW_ID); \
+ add ## _func(name, sig1, sig2, sig3, sig4, sig5, src); \
+ return sig5; \
+ }
+DEF_METHOD_2(BufGate, "$_BUF_", A, Y)
+DEF_METHOD_2(NotGate, "$_NOT_", A, Y)
+DEF_METHOD_3(AndGate, "$_AND_", A, B, Y)
+DEF_METHOD_3(NandGate, "$_NAND_", A, B, Y)
+DEF_METHOD_3(OrGate, "$_OR_", A, B, Y)
+DEF_METHOD_3(NorGate, "$_NOR_", A, B, Y)
+DEF_METHOD_3(XorGate, "$_XOR_", A, B, Y)
+DEF_METHOD_3(XnorGate, "$_XNOR_", A, B, Y)
+DEF_METHOD_3(AndnotGate, "$_ANDNOT_", A, B, Y)
+DEF_METHOD_3(OrnotGate, "$_ORNOT_", A, B, Y)
+DEF_METHOD_4(MuxGate, "$_MUX_", A, B, S, Y)
+DEF_METHOD_4(Aoi3Gate, "$_AOI3_", A, B, C, Y)
+DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y)
+DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y)
+DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y)
#undef DEF_METHOD_2
#undef DEF_METHOD_3
#undef DEF_METHOD_4
#undef DEF_METHOD_5
-RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed, bool b_signed)
+RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed, bool b_signed, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$pow");
cell->parameters["\\A_SIGNED"] = a_signed;
@@ -1756,10 +1831,11 @@ RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, RTLIL::SigSpec sig_a, R
cell->setPort("\\A", sig_a);
cell->setPort("\\B", sig_b);
cell->setPort("\\Y", sig_y);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset)
+RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$slice");
cell->parameters["\\A_WIDTH"] = sig_a.size();
@@ -1767,10 +1843,11 @@ RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, RTLIL::SigSpec sig_a,
cell->parameters["\\OFFSET"] = offset;
cell->setPort("\\A", sig_a);
cell->setPort("\\Y", sig_y);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y)
+RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$concat");
cell->parameters["\\A_WIDTH"] = sig_a.size();
@@ -1778,55 +1855,88 @@ RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a
cell->setPort("\\A", sig_a);
cell->setPort("\\B", sig_b);
cell->setPort("\\Y", sig_y);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut)
+RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$lut");
cell->parameters["\\LUT"] = lut;
cell->parameters["\\WIDTH"] = sig_a.size();
cell->setPort("\\A", sig_a);
cell->setPort("\\Y", sig_y);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addTribuf(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y)
+RTLIL::Cell* RTLIL::Module::addTribuf(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$tribuf");
cell->parameters["\\WIDTH"] = sig_a.size();
cell->setPort("\\A", sig_a);
cell->setPort("\\EN", sig_en);
cell->setPort("\\Y", sig_y);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en)
+RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$assert");
cell->setPort("\\A", sig_a);
cell->setPort("\\EN", sig_en);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en)
+RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$assume");
cell->setPort("\\A", sig_a);
cell->setPort("\\EN", sig_en);
+ cell->set_src_attribute(src);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addLive(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
+{
+ RTLIL::Cell *cell = addCell(name, "$live");
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\EN", sig_en);
+ cell->set_src_attribute(src);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addFair(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
+{
+ RTLIL::Cell *cell = addCell(name, "$fair");
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\EN", sig_en);
+ cell->set_src_attribute(src);
+ return cell;
+}
+
+RTLIL::Cell* RTLIL::Module::addCover(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src)
+{
+ RTLIL::Cell *cell = addCell(name, "$cover");
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\EN", sig_en);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y)
+RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$equiv");
cell->setPort("\\A", sig_a);
cell->setPort("\\B", sig_b);
cell->setPort("\\Y", sig_y);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity, bool clr_polarity)
+RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity, bool clr_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$sr");
cell->parameters["\\SET_POLARITY"] = set_polarity;
@@ -1835,19 +1945,21 @@ RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set,
cell->setPort("\\SET", sig_set);
cell->setPort("\\CLR", sig_clr);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addFf(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q)
+RTLIL::Cell* RTLIL::Module::addFf(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$ff");
cell->parameters["\\WIDTH"] = sig_q.size();
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity)
+RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$dff");
cell->parameters["\\CLK_POLARITY"] = clk_polarity;
@@ -1855,10 +1967,11 @@ RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk,
cell->setPort("\\CLK", sig_clk);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity)
+RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$dffe");
cell->parameters["\\CLK_POLARITY"] = clk_polarity;
@@ -1868,11 +1981,12 @@ RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk
cell->setPort("\\EN", sig_en);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
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)
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$dffsr");
cell->parameters["\\CLK_POLARITY"] = clk_polarity;
@@ -1884,11 +1998,12 @@ RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, RTLIL::SigSpec sig_cl
cell->setPort("\\CLR", sig_clr);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
- RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity)
+ RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$adff");
cell->parameters["\\CLK_POLARITY"] = clk_polarity;
@@ -1899,10 +2014,11 @@ RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, RTLIL::SigSpec sig_clk
cell->setPort("\\ARST", sig_arst);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity)
+RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$dlatch");
cell->parameters["\\EN_POLARITY"] = en_polarity;
@@ -1910,11 +2026,12 @@ RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_e
cell->setPort("\\EN", sig_en);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addDlatchsr(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
- RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity)
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$dlatchsr");
cell->parameters["\\EN_POLARITY"] = en_polarity;
@@ -1926,38 +2043,42 @@ RTLIL::Cell* RTLIL::Module::addDlatchsr(RTLIL::IdString name, RTLIL::SigSpec sig
cell->setPort("\\CLR", sig_clr);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addFfGate(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q)
+RTLIL::Cell* RTLIL::Module::addFfGate(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, "$_FF_");
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity)
+RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N'));
cell->setPort("\\C", sig_clk);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
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* RTLIL::Module::addDffeGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
cell->setPort("\\C", sig_clk);
cell->setPort("\\E", sig_en);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
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)
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N'));
cell->setPort("\\C", sig_clk);
@@ -1965,31 +2086,34 @@ RTLIL::Cell* RTLIL::Module::addDffsrGate(RTLIL::IdString name, RTLIL::SigSpec si
cell->setPort("\\R", sig_clr);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
- bool arst_value, bool clk_polarity, bool arst_polarity)
+ bool arst_value, bool clk_polarity, bool arst_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0'));
cell->setPort("\\C", sig_clk);
cell->setPort("\\R", sig_arst);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity)
+RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DLATCH_%c_", en_polarity ? 'P' : 'N'));
cell->setPort("\\E", sig_en);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
- RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity)
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src)
{
RTLIL::Cell *cell = addCell(name, stringf("$_DLATCHSR_%c%c%c_", en_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N'));
cell->setPort("\\E", sig_en);
@@ -1997,32 +2121,56 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec
cell->setPort("\\R", sig_clr);
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
+ cell->set_src_attribute(src);
return cell;
}
-RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width)
+RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID, width);
Cell *cell = addCell(name, "$anyconst");
cell->setParam("\\WIDTH", width);
cell->setPort("\\Y", sig);
+ cell->set_src_attribute(src);
return sig;
}
-RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width)
+RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID, width);
Cell *cell = addCell(name, "$anyseq");
cell->setParam("\\WIDTH", width);
cell->setPort("\\Y", sig);
+ cell->set_src_attribute(src);
return sig;
}
-RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name)
+RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const std::string &src)
+{
+ RTLIL::SigSpec sig = addWire(NEW_ID, width);
+ Cell *cell = addCell(name, "$allconst");
+ cell->setParam("\\WIDTH", width);
+ cell->setPort("\\Y", sig);
+ cell->set_src_attribute(src);
+ return sig;
+}
+
+RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const std::string &src)
+{
+ RTLIL::SigSpec sig = addWire(NEW_ID, width);
+ Cell *cell = addCell(name, "$allseq");
+ cell->setParam("\\WIDTH", width);
+ cell->setPort("\\Y", sig);
+ cell->set_src_attribute(src);
+ return sig;
+}
+
+RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID);
Cell *cell = addCell(name, "$initstate");
cell->setPort("\\Y", sig);
+ cell->set_src_attribute(src);
return sig;
}
@@ -2048,6 +2196,7 @@ RTLIL::Memory::Memory()
hashidx_ = hashidx_count;
width = 1;
+ start_offset = 0;
size = 0;
}
@@ -2764,10 +2913,11 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe
other->unpack();
}
- for (int i = GetSize(bits_) - 1; i >= 0; i--) {
+ for (int i = GetSize(bits_) - 1; i >= 0; i--)
+ {
if (bits_[i].wire == NULL) continue;
- for (auto &pattern_chunk : pattern.chunks()) {
+ for (auto &pattern_chunk : pattern.chunks())
if (bits_[i].wire == pattern_chunk.wire &&
bits_[i].offset >= pattern_chunk.offset &&
bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) {
@@ -2777,8 +2927,8 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe
other->bits_.erase(other->bits_.begin() + i);
other->width_--;
}
+ break;
}
- }
}
check();
@@ -3236,6 +3386,21 @@ bool RTLIL::SigSpec::is_fully_zero() const
return true;
}
+bool RTLIL::SigSpec::is_fully_ones() const
+{
+ cover("kernel.rtlil.sigspec.is_fully_ones");
+
+ pack();
+ for (auto it = chunks_.begin(); it != chunks_.end(); it++) {
+ if (it->width > 0 && it->wire != NULL)
+ return false;
+ for (size_t i = 0; i < it->data.size(); i++)
+ if (it->data[i] != RTLIL::State::S1)
+ return false;
+ }
+ return true;
+}
+
bool RTLIL::SigSpec::is_fully_def() const
{
cover("kernel.rtlil.sigspec.is_fully_def");
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 9430dcb3..027faf41 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -1,4 +1,4 @@
-/*
+/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
@@ -479,6 +479,11 @@ struct RTLIL::Const
inline RTLIL::State &operator[](int index) { return bits.at(index); }
inline const RTLIL::State &operator[](int index) const { return bits.at(index); }
+ bool is_fully_zero() const;
+ bool is_fully_ones() const;
+ bool is_fully_def() const;
+ bool is_fully_undef() const;
+
inline RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const {
RTLIL::Const ret;
ret.bits.reserve(len);
@@ -501,9 +506,13 @@ struct RTLIL::AttrObject
void set_bool_attribute(RTLIL::IdString id);
bool get_bool_attribute(RTLIL::IdString id) const;
+
void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
pool<string> get_strpool_attribute(RTLIL::IdString id) const;
+
+ void set_src_attribute(const std::string &src);
+ std::string get_src_attribute() const;
};
struct RTLIL::SigChunk
@@ -696,6 +705,7 @@ public:
bool is_fully_const() const;
bool is_fully_zero() const;
+ bool is_fully_ones() const;
bool is_fully_def() const;
bool is_fully_undef() const;
bool has_const() const;
@@ -793,7 +803,8 @@ struct RTLIL::Design
int refcount_modules_;
dict<RTLIL::IdString, RTLIL::Module*> modules_;
- std::vector<AST::AstNode*> verilog_packages;
+ std::vector<AST::AstNode*> verilog_packages, verilog_globals;
+ dict<std::string, std::pair<std::string, bool>> verilog_defines;
std::vector<RTLIL::Selection> selection_stack;
dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
@@ -895,7 +906,7 @@ public:
Module();
virtual ~Module();
- virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
+ virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail = false);
virtual size_t count_id(RTLIL::IdString id);
virtual void sort();
@@ -910,7 +921,7 @@ public:
std::vector<RTLIL::IdString> ports;
void fixup_ports();
- template<typename T> void rewrite_sigspecs(T functor);
+ template<typename T> void rewrite_sigspecs(T &functor);
void cloneInto(RTLIL::Module *new_mod) const;
virtual RTLIL::Module *clone() const;
@@ -955,161 +966,170 @@ public:
// The add* methods create a cell and return the created cell. All signals must exist in advance.
- RTLIL::Cell* addNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addPos (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addNeg (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
-
- RTLIL::Cell* addAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
-
- RTLIL::Cell* addReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
-
- RTLIL::Cell* addShl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addShr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addSshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addSshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addShift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addShiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
-
- RTLIL::Cell* addLt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addLe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addEq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addNe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addEqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addNex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addGe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addGt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
-
- RTLIL::Cell* addAdd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addSub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addMul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addDiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addMod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addPow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed = false, bool b_signed = false);
-
- RTLIL::Cell* addLogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addLogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
- RTLIL::Cell* addLogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false);
-
- RTLIL::Cell* addMux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y);
- RTLIL::Cell* addPmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y);
-
- RTLIL::Cell* addSlice (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset);
- 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_a, RTLIL::SigSpec sig_y, RTLIL::Const lut);
- RTLIL::Cell* addTribuf (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y);
- RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
- RTLIL::Cell* addAssume (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* addFf (RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q);
- 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* addNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addPos (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addNeg (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::Cell* addAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::Cell* addReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::Cell* addShl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addShr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addSshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addSshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addShift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addShiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::Cell* addLt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addLe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addEq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addNe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addEqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addNex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addGe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addGt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::Cell* addAdd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addSub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addMul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addDiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addMod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addPow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = "");
+
+ RTLIL::Cell* addLogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addLogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+ RTLIL::Cell* addLogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::Cell* addMux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y, const std::string &src = "");
+ RTLIL::Cell* addPmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y, const std::string &src = "");
+
+ RTLIL::Cell* addSlice (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset, const std::string &src = "");
+ RTLIL::Cell* addConcat (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src = "");
+ RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut, const std::string &src = "");
+ RTLIL::Cell* addTribuf (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y, const std::string &src = "");
+ RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = "");
+ RTLIL::Cell* addAssume (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = "");
+ RTLIL::Cell* addLive (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = "");
+ RTLIL::Cell* addFair (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = "");
+ RTLIL::Cell* addCover (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = "");
+ RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src = "");
+
+ 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, const std::string &src = "");
+ RTLIL::Cell* addFf (RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src = "");
+ RTLIL::Cell* addDff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, const std::string &src = "");
+ 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, const std::string &src = "");
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::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
RTLIL::Cell* addAdff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
- RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true);
- RTLIL::Cell* addDlatch (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true);
+ RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = "");
+ RTLIL::Cell* addDlatch (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, const std::string &src = "");
RTLIL::Cell* addDlatchsr (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
- RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true);
-
- RTLIL::Cell* addBufGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y);
- RTLIL::Cell* addNotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y);
- RTLIL::Cell* addAndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
- RTLIL::Cell* addNandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
- RTLIL::Cell* addOrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
- RTLIL::Cell* addNorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
- RTLIL::Cell* addXorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
- RTLIL::Cell* addXnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
- RTLIL::Cell* addMuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y);
- RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y);
- RTLIL::Cell* addOai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y);
- RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y);
- 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* addFfGate (RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q);
- 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::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
+
+ RTLIL::Cell* addBufGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addNotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addAndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addNandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addOrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addNorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addXorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addXnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addAndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addOrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addMuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addOai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = "");
+ RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y, const std::string &src = "");
+ 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, const std::string &src = "");
+
+ RTLIL::Cell* addFfGate (RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src = "");
+ RTLIL::Cell* addDffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, const std::string &src = "");
+ 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, const std::string &src = "");
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::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
RTLIL::Cell* addAdffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
- bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true);
- RTLIL::Cell* addDlatchGate (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true);
+ bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = "");
+ RTLIL::Cell* addDlatchGate (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, const std::string &src = "");
RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
- RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true);
+ RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
// The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.
- RTLIL::SigSpec Not (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
- RTLIL::SigSpec Pos (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
- RTLIL::SigSpec Bu0 (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
- RTLIL::SigSpec Neg (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
-
- RTLIL::SigSpec And (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Or (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Xor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Xnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
-
- RTLIL::SigSpec ReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
- RTLIL::SigSpec ReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
- RTLIL::SigSpec ReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
- RTLIL::SigSpec ReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
- RTLIL::SigSpec ReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
-
- RTLIL::SigSpec Shl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Shr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Sshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Sshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Shift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Shiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
-
- RTLIL::SigSpec Lt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Le (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Eq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Ne (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Eqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Nex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Ge (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Gt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
-
- RTLIL::SigSpec Add (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Sub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Mul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Div (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Mod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec Pow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool a_signed = false, bool b_signed = false);
-
- RTLIL::SigSpec LogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false);
- RTLIL::SigSpec LogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
- RTLIL::SigSpec LogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false);
-
- RTLIL::SigSpec Mux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s);
- RTLIL::SigSpec Pmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s);
-
- RTLIL::SigBit BufGate (RTLIL::IdString name, RTLIL::SigBit sig_a);
- RTLIL::SigBit NotGate (RTLIL::IdString name, RTLIL::SigBit sig_a);
- RTLIL::SigBit AndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
- RTLIL::SigBit NandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
- RTLIL::SigBit OrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
- RTLIL::SigBit NorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
- RTLIL::SigBit XorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
- RTLIL::SigBit XnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b);
- RTLIL::SigBit MuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s);
- RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c);
- RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c);
- RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d);
- RTLIL::SigBit Oai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d);
-
- RTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1);
- RTLIL::SigSpec Anyseq (RTLIL::IdString name, int width = 1);
- RTLIL::SigSpec Initstate (RTLIL::IdString name);
+ RTLIL::SigSpec Not (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Pos (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Bu0 (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Neg (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::SigSpec And (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Or (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Xor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Xnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::SigSpec ReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec ReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec ReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec ReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec ReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::SigSpec Shl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Shr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Sshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Sshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Shift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Shiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::SigSpec Lt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Le (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Eq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Ne (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Eqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Nex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Ge (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Gt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::SigSpec Add (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Sub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Mul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Div (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Mod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec Pow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = "");
+
+ RTLIL::SigSpec LogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec LogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+ RTLIL::SigSpec LogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = "");
+
+ RTLIL::SigSpec Mux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, const std::string &src = "");
+ RTLIL::SigSpec Pmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, const std::string &src = "");
+
+ RTLIL::SigBit BufGate (RTLIL::IdString name, RTLIL::SigBit sig_a, const std::string &src = "");
+ RTLIL::SigBit NotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, const std::string &src = "");
+ RTLIL::SigBit AndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
+ RTLIL::SigBit NandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
+ RTLIL::SigBit OrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
+ RTLIL::SigBit NorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
+ RTLIL::SigBit XorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
+ RTLIL::SigBit XnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
+ RTLIL::SigBit AndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
+ RTLIL::SigBit OrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
+ RTLIL::SigBit MuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = "");
+ RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = "");
+ RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = "");
+ RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, const std::string &src = "");
+ RTLIL::SigBit Oai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, const std::string &src = "");
+
+ RTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1, const std::string &src = "");
+ RTLIL::SigSpec Anyseq (RTLIL::IdString name, int width = 1, const std::string &src = "");
+ RTLIL::SigSpec Allconst (RTLIL::IdString name, int width = 1, const std::string &src = "");
+ RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = "");
+ RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = "");
};
struct RTLIL::Wire : public RTLIL::AttrObject
@@ -1193,7 +1213,7 @@ public:
module->design->module(type)->get_bool_attribute("\\keep"));
}
- template<typename T> void rewrite_sigspecs(T functor);
+ template<typename T> void rewrite_sigspecs(T &functor);
};
struct RTLIL::CaseRule
@@ -1205,7 +1225,7 @@ struct RTLIL::CaseRule
~CaseRule();
void optimize();
- template<typename T> void rewrite_sigspecs(T functor);
+ template<typename T> void rewrite_sigspecs(T &functor);
RTLIL::CaseRule *clone() const;
};
@@ -1216,7 +1236,7 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
~SwitchRule();
- template<typename T> void rewrite_sigspecs(T functor);
+ template<typename T> void rewrite_sigspecs(T &functor);
RTLIL::SwitchRule *clone() const;
};
@@ -1226,7 +1246,7 @@ struct RTLIL::SyncRule
RTLIL::SigSpec signal;
std::vector<RTLIL::SigSig> actions;
- template<typename T> void rewrite_sigspecs(T functor);
+ template<typename T> void rewrite_sigspecs(T &functor);
RTLIL::SyncRule *clone() const;
};
@@ -1238,7 +1258,7 @@ struct RTLIL::Process : public RTLIL::AttrObject
~Process();
- template<typename T> void rewrite_sigspecs(T functor);
+ template<typename T> void rewrite_sigspecs(T &functor);
RTLIL::Process *clone() const;
};
@@ -1287,7 +1307,7 @@ inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
}
template<typename T>
-void RTLIL::Module::rewrite_sigspecs(T functor)
+void RTLIL::Module::rewrite_sigspecs(T &functor)
{
for (auto &it : cells_)
it.second->rewrite_sigspecs(functor);
@@ -1300,13 +1320,13 @@ void RTLIL::Module::rewrite_sigspecs(T functor)
}
template<typename T>
-void RTLIL::Cell::rewrite_sigspecs(T functor) {
+void RTLIL::Cell::rewrite_sigspecs(T &functor) {
for (auto &it : connections_)
functor(it.second);
}
template<typename T>
-void RTLIL::CaseRule::rewrite_sigspecs(T functor) {
+void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
for (auto &it : compare)
functor(it);
for (auto &it : actions) {
@@ -1318,7 +1338,7 @@ void RTLIL::CaseRule::rewrite_sigspecs(T functor) {
}
template<typename T>
-void RTLIL::SwitchRule::rewrite_sigspecs(T functor)
+void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
{
functor(signal);
for (auto it : cases)
@@ -1326,7 +1346,7 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T functor)
}
template<typename T>
-void RTLIL::SyncRule::rewrite_sigspecs(T functor)
+void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
{
functor(signal);
for (auto &it : actions) {
@@ -1336,7 +1356,7 @@ void RTLIL::SyncRule::rewrite_sigspecs(T functor)
}
template<typename T>
-void RTLIL::Process::rewrite_sigspecs(T functor)
+void RTLIL::Process::rewrite_sigspecs(T &functor)
{
root_case.rewrite_sigspecs(functor);
for (auto it : syncs)
diff --git a/kernel/satgen.h b/kernel/satgen.h
index 690f8e33..210cca3f 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -1,4 +1,4 @@
-/*
+/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
@@ -310,7 +310,7 @@ struct SatGen
arith_undef_handled = true;
}
- if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_",
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_",
"$and", "$or", "$xor", "$xnor", "$add", "$sub"))
{
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
@@ -332,6 +332,10 @@ struct SatGen
ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy));
if (cell->type == "$xnor" || cell->type == "$_XNOR_")
ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy));
+ if (cell->type == "$_ANDNOT_")
+ ez->assume(ez->vec_eq(ez->vec_and(a, ez->vec_not(b)), yy));
+ if (cell->type == "$_ORNOT_")
+ ez->assume(ez->vec_eq(ez->vec_or(a, ez->vec_not(b)), yy));
if (cell->type == "$add")
ez->assume(ez->vec_eq(ez->vec_add(a, b), yy));
if (cell->type == "$sub")
@@ -360,6 +364,19 @@ struct SatGen
std::vector<int> yX = ez->vec_or(undef_a, undef_b);
ez->assume(ez->vec_eq(yX, undef_y));
}
+ else if (cell->type == "$_ANDNOT_") {
+ std::vector<int> a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a));
+ std::vector<int> b1 = ez->vec_and(b, ez->vec_not(undef_b));
+ std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b1)));
+ ez->assume(ez->vec_eq(yX, undef_y));
+ }
+
+ else if (cell->type == "$_ORNOT_") {
+ std::vector<int> a1 = ez->vec_and(a, ez->vec_not(undef_a));
+ std::vector<int> b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b));
+ std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b0)));
+ ez->assume(ez->vec_eq(yX, undef_y));
+ }
else
log_abort();
@@ -507,11 +524,7 @@ 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->CONST_FALSE;
- int maybe_many_hot = ez->CONST_FALSE;
-
- int sure_one_hot = ez->CONST_FALSE;
- int sure_many_hot = ez->CONST_FALSE;
+ int maybe_a = ez->CONST_TRUE;
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);
@@ -524,18 +537,12 @@ struct SatGen
int maybe_s = ez->OR(s.at(i), undef_s.at(i));
int sure_s = ez->AND(s.at(i), ez->NOT(undef_s.at(i)));
- maybe_one_hot = ez->OR(maybe_one_hot, maybe_s);
- maybe_many_hot = ez->OR(maybe_many_hot, ez->AND(maybe_one_hot, maybe_s));
-
- sure_one_hot = ez->OR(sure_one_hot, sure_s);
- sure_many_hot = ez->OR(sure_many_hot, ez->AND(sure_one_hot, sure_s));
+ maybe_a = ez->AND(maybe_a, ez->NOT(sure_s));
- bits_set = ez->vec_ite(maybe_s, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(part_of_b, part_of_undef_b))), bits_set);
- bits_clr = ez->vec_ite(maybe_s, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(part_of_b), part_of_undef_b))), bits_clr);
+ bits_set = ez->vec_ite(maybe_s, ez->vec_or(bits_set, ez->vec_or(part_of_b, part_of_undef_b)), bits_set);
+ bits_clr = ez->vec_ite(maybe_s, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(part_of_b), part_of_undef_b)), bits_clr);
}
- int maybe_a = ez->NOT(maybe_one_hot);
-
bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set);
bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr);
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 08fee974..264b1f63 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -25,6 +25,10 @@
# include <readline/history.h>
#endif
+#ifdef YOSYS_ENABLE_EDITLINE
+# include <editline/readline.h>
+#endif
+
#ifdef YOSYS_ENABLE_PLUGINS
# include <dlfcn.h>
#endif
@@ -42,10 +46,15 @@
# include <unistd.h>
# include <dirent.h>
# include <sys/types.h>
+# include <sys/wait.h>
# include <sys/stat.h>
# include <glob.h>
#endif
+#ifdef __FreeBSD__
+# include <sys/sysctl.h>
+#endif
+
#include <limits.h>
#include <errno.h>
@@ -60,13 +69,15 @@ CellTypes yosys_celltypes;
Tcl_Interp *yosys_tcl_interp = NULL;
#endif
+std::set<std::string> yosys_input_files, yosys_output_files;
+
bool memhasher_active = false;
uint32_t memhasher_rng = 123456;
std::vector<void*> memhasher_store;
void memhasher_on()
{
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
memhasher_rng += time(NULL) << 16 ^ getpid();
#endif
memhasher_store.resize(0x10000);
@@ -106,7 +117,7 @@ void yosys_banner()
log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n");
- log(" | Copyright (C) 2012 - 2016 Clifford Wolf <clifford@clifford.at> |\n");
+ log(" | Copyright (C) 2012 - 2018 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");
@@ -592,6 +603,8 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
std::string tcl_command_name = it.first;
if (tcl_command_name == "proc")
tcl_command_name = "procs";
+ else if (tcl_command_name == "rename")
+ tcl_command_name = "renames";
Tcl_CmdInfo info;
if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
@@ -623,7 +636,7 @@ extern Tcl_Interp *yosys_get_tcl_interp()
struct TclPass : public Pass {
TclPass() : Pass("tcl", "execute a TCL script file") { }
- virtual void help() {
+ void help() YS_OVERRIDE {
log("\n");
log(" tcl <filename>\n");
log("\n");
@@ -631,12 +644,12 @@ struct TclPass : public Pass {
log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
log("\n");
log("The tcl command 'yosys -import' can be used to import all yosys\n");
- log("commands directly as tcl commands to the tcl shell. The yosys\n");
- log("command 'proc' is wrapped using the tcl command 'procs' in order\n");
- log("to avoid a name collision with the tcl builtin command 'proc'.\n");
+ log("commands directly as tcl commands to the tcl shell. Yosys commands\n");
+ log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n");
+ log("in order to avoid a name collision with the built in commands.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
if (args.size() > 2)
@@ -659,6 +672,26 @@ std::string proc_self_dirname()
buflen--;
return std::string(path, buflen);
}
+#elif defined(__FreeBSD__)
+std::string proc_self_dirname()
+{
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+ size_t buflen;
+ char *buffer;
+ std::string path;
+ if (sysctl(mib, 4, NULL, &buflen, NULL, 0) != 0)
+ log_error("sysctl failed: %s\n", strerror(errno));
+ buffer = (char*)malloc(buflen);
+ if (buffer == NULL)
+ log_error("malloc failed: %s\n", strerror(errno));
+ if (sysctl(mib, 4, buffer, &buflen, NULL, 0) != 0)
+ log_error("sysctl failed: %s\n", strerror(errno));
+ while (buflen > 0 && buffer[buflen-1] != '/')
+ buflen--;
+ path.assign(buffer, buflen);
+ free(buffer);
+ return path;
+}
#elif defined(__APPLE__)
std::string proc_self_dirname()
{
@@ -706,7 +739,7 @@ std::string proc_self_dirname()
#ifdef EMSCRIPTEN
std::string proc_share_dirname()
{
- return "/share";
+ return "/share/";
}
#else
std::string proc_share_dirname()
@@ -792,10 +825,16 @@ void run_frontend(std::string filename, std::string command, std::string *backen
command = "vhdl";
else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif")
command = "blif";
+ else if (filename.size() > 5 && filename.substr(filename.size()-6) == ".eblif")
+ command = "blif";
+ else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".json")
+ command = "json";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
command = "ilang";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
command = "script";
+ else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".tcl")
+ command = "tcl";
else if (filename == "-")
command = "script";
else
@@ -823,8 +862,10 @@ void run_frontend(std::string filename, std::string command, std::string *backen
FILE *f = stdin;
- if (filename != "-")
+ if (filename != "-") {
f = fopen(filename.c_str(), "r");
+ yosys_input_files.insert(filename);
+ }
if (f == NULL)
log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
@@ -875,7 +916,10 @@ void run_frontend(std::string filename, std::string command, std::string *backen
log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
}
- Frontend::frontend_call(design, NULL, filename, command);
+ if (command == "tcl")
+ Pass::call(design, vector<string>({command, filename}));
+ else
+ Frontend::frontend_call(design, NULL, filename, command);
}
void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
@@ -903,6 +947,8 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig
command = "verilog";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
command = "ilang";
+ else if (filename.size() > 4 && filename.substr(filename.size()-4) == ".aig")
+ command = "aiger";
else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
command = "blif";
else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".edif")
@@ -929,7 +975,7 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig
Backend::backend_call(design, NULL, filename, command);
}
-#ifdef YOSYS_ENABLE_READLINE
+#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
static char *readline_cmd_generator(const char *text, int state)
{
static std::map<std::string, Pass*>::iterator it;
@@ -1016,14 +1062,14 @@ void shell(RTLIL::Design *design)
recursion_counter++;
log_cmd_error_throw = true;
-#ifdef YOSYS_ENABLE_READLINE
- rl_readline_name = "yosys";
+#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
+ rl_readline_name = (char*)"yosys";
rl_attempted_completion_function = readline_completion;
- rl_basic_word_break_characters = " \t\n";
+ rl_basic_word_break_characters = (char*)" \t\n";
#endif
char *command = NULL;
-#ifdef YOSYS_ENABLE_READLINE
+#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
{
#else
@@ -1037,7 +1083,7 @@ void shell(RTLIL::Design *design)
#endif
if (command[strspn(command, " \t\r\n")] == 0)
continue;
-#ifdef YOSYS_ENABLE_READLINE
+#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
add_history(command);
#endif
@@ -1067,7 +1113,7 @@ void shell(RTLIL::Design *design)
struct ShellPass : public Pass {
ShellPass() : Pass("shell", "enter interactive command mode") { }
- virtual void help() {
+ void help() YS_OVERRIDE {
log("\n");
log(" shell\n");
log("\n");
@@ -1099,16 +1145,16 @@ struct ShellPass : public Pass {
log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
extra_args(args, 1, design, false);
shell(design);
}
} ShellPass;
-#ifdef YOSYS_ENABLE_READLINE
+#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
struct HistoryPass : public Pass {
HistoryPass() : Pass("history", "show last interactive commands") { }
- virtual void help() {
+ void help() YS_OVERRIDE {
log("\n");
log(" history\n");
log("\n");
@@ -1117,17 +1163,22 @@ struct HistoryPass : public Pass {
log("from executed scripts.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
extra_args(args, 1, design, false);
+#ifdef YOSYS_ENABLE_READLINE
for(HIST_ENTRY **list = history_list(); *list != NULL; list++)
log("%s\n", (*list)->line);
+#else
+ for (int i = where_history(); history_get(i); i++)
+ log("%s\n", history_get(i)->line);
+#endif
}
} HistoryPass;
#endif
struct ScriptCmdPass : public Pass {
ScriptCmdPass() : Pass("script", "execute commands from script file") { }
- virtual void help() {
+ void help() YS_OVERRIDE {
log("\n");
log(" script <filename> [<from_label>:<to_label>]\n");
log("\n");
@@ -1142,7 +1193,7 @@ struct ScriptCmdPass : public Pass {
log("marked with that label (until the next label) is executed.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
else if (args.size() == 2)
diff --git a/kernel/yosys.h b/kernel/yosys.h
index ae73146b..c9f97331 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -1,4 +1,4 @@
-/*
+/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
@@ -74,6 +74,16 @@
#ifdef YOSYS_ENABLE_TCL
# include <tcl.h>
+# ifdef YOSYS_MXE_HACKS
+extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
+extern Tcl_Interp *Tcl_CreateInterp(void);
+extern void Tcl_DeleteInterp(Tcl_Interp *interp);
+extern int Tcl_Eval(Tcl_Interp *interp, const char *script);
+extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
+extern void Tcl_Finalize(void);
+extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
+extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
+# endif
#endif
#ifdef _WIN32
@@ -150,6 +160,7 @@ using std::pair;
using std::make_tuple;
using std::make_pair;
+using std::get;
using std::min;
using std::max;
@@ -294,6 +305,9 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi
void run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
void shell(RTLIL::Design *design);
+// journal of all input and output files read (for "yosys -E")
+extern std::set<std::string> yosys_input_files, yosys_output_files;
+
// from kernel/version_*.o (cc source generated from Makefile)
extern const char *yosys_version_str;
diff --git a/libs/ezsat/ezminisat.cc b/libs/ezsat/ezminisat.cc
index e0ee6292..4be5fd49 100644
--- a/libs/ezsat/ezminisat.cc
+++ b/libs/ezsat/ezminisat.cc
@@ -18,8 +18,12 @@
*/
// needed for MiniSAT headers (see Minisat Makefile)
-#define __STDC_LIMIT_MACROS
+#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
+#endif
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
#include "ezminisat.h"
diff --git a/libs/minisat/00_PATCH_no_fpu_control.patch b/libs/minisat/00_PATCH_no_fpu_control.patch
new file mode 100644
index 00000000..6c754b1e
--- /dev/null
+++ b/libs/minisat/00_PATCH_no_fpu_control.patch
@@ -0,0 +1,43 @@
+--- System.cc
++++ System.cc
+@@ -97,17 +97,6 @@ double Minisat::memUsedPeak(bool) { return 0; }
+ #endif
+
+
+-void Minisat::setX86FPUPrecision()
+-{
+-#if defined(__linux__) && defined(_FPU_EXTENDED) && defined(_FPU_DOUBLE) && defined(_FPU_GETCW)
+- // Only correct FPU precision on Linux architectures that needs and supports it:
+- fpu_control_t oldcw, newcw;
+- _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
+- printf("WARNING: for repeatability, setting FPU to use double precision\n");
+-#endif
+-}
+-
+-
+ #if !defined(_MSC_VER) && !defined(__MINGW32__)
+ void Minisat::limitMemory(uint64_t max_mem_mb)
+ {
+--- System.h
++++ System.h
+@@ -21,10 +21,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
+ #ifndef Minisat_System_h
+ #define Minisat_System_h
+
+-#if defined(__linux__)
+-#include <fpu_control.h>
+-#endif
+-
+ #include "IntTypes.h"
+
+ //-------------------------------------------------------------------------------------------------
+@@ -36,9 +32,6 @@ static inline double cpuTime(void); // CPU-time in seconds.
+ extern double memUsed(); // Memory in mega bytes (returns 0 for unsupported architectures).
+ extern double memUsedPeak(bool strictlyPeak = false); // Peak-memory in mega bytes (returns 0 for unsupported architectures).
+
+-extern void setX86FPUPrecision(); // Make sure double's are represented with the same precision
+- // in memory and registers.
+-
+ extern void limitMemory(uint64_t max_mem_mb); // Set a limit on total memory usage. The exact
+ // semantics varies depending on architecture.
+
diff --git a/libs/minisat/00_PATCH_remove_zlib.patch b/libs/minisat/00_PATCH_remove_zlib.patch
index 61a36f7e..068356b7 100644
--- a/libs/minisat/00_PATCH_remove_zlib.patch
+++ b/libs/minisat/00_PATCH_remove_zlib.patch
@@ -36,3 +36,20 @@
int operator * () const { return (pos >= size) ? EOF : buf[pos]; }
void operator ++ () { pos++; assureLookahead(); }
+--- Dimacs.h
++++ Dimacs.h
+@@ -76,10 +76,10 @@ static void parse_DIMACS_main(B& in, Solver& S, bool strictp = false) {
+
+ // Inserts problem into solver.
+ //
+-template<class Solver>
+-static void parse_DIMACS(gzFile input_stream, Solver& S, bool strictp = false) {
+- StreamBuffer in(input_stream);
+- parse_DIMACS_main(in, S, strictp); }
++//template<class Solver>
++//static void parse_DIMACS(gzFile input_stream, Solver& S, bool strictp = false) {
++// StreamBuffer in(input_stream);
++// parse_DIMACS_main(in, S, strictp); }
+
+ //=================================================================================================
+ }
diff --git a/libs/minisat/00_PATCH_typofixes.patch b/libs/minisat/00_PATCH_typofixes.patch
new file mode 100644
index 00000000..175f483b
--- /dev/null
+++ b/libs/minisat/00_PATCH_typofixes.patch
@@ -0,0 +1,20 @@
+--- Solver.h
++++ Solver.h
+@@ -103,7 +103,7 @@ public:
+ int nFreeVars () const;
+ void printStats () const; // Print some current statistics to standard output.
+
+- // Resource contraints:
++ // Resource constraints:
+ //
+ void setConfBudget(int64_t x);
+ void setPropBudget(int64_t x);
+@@ -230,7 +230,7 @@ protected:
+ double learntsize_adjust_confl;
+ int learntsize_adjust_cnt;
+
+- // Resource contraints:
++ // Resource constraints:
+ //
+ int64_t conflict_budget; // -1 means no budget.
+ int64_t propagation_budget; // -1 means no budget.
diff --git a/libs/minisat/00_UPDATE.sh b/libs/minisat/00_UPDATE.sh
index 96a34ec9..ea26215a 100644..100755
--- a/libs/minisat/00_UPDATE.sh
+++ b/libs/minisat/00_UPDATE.sh
@@ -9,9 +9,11 @@ rm -rf minisat_upstream
sed -i -e 's,^#include *"minisat/[^/]\+/\?,#include ",' *.cc *.h
sed -i -e 's/Minisat::memUsedPeak()/Minisat::memUsedPeak(bool)/' System.cc
sed -i -e 's/PRI[iu]64/ & /' Options.h Solver.cc
-sed -i -e '1 i #define __STDC_LIMIT_MACROS' *.cc
-sed -i -e '1 i #define __STDC_FORMAT_MACROS' *.cc
+sed -i -e '1 i #ifndef __STDC_LIMIT_MACROS\n#define __STDC_LIMIT_MACROS\n#endif' *.cc
+sed -i -e '1 i #ifndef __STDC_FORMAT_MACROS\n#define __STDC_FORMAT_MACROS\n#endif' *.cc
patch -p0 < 00_PATCH_mkLit_default_arg.patch
patch -p0 < 00_PATCH_remove_zlib.patch
+patch -p0 < 00_PATCH_no_fpu_control.patch
+patch -p0 < 00_PATCH_typofixes.patch
diff --git a/libs/minisat/Dimacs.h b/libs/minisat/Dimacs.h
index ccfa1c01..61b9d3ca 100644
--- a/libs/minisat/Dimacs.h
+++ b/libs/minisat/Dimacs.h
@@ -76,10 +76,10 @@ static void parse_DIMACS_main(B& in, Solver& S, bool strictp = false) {
// Inserts problem into solver.
//
-template<class Solver>
-static void parse_DIMACS(gzFile input_stream, Solver& S, bool strictp = false) {
- StreamBuffer in(input_stream);
- parse_DIMACS_main(in, S, strictp); }
+//template<class Solver>
+//static void parse_DIMACS(gzFile input_stream, Solver& S, bool strictp = false) {
+// StreamBuffer in(input_stream);
+// parse_DIMACS_main(in, S, strictp); }
//=================================================================================================
}
diff --git a/libs/minisat/Options.cc b/libs/minisat/Options.cc
index 1aff3fab..5c45dd6a 100644
--- a/libs/minisat/Options.cc
+++ b/libs/minisat/Options.cc
@@ -1,5 +1,9 @@
+#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
+#endif
+#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
+#endif
/**************************************************************************************[Options.cc]
Copyright (c) 2008-2010, Niklas Sorensson
diff --git a/libs/minisat/SimpSolver.cc b/libs/minisat/SimpSolver.cc
index fd5774e0..7348a905 100644
--- a/libs/minisat/SimpSolver.cc
+++ b/libs/minisat/SimpSolver.cc
@@ -1,5 +1,9 @@
+#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
+#endif
+#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
+#endif
/***********************************************************************************[SimpSolver.cc]
Copyright (c) 2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
diff --git a/libs/minisat/Solver.cc b/libs/minisat/Solver.cc
index ab476853..f6d4fb5a 100644
--- a/libs/minisat/Solver.cc
+++ b/libs/minisat/Solver.cc
@@ -1,5 +1,9 @@
+#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
+#endif
+#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
+#endif
/***************************************************************************************[Solver.cc]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
diff --git a/libs/minisat/System.cc b/libs/minisat/System.cc
index febe3b40..1921a1d7 100644
--- a/libs/minisat/System.cc
+++ b/libs/minisat/System.cc
@@ -1,5 +1,9 @@
+#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
+#endif
+#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
+#endif
/***************************************************************************************[System.cc]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
@@ -97,17 +101,6 @@ double Minisat::memUsedPeak(bool) { return 0; }
#endif
-void Minisat::setX86FPUPrecision()
-{
-#if defined(__linux__) && defined(_FPU_EXTENDED) && defined(_FPU_DOUBLE) && defined(_FPU_GETCW)
- // Only correct FPU precision on Linux architectures that needs and supports it:
- fpu_control_t oldcw, newcw;
- _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
- printf("WARNING: for repeatability, setting FPU to use double precision\n");
-#endif
-}
-
-
#if !defined(_MSC_VER) && !defined(__MINGW32__)
void Minisat::limitMemory(uint64_t max_mem_mb)
{
diff --git a/libs/minisat/System.h b/libs/minisat/System.h
index ee92a6e0..cd9d020c 100644
--- a/libs/minisat/System.h
+++ b/libs/minisat/System.h
@@ -21,10 +21,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#ifndef Minisat_System_h
#define Minisat_System_h
-#if defined(__linux__)
-#include <fpu_control.h>
-#endif
-
#include "IntTypes.h"
//-------------------------------------------------------------------------------------------------
@@ -36,9 +32,6 @@ static inline double cpuTime(void); // CPU-time in seconds.
extern double memUsed(); // Memory in mega bytes (returns 0 for unsupported architectures).
extern double memUsedPeak(bool strictlyPeak = false); // Peak-memory in mega bytes (returns 0 for unsupported architectures).
-extern void setX86FPUPrecision(); // Make sure double's are represented with the same precision
- // in memory and registers.
-
extern void limitMemory(uint64_t max_mem_mb); // Set a limit on total memory usage. The exact
// semantics varies depending on architecture.
diff --git a/libs/subcircuit/subcircuit.h b/libs/subcircuit/subcircuit.h
index 5291c642..8368efab 100644
--- a/libs/subcircuit/subcircuit.h
+++ b/libs/subcircuit/subcircuit.h
@@ -131,7 +131,7 @@ namespace SubCircuit
public:
Solver();
- ~Solver();
+ virtual ~Solver();
void setVerbose();
void addGraph(std::string graphId, const Graph &graph);
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index a831fdf3..277e8932 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -421,7 +421,8 @@ 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}, {\tt \$assume}, {\tt \$equiv}, {\tt \$initstate}, {\tt \$anyconst}, and {\tt \$anyseq} cells.
+Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}, {\tt \$cover}, {\tt \$equiv},
+{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells.
\end{fixme}
\begin{fixme}
@@ -449,6 +450,7 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA
\end{fixme}
\begin{fixme}
-Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
+Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_ORNOT\_},
+{\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
\end{fixme}
diff --git a/manual/CHAPTER_Prog/stubnets.cc b/manual/CHAPTER_Prog/stubnets.cc
index eb77bd40..8123e63d 100644
--- a/manual/CHAPTER_Prog/stubnets.cc
+++ b/manual/CHAPTER_Prog/stubnets.cc
@@ -98,7 +98,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
// each pass contains a singleton object that is derived from Pass
struct StubnetsPass : public Pass {
StubnetsPass() : Pass("stubnets") { }
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
// variables to mirror information from passed options
bool report_bits = 0;
diff --git a/manual/PRESENTATION_Prog/my_cmd.cc b/manual/PRESENTATION_Prog/my_cmd.cc
index d99bfe1e..5d9a7e13 100644
--- a/manual/PRESENTATION_Prog/my_cmd.cc
+++ b/manual/PRESENTATION_Prog/my_cmd.cc
@@ -6,7 +6,7 @@ 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)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log("Arguments to my_cmd:\n");
for (auto &arg : args)
@@ -22,7 +22,7 @@ struct MyPass : public Pass {
struct Test1Pass : public Pass {
Test1Pass() : Pass("test1", "creating the absval module") { }
- virtual void execute(std::vector<std::string>, RTLIL::Design *design)
+ void execute(std::vector<std::string>, RTLIL::Design *design) YS_OVERRIDE
{
if (design->has("\\absval") != 0)
log_error("A module with the name absval already exists!\n");
@@ -49,7 +49,7 @@ struct Test1Pass : public Pass {
struct Test2Pass : public Pass {
Test2Pass() : Pass("test2", "demonstrating sigmap on test module") { }
- virtual void execute(std::vector<std::string>, RTLIL::Design *design)
+ void execute(std::vector<std::string>, RTLIL::Design *design) YS_OVERRIDE
{
if (design->selection_stack.back().empty())
log_cmd_error("This command can't operator on an empty selection!\n");
diff --git a/manual/clean.sh b/manual/clean.sh
index 11c2e7bf..addc34ed 100755
--- a/manual/clean.sh
+++ b/manual/clean.sh
@@ -1,2 +1,2 @@
#!/bin/bash
-for f in $( find . -name .gitignore ); do sed -re "s,^,find ${f%.gitignore} -name ',; s,$,' | xargs rm -f,;" $f; done | bash -v
+for f in $( find . -name .gitignore ); do sed -Ee "s,^,find ${f%.gitignore} -name ',; s,$,' | xargs rm -f,;" $f; done | bash -v
diff --git a/misc/yosys.proto b/misc/yosys.proto
new file mode 100644
index 00000000..2870176c
--- /dev/null
+++ b/misc/yosys.proto
@@ -0,0 +1,175 @@
+//
+// yosys -- Yosys Open SYnthesis Suite
+//
+// Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// 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.
+//
+
+/// Protobuf definition of Yosys RTLIL dump/restore format for RTL designs.
+
+syntax = "proto3";
+
+package yosys.pb;
+
+// Port direction.
+enum Direction {
+ DIRECTION_INVALID = 0;
+ DIRECTION_INPUT = 1;
+ DIRECTION_OUTPUT = 2;
+ DIRECTION_INOUT = 3;
+}
+
+// A freeform parameter/attribute value.
+message Parameter {
+ oneof value {
+ int64 int = 1;
+ string str = 2;
+ }
+}
+
+// A signal in the design - either a unique identifier for one, or a constant
+// driver (low or high).
+message Signal {
+ // A constant signal driver in the design.
+ enum ConstantDriver {
+ CONSTANT_DRIVER_INVALID = 0;
+ CONSTANT_DRIVER_LOW = 1;
+ CONSTANT_DRIVER_HIGH = 2;
+ CONSTANT_DRIVER_Z = 3;
+ CONSTANT_DRIVER_X = 4;
+ }
+ oneof type {
+ // Signal uniquely identified by ID number.
+ int64 id = 1;
+ // Constant driver.
+ ConstantDriver constant = 2;
+ }
+}
+
+// A vector of signals.
+message BitVector {
+ repeated Signal signal = 1;
+}
+
+// A netlist module.
+message Module {
+ // Freeform attributes.
+ map<string, Parameter> attribute = 1;
+
+ // Named ports in this module.
+ message Port {
+ Direction direction = 1;
+ BitVector bits = 2;
+ }
+ map<string, Port> port = 2;
+
+ // Named cells in this module.
+ message Cell {
+ // Set to true when the name of this cell is automatically created and
+ // likely not of interest for a regular user.
+ bool hide_name = 1;
+ string type = 2;
+ // Set if this module has an AIG model available.
+ string model = 3;
+ // Freeform parameters.
+ map<string, Parameter> parameter = 4;
+ // Freeform attributes.
+ map<string, Parameter> attribute = 5;
+
+ /// Ports of the cell.
+ // Direction of the port, if interface is known.
+ map<string, Direction> port_direction = 6;
+ // Connection of named port to signal(s).
+ map<string, BitVector> connection = 7;
+ }
+ map<string, Cell> cell = 3;
+
+ // Nets in this module.
+ message Netname {
+ // Set to true when the name of this net is automatically created and
+ // likely not of interest for a regular user.
+ bool hide_name = 1;
+ // Signal(s) that make up this net.
+ BitVector bits = 2;
+ // Freeform attributes.
+ map<string, Parameter> attributes = 3;
+ }
+ repeated Netname netname = 4;
+}
+
+// And-Inverter-Graph model.
+message Model {
+ message Node {
+ // Type of AIG node - or, what its' value is.
+ enum Type {
+ TYPE_INVALID = 0;
+ // The node's value is the value of the specified input port bit.
+ TYPE_PORT = 1;
+ // The node's value is the inverted value of the specified input
+ // port bit.
+ TYPE_NPORT = 2;
+ // The node's value is the ANDed value of specified nodes.
+ TYPE_AND = 3;
+ // The node's value is the NANDed value of specified nodes.
+ TYPE_NAND = 4;
+ // The node's value is a constant 1.
+ TYPE_TRUE = 5;
+ // The node's value is a constant 0.
+ TYPE_FALSE = 6;
+ };
+ Type type = 1;
+
+ message Port {
+ // Name of port.
+ string portname = 1;
+ // Bit index in port.
+ int64 bitindex = 2;
+ }
+ message Gate {
+ // Node index of left side of operation.
+ int64 left = 1;
+ // Node index of right side of operation.
+ int64 right = 2;
+ }
+ oneof node {
+ // Set for PORT, NPORT
+ Port port = 2;
+ // Set for AND, NAND.
+ Gate gate = 3;
+ }
+
+ // Set when the node drives given output port(s).
+ message OutPort {
+ // Name of port.
+ string name = 1;
+ // Bit index in port.
+ int64 bit_index = 2;
+ }
+ repeated OutPort out_port = 4;
+ }
+
+ // List of AIG nodes - each is explicitely numbered by its' index in this
+ // array.
+ repeated Node node = 1;
+}
+
+// A Yosys design netlist dumped from RTLIL.
+message Design {
+ // Human-readable freeform 'remark' string.
+ string creator = 1;
+ // List of named modules in design.
+ map<string, Module> modules = 2;
+ // List of named AIG models in design (if AIG export enabled).
+ map<string, Model> models = 3;
+}
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index 01ada773..44a83b2b 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -25,4 +25,8 @@ OBJS += passes/cmds/plugin.o
OBJS += passes/cmds/check.o
OBJS += passes/cmds/qwp.o
OBJS += passes/cmds/edgetypes.o
+OBJS += passes/cmds/chformal.o
+OBJS += passes/cmds/chtype.o
+OBJS += passes/cmds/blackbox.o
+OBJS += passes/cmds/ltp.o
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index e698926f..cfccca96 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -83,7 +83,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
struct AddPass : public Pass {
AddPass() : Pass("add", "add objects to the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -106,7 +106,7 @@ struct AddPass : public Pass {
log("selected modules.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string command;
std::string arg_name;
diff --git a/passes/cmds/blackbox.cc b/passes/cmds/blackbox.cc
new file mode 100644
index 00000000..6094f8f1
--- /dev/null
+++ b/passes/cmds/blackbox.cc
@@ -0,0 +1,81 @@
+/*
+ * 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 BlackboxPass : public Pass {
+ BlackboxPass() : Pass("blackbox", "change type of cells in the design") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" blackbox [options] [selection]\n");
+ log("\n");
+ log("Convert modules into blackbox modules (remove contents and set the blackbox\n");
+ log("module attribute).\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-???") {
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_whole_modules_warn())
+ {
+ pool<Cell*> remove_cells;
+ pool<Wire*> remove_wires;
+
+ for (auto cell : module->cells())
+ remove_cells.insert(cell);
+
+ for (auto wire : module->wires())
+ if (wire->port_id == 0)
+ remove_wires.insert(wire);
+
+ for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
+ delete it->second;
+ module->memories.clear();
+
+ for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
+ delete it->second;
+ module->processes.clear();
+
+ module->new_connections(std::vector<RTLIL::SigSig>());
+
+ for (auto cell : remove_cells)
+ module->remove(cell);
+
+ module->remove(remove_wires);
+
+ module->set_bool_attribute("\\blackbox");
+ }
+ }
+} BlackboxPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
index b3622cb1..64697c13 100644
--- a/passes/cmds/check.cc
+++ b/passes/cmds/check.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CheckPass : public Pass {
CheckPass() : Pass("check", "check for obvious problems in the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -44,14 +44,18 @@ struct CheckPass : public Pass {
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 -initdrv then this command also checks for wires which have\n");
+ log("the 'init' attribute set and aren't driven by a FF cell type.\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)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int counter = 0;
bool noinit = false;
+ bool initdrv = false;
bool assert_mode = false;
size_t argidx;
@@ -60,6 +64,10 @@ struct CheckPass : public Pass {
noinit = true;
continue;
}
+ if (args[argidx] == "-initdrv") {
+ initdrv = true;
+ continue;
+ }
if (args[argidx] == "-assert") {
assert_mode = true;
continue;
@@ -70,6 +78,49 @@ struct CheckPass : public Pass {
log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
+ pool<IdString> fftypes;
+ fftypes.insert("$sr");
+ fftypes.insert("$ff");
+ fftypes.insert("$dff");
+ fftypes.insert("$dffe");
+ fftypes.insert("$dffsr");
+ fftypes.insert("$adff");
+ fftypes.insert("$dlatch");
+ fftypes.insert("$dlatchsr");
+ fftypes.insert("$_DFFE_NN_");
+ fftypes.insert("$_DFFE_NP_");
+ fftypes.insert("$_DFFE_PN_");
+ fftypes.insert("$_DFFE_PP_");
+ fftypes.insert("$_DFFSR_NNN_");
+ fftypes.insert("$_DFFSR_NNP_");
+ fftypes.insert("$_DFFSR_NPN_");
+ fftypes.insert("$_DFFSR_NPP_");
+ fftypes.insert("$_DFFSR_PNN_");
+ fftypes.insert("$_DFFSR_PNP_");
+ fftypes.insert("$_DFFSR_PPN_");
+ fftypes.insert("$_DFFSR_PPP_");
+ fftypes.insert("$_DFF_NN0_");
+ fftypes.insert("$_DFF_NN1_");
+ fftypes.insert("$_DFF_NP0_");
+ fftypes.insert("$_DFF_NP1_");
+ fftypes.insert("$_DFF_N_");
+ fftypes.insert("$_DFF_PN0_");
+ fftypes.insert("$_DFF_PN1_");
+ fftypes.insert("$_DFF_PP0_");
+ fftypes.insert("$_DFF_PP1_");
+ fftypes.insert("$_DFF_P_");
+ fftypes.insert("$_DLATCHSR_NNN_");
+ fftypes.insert("$_DLATCHSR_NNP_");
+ fftypes.insert("$_DLATCHSR_NPN_");
+ fftypes.insert("$_DLATCHSR_NPP_");
+ fftypes.insert("$_DLATCHSR_PNN_");
+ fftypes.insert("$_DLATCHSR_PNP_");
+ fftypes.insert("$_DLATCHSR_PPN_");
+ fftypes.insert("$_DLATCHSR_PPP_");
+ fftypes.insert("$_DLATCH_N_");
+ fftypes.insert("$_DLATCH_P_");
+ fftypes.insert("$_FF_");
+
for (auto module : design->selected_whole_modules_warn())
{
if (module->has_processes_warn())
@@ -109,6 +160,8 @@ struct CheckPass : public Pass {
if (bit.wire) wire_drivers_count[bit]++;
}
+ pool<SigBit> init_bits;
+
for (auto wire : module->wires()) {
if (wire->port_input) {
SigSpec sig = sigmap(wire);
@@ -121,9 +174,15 @@ struct CheckPass : public Pass {
if (wire->port_input && !wire->port_output)
for (auto bit : sigmap(wire))
if (bit.wire) wire_drivers_count[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++;
+ if (wire->attributes.count("\\init")) {
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ init_bits.insert(sigmap(SigBit(wire, i)));
+ if (noinit) {
+ log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire));
+ counter++;
+ }
}
}
@@ -150,6 +209,26 @@ struct CheckPass : public Pass {
log_warning("%s", message.c_str());
counter++;
}
+
+ if (initdrv)
+ {
+ for (auto cell : module->cells())
+ {
+ if (fftypes.count(cell->type) == 0)
+ continue;
+
+ for (auto bit : sigmap(cell->getPort("\\Q")))
+ init_bits.erase(bit);
+ }
+
+ SigSpec init_sig(init_bits);
+ init_sig.sort_and_unify();
+
+ for (auto chunk : init_sig.chunks()) {
+ log_warning("Wire %s.%s has 'init' attribute and is not driven by an FF cell.\n", log_id(module), log_signal(chunk));
+ counter++;
+ }
+ }
}
log("found and reported %d problems.\n", counter);
diff --git a/passes/cmds/chformal.cc b/passes/cmds/chformal.cc
new file mode 100644
index 00000000..522758ea
--- /dev/null
+++ b/passes/cmds/chformal.cc
@@ -0,0 +1,282 @@
+/*
+ * 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 ChformalPass : public Pass {
+ ChformalPass() : Pass("chformal", "change formal constraints of the design") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" chformal [types] [mode] [options] [selection]\n");
+ log("\n");
+ log("Make changes to the formal constraints of the design. The [types] options\n");
+ log("the type of constraint to operate on. If none of the folling options is given,\n");
+ log("the command will operate on all constraint types:\n");
+ log("\n");
+ log(" -assert $assert cells, representing assert(...) constraints\n");
+ log(" -assume $assume cells, representing assume(...) constraints\n");
+ log(" -live $live cells, representing assert(s_eventually ...)\n");
+ log(" -fair $fair cells, representing assume(s_eventually ...)\n");
+ log(" -cover $cover cells, representing cover() statements\n");
+ log("\n");
+ log("Exactly one of the following modes must be specified:\n");
+ log("\n");
+ log(" -remove\n");
+ log(" remove the cells and thus constraints from the design\n");
+ log("\n");
+ log(" -early\n");
+ log(" bypass FFs that only delay the activation of a constraint\n");
+ log("\n");
+ log(" -delay <N>\n");
+ log(" delay activation of the constraint by <N> clock cycles\n");
+ log("\n");
+ log(" -skip <N>\n");
+ log(" ignore activation of the constraint in the first <N> clock cycles\n");
+ log("\n");
+ log(" -assert2assume\n");
+ log(" -assume2assert\n");
+ log(" -live2fair\n");
+ log(" -fair2live\n");
+ log(" change the roles of cells as indicated. this options can be combined\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool assert2assume = false;
+ bool assume2assert = false;
+ bool live2fair = false;
+ bool fair2live = false;
+
+ pool<IdString> constr_types;
+ char mode = 0;
+ int mode_arg = 0;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-assert") {
+ constr_types.insert("$assert");
+ continue;
+ }
+ if (args[argidx] == "-assume") {
+ constr_types.insert("$assume");
+ continue;
+ }
+ if (args[argidx] == "-live") {
+ constr_types.insert("$live");
+ continue;
+ }
+ if (args[argidx] == "-fair") {
+ constr_types.insert("$fair");
+ continue;
+ }
+ if (args[argidx] == "-cover") {
+ constr_types.insert("$cover");
+ continue;
+ }
+ if (mode == 0 && args[argidx] == "-remove") {
+ mode = 'r';
+ continue;
+ }
+ if (mode == 0 && args[argidx] == "-early") {
+ mode = 'e';
+ continue;
+ }
+ if (mode == 0 && args[argidx] == "-delay" && argidx+1 < args.size()) {
+ mode = 'd';
+ mode_arg = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (mode == 0 && args[argidx] == "-skip" && argidx+1 < args.size()) {
+ mode = 's';
+ mode_arg = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if ((mode == 0 || mode == 'c') && args[argidx] == "-assert2assume") {
+ assert2assume = true;
+ mode = 'c';
+ continue;
+ }
+ if ((mode == 0 || mode == 'c') && args[argidx] == "-assume2assert") {
+ assume2assert = true;
+ mode = 'c';
+ continue;
+ }
+ if ((mode == 0 || mode == 'c') && args[argidx] == "-live2fair") {
+ live2fair = true;
+ mode = 'c';
+ continue;
+ }
+ if ((mode == 0 || mode == 'c') && args[argidx] == "-fair2live") {
+ fair2live = true;
+ mode = 'c';
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (constr_types.empty()) {
+ constr_types.insert("$assert");
+ constr_types.insert("$assume");
+ constr_types.insert("$live");
+ constr_types.insert("$fair");
+ constr_types.insert("$cover");
+ }
+
+ if (mode == 0)
+ log_cmd_error("Mode option is missing.\n");
+
+ for (auto module : design->selected_modules())
+ {
+ vector<Cell*> constr_cells;
+
+ for (auto cell : module->selected_cells())
+ if (constr_types.count(cell->type))
+ constr_cells.push_back(cell);
+
+ if (mode == 'r')
+ {
+ for (auto cell : constr_cells)
+ module->remove(cell);
+ }
+ else
+ if (mode == 'e')
+ {
+ SigMap sigmap(module);
+ dict<SigBit, pair<SigBit, pair<SigBit, bool>>> ffmap;
+ pool<SigBit> init_zero, init_one;
+
+ for (auto wire : module->wires())
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec initsig = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+
+ for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) {
+ if (initval[i] == State::S0)
+ init_zero.insert(initsig[i]);
+ if (initval[i] == State::S1)
+ init_one.insert(initsig[i]);
+ }
+ }
+
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "$ff") {
+ SigSpec D = sigmap(cell->getPort("\\D"));
+ SigSpec Q = sigmap(cell->getPort("\\Q"));
+ for (int i = 0; i < GetSize(D); i++)
+ ffmap[Q[i]] = make_pair(D[i], make_pair(State::Sm, false));
+ }
+ if (cell->type == "$dff") {
+ SigSpec D = sigmap(cell->getPort("\\D"));
+ SigSpec Q = sigmap(cell->getPort("\\Q"));
+ SigSpec C = sigmap(cell->getPort("\\CLK"));
+ bool clockpol = cell->getParam("\\CLK_POLARITY").as_bool();
+ for (int i = 0; i < GetSize(D); i++)
+ ffmap[Q[i]] = make_pair(D[i], make_pair(C, clockpol));
+ }
+ }
+
+ for (auto cell : constr_cells)
+ while (true)
+ {
+ SigSpec A = sigmap(cell->getPort("\\A"));
+ SigSpec EN = sigmap(cell->getPort("\\EN"));
+
+ if (ffmap.count(A) == 0 || ffmap.count(EN) == 0)
+ break;
+
+ if (!init_zero.count(EN)) {
+ if (cell->type == "$cover") break;
+ if (cell->type.in("$assert", "$assume") && !init_one.count(A)) break;
+ }
+
+ const auto &A_map = ffmap.at(A);
+ const auto &EN_map = ffmap.at(EN);
+
+ if (A_map.second != EN_map.second)
+ break;
+
+ cell->setPort("\\A", A_map.first);
+ cell->setPort("\\EN", EN_map.first);
+ }
+ }
+ else
+ if (mode == 'd')
+ {
+ for (auto cell : constr_cells)
+ for (int i = 0; i < mode_arg; i++)
+ {
+ SigSpec orig_a = cell->getPort("\\A");
+ SigSpec orig_en = cell->getPort("\\EN");
+
+ Wire *new_a = module->addWire(NEW_ID);
+ Wire *new_en = module->addWire(NEW_ID);
+ new_en->attributes["\\init"] = State::S0;
+
+ module->addFf(NEW_ID, orig_a, new_a);
+ module->addFf(NEW_ID, orig_en, new_en);
+
+ cell->setPort("\\A", new_a);
+ cell->setPort("\\EN", new_en);
+ }
+ }
+ else
+ if (mode == 's')
+ {
+ SigSpec en = State::S1;
+
+ for (int i = 0; i < mode_arg; i++) {
+ Wire *w = module->addWire(NEW_ID);
+ w->attributes["\\init"] = State::S0;
+ module->addFf(NEW_ID, en, w);
+ en = w;
+ }
+
+ for (auto cell : constr_cells)
+ cell->setPort("\\EN", module->LogicAnd(NEW_ID, en, cell->getPort("\\EN")));
+ }
+ else
+ if (mode == 'c')
+ {
+ for (auto cell : constr_cells)
+ if (assert2assume && cell->type == "$assert")
+ cell->type = "$assume";
+ else if (assume2assert && cell->type == "$assume")
+ cell->type = "$assert";
+ else if (live2fair && cell->type == "$live")
+ cell->type = "$fair";
+ else if (fair2live && cell->type == "$fair")
+ cell->type = "$live";
+ }
+ }
+ }
+} ChformalPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/chtype.cc b/passes/cmds/chtype.cc
new file mode 100644
index 00000000..979aeadd
--- /dev/null
+++ b/passes/cmds/chtype.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 ChtypePass : public Pass {
+ ChtypePass() : Pass("chtype", "change type of cells in the design") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" chtype [options] [selection]\n");
+ log("\n");
+ log("Change the types of cells in the design.\n");
+ log("\n");
+ log(" -set <type>\n");
+ log(" set the cell type to the given type\n");
+ log("\n");
+ log(" -map <old_type> <new_type>\n");
+ log(" change cells types that match <old_type> to <new_type>\n");
+ log("\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ IdString set_type;
+ dict<IdString, IdString> map_types;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (set_type == IdString() && args[argidx] == "-set" && argidx+1 < args.size()) {
+ set_type = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-map" && argidx+2 < args.size()) {
+ IdString old_type = RTLIL::escape_id(args[++argidx]);
+ IdString new_type = RTLIL::escape_id(args[++argidx]);
+ map_types[old_type] = new_type;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ for (auto cell : module->selected_cells())
+ {
+ if (map_types.count(cell->type)) {
+ cell->type = map_types.at(cell->type);
+ continue;
+ }
+
+ if (set_type != IdString()) {
+ cell->type = set_type;
+ continue;
+ }
+ }
+ }
+ }
+} ChtypePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc
index 52611cf4..d480b79a 100644
--- a/passes/cmds/connect.cc
+++ b/passes/cmds/connect.cc
@@ -43,7 +43,7 @@ static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &
struct ConnectPass : public Pass {
ConnectPass() : Pass("connect", "create or remove connections") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -75,7 +75,7 @@ struct ConnectPass : public Pass {
log("This command does not operate on module with processes.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
RTLIL::Module *module = NULL;
for (auto &it : design->modules_) {
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
index c9ab226d..5a15cbba 100644
--- a/passes/cmds/connwrappers.cc
+++ b/passes/cmds/connwrappers.cc
@@ -149,8 +149,8 @@ struct ConnwrappersWorker
};
struct ConnwrappersPass : public Pass {
- ConnwrappersPass() : Pass("connwrappers", "replace undef values with defined constants") { }
- virtual void help()
+ ConnwrappersPass() : Pass("connwrappers", "match width of input-output port pairs") { }
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -172,7 +172,7 @@ struct ConnwrappersPass : public Pass {
log("The options -signed, -unsigned, and -port can be specified multiple times.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
ConnwrappersWorker worker;
diff --git a/passes/cmds/copy.cc b/passes/cmds/copy.cc
index fb863512..acd2dba5 100644
--- a/passes/cmds/copy.cc
+++ b/passes/cmds/copy.cc
@@ -26,7 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CopyPass : public Pass {
CopyPass() : Pass("copy", "copy modules in the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -36,7 +36,7 @@ struct CopyPass : public Pass {
log("by this command.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
if (args.size() != 3)
log_cmd_error("Invalid number of arguments!\n");
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 1475475c..0ec74767 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -35,7 +35,7 @@ PRIVATE_NAMESPACE_BEGIN
struct CoverPass : public Pass {
CoverPass() : Pass("cover", "print code coverage counters") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -83,7 +83,7 @@ struct CoverPass : public Pass {
log("Coverage counters are only available in Yosys for Linux.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<FILE*> out_files;
std::vector<std::string> patterns;
@@ -128,7 +128,7 @@ struct CoverPass : public Pass {
log("\n");
}
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
for (auto &it : get_coverage_data()) {
if (!patterns.empty()) {
for (auto &p : patterns)
diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc
index 6d51d30e..f8d91ea4 100644
--- a/passes/cmds/delete.cc
+++ b/passes/cmds/delete.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct DeletePass : public Pass {
DeletePass() : Pass("delete", "delete objects in the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -40,7 +40,7 @@ struct DeletePass : public Pass {
log("selected wires, thus 'deleting' module ports.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_input = false;
bool flag_output = false;
diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc
index e900e7b9..172addcc 100644
--- a/passes/cmds/design.cc
+++ b/passes/cmds/design.cc
@@ -17,10 +17,8 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/celltypes.h"
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+#include "frontends/ast/ast.h"
YOSYS_NAMESPACE_BEGIN
@@ -29,7 +27,7 @@ std::vector<RTLIL::Design*> pushed_designs;
struct DesignPass : public Pass {
DesignPass() : Pass("design", "save, restore and reset current design") { }
- virtual ~DesignPass() {
+ ~DesignPass() YS_OVERRIDE {
for (auto &it : saved_designs)
delete it.second;
saved_designs.clear();
@@ -37,7 +35,7 @@ struct DesignPass : public Pass {
delete it;
pushed_designs.clear();
}
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -82,13 +80,28 @@ struct DesignPass : public Pass {
log("\n");
log("Copy modules from the current design into the specified one.\n");
log("\n");
+ log("\n");
+ log(" design -import <name> [-as <new_top_name>] [selection]\n");
+ log("\n");
+ log("Import the specified design into the current design. The source design must\n");
+ log("either have a selected top module or the selection must contain exactly one\n");
+ log("module that is then used as top module for this command.\n");
+ log("\n");
+ log("\n");
+ log(" design -reset-vlog\n");
+ log("\n");
+ log("The Verilog front-end remembers defined macros and top-level declarations\n");
+ log("between calls to 'read_verilog'. This command resets this memory.\n");
+ log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool got_mode = false;
bool reset_mode = false;
+ bool reset_vlog_mode = false;
bool push_mode = false;
bool pop_mode = false;
+ bool import_mode = false;
RTLIL::Design *copy_from_design = NULL, *copy_to_design = NULL;
std::string save_name, load_name, as_name;
std::vector<RTLIL::Module*> copy_src_modules;
@@ -102,6 +115,11 @@ struct DesignPass : public Pass {
reset_mode = true;
continue;
}
+ if (!got_mode && args[argidx] == "-reset-vlog") {
+ got_mode = true;
+ reset_vlog_mode = true;
+ continue;
+ }
if (!got_mode && args[argidx] == "-push") {
got_mode = true;
push_mode = true;
@@ -146,8 +164,17 @@ struct DesignPass : public Pass {
copy_from_design = design;
continue;
}
- if (copy_from_design != NULL && args[argidx] == "-as" && argidx+1 < args.size()) {
+ if (!got_mode && args[argidx] == "-import" && argidx+1 < args.size()) {
got_mode = true;
+ import_mode = true;
+ if (saved_designs.count(args[++argidx]) == 0)
+ log_cmd_error("No saved design '%s' found!\n", args[argidx].c_str());
+ copy_from_design = saved_designs.at(args[argidx]);
+ copy_to_design = design;
+ as_name = args[argidx];
+ continue;
+ }
+ if (copy_from_design != NULL && args[argidx] == "-as" && argidx+1 < args.size()) {
as_name = args[++argidx];
continue;
}
@@ -156,10 +183,10 @@ struct DesignPass : public Pass {
if (copy_from_design != NULL)
{
- if (copy_from_design != design && argidx == args.size())
+ if (copy_from_design != design && argidx == args.size() && !import_mode)
cmd_error(args, argidx, "Missing selection.");
- RTLIL::Selection sel = design->selection_stack.back();
+ RTLIL::Selection sel;
if (argidx != args.size()) {
handle_extra_select_args(this, args, argidx, args.size(), copy_from_design);
sel = copy_from_design->selection_stack.back();
@@ -175,6 +202,17 @@ struct DesignPass : public Pass {
if (sel.selected_module(it.first))
log_cmd_error("Module %s is only partly selected.\n", RTLIL::id2cstr(it.first));
}
+
+ if (import_mode) {
+ for (auto module : copy_src_modules)
+ {
+ if (module->get_bool_attribute("\\top")) {
+ copy_src_modules.clear();
+ copy_src_modules.push_back(module);
+ break;
+ }
+ }
+ }
}
extra_args(args, argidx, design, false);
@@ -185,6 +223,68 @@ struct DesignPass : public Pass {
if (pop_mode && pushed_designs.empty())
log_cmd_error("No pushed designs.\n");
+ if (import_mode)
+ {
+ std::string prefix = RTLIL::escape_id(as_name);
+
+ pool<Module*> queue;
+ dict<IdString, IdString> done;
+
+ if (copy_to_design->modules_.count(prefix))
+ delete copy_to_design->modules_.at(prefix);
+
+ if (GetSize(copy_src_modules) != 1)
+ log_cmd_error("No top module found in source design.\n");
+
+ for (auto mod : copy_src_modules)
+ {
+ log("Importing %s as %s.\n", log_id(mod), log_id(prefix));
+
+ copy_to_design->modules_[prefix] = mod->clone();
+ copy_to_design->modules_[prefix]->name = prefix;
+ copy_to_design->modules_[prefix]->design = copy_to_design;
+ copy_to_design->modules_[prefix]->attributes.erase("\\top");
+
+ queue.insert(copy_to_design->modules_[prefix]);
+ done[mod->name] = prefix;
+ }
+
+ while (!queue.empty())
+ {
+ pool<Module*> old_queue;
+ old_queue.swap(queue);
+
+ for (auto mod : old_queue)
+ for (auto cell : mod->cells())
+ {
+ Module *fmod = copy_from_design->module(cell->type);
+
+ if (fmod == nullptr)
+ continue;
+
+ if (done.count(cell->type) == 0)
+ {
+ std::string trg_name = prefix + "." + (cell->type.c_str() + (*cell->type.c_str() == '\\'));
+
+ log("Importing %s as %s.\n", log_id(fmod), log_id(trg_name));
+
+ if (copy_to_design->modules_.count(trg_name))
+ delete copy_to_design->modules_.at(trg_name);
+
+ copy_to_design->modules_[trg_name] = fmod->clone();
+ copy_to_design->modules_[trg_name]->name = trg_name;
+ copy_to_design->modules_[trg_name]->design = copy_to_design;
+ copy_to_design->modules_[trg_name]->attributes.erase("\\top");
+
+ queue.insert(copy_to_design->modules_[trg_name]);
+ done[cell->type] = trg_name;
+ }
+
+ cell->type = done.at(cell->type);
+ }
+ }
+ }
+ else
if (copy_to_design != NULL)
{
if (!as_name.empty() && copy_src_modules.size() > 1)
@@ -196,6 +296,7 @@ struct DesignPass : public Pass {
if (copy_to_design->modules_.count(trg_name))
delete copy_to_design->modules_.at(trg_name);
+
copy_to_design->modules_[trg_name] = mod->clone();
copy_to_design->modules_[trg_name]->name = trg_name;
copy_to_design->modules_[trg_name]->design = copy_to_design;
@@ -235,19 +336,34 @@ struct DesignPass : public Pass {
design->selection_stack.push_back(RTLIL::Selection());
}
+ if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode)
+ {
+ for (auto node : design->verilog_packages)
+ delete node;
+ design->verilog_packages.clear();
+
+ for (auto node : design->verilog_globals)
+ delete node;
+ design->verilog_globals.clear();
+
+ design->verilog_defines.clear();
+ }
+
if (!load_name.empty() || pop_mode)
{
RTLIL::Design *saved_design = pop_mode ? pushed_designs.back() : saved_designs.at(load_name);
- if (pop_mode)
- pushed_designs.pop_back();
-
for (auto &it : saved_design->modules_)
design->add(it.second->clone());
design->selection_stack = saved_design->selection_stack;
design->selection_vars = saved_design->selection_vars;
design->selected_active_module = saved_design->selected_active_module;
+
+ if (pop_mode) {
+ delete saved_design;
+ pushed_designs.pop_back();
+ }
}
}
} DesignPass;
diff --git a/passes/cmds/edgetypes.cc b/passes/cmds/edgetypes.cc
index 7b75a009..58ed6457 100644
--- a/passes/cmds/edgetypes.cc
+++ b/passes/cmds/edgetypes.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EdgetypePass : public Pass {
EdgetypePass() : Pass("edgetypes", "list all types of edges in selection") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -35,7 +35,7 @@ struct EdgetypePass : public Pass {
log("is a 4-tuple of source and sink cell type and port name.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/cmds/logcmd.cc b/passes/cmds/logcmd.cc
index 85386f3d..522e1089 100644
--- a/passes/cmds/logcmd.cc
+++ b/passes/cmds/logcmd.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct LogPass : public Pass {
LogPass() : Pass("log", "print text and log files") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -52,7 +52,7 @@ struct LogPass : public Pass {
log(" do not append a newline\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
size_t argidx;
bool to_stdout = false;
diff --git a/passes/cmds/ltp.cc b/passes/cmds/ltp.cc
new file mode 100644
index 00000000..05701710
--- /dev/null
+++ b/passes/cmds/ltp.cc
@@ -0,0 +1,185 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/celltypes.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct LtpWorker
+{
+ RTLIL::Design *design;
+ RTLIL::Module *module;
+ SigMap sigmap;
+
+ dict<SigBit, tuple<int, SigBit, Cell*>> bits;
+ dict<SigBit, dict<SigBit, Cell*>> bit2bits;
+ dict<SigBit, tuple<SigBit, Cell*>> bit2ff;
+
+ int maxlvl;
+ SigBit maxbit;
+ pool<SigBit> busy;
+
+ LtpWorker(RTLIL::Module *module, bool noff) : design(module->design), module(module), sigmap(module)
+ {
+ CellTypes ff_celltypes;
+
+ if (noff) {
+ ff_celltypes.setup_internals_mem();
+ ff_celltypes.setup_stdcells_mem();
+ }
+
+ for (auto wire : module->selected_wires())
+ for (auto bit : sigmap(wire))
+ bits[bit] = tuple<int, SigBit, Cell*>(-1, State::Sx, nullptr);
+
+ for (auto cell : module->selected_cells())
+ {
+ pool<SigBit> src_bits, dst_bits;
+
+ for (auto &conn : cell->connections())
+ for (auto bit : sigmap(conn.second)) {
+ if (cell->input(conn.first))
+ src_bits.insert(bit);
+ if (cell->output(conn.first))
+ dst_bits.insert(bit);
+ }
+
+ if (noff && ff_celltypes.cell_known(cell->type)) {
+ for (auto s : src_bits)
+ for (auto d : dst_bits) {
+ bit2ff[s] = tuple<SigBit, Cell*>(d, cell);
+ break;
+ }
+ continue;
+ }
+
+ for (auto s : src_bits)
+ for (auto d : dst_bits)
+ bit2bits[s][d] = cell;
+ }
+
+ maxlvl = -1;
+ maxbit = State::Sx;
+ }
+
+ void runner(SigBit bit, int level, SigBit from, Cell *via)
+ {
+ auto &bitinfo = bits.at(bit);
+
+ if (get<0>(bitinfo) >= level)
+ return;
+
+ if (busy.count(bit) > 0) {
+ log_warning("Detected loop at %s in %s\n", log_signal(bit), log_id(module));
+ return;
+ }
+
+ busy.insert(bit);
+ get<0>(bitinfo) = level;
+ get<1>(bitinfo) = from;
+ get<2>(bitinfo) = via;
+
+ if (level > maxlvl) {
+ maxlvl = level;
+ maxbit = bit;
+ }
+
+ if (bit2bits.count(bit)) {
+ for (auto &it : bit2bits.at(bit))
+ runner(it.first, level+1, bit, it.second);
+ }
+
+ busy.erase(bit);
+ }
+
+ void printpath(SigBit bit)
+ {
+ auto &bitinfo = bits.at(bit);
+ if (get<2>(bitinfo)) {
+ printpath(get<1>(bitinfo));
+ log("%5d: %s (via %s)\n", get<0>(bitinfo), log_signal(bit), log_id(get<2>(bitinfo)));
+ } else {
+ log("%5d: %s\n", get<0>(bitinfo), log_signal(bit));
+ }
+ }
+
+ void run()
+ {
+ for (auto &it : bits)
+ if (get<0>(it.second) < 0)
+ runner(it.first, 0, State::Sx, nullptr);
+
+ log("\n");
+ log("Longest topological path in %s (length=%d):\n", log_id(module), maxlvl);
+
+ if (maxlvl >= 0)
+ printpath(maxbit);
+
+ if (bit2ff.count(maxbit))
+ log("%5s: %s (via %s)\n", "ff", log_signal(get<0>(bit2ff.at(maxbit))), log_id(get<1>(bit2ff.at(maxbit))));
+ }
+};
+
+struct LtpPass : public Pass {
+ LtpPass() : Pass("ltp", "print longest topological path") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ltp [options] [selection]\n");
+ log("\n");
+ log("This command prints the longest topological path in the design. (Only considers\n");
+ log("paths within a single module, so the design must be flattened.)\n");
+ log("\n");
+ log(" -noff\n");
+ log(" automatically exclude FF cell types\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool noff = false;
+
+ log_header(design, "Executing LTP pass (find longest path).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-noff") {
+ noff = true;
+ continue;
+ }
+ break;
+ }
+
+ extra_args(args, argidx, design);
+
+ for (Module *module : design->selected_modules())
+ {
+ if (module->has_processes_warn())
+ continue;
+
+ LtpWorker worker(module, noff);
+ worker.run();
+ }
+ }
+} LtpPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
index 828c671d..aa6d5b6c 100644
--- a/passes/cmds/plugin.cc
+++ b/passes/cmds/plugin.cc
@@ -58,7 +58,7 @@ void load_plugin(std::string, std::vector<std::string>)
struct PluginPass : public Pass {
PluginPass() : Pass("plugin", "load and list loaded plugins") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -76,7 +76,7 @@ struct PluginPass : public Pass {
log(" List loaded plugins\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string plugin_filename;
std::vector<std::string> plugin_aliases;
diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc
index 1b800b6d..1c64a7b7 100644
--- a/passes/cmds/qwp.cc
+++ b/passes/cmds/qwp.cc
@@ -778,7 +778,7 @@ struct QwpWorker
struct QwpPass : public Pass {
QwpPass() : Pass("qwp", "quadratic wirelength placer") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -808,7 +808,7 @@ struct QwpPass : public Pass {
log("dense matrix operations. It is only a toy-placer for small circuits.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
QwpConfig config;
xorshift32_state = 123456789;
@@ -835,6 +835,7 @@ struct QwpPass : public Pass {
}
if (args[argidx] == "-dump" && argidx+1 < args.size()) {
config.dump_file.open(args[++argidx], std::ofstream::trunc);
+ yosys_output_files.insert(args[argidx]);
continue;
}
break;
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 6a002869..dce576fd 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -54,7 +54,7 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
struct RenamePass : public Pass {
RenamePass() : Pass("rename", "rename object in the design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -81,7 +81,7 @@ struct RenamePass : public Pass {
log("Rename top module.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string pattern_prefix = "_", pattern_suffix = "_";
bool flag_enumerate = false;
diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc
index f083e1f6..7123ba9f 100644
--- a/passes/cmds/scatter.cc
+++ b/passes/cmds/scatter.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ScatterPass : public Pass {
ScatterPass() : Pass("scatter", "add additional intermediate nets") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -41,7 +41,7 @@ struct ScatterPass : public Pass {
log("Use the opt_clean command to get rid of the additional nets.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
CellTypes ct(design);
extra_args(args, 1, design);
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index bb6d7447..99f4fbae 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -163,16 +163,8 @@ struct SccWorker
}
for (auto cell : workQueue)
- cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);
-
- labelCounter = 0;
- cellLabels.clear();
-
- while (workQueue.size() > 0)
{
- RTLIL::Cell *cell = *workQueue.begin();
- log_assert(cellStack.size() == 0);
- cellDepth.clear();
+ cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);
if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
log("Found an SCC:");
@@ -183,6 +175,16 @@ struct SccWorker
sccList.push_back(scc);
log("\n");
}
+ }
+
+ labelCounter = 0;
+ cellLabels.clear();
+
+ while (!workQueue.empty())
+ {
+ RTLIL::Cell *cell = *workQueue.begin();
+ log_assert(cellStack.size() == 0);
+ cellDepth.clear();
run(cell, 0, maxDepth);
}
@@ -216,7 +218,7 @@ struct SccWorker
struct SccPass : public Pass {
SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -244,20 +246,18 @@ struct SccPass : public Pass {
log(" are assumed to be bidirectional 'inout' ports.\n");
log("\n");
log(" -set_attr <name> <value>\n");
- log(" -set_cell_attr <name> <value>\n");
- log(" -set_wire_attr <name> <value>\n");
- log(" set the specified attribute on all cells and/or wires that are part of\n");
- log(" a logic loop. the special token {} in the value is replaced with a\n");
- log(" unique identifier for the logic loop.\n");
+ log(" set the specified attribute on all cells that are part of a logic\n");
+ log(" loop. the special token {} in the value is replaced with a unique\n");
+ log(" identifier for the logic loop.\n");
log("\n");
log(" -select\n");
log(" replace the current selection with a selection of all cells and wires\n");
log(" that are part of a found logic loop\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- std::map<std::string, std::string> setCellAttr, setWireAttr;
+ std::map<std::string, std::string> setAttr;
bool allCellTypes = false;
bool selectMode = false;
bool nofeedbackMode = false;
@@ -285,18 +285,7 @@ struct SccPass : public Pass {
continue;
}
if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
- setCellAttr[args[argidx+1]] = args[argidx+2];
- setWireAttr[args[argidx+1]] = args[argidx+2];
- argidx += 2;
- continue;
- }
- if (args[argidx] == "-set_cell_attr" && argidx+2 < args.size()) {
- setCellAttr[args[argidx+1]] = args[argidx+2];
- argidx += 2;
- continue;
- }
- if (args[argidx] == "-set_wire_attr" && argidx+2 < args.size()) {
- setWireAttr[args[argidx+1]] = args[argidx+2];
+ setAttr[args[argidx+1]] = args[argidx+2];
argidx += 2;
continue;
}
@@ -309,9 +298,6 @@ struct SccPass : public Pass {
int origSelectPos = design->selection_stack.size() - 1;
extra_args(args, argidx, design);
- if (setCellAttr.size() > 0 || setWireAttr.size() > 0)
- log_cmd_error("The -set*_attr options are not implemented at the moment!\n");
-
RTLIL::Selection newSelection(false);
int scc_counter = 0;
@@ -319,7 +305,33 @@ struct SccPass : public Pass {
if (design->selected(mod_it.second))
{
SccWorker worker(design, mod_it.second, nofeedbackMode, allCellTypes, maxDepth);
- scc_counter += GetSize(worker.sccList);
+
+ if (!setAttr.empty())
+ {
+ for (const auto &cells : worker.sccList)
+ {
+ for (auto attr : setAttr)
+ {
+ IdString attr_name(RTLIL::escape_id(attr.first));
+ string attr_valstr = attr.second;
+ string index = stringf("%d", scc_counter);
+
+ for (size_t pos = 0; (pos = attr_valstr.find("{}", pos)) != string::npos; pos += index.size())
+ attr_valstr.replace(pos, 2, index);
+
+ Const attr_value(attr_valstr);
+
+ for (auto cell : cells)
+ cell->attributes[attr_name] = attr_value;
+ }
+
+ scc_counter++;
+ }
+ }
+ else
+ {
+ scc_counter += GetSize(worker.sccList);
+ }
if (selectMode)
worker.select(newSelection);
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index d2e1a2e2..d97aa2b3 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -760,6 +760,9 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (!design->selected_active_module.empty()) {
arg_mod = design->selected_active_module;
arg_memb = arg;
+ } else
+ if (GetSize(arg) >= 2 && arg[0] >= 'a' && arg[0] <= 'z' && arg[1] == ':') {
+ arg_mod = "*", arg_memb = arg;
} else {
size_t pos = arg.find('/');
if (pos == std::string::npos) {
@@ -947,7 +950,7 @@ PRIVATE_NAMESPACE_BEGIN
struct SelectPass : public Pass {
SelectPass() : Pass("select", "modify and view the list of selected objects") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -961,7 +964,7 @@ struct SelectPass : public Pass {
log("list of selected objects.\n");
log("\n");
log("Note that many commands support an optional [selection] argument that can be\n");
- log("used to override the global selection for the command. The syntax of this\n");
+ log("used to YS_OVERRIDE the global selection for the command. The syntax of this\n");
log("optional argument is identical to the syntax of the <selection> argument\n");
log("described here.\n");
log("\n");
@@ -1164,7 +1167,7 @@ struct SelectPass : public Pass {
log(" select */t:SWITCH %%x:+[GATE] */t:SWITCH %%d\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool add_mode = false;
bool del_mode = false;
@@ -1263,6 +1266,7 @@ struct SelectPass : public Pass {
log_cmd_error("Option -read can not be combined with a selection expression.\n");
std::ifstream f(read_file);
+ yosys_input_files.insert(read_file);
if (f.fail())
log_error("Can't open '%s' for reading: %s\n", read_file.c_str(), strerror(errno));
@@ -1331,6 +1335,7 @@ struct SelectPass : public Pass {
FILE *f = NULL;
if (!write_file.empty()) {
f = fopen(write_file.c_str(), "w");
+ yosys_output_files.insert(write_file);
if (f == NULL)
log_error("Can't open '%s' for writing: %s\n", write_file.c_str(), strerror(errno));
}
@@ -1465,7 +1470,7 @@ struct SelectPass : public Pass {
struct CdPass : public Pass {
CdPass() : Pass("cd", "a shortcut for 'select -module <name>'") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1482,17 +1487,53 @@ struct CdPass : public Pass {
log("\n");
log(" cd ..\n");
log("\n");
+ log("Remove trailing substrings that start with '.' in current module name until\n");
+ log("the name of a module in the current design is generated, then switch to that\n");
+ log("module. Otherwise clear the current selection.\n");
+ log("\n");
+ log(" cd\n");
+ log("\n");
log("This is just a shortcut for 'select -clear'.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- if (args.size() != 2)
+ if (args.size() != 1 && args.size() != 2)
log_cmd_error("Invalid number of arguments.\n");
- if (args[1] == "..") {
+ if (args.size() == 1 || args[1] == "/") {
+ design->selection_stack.back() = RTLIL::Selection(true);
+ design->selected_active_module = std::string();
+ return;
+ }
+
+ if (args[1] == "..")
+ {
+ string modname = design->selected_active_module;
+
design->selection_stack.back() = RTLIL::Selection(true);
design->selected_active_module = std::string();
+
+ while (1)
+ {
+ size_t pos = modname.rfind('.');
+
+ if (pos == string::npos)
+ break;
+
+ modname = modname.substr(0, pos);
+ Module *mod = design->module(modname);
+
+ if (mod == nullptr)
+ continue;
+
+ design->selected_active_module = modname;
+ design->selection_stack.back() = RTLIL::Selection();
+ select_filter_active_mod(design, design->selection_stack.back());
+ design->selection_stack.back().optimize(design);
+ return;
+ }
+
return;
}
@@ -1537,7 +1578,7 @@ static void log_matches(const char *title, Module *module, T list)
struct LsPass : public Pass {
LsPass() : Pass("ls", "list modules or objects in modules") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1548,7 +1589,7 @@ struct LsPass : public Pass {
log("When an active module is selected, this prints a list of objects in the module.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx = 1;
extra_args(args, argidx, design);
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 689e3148..d38a6b3d 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -56,7 +56,7 @@ static void do_setunset(dict<RTLIL::IdString, RTLIL::Const> &attrs, const std::v
struct SetattrPass : public Pass {
SetattrPass() : Pass("setattr", "set/unset attributes on objects") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -69,7 +69,7 @@ struct SetattrPass : public Pass {
log("instead of objects within modules.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<setunset_t> setunset_list;
bool flag_mod = false;
@@ -130,7 +130,7 @@ struct SetattrPass : public Pass {
struct SetparamPass : public Pass {
SetparamPass() : Pass("setparam", "set/unset parameters on objects") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -142,7 +142,7 @@ struct SetparamPass : public Pass {
log("The -type option can be used to change the cell type of the selected cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
vector<setunset_t> setunset_list;
string new_cell_type;
@@ -188,7 +188,7 @@ struct SetparamPass : public Pass {
struct ChparamPass : public Pass {
ChparamPass() : Pass("chparam", "re-evaluate modules with new parameters") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -203,7 +203,7 @@ struct ChparamPass : public Pass {
log("List the available parameters of the selected modules.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<setunset_t> setunset_list;
dict<RTLIL::IdString, RTLIL::Const> new_parameters;
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index 26b2eb87..62d940ce 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -23,33 +23,82 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+#define MODE_ZERO 0
+#define MODE_ONE 1
+#define MODE_UNDEF 2
+#define MODE_RANDOM 3
+#define MODE_ANYSEQ 4
+#define MODE_ANYCONST 5
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+static RTLIL::Wire * add_wire(RTLIL::Module *module, std::string name, int width, bool flag_input, bool flag_output)
+{
+ RTLIL::Wire *wire = NULL;
+ name = RTLIL::escape_id(name);
+
+ if (module->count_id(name) != 0)
+ {
+ log("Module %s already has such an object %s.\n", module->name.c_str(), name.c_str());
+ name += "$";
+ return add_wire(module, name, width, flag_input, flag_output);
+ }
+ else
+ {
+ wire = module->addWire(name, width);
+ wire->port_input = flag_input;
+ wire->port_output = flag_output;
+
+ if (flag_input || flag_output) {
+ wire->port_id = module->wires_.size();
+ module->fixup_ports();
+ }
+
+ log("Added wire %s to module %s.\n", name.c_str(), module->name.c_str());
+ }
+
+ return wire;
+}
+
struct SetundefWorker
{
int next_bit_mode;
uint32_t next_bit_state;
+ vector<SigSpec*> siglist;
RTLIL::State next_bit()
{
- if (next_bit_mode == 0)
+ if (next_bit_mode == MODE_ZERO)
return RTLIL::State::S0;
- if (next_bit_mode == 1)
+ if (next_bit_mode == MODE_ONE)
return RTLIL::State::S1;
- // xorshift32
- next_bit_state ^= next_bit_state << 13;
- next_bit_state ^= next_bit_state >> 17;
- next_bit_state ^= next_bit_state << 5;
- log_assert(next_bit_state != 0);
+ if (next_bit_mode == MODE_UNDEF)
+ return RTLIL::State::Sx;
+
+ if (next_bit_mode == MODE_RANDOM)
+ {
+ // xorshift32
+ next_bit_state ^= next_bit_state << 13;
+ next_bit_state ^= next_bit_state >> 17;
+ next_bit_state ^= next_bit_state << 5;
+ log_assert(next_bit_state != 0);
- return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
+ return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
+ }
+
+ log_abort();
}
void operator()(RTLIL::SigSpec &sig)
{
+ if (next_bit_mode == MODE_ANYSEQ || next_bit_mode == MODE_ANYCONST) {
+ siglist.push_back(&sig);
+ return;
+ }
+
for (auto &bit : sig)
if (bit.wire == NULL && bit.data > RTLIL::State::S1)
bit = next_bit();
@@ -58,23 +107,35 @@ struct SetundefWorker
struct SetundefPass : public Pass {
SetundefPass() : Pass("setundef", "replace undef values with defined constants") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" setundef [options] [selection]\n");
log("\n");
- log("This command replaced undef (x) constants with defined (0/1) constants.\n");
+ log("This command replaces undef (x) constants with defined (0/1) constants.\n");
log("\n");
log(" -undriven\n");
log(" also set undriven nets to constant values\n");
log("\n");
+ log(" -expose\n");
+ log(" also expose undriven nets as inputs (use with -undriven)\n");
+ log("\n");
log(" -zero\n");
log(" replace with bits cleared (0)\n");
log("\n");
log(" -one\n");
log(" replace with bits set (1)\n");
log("\n");
+ log(" -undef\n");
+ log(" replace with undef (x) bits, may be used with -undriven\n");
+ log("\n");
+ log(" -anyseq\n");
+ log(" replace with $anyseq drivers (for formal)\n");
+ log("\n");
+ log(" -anyconst\n");
+ log(" replace with $anyconst drivers (for formal)\n");
+ log("\n");
log(" -random <seed>\n");
log(" replace with random bits using the specified integer als seed\n");
log(" value for the random number generator.\n");
@@ -83,13 +144,16 @@ struct SetundefPass : public Pass {
log(" also create/update init values for flip-flops\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool got_value = false;
bool undriven_mode = false;
+ bool expose_mode = false;
bool init_mode = false;
SetundefWorker worker;
+ log_header(design, "Executing SETUNDEF pass (replace undef values with defined constants).\n");
+
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
@@ -97,14 +161,39 @@ struct SetundefPass : public Pass {
undriven_mode = true;
continue;
}
+ if (args[argidx] == "-expose") {
+ got_value = true;
+ expose_mode = true;
+ continue;
+ }
if (args[argidx] == "-zero") {
got_value = true;
- worker.next_bit_mode = 0;
+ worker.next_bit_mode = MODE_ZERO;
+ worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-one") {
got_value = true;
- worker.next_bit_mode = 1;
+ worker.next_bit_mode = MODE_ONE;
+ worker.next_bit_state = 0;
+ continue;
+ }
+ if (args[argidx] == "-anyseq") {
+ got_value = true;
+ worker.next_bit_mode = MODE_ANYSEQ;
+ worker.next_bit_state = 0;
+ continue;
+ }
+ if (args[argidx] == "-anyconst") {
+ got_value = true;
+ worker.next_bit_mode = MODE_ANYCONST;
+ worker.next_bit_state = 0;
+ continue;
+ }
+ if (args[argidx] == "-undef") {
+ got_value = true;
+ worker.next_bit_mode = MODE_UNDEF;
+ worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-init") {
@@ -113,7 +202,7 @@ struct SetundefPass : public Pass {
}
if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
got_value = true;
- worker.next_bit_mode = 2;
+ worker.next_bit_mode = MODE_RANDOM;
worker.next_bit_state = atoi(args[++argidx].c_str()) + 1;
for (int i = 0; i < 10; i++)
worker.next_bit();
@@ -123,8 +212,13 @@ struct SetundefPass : public Pass {
}
extra_args(args, argidx, design);
+ if (expose_mode && !undriven_mode)
+ log_cmd_error("Option -expose must be used with option -undriven.\n");
if (!got_value)
- log_cmd_error("One of the options -zero, -one, or -random <seed> must be specified.\n");
+ log_cmd_error("One of the options -zero, -one, -anyseq, -anyconst, or -random <seed> must be specified.\n");
+
+ if (init_mode && (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST))
+ log_cmd_error("The options -init and -anyseq / -anyconst are exclusive.\n");
for (auto module : design->selected_modules())
{
@@ -133,25 +227,103 @@ struct SetundefPass : public Pass {
if (!module->processes.empty())
log_error("The 'setundef' command can't operate in -undriven mode on modules with processes. Run 'proc' first.\n");
- SigMap sigmap(module);
- SigPool undriven_signals;
+ if (expose_mode)
+ {
+ SigMap sigmap(module);
+ dict<SigBit, bool> wire_drivers;
+ pool<SigBit> used_wires;
+ SigPool undriven_signals;
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections()) {
+ SigSpec sig = sigmap(conn.second);
+ if (cell->input(conn.first))
+ for (auto bit : sig)
+ if (bit.wire)
+ used_wires.insert(bit);
+ if (cell->output(conn.first))
+ for (int i = 0; i < GetSize(sig); i++)
+ if (sig[i].wire)
+ wire_drivers[sig[i]] = true;
+ }
+
+ 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]] = true;
+ }
+ if (wire->port_output) {
+ SigSpec sig = sigmap(wire);
+ for (auto bit : sig)
+ if (bit.wire)
+ used_wires.insert(bit);
+ }
+ }
+
+ pool<RTLIL::Wire*> undriven_wires;
+ for (auto bit : used_wires)
+ if (!wire_drivers.count(bit))
+ undriven_wires.insert(bit.wire);
+
+ for (auto &it : undriven_wires)
+ undriven_signals.add(sigmap(it));
+
+ for (auto &it : undriven_wires)
+ if (it->port_input)
+ undriven_signals.del(sigmap(it));
+
+ CellTypes ct(design);
+ for (auto &it : module->cells_)
+ for (auto &conn : it.second->connections())
+ if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
+ undriven_signals.del(sigmap(conn.second));
+
+ RTLIL::SigSpec sig = undriven_signals.export_all();
+ for (auto &c : sig.chunks()) {
+ RTLIL::Wire * wire;
+ if (c.wire->width == c.width) {
+ wire = c.wire;
+ wire->port_input = true;
+ } else {
+ string name = c.wire->name.str() + "$[" + std::to_string(c.width + c.offset) + ":" + std::to_string(c.offset) + "]";
+ wire = add_wire(module, name, c.width, true, false);
+ module->connect(RTLIL::SigSig(c, wire));
+ }
+ log("Exposing undriven wire %s as input.\n", wire->name.c_str());
+ }
+ module->fixup_ports();
+ }
+ else
+ {
+ SigMap sigmap(module);
+ SigPool undriven_signals;
- for (auto &it : module->wires_)
- if (!it.second->port_input)
+ for (auto &it : module->wires_)
undriven_signals.add(sigmap(it.second));
- CellTypes ct(design);
- for (auto &it : module->cells_)
- for (auto &conn : it.second->connections())
- if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
- undriven_signals.del(sigmap(conn.second));
-
- RTLIL::SigSpec sig = undriven_signals.export_all();
- for (auto &c : sig.chunks()) {
- RTLIL::SigSpec bits;
- for (int i = 0; i < c.width; i++)
- bits.append(worker.next_bit());
- module->connect(RTLIL::SigSig(c, bits));
+ for (auto &it : module->wires_)
+ if (it.second->port_input)
+ undriven_signals.del(sigmap(it.second));
+
+ CellTypes ct(design);
+ for (auto &it : module->cells_)
+ for (auto &conn : it.second->connections())
+ if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
+ undriven_signals.del(sigmap(conn.second));
+
+ RTLIL::SigSpec sig = undriven_signals.export_all();
+ for (auto &c : sig.chunks()) {
+ RTLIL::SigSpec bits;
+ if (worker.next_bit_mode == MODE_ANYSEQ)
+ bits = module->Anyseq(NEW_ID, c.width);
+ else if (worker.next_bit_mode == MODE_ANYCONST)
+ bits = module->Anyconst(NEW_ID, c.width);
+ else
+ for (int i = 0; i < c.width; i++)
+ bits.append(worker.next_bit());
+ module->connect(RTLIL::SigSig(c, bits));
+ }
}
}
@@ -236,6 +408,35 @@ struct SetundefPass : public Pass {
}
module->rewrite_sigspecs(worker);
+
+ if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST)
+ {
+ vector<SigSpec*> siglist;
+ siglist.swap(worker.siglist);
+
+ for (auto sigptr : siglist)
+ {
+ SigSpec &sig = *sigptr;
+ int cursor = 0;
+
+ while (cursor < GetSize(sig))
+ {
+ int width = 0;
+ while (cursor+width < GetSize(sig) && sig[cursor+width] == State::Sx)
+ width++;
+
+ if (width > 0) {
+ if (worker.next_bit_mode == MODE_ANYSEQ)
+ sig.replace(cursor, module->Anyseq(NEW_ID, width));
+ else
+ sig.replace(cursor, module->Anyconst(NEW_ID, width));
+ cursor += width;
+ } else {
+ cursor++;
+ }
+ }
+ }
+ }
}
}
} SetundefPass;
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 3a3939a8..a4887324 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -30,6 +30,10 @@
# include <readline/readline.h>
#endif
+#ifdef YOSYS_ENABLE_EDITLINE
+# include <editline/readline.h>
+#endif
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -569,7 +573,7 @@ struct ShowWorker
struct ShowPass : public Pass {
ShowPass() : Pass("show", "generate schematics using graphviz") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -580,6 +584,7 @@ struct ShowPass : public Pass {
log("\n");
log(" -viewer <viewer>\n");
log(" Run the specified command with the graphics file as parameter.\n");
+ log(" On Windows, this pauses yosys until the viewer exits.\n");
log("\n");
log(" -format <format>\n");
log(" Generate a graphics file in the specified format. Use 'dot' to just\n");
@@ -641,7 +646,7 @@ struct ShowPass : public Pass {
log(" do not add the module name as graph title to the dot file\n");
log("\n");
log("When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n");
- log("specified, 'xdot' is used to display the schematic.\n");
+ log("specified, 'xdot' is used to display the schematic (POSIX systems only).\n");
log("\n");
log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
log("unless another prefix is specified using -prefix <prefix>.\n");
@@ -651,7 +656,7 @@ struct ShowPass : public Pass {
log("the 'show' command is executed.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Generating Graphviz representation of design.\n");
log_push();
@@ -677,6 +682,7 @@ struct ShowPass : public Pass {
bool flag_enum = false;
bool flag_abbreviate = true;
bool flag_notitle = false;
+ bool custom_prefix = false;
RTLIL::IdString colorattr;
size_t argidx;
@@ -693,6 +699,7 @@ struct ShowPass : public Pass {
}
if (arg == "-prefix" && argidx+1 < args.size()) {
prefix = args[++argidx];
+ custom_prefix = true;
continue;
}
if (arg == "-color" && argidx+2 < args.size()) {
@@ -778,6 +785,7 @@ struct ShowPass : public Pass {
for (auto filename : libfiles) {
std::ifstream f;
f.open(filename.c_str());
+ yosys_input_files.insert(filename);
if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str());
RTLIL::Design *lib = new RTLIL::Design;
@@ -793,6 +801,8 @@ struct ShowPass : public Pass {
log("Writing dot description to `%s'.\n", dot_file.c_str());
FILE *f = fopen(dot_file.c_str(), "w");
+ if (custom_prefix)
+ yosys_output_files.insert(dot_file);
if (f == NULL) {
for (auto lib : libs)
delete lib;
@@ -808,14 +818,30 @@ struct ShowPass : public Pass {
log_cmd_error("Nothing there to show.\n");
if (format != "dot" && !format.empty()) {
- std::string cmd = stringf("dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'", format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str());
+ #ifdef _WIN32
+ // system()/cmd.exe does not understand single quotes on Windows.
+ #define DOT_CMD "dot -T%s \"%s\" > \"%s.new\" && move \"%s.new\" \"%s\""
+ #else
+ #define DOT_CMD "dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'"
+ #endif
+ std::string cmd = stringf(DOT_CMD, format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str());
+ #undef DOT_CMD
log("Exec: %s\n", cmd.c_str());
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());
+ #ifdef _WIN32
+ // system()/cmd.exe does not understand single quotes nor
+ // background tasks on Windows. So we have to pause yosys
+ // until the viewer exits.
+ #define VIEW_CMD "%s \"%s\""
+ #else
+ #define VIEW_CMD "%s '%s' &"
+ #endif
+ std::string cmd = stringf(VIEW_CMD, viewer_exe.c_str(), out_file.c_str());
+ #undef VIEW_CMD
log("Exec: %s\n", cmd.c_str());
if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index 7418ec4d..bafafca4 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -247,7 +247,7 @@ struct SpliceWorker
struct SplicePass : public Pass {
SplicePass() : Pass("splice", "create explicit splicing cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -288,7 +288,7 @@ struct SplicePass : public Pass {
log("by selected wires are rewired.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool sel_by_cell = false;
bool sel_by_wire = false;
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index 14eeb066..f5a1f17b 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -37,14 +37,20 @@ struct SplitnetsWorker
new_wire_name += format.substr(0, 1);
if (width > 1) {
- new_wire_name += stringf("%d", offset+width-1);
+ if (wire->upto)
+ new_wire_name += stringf("%d", wire->start_offset+wire->width-(offset+width)-1);
+ else
+ new_wire_name += stringf("%d", wire->start_offset+offset+width-1);
if (format.size() > 2)
new_wire_name += format.substr(2, 1);
else
new_wire_name += ":";
}
- new_wire_name += stringf("%d", offset);
+ if (wire->upto)
+ new_wire_name += stringf("%d", wire->start_offset+wire->width-offset-1);
+ else
+ new_wire_name += stringf("%d", wire->start_offset+offset);
if (format.size() > 1)
new_wire_name += format.substr(1, 1);
@@ -81,7 +87,7 @@ struct SplitnetsWorker
struct SplitnetsPass : public Pass {
SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -103,7 +109,7 @@ struct SplitnetsPass : public Pass {
log(" and split nets so that no driver drives only part of a net.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_ports = false;
bool flag_driver = false;
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 362a0edf..54f4ea81 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -112,7 +112,7 @@ struct statdata_t
"$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")) {
+ "$add", "$sub", "$mul", "$div", "$mod", "$pow", "$alu")) {
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;
@@ -142,7 +142,7 @@ struct statdata_t
}
}
- void log_data()
+ void log_data(RTLIL::IdString mod_name, bool top_mod)
{
log(" Number of wires: %6d\n", num_wires);
log(" Number of wire bits: %6d\n", num_wire_bits);
@@ -163,7 +163,7 @@ struct statdata_t
if (area != 0) {
log("\n");
- log(" Chip area for this module: %f\n", area);
+ log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
}
}
};
@@ -190,6 +190,7 @@ void read_liberty_cellarea(dict<IdString, double> &cell_area, string liberty_fil
{
std::ifstream f;
f.open(liberty_file.c_str());
+ yosys_input_files.insert(liberty_file);
if (f.fail())
log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
LibertyParser libparser(f);
@@ -208,7 +209,7 @@ void read_liberty_cellarea(dict<IdString, double> &cell_area, string liberty_fil
struct StatPass : public Pass {
StatPass() : Pass("stat", "print some statistics") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -230,7 +231,7 @@ struct StatPass : public Pass {
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Printing statistics.\n");
@@ -274,7 +275,7 @@ struct StatPass : public Pass {
log("\n");
log("=== %s%s ===\n", RTLIL::id2cstr(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
log("\n");
- data.log_data();
+ data.log_data(mod->name, false);
}
if (top_mod != NULL && GetSize(mod_stat) > 1)
@@ -287,7 +288,7 @@ struct StatPass : public Pass {
statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0);
log("\n");
- data.log_data();
+ data.log_data(top_mod->name, true);
}
log("\n");
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index 3db2dbf0..ff80f385 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct TeePass : public Pass {
TeePass() : Pass("tee", "redirect command output to file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -49,7 +49,7 @@ struct TeePass : public Pass {
log(" Add/subract INT from the -v setting for this command.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<FILE*> backup_log_files, files_to_close;
int backup_log_verbose_level = log_verbose_level;
@@ -65,6 +65,7 @@ struct TeePass : public Pass {
if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) {
const char *open_mode = args[argidx] == "-o" ? "w" : "a+";
FILE *f = fopen(args[++argidx].c_str(), open_mode);
+ yosys_input_files.insert(args[argidx]);
if (f == NULL) {
for (auto cf : files_to_close)
fclose(cf);
diff --git a/passes/cmds/torder.cc b/passes/cmds/torder.cc
index 56223610..3c0eac8d 100644
--- a/passes/cmds/torder.cc
+++ b/passes/cmds/torder.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct TorderPass : public Pass {
TorderPass() : Pass("torder", "print cells in topological order") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -43,7 +43,7 @@ struct TorderPass : public Pass {
log(" are not used in topological sorting. this option deactivates that.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool noautostop = false;
dict<IdString, pool<IdString>> stop_db;
diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc
index 1a5f873f..f5305cde 100644
--- a/passes/cmds/trace.cc
+++ b/passes/cmds/trace.cc
@@ -25,34 +25,34 @@ PRIVATE_NAMESPACE_BEGIN
struct TraceMonitor : public RTLIL::Monitor
{
- virtual void notify_module_add(RTLIL::Module *module) YS_OVERRIDE
+ 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) YS_OVERRIDE
+ 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) YS_OVERRIDE
+ 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) YS_OVERRIDE
+ 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) YS_OVERRIDE
+ 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) YS_OVERRIDE
+ void notify_blackout(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Blackout in module %s:\n", log_id(module));
}
@@ -60,7 +60,7 @@ struct TraceMonitor : public RTLIL::Monitor
struct TracePass : public Pass {
TracePass() : Pass("trace", "redirect command output to file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -70,7 +70,7 @@ struct TracePass : public Pass {
log("the design in real time.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -95,4 +95,3 @@ struct TracePass : public Pass {
} TracePass;
PRIVATE_NAMESPACE_END
-
diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc
index b7826593..9613b462 100644
--- a/passes/cmds/write_file.cc
+++ b/passes/cmds/write_file.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct WriteFileFrontend : public Frontend {
WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -44,7 +44,7 @@ struct WriteFileFrontend : public Frontend {
log(" EOT\n");
log("\n");
}
- virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
bool append_mode = false;
std::string output_filename;
@@ -67,6 +67,7 @@ struct WriteFileFrontend : public Frontend {
extra_args(f, filename, args, argidx);
FILE *of = fopen(output_filename.c_str(), append_mode ? "a" : "w");
+ yosys_output_files.insert(output_filename);
char buffer[64 * 1024];
int bytes;
diff --git a/passes/equiv/equiv_add.cc b/passes/equiv/equiv_add.cc
index 0494a724..71599f46 100644
--- a/passes/equiv/equiv_add.cc
+++ b/passes/equiv/equiv_add.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EquivAddPass : public Pass {
EquivAddPass() : Pass("equiv_add", "add a $equiv cell") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -39,7 +39,7 @@ struct EquivAddPass : public Pass {
log("This command adds $equiv cells for the ports of the specified cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
bool try_mode = false;
diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc
index c958c3de..bcc68d6d 100644
--- a/passes/equiv/equiv_induct.cc
+++ b/passes/equiv/equiv_induct.cc
@@ -162,7 +162,7 @@ struct EquivInductWorker
struct EquivInductPass : public Pass {
EquivInductPass() : Pass("equiv_induct", "proving $equiv cells using temporal induction") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -192,7 +192,7 @@ struct EquivInductPass : public Pass {
log("after reset.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
int success_counter = 0;
bool model_undef = false;
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
index 40ca4262..b1f88d55 100644
--- a/passes/equiv/equiv_make.cc
+++ b/passes/equiv/equiv_make.cc
@@ -260,11 +260,11 @@ struct EquivMakeWorker
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);
+ log(" Skipping signal bit %s [%d]: undriven on gold side.\n", id2cstr(gold_wire->name), i);
continue;
}
if (undriven_bits.count(assign_map(SigBit(gate_wire, i)))) {
- log(" Skipping signal bit %d: undriven on gate side.\n", i);
+ log(" Skipping signal bit %s [%d]: undriven on gate side.\n", id2cstr(gate_wire->name), i);
continue;
}
equiv_mod->addEquiv(NEW_ID, SigSpec(gold_wire, i), SigSpec(gate_wire, i), SigSpec(wire, i));
@@ -390,7 +390,7 @@ struct EquivMakeWorker
struct EquivMakePass : public Pass {
EquivMakePass() : Pass("equiv_make", "prepare a circuit for equivalence checking") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -415,7 +415,7 @@ struct EquivMakePass : public Pass {
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)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
EquivMakeWorker worker;
worker.ct.setup(design);
diff --git a/passes/equiv/equiv_mark.cc b/passes/equiv/equiv_mark.cc
index 22c50176..135eaf14 100644
--- a/passes/equiv/equiv_mark.cc
+++ b/passes/equiv/equiv_mark.cc
@@ -204,7 +204,7 @@ struct EquivMarkWorker
struct EquivMarkPass : public Pass {
EquivMarkPass() : Pass("equiv_mark", "mark equivalence checking regions") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -216,7 +216,7 @@ struct EquivMarkPass : public Pass {
log("wires and cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
log_header(design, "Executing EQUIV_MARK pass.\n");
diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc
index eb2e5a17..e06f9515 100644
--- a/passes/equiv/equiv_miter.cc
+++ b/passes/equiv/equiv_miter.cc
@@ -261,7 +261,7 @@ struct EquivMiterWorker
struct EquivMiterPass : public Pass {
EquivMiterPass() : Pass("equiv_miter", "extract miter from equiv circuit") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -282,7 +282,7 @@ struct EquivMiterPass : public Pass {
log(" Create compare logic that handles undefs correctly\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
EquivMiterWorker worker;
worker.ct.setup(design);
diff --git a/passes/equiv/equiv_purge.cc b/passes/equiv/equiv_purge.cc
index 163b1009..18b3e7d3 100644
--- a/passes/equiv/equiv_purge.cc
+++ b/passes/equiv/equiv_purge.cc
@@ -80,7 +80,7 @@ struct EquivPurgeWorker
Wire *wire = module->addWire(name, GetSize(sig));
wire->port_input = true;
module->connect(sig, wire);
- log(" Module input: %s\n", log_signal(wire));
+ log(" Module input: %s (%s)\n", log_signal(wire), log_signal(sig));
return module->addWire(NEW_ID, GetSize(sig));
}
}
@@ -142,7 +142,7 @@ struct EquivPurgeWorker
for (auto bit : queue)
visited.insert(bit);
-
+
for (auto bit : queue)
{
auto &cells = up_bit2cells[bit];
@@ -176,7 +176,7 @@ struct EquivPurgeWorker
struct EquivPurgePass : public Pass {
EquivPurgePass() : Pass("equiv_purge", "purge equivalence checking module") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -187,7 +187,7 @@ struct EquivPurgePass : public Pass {
log("ports as needed.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
log_header(design, "Executing EQUIV_PURGE pass.\n");
diff --git a/passes/equiv/equiv_remove.cc b/passes/equiv/equiv_remove.cc
index 770497a5..c5c28c7d 100644
--- a/passes/equiv/equiv_remove.cc
+++ b/passes/equiv/equiv_remove.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EquivRemovePass : public Pass {
EquivRemovePass() : Pass("equiv_remove", "remove $equiv cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -40,7 +40,7 @@ struct EquivRemovePass : public Pass {
log(" keep gate circuit\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
bool mode_gold = false;
bool mode_gate = false;
diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc
index 49963ed6..c2fab26f 100644
--- a/passes/equiv/equiv_simple.cc
+++ b/passes/equiv/equiv_simple.cc
@@ -35,13 +35,14 @@ struct EquivSimpleWorker
ezSatPtr ez;
SatGen satgen;
int max_seq;
+ bool short_cones;
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) :
+ EquivSimpleWorker(const vector<Cell*> &equiv_cells, SigMap &sigmap, dict<SigBit, Cell*> &bit2driver, int max_seq, bool short_cones, 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)
+ sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), short_cones(short_cones), verbose(verbose)
{
satgen.model_undef = model_undef;
}
@@ -59,7 +60,7 @@ struct EquivSimpleWorker
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 (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_")) {
if (!conn.first.in("\\CLK", "\\C"))
next_seed.insert(bit);
} else
@@ -142,22 +143,44 @@ struct EquivSimpleWorker
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);
+ if (short_cones)
+ {
+ 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);
+ 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);
+ }
+ else
+ {
+ short_cells_cone_a = full_cells_cone_a;
+ short_bits_cone_a = full_bits_cone_a;
+ next_seed_a.swap(seed_a);
+
+ short_cells_cone_b = full_cells_cone_b;
+ short_bits_cone_b = full_bits_cone_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));
+ #if 0
+ for (auto cell : short_cells_cone_a)
+ log(" A-side cell: %s\n", log_id(cell));
+
+ for (auto cell : short_cells_cone_b)
+ log(" B-side cell: %s\n", log_id(cell));
+ #endif
+ }
for (auto cell : problem_cells) {
auto key = pair<Cell*, int>(cell, step+1);
@@ -250,7 +273,7 @@ struct EquivSimpleWorker
struct EquivSimplePass : public Pass {
EquivSimplePass() : Pass("equiv_simple", "try proving simple $equiv instances") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -264,6 +287,10 @@ struct EquivSimplePass : public Pass {
log(" -undef\n");
log(" enable modelling of undef states\n");
log("\n");
+ log(" -short\n");
+ log(" create shorter input cones that stop at shared nodes. This yields\n");
+ log(" simpler SAT problems but sometimes fails to prove equivalence.\n");
+ log("\n");
log(" -nogroup\n");
log(" disabling grouping of $equiv cells by output wire\n");
log("\n");
@@ -271,9 +298,9 @@ struct EquivSimplePass : public Pass {
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)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
- bool verbose = false, model_undef = false, nogroup = false;
+ bool verbose = false, short_cones = false, model_undef = false, nogroup = false;
int success_counter = 0;
int max_seq = 1;
@@ -285,6 +312,10 @@ struct EquivSimplePass : public Pass {
verbose = true;
continue;
}
+ if (args[argidx] == "-short") {
+ short_cones = true;
+ continue;
+ }
if (args[argidx] == "-undef") {
model_undef = true;
continue;
@@ -329,7 +360,7 @@ struct EquivSimplePass : public Pass {
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_"))
+ if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_"))
continue;
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_output(cell->type, conn.first))
@@ -346,7 +377,7 @@ struct EquivSimplePass : public Pass {
for (auto it2 : it.second)
cells.push_back(it2.second);
- EquivSimpleWorker worker(cells, sigmap, bit2driver, max_seq, verbose, model_undef);
+ EquivSimpleWorker worker(cells, sigmap, bit2driver, max_seq, short_cones, verbose, model_undef);
success_counter += worker.run();
}
}
diff --git a/passes/equiv/equiv_status.cc b/passes/equiv/equiv_status.cc
index 7b9230b3..b4a93ccf 100644
--- a/passes/equiv/equiv_status.cc
+++ b/passes/equiv/equiv_status.cc
@@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
struct EquivStatusPass : public Pass {
EquivStatusPass() : Pass("equiv_status", "print status of equivalent checking module") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -36,7 +36,7 @@ struct EquivStatusPass : public Pass {
log(" produce an error if any unproven $equiv cell is found\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
bool assert_mode = false;
int unproven_count = 0;
diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc
index c4ced6a7..a7973fd0 100644
--- a/passes/equiv/equiv_struct.cc
+++ b/passes/equiv/equiv_struct.cc
@@ -283,7 +283,7 @@ struct EquivStructWorker
struct EquivStructPass : public Pass {
EquivStructPass() : Pass("equiv_struct", "structural equivalence checking") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -314,7 +314,7 @@ struct EquivStructPass : public Pass {
log(" maximum number of iterations to run before aborting\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
pool<IdString> fwonly_cells({ "$equiv" });
bool mode_icells = false;
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index 997558b8..c5cb338a 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FsmPass : public Pass {
FsmPass() : Pass("fsm", "extract and optimize finite state machines") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -68,7 +68,7 @@ struct FsmPass : public Pass {
log(" passed through to fsm_recode pass\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_nomap = false;
bool flag_norecode = false;
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index 6a560f16..fc504e98 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -180,7 +180,7 @@ static void detect_fsm(RTLIL::Wire *wire)
for (auto &port_it : cell->connections())
if (cell->output(port_it.first)) {
SigSpec sig = assign_map(port_it.second);
- Const val(set_output ? State::S1 : State::S0, GetSize(sig));
+ Const val(set_output ? State::S1 : State::S0, GetSize(sig));
ce.set(sig, val);
}
}
@@ -215,7 +215,7 @@ static void detect_fsm(RTLIL::Wire *wire)
for (auto w : warnings) warnmsg += " " + w;
log_warning("%s", warnmsg.c_str());
} else {
- log("FSM state register %s.%s already has fsm_encoding attribute.\n", log_id(wire->module), log_id(wire));
+ log("FSM state register %s.%s already has fsm_encoding attribute.\n", log_id(wire->module), log_id(wire));
}
}
else
@@ -245,7 +245,7 @@ static void detect_fsm(RTLIL::Wire *wire)
struct FsmDetectPass : public Pass {
FsmDetectPass() : Pass("fsm_detect", "finding FSMs in design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -261,7 +261,7 @@ struct FsmDetectPass : public Pass {
log("'fsm_encoding' attribute to \"none\".\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_DETECT pass (finding FSMs in design).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index e7b9dcf9..c34d0c15 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -54,13 +54,27 @@ struct FsmExpand
if (cell->getPort("\\A").size() < 2)
return true;
+ int in_bits = 0;
RTLIL::SigSpec new_signals;
- if (cell->hasPort("\\A"))
+
+ if (cell->hasPort("\\A")) {
+ in_bits += GetSize(cell->getPort("\\A"));
new_signals.append(assign_map(cell->getPort("\\A")));
- if (cell->hasPort("\\B"))
+ }
+
+ if (cell->hasPort("\\B")) {
+ in_bits += GetSize(cell->getPort("\\B"));
new_signals.append(assign_map(cell->getPort("\\B")));
- if (cell->hasPort("\\S"))
+ }
+
+ if (cell->hasPort("\\S")) {
+ in_bits += GetSize(cell->getPort("\\S"));
new_signals.append(assign_map(cell->getPort("\\S")));
+ }
+
+ if (in_bits > 8)
+ return false;
+
if (cell->hasPort("\\Y"))
new_signals.append(assign_map(cell->getPort("\\Y")));
@@ -173,6 +187,16 @@ struct FsmExpand
new_ctrl_out.append(output_sig);
fsm_cell->setPort("\\CTRL_OUT", new_ctrl_out);
+ if (GetSize(input_sig) > 10)
+ log_warning("Cell %s.%s (%s) has %d input bits, merging into FSM %s.%s might be problematic.\n",
+ log_id(cell->module), log_id(cell), log_id(cell->type),
+ GetSize(input_sig), log_id(fsm_cell->module), log_id(fsm_cell));
+
+ if (GetSize(fsm_data.transition_table) > 10000)
+ log_warning("Transition table for FSM %s.%s already has %d rows, merging more cells "
+ "into this FSM might be problematic.\n", log_id(fsm_cell->module), log_id(fsm_cell),
+ GetSize(fsm_data.transition_table));
+
std::vector<FsmData::transition_t> new_transition_table;
for (auto &tr : fsm_data.transition_table) {
for (int i = 0; i < (1 << input_sig.size()); i++) {
@@ -241,7 +265,7 @@ struct FsmExpand
struct FsmExpandPass : public Pass {
FsmExpandPass() : Pass("fsm_expand", "expand FSM cells by merging logic into it") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -255,7 +279,7 @@ struct FsmExpandPass : public Pass {
log("word-wide cells. Call with -full to consider all cells for merging.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool full_mode = false;
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index 1cbfcfae..8eb1872f 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -120,7 +120,7 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::st
*/
struct FsmExportPass : public Pass {
FsmExportPass() : Pass("fsm_export", "exporting FSMs to KISS2 files") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -143,7 +143,7 @@ struct FsmExportPass : public Pass {
log(" use binary state encoding as state names instead of s0, s1, ...\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
dict<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
std::string arg;
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index 8a4ee3f2..67551f67 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -401,7 +401,7 @@ static void extract_fsm(RTLIL::Wire *wire)
struct FsmExtractPass : public Pass {
FsmExtractPass() : Pass("fsm_extract", "extracting FSMs in design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -417,7 +417,7 @@ struct FsmExtractPass : public Pass {
log("'opt_clean' pass to eliminate this signal.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_EXTRACT pass (extracting FSM from design).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
index 2cc1a7d5..0548259e 100644
--- a/passes/fsm/fsm_info.cc
+++ b/passes/fsm/fsm_info.cc
@@ -30,7 +30,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FsmInfoPass : public Pass {
FsmInfoPass() : Pass("fsm_info", "print information on finite state machines") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -41,7 +41,7 @@ struct FsmInfoPass : public Pass {
log("pass so that this information is included in the synthesis log file.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index c4230375..90c95891 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -274,9 +274,6 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
{
RTLIL::SigSpec sig_a(RTLIL::State::Sx, next_state_wire->width);
RTLIL::SigSpec sig_b, sig_s;
- int reset_state = fsm_data.reset_state;
- if (reset_state < 0)
- reset_state = 0;
for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
RTLIL::Const state = fsm_data.state_table[i];
@@ -325,7 +322,7 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
struct FsmMapPass : public Pass {
FsmMapPass() : Pass("fsm_map", "mapping FSMs to basic logic") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -334,7 +331,7 @@ struct FsmMapPass : public Pass {
log("This pass translates FSM cells to flip-flops and logic.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_MAP pass (mapping FSMs to basic logic).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index 5b1da44f..3a6ac274 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -323,7 +323,7 @@ PRIVATE_NAMESPACE_BEGIN
struct FsmOptPass : public Pass {
FsmOptPass() : Pass("fsm_opt", "optimize finite state machines") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -334,7 +334,7 @@ struct FsmOptPass : public Pass {
log("combination with the 'opt_clean' pass (see also 'help fsm').\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FSM_OPT pass (simple optimizations of FSMs).\n");
extra_args(args, 1, design);
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index e1bde728..fa1ff48c 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -126,7 +126,7 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
struct FsmRecodePass : public Pass {
FsmRecodePass() : Pass("fsm_recode", "recoding finite state machines") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -151,7 +151,7 @@ struct FsmRecodePass : public Pass {
log(" .map <old_bitpattern> <new_bitpattern>\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
FILE *fm_set_fsm_file = NULL;
FILE *encfile = NULL;
diff --git a/passes/hierarchy/Makefile.inc b/passes/hierarchy/Makefile.inc
index 1fb669c1..b3f139b7 100644
--- a/passes/hierarchy/Makefile.inc
+++ b/passes/hierarchy/Makefile.inc
@@ -1,5 +1,5 @@
OBJS += passes/hierarchy/hierarchy.o
-OBJS += passes/hierarchy/singleton.o
+OBJS += passes/hierarchy/uniquify.o
OBJS += passes/hierarchy/submod.o
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index e21a7a4e..5df69848 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -18,6 +18,7 @@
*/
#include "kernel/yosys.h"
+#include "frontends/verific/verific.h"
#include <stdlib.h>
#include <stdio.h>
#include <set>
@@ -138,7 +139,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
}
}
-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, bool flag_simcheck, std::vector<std::string> &libdirs)
{
bool did_something = false;
std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
@@ -173,24 +174,24 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
for (auto &dir : libdirs)
{
- filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
- if (check_file_exists(filename)) {
- std::vector<std::string> args;
- args.push_back(filename);
- Frontend::frontend_call(design, NULL, filename, "verilog");
- goto loaded_module;
- }
-
- filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
- if (check_file_exists(filename)) {
- std::vector<std::string> args;
- args.push_back(filename);
- Frontend::frontend_call(design, NULL, filename, "ilang");
- goto loaded_module;
+ static const vector<pair<string, string>> extensions_list =
+ {
+ {".v", "verilog"},
+ {".sv", "verilog -sv"},
+ {".il", "ilang"}
+ };
+
+ for (auto &ext : extensions_list)
+ {
+ filename = dir + "/" + RTLIL::unescape_id(cell->type) + ext.first;
+ if (check_file_exists(filename)) {
+ Frontend::frontend_call(design, NULL, filename, ext.second);
+ goto loaded_module;
+ }
}
}
- if (flag_check && cell->type[0] != '$')
+ if ((flag_check || flag_simcheck) && cell->type[0] != '$')
log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue;
@@ -200,7 +201,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
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)
+ if (flag_check || flag_simcheck)
{
RTLIL::Module *mod = design->module(cell->type);
for (auto &conn : cell->connections())
@@ -213,15 +214,19 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
for (auto &param : cell->parameters)
- if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$')
+ if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL)
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n",
log_id(cell->type), log_id(module), log_id(cell), log_id(param.first));
}
- if (cell->parameters.size() == 0)
+ if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
+ if (flag_simcheck)
+ log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n",
+ cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue;
+ }
- if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox"))
+ if (cell->parameters.size() == 0)
continue;
RTLIL::Module *mod = design->modules_[cell->type];
@@ -254,7 +259,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
if (mod->wires_.count(portname) == 0)
log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
int port_size = mod->wires_.at(portname)->width;
- if (conn_size == port_size)
+ if (conn_size == port_size || conn_size == 0)
continue;
if (conn_size != port_size*num)
log_error("Array cell `%s.%s' has invalid port vs. signal size for port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
@@ -317,7 +322,7 @@ 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.in("$assert", "$assume"))
+ if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in("$assert", "$assume", "$live", "$fair", "$cover"))
return cache[mod] = true;
}
return cache[mod];
@@ -338,7 +343,7 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
struct HierarchyPass : public Pass {
HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -354,6 +359,10 @@ struct HierarchyPass : public Pass {
log(" also check the design hierarchy. this generates an error when\n");
log(" an unknown module is used as cell type.\n");
log("\n");
+ log(" -simcheck\n");
+ log(" like -check, but also thow an error if blackbox modules are\n");
+ log(" instantiated, and throw an error if the design has no top module\n");
+ log("\n");
log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n");
log(" modules. use this option to also remove unused blackbox modules.\n");
@@ -367,6 +376,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(" -keep_portwidths\n");
+ log(" per default this pass adjusts the port width on cells that are\n");
+ log(" module instances when the width does not match the module port. this\n");
+ log(" 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");
@@ -400,18 +414,21 @@ struct HierarchyPass : public Pass {
log("in the current design.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
bool flag_check = false;
+ bool flag_simcheck = false;
bool purge_lib = false;
RTLIL::Module *top_mod = NULL;
+ std::string load_top_mod;
std::vector<std::string> libdirs;
bool auto_top_mode = false;
bool generate_mode = false;
bool keep_positionals = false;
+ bool keep_portwidths = false;
bool nokeep_asserts = false;
std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports;
@@ -419,7 +436,7 @@ struct HierarchyPass : public Pass {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
- if (args[argidx] == "-generate" && !flag_check && !top_mod) {
+ if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !top_mod) {
generate_mode = true;
log("Entering generate mode.\n");
while (++argidx < args.size()) {
@@ -462,6 +479,10 @@ struct HierarchyPass : public Pass {
flag_check = true;
continue;
}
+ if (args[argidx] == "-simcheck") {
+ flag_simcheck = true;
+ continue;
+ }
if (args[argidx] == "-purge_lib") {
purge_lib = true;
continue;
@@ -470,6 +491,10 @@ struct HierarchyPass : public Pass {
keep_positionals = true;
continue;
}
+ if (args[argidx] == "-keep_portwidths") {
+ keep_portwidths = true;
+ continue;
+ }
if (args[argidx] == "-nokeep_asserts") {
nokeep_asserts = true;
continue;
@@ -488,7 +513,7 @@ struct HierarchyPass : public Pass {
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
if (top_mod == NULL)
- log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
+ load_top_mod = args[argidx];
continue;
}
if (args[argidx] == "-auto-top") {
@@ -499,6 +524,22 @@ struct HierarchyPass : public Pass {
}
extra_args(args, argidx, design, false);
+ if (!load_top_mod.empty()) {
+#ifdef YOSYS_ENABLE_VERIFIC
+ if (verific_import_pending) {
+ verific_import(design, load_top_mod);
+ top_mod = design->module(RTLIL::escape_id(load_top_mod));
+ }
+#endif
+ if (top_mod == NULL)
+ log_cmd_error("Module `%s' not found!\n", load_top_mod.c_str());
+ } else {
+#ifdef YOSYS_ENABLE_VERIFIC
+ if (verific_import_pending)
+ verific_import(design);
+#endif
+ }
+
if (generate_mode) {
generate(design, generate_cells, generate_ports);
return;
@@ -524,6 +565,9 @@ struct HierarchyPass : public Pass {
log("Automatically selected %s as design top module.\n", log_id(top_mod));
}
+ if (flag_simcheck && top_mod == nullptr)
+ log_error("Design has no top module.\n");
+
bool did_something = true;
while (did_something)
{
@@ -539,7 +583,7 @@ struct HierarchyPass : public Pass {
}
for (auto module : used_modules) {
- if (expand_module(design, module, flag_check, libdirs))
+ if (expand_module(design, module, flag_check, flag_simcheck, libdirs))
did_something = true;
}
}
@@ -614,6 +658,72 @@ struct HierarchyPass : public Pass {
}
}
+ std::set<Module*> blackbox_derivatives;
+ std::vector<Module*> design_modules = design->modules();
+
+ for (auto module : design_modules)
+ for (auto cell : module->cells())
+ {
+ Module *m = design->module(cell->type);
+
+ if (m == nullptr)
+ continue;
+
+ if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) {
+ IdString new_m_name = m->derive(design, cell->parameters, true);
+ if (new_m_name.empty())
+ continue;
+ if (new_m_name != m->name) {
+ m = design->module(new_m_name);
+ blackbox_derivatives.insert(m);
+ }
+ }
+
+ for (auto &conn : cell->connections())
+ {
+ Wire *w = m->wire(conn.first);
+
+ if (w == nullptr || w->port_id == 0)
+ continue;
+
+ if (GetSize(conn.second) == 0)
+ continue;
+
+ SigSpec sig = conn.second;
+
+ if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
+ {
+ if (GetSize(w) < GetSize(conn.second))
+ {
+ int n = GetSize(conn.second) - GetSize(w);
+ if (!w->port_input && w->port_output)
+ module->connect(sig.extract(GetSize(w), n), Const(0, n));
+ sig.remove(GetSize(w), n);
+ }
+ else
+ {
+ int n = GetSize(w) - GetSize(conn.second);
+ if (w->port_input && !w->port_output)
+ sig.append(Const(0, n));
+ else
+ sig.append(module->addWire(NEW_ID, n));
+ }
+
+ if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
+ log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
+ log_id(conn.first), GetSize(conn.second), GetSize(sig));
+ cell->setPort(conn.first, sig);
+ }
+
+ if (w->port_output && !w->port_input && sig.has_const())
+ log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n",
+ log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig));
+ }
+ }
+
+ for (auto module : blackbox_derivatives)
+ design->remove(module);
+
log_pop();
}
} HierarchyPass;
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index 9f312f82..ec242aa1 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -169,6 +169,7 @@ struct SubmodWorker
}
new_mod->fixup_ports();
+ ct.setup_module(new_mod);
for (RTLIL::Cell *cell : submod.cells) {
RTLIL::Cell *new_cell = new_mod->addCell(cell->name, cell);
@@ -268,7 +269,7 @@ struct SubmodWorker
struct SubmodPass : public Pass {
SubmodPass() : Pass("submod", "moving part of a module to a new submodule") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -296,7 +297,7 @@ struct SubmodPass : public Pass {
log("with -copy to not modify the source module.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing SUBMOD pass (moving cells to submodules as requested).\n");
log_push();
diff --git a/passes/hierarchy/singleton.cc b/passes/hierarchy/uniquify.cc
index 03c365fb..c88ecd82 100644
--- a/passes/hierarchy/singleton.cc
+++ b/passes/hierarchy/uniquify.cc
@@ -22,28 +22,28 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-struct SingletonPass : public Pass {
- SingletonPass() : Pass("singleton", "create singleton modules") { }
- virtual void help()
+struct UniquifyPass : public Pass {
+ UniquifyPass() : Pass("uniquify", "create unique copies of modules") { }
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" singleton [selection]\n");
+ log(" uniquify [selection]\n");
log("\n");
log("By default, a module that is instantiated by several other modules is only\n");
log("kept once in the design. This preserves the original modularity of the design\n");
log("and reduces the overall size of the design in memory. But it prevents certain\n");
- log("optimizations and other operations on the design. This pass creates singleton\n");
+ log("optimizations and other operations on the design. This pass creates unique\n");
log("modules for all selected cells. The created modules are marked with the\n");
- log("'singleton' attribute.\n");
+ log("'unique' attribute.\n");
log("\n");
- log("This commands only operates on modules that by themself have the 'singleton'\n");
- log("attribute set (the 'top' module is a singleton implicitly).\n");
+ log("This commands only operates on modules that by themself have the 'unique'\n");
+ log("attribute set (the 'top' module is unique implicitly).\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- log_header(design, "Executing SINGLETON pass (creating singleton modules).\n");
+ log_header(design, "Executing UNIQUIFY pass (creating unique copies of modules).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -56,7 +56,7 @@ struct SingletonPass : public Pass {
extra_args(args, argidx, design);
bool did_something = true;
- int singleton_cnt = 0;
+ int count = 0;
while (did_something)
{
@@ -64,12 +64,13 @@ struct SingletonPass : public Pass {
for (auto module : design->selected_modules())
{
- if (!module->get_bool_attribute("\\singleton") && !module->get_bool_attribute("\\top"))
+ if (!module->get_bool_attribute("\\unique") && !module->get_bool_attribute("\\top"))
continue;
for (auto cell : module->selected_cells())
{
- auto tmod = design->module(cell->type);
+ Module *tmod = design->module(cell->type);
+ IdString newname = module->name.str() + "." + log_id(cell->name);
if (tmod == nullptr)
continue;
@@ -77,25 +78,25 @@ struct SingletonPass : public Pass {
if (tmod->get_bool_attribute("\\blackbox"))
continue;
- if (tmod->get_bool_attribute("\\singleton"))
+ if (tmod->get_bool_attribute("\\unique") && newname == tmod->name)
continue;
- cell->type = module->name.str() + "." + log_id(cell->name);
- log("Creating singleton '%s'.\n", log_id(cell->type));
+ log("Creating module %s from %s.\n", log_id(newname), log_id(tmod));
auto smod = tmod->clone();
- smod->name = cell->type;
- smod->set_bool_attribute("\\singleton");
+ smod->name = newname;
+ cell->type = newname;
+ smod->set_bool_attribute("\\unique");
design->add(smod);
did_something = true;
- singleton_cnt++;
+ count++;
}
}
}
- log("Created %d singleton modules.\n", singleton_cnt);
+ log("Created %d unique modules.\n", count);
}
-} SingletonPass;
+} UniquifyPass;
PRIVATE_NAMESPACE_END
diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc
index ad359c01..e468c3a0 100644
--- a/passes/memory/Makefile.inc
+++ b/passes/memory/Makefile.inc
@@ -7,4 +7,5 @@ OBJS += passes/memory/memory_unpack.o
OBJS += passes/memory/memory_bram.o
OBJS += passes/memory/memory_map.o
OBJS += passes/memory/memory_memx.o
+OBJS += passes/memory/memory_nordff.o
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index 947d598b..712bc253 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct MemoryPass : public Pass {
MemoryPass() : Pass("memory", "translate memories to basic cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -48,7 +48,7 @@ struct MemoryPass : public Pass {
log("or multiport memory blocks if called with the -nomap option.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_nomap = false;
bool flag_nordff = false;
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index a7f9cf38..e8552bbc 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -1120,7 +1120,7 @@ void handle_cell(Cell *cell, const rules_t &rules)
struct MemoryBramPass : public Pass {
MemoryBramPass() : Pass("memory_bram", "map memories to block rams") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1210,7 +1210,7 @@ struct MemoryBramPass : public Pass {
log("the data bits to accommodate the enable pattern of port A.\n");
log("\n");
}
- virtual void execute(vector<string> args, Design *design)
+ void execute(vector<string> args, Design *design) YS_OVERRIDE
{
rules_t rules;
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index ab66e3fb..70d98713 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -246,7 +246,7 @@ static void handle_module(Design *design, Module *module)
struct MemoryCollectPass : public Pass {
MemoryCollectPass() : Pass("memory_collect", "creating multi-port memory cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -256,7 +256,7 @@ struct MemoryCollectPass : public Pass {
log("memory cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_COLLECT pass (generating $mem cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 40691d16..32df1917 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -33,8 +33,20 @@ struct MemoryDffWorker
dict<SigBit, int> sigbit_users_count;
dict<SigSpec, Cell*> mux_cells_a, mux_cells_b;
pool<Cell*> forward_merged_dffs, candidate_dffs;
+ pool<SigBit> init_bits;
- MemoryDffWorker(Module *module) : module(module), sigmap(module) { }
+ MemoryDffWorker(Module *module) : module(module), sigmap(module)
+ {
+ for (auto wire : module->wires()) {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+ SigSpec sig = sigmap(wire);
+ Const initval = wire->attributes.count("\\init");
+ for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ init_bits.insert(sig[i]);
+ }
+ }
bool find_sig_before_dff(RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
{
@@ -45,6 +57,9 @@ struct MemoryDffWorker
if (bit.wire == NULL)
continue;
+ if (!after && init_bits.count(sigmap(bit)))
+ return false;
+
for (auto cell : dff_cells)
{
if (after && forward_merged_dffs.count(cell))
@@ -72,6 +87,9 @@ struct MemoryDffWorker
if (d.size() != 1)
continue;
+ if (after && init_bits.count(d))
+ return false;
+
bit = d;
clk = this_clk;
clk_polarity = this_clk_polarity;
@@ -265,7 +283,7 @@ struct MemoryDffWorker
struct MemoryDffPass : public Pass {
MemoryDffPass() : Pass("memory_dff", "merge input/output DFFs into memories") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -279,7 +297,7 @@ struct MemoryDffPass : public Pass {
log(" do not merge registers on read ports\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_wr_only = false;
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index bffeec85..a0b808e5 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -352,7 +352,7 @@ struct MemoryMapWorker
struct MemoryMapPass : public Pass {
MemoryMapPass() : Pass("memory_map", "translate multiport memories to basic cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -362,7 +362,7 @@ struct MemoryMapPass : public Pass {
log("pass to word-wide DFFs and address decoders.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
extra_args(args, 1, design);
for (auto mod : design->selected_modules())
diff --git a/passes/memory/memory_memx.cc b/passes/memory/memory_memx.cc
index 2b02e249..95837016 100644
--- a/passes/memory/memory_memx.cc
+++ b/passes/memory/memory_memx.cc
@@ -28,7 +28,7 @@ PRIVATE_NAMESPACE_BEGIN
struct MemoryMemxPass : public Pass {
MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -38,7 +38,7 @@ struct MemoryMemxPass : public Pass {
log("behavior for out-of-bounds memory reads and writes.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_MEMX pass (converting $mem cells to logic and flip-flops).\n");
extra_args(args, 1, design);
diff --git a/passes/memory/memory_nordff.cc b/passes/memory/memory_nordff.cc
new file mode 100644
index 00000000..ba0361c0
--- /dev/null
+++ b/passes/memory/memory_nordff.cc
@@ -0,0 +1,121 @@
+/*
+ * 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 MemoryNordffPass : public Pass {
+ MemoryNordffPass() : Pass("memory_nordff", "extract read port FFs from memories") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" memory_nordff [options] [selection]\n");
+ log("\n");
+ log("This pass extracts FFs from memory read ports. This results in a netlist\n");
+ log("similar to what one would get from calling memory_dff with -nordff.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing MEMORY_NORDFF pass (extracting $dff cells from $mem).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ // if (args[argidx] == "-nordff" || args[argidx] == "-wr_only") {
+ // flag_wr_only = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ for (auto cell : vector<Cell*>(module->selected_cells()))
+ {
+ if (cell->type != "$mem")
+ continue;
+
+ int rd_ports = cell->getParam("\\RD_PORTS").as_int();
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+
+ SigSpec rd_addr = cell->getPort("\\RD_ADDR");
+ SigSpec rd_data = cell->getPort("\\RD_DATA");
+ SigSpec rd_clk = cell->getPort("\\RD_CLK");
+ SigSpec rd_en = cell->getPort("\\RD_EN");
+ Const rd_clk_enable = cell->getParam("\\RD_CLK_ENABLE");
+ Const rd_clk_polarity = cell->getParam("\\RD_CLK_POLARITY");
+
+ for (int i = 0; i < rd_ports; i++)
+ {
+ bool clk_enable = rd_clk_enable[i] == State::S1;
+
+ if (clk_enable)
+ {
+ bool clk_polarity = cell->getParam("\\RD_CLK_POLARITY")[i] == State::S1;
+ bool transparent = cell->getParam("\\RD_TRANSPARENT")[i] == State::S1;
+
+ SigSpec clk = cell->getPort("\\RD_CLK")[i] ;
+ SigSpec en = cell->getPort("\\RD_EN")[i];
+ Cell *c;
+
+ if (transparent)
+ {
+ SigSpec sig_q = module->addWire(NEW_ID, abits);
+ SigSpec sig_d = rd_addr.extract(abits * i, abits);
+ rd_addr.replace(abits * i, sig_q);
+ if (en != State::S1)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
+ c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
+ }
+ else
+ {
+ SigSpec sig_d = module->addWire(NEW_ID, width);
+ SigSpec sig_q = rd_data.extract(width * i, width);
+ rd_data.replace(width *i, sig_d);
+ if (en != State::S1)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
+ c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
+ }
+
+ log("Extracted %s FF from read port %d of %s.%s: %s\n", transparent ? "addr" : "data",
+ i, log_id(module), log_id(cell), log_id(c));
+ }
+
+ rd_en[i] = State::S1;
+ rd_clk[i] = State::S0;
+ rd_clk_enable[i] = State::S0;
+ rd_clk_polarity[i] = State::S1;
+ }
+
+ cell->setPort("\\RD_ADDR", rd_addr);
+ cell->setPort("\\RD_DATA", rd_data);
+ cell->setPort("\\RD_CLK", rd_clk);
+ cell->setPort("\\RD_EN", rd_en);
+ cell->setParam("\\RD_CLK_ENABLE", rd_clk_enable);
+ cell->setParam("\\RD_CLK_POLARITY", rd_clk_polarity);
+ }
+ }
+} MemoryNordffPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index ca09ac52..172afe0c 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -726,7 +726,7 @@ struct MemoryShareWorker
struct MemorySharePass : public Pass {
MemorySharePass() : Pass("memory_share", "consolidate memory ports") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -752,7 +752,7 @@ struct MemorySharePass : public Pass {
log("optimizations) such as \"share\" and \"opt_merge\".\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_SHARE pass (consolidating $memrd/$memwr cells).\n");
extra_args(args, 1, design);
for (auto module : design->selected_modules())
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index a0fc31b5..49ec6679 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -127,7 +127,7 @@ void handle_module(RTLIL::Design *design, RTLIL::Module *module)
struct MemoryUnpackPass : public Pass {
MemoryUnpackPass() : Pass("memory_unpack", "unpack multi-port memory cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -137,7 +137,7 @@ struct MemoryUnpackPass : public Pass {
log("$memwr cells. It is the counterpart to the memory_collect pass.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
log_header(design, "Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index a8b1537b..0d01e9d3 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -10,5 +10,7 @@ OBJS += passes/opt/opt_expr.o
ifneq ($(SMALL),1)
OBJS += passes/opt/share.o
OBJS += passes/opt/wreduce.o
+OBJS += passes/opt/opt_demorgan.o
+OBJS += passes/opt/rmports.o
endif
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index 021c1a03..a4aca2fe 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct OptPass : public Pass {
OptPass() : Pass("opt", "perform simple optimizations") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -63,7 +63,7 @@ struct OptPass : public Pass {
log("\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string opt_clean_args;
std::string opt_expr_args;
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 6600ffa2..c3b13aca 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell)
{
- if (cell->type.in("$memwr", "$meminit", "$assert", "$assume"))
+ if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover"))
return true;
if (cell->has_keep_attr())
@@ -91,9 +91,16 @@ void rmunused_module_cells(Module *module, bool verbose)
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
- for (auto bit : sigmap(it2.second))
+ for (auto raw_bit : it2.second) {
+ if (raw_bit.wire == nullptr)
+ continue;
+ auto bit = sigmap(raw_bit);
+ if (bit.wire == nullptr)
+ log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
+ log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module));
if (bit.wire != nullptr)
wire2driver[bit].insert(cell);
+ }
}
if (keep_cache.query(cell))
queue.insert(cell);
@@ -320,19 +327,89 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) {
log(" removing unused non-port wire %s.\n", wire->name.c_str());
- del_wires_count++;
}
del_wires.insert(wire);
+ del_wires_count++;
}
module->remove(del_wires);
- count_rm_wires += del_wires.size();;
+ count_rm_wires += del_wires.size();
- if (del_wires_count > 0)
+ if (verbose && del_wires_count > 0)
log(" removed %d unused temporary wires.\n", del_wires_count);
}
-void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
+bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
+{
+ bool did_something = false;
+ CellTypes fftypes;
+ fftypes.setup_internals_mem();
+
+ SigMap sigmap(module);
+ dict<SigBit, State> qbits;
+
+ for (auto cell : module->cells())
+ if (fftypes.cell_known(cell->type) && cell->hasPort("\\Q"))
+ {
+ SigSpec sig = cell->getPort("\\Q");
+
+ for (int i = 0; i < GetSize(sig); i++)
+ {
+ SigBit bit = sig[i];
+
+ if (bit.wire == nullptr || bit.wire->attributes.count("\\init") == 0)
+ continue;
+
+ Const init = bit.wire->attributes.at("\\init");
+
+ if (i >= GetSize(init) || init[i] == State::Sx || init[i] == State::Sz)
+ continue;
+
+ sigmap.add(bit);
+ qbits[bit] = init[i];
+ }
+ }
+
+ for (auto wire : module->wires())
+ {
+ if (!purge_mode && wire->name[0] == '\\')
+ continue;
+
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ Const init = wire->attributes.at("\\init");
+
+ for (int i = 0; i < GetSize(wire) && i < GetSize(init); i++)
+ {
+ if (init[i] == State::Sx || init[i] == State::Sz)
+ continue;
+
+ SigBit wire_bit = SigBit(wire, i);
+ SigBit mapped_wire_bit = sigmap(wire_bit);
+
+ if (wire_bit == mapped_wire_bit)
+ goto next_wire;
+
+ if (qbits.count(sigmap(SigBit(wire, i))) == 0)
+ goto next_wire;
+
+ if (qbits.at(sigmap(SigBit(wire, i))) != init[i])
+ goto next_wire;
+ }
+
+ if (verbose)
+ log(" removing redundant init attribute on %s.\n", log_id(wire));
+
+ wire->attributes.erase("\\init");
+ did_something = true;
+ next_wire:;
+ }
+
+ return did_something;
+}
+
+void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool rminit)
{
if (verbose)
log("Finding unused cells or wires in module %s..\n", module->name.c_str());
@@ -358,11 +435,14 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
rmunused_module_cells(module, verbose);
rmunused_module_signals(module, purge_mode, verbose);
+
+ if (rminit && rmunused_module_init(module, purge_mode, verbose))
+ rmunused_module_signals(module, purge_mode, verbose);
}
struct OptCleanPass : public Pass {
OptCleanPass() : Pass("opt_clean", "remove unused cells and wires") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -379,7 +459,7 @@ struct OptCleanPass : public Pass {
log(" also remove internal nets if they have a public name\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool purge_mode = false;
@@ -406,9 +486,12 @@ struct OptCleanPass : public Pass {
for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn())
continue;
- rmunused_module(module, purge_mode, true);
+ rmunused_module(module, purge_mode, true, true);
}
+ 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();
@@ -422,7 +505,7 @@ struct OptCleanPass : public Pass {
struct CleanPass : public Pass {
CleanPass() : Pass("clean", "remove unused cells and wires") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -437,7 +520,7 @@ struct CleanPass : public Pass {
log("in -purge mode between the commands.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool purge_mode = false;
@@ -465,7 +548,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) {
if (module->has_processes())
continue;
- rmunused_module(module, purge_mode, false);
+ rmunused_module(module, purge_mode, false, false);
}
if (count_rm_cells > 0 || count_rm_wires > 0)
diff --git a/passes/opt/opt_demorgan.cc b/passes/opt/opt_demorgan.cc
new file mode 100644
index 00000000..1699a645
--- /dev/null
+++ b/passes/opt/opt_demorgan.cc
@@ -0,0 +1,202 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2017 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/modtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void demorgan_worker(
+ ModIndex& index,
+ Cell *cell,
+ unsigned int& cells_changed)
+{
+ SigMap& sigmap = index.sigmap;
+ auto m = cell->module;
+
+ //TODO: Add support for reduce_xor
+ //DeMorgan of XOR is either XOR (if even number of inputs) or XNOR (if odd number)
+
+ if( (cell->type != "$reduce_and") && (cell->type != "$reduce_or") )
+ return;
+
+ auto insig = sigmap(cell->getPort("\\A"));
+ log("Inspecting %s cell %s (%d inputs)\n", log_id(cell->type), log_id(cell->name), GetSize(insig));
+ int num_inverted = 0;
+ for(int i=0; i<GetSize(insig); i++)
+ {
+ auto b = insig[i];
+
+ //See if this bit is driven by a $not cell
+ //TODO: do other stuff like nor/nand?
+ pool<ModIndex::PortInfo> ports = index.query_ports(b);
+ bool inverted = false;
+ for(auto x : ports)
+ {
+ if(x.port == "\\Y" && x.cell->type == "$_NOT_")
+ {
+ inverted = true;
+ break;
+ }
+ }
+
+ if(inverted)
+ num_inverted ++;
+ }
+
+ //Stop if less than half of the inputs are inverted
+ if(num_inverted*2 < GetSize(insig))
+ {
+ log(" %d / %d inputs are inverted, not pushing\n", num_inverted, GetSize(insig));
+ return;
+ }
+
+ //More than half of the inputs are inverted! Push through
+ cells_changed ++;
+ log(" %d / %d inputs are inverted, pushing inverter through reduction\n", num_inverted, GetSize(insig));
+
+ //For each input, either add or remove the inverter as needed
+ //TODO: this duplicates the loop up above, can we refactor it?
+ for(int i=0; i<GetSize(insig); i++)
+ {
+ auto b = insig[i];
+
+ //See if this bit is driven by a $not cell
+ //TODO: do other stuff like nor/nand?
+ pool<ModIndex::PortInfo> ports = index.query_ports(b);
+ RTLIL::Cell* srcinv = NULL;
+ for(auto x : ports)
+ {
+ if(x.port == "\\Y" && x.cell->type == "$_NOT_")
+ {
+ srcinv = x.cell;
+ break;
+ }
+ }
+
+ //We are NOT inverted! Add an inverter
+ if(!srcinv)
+ {
+ auto inverted_b = m->addWire(NEW_ID);
+ m->addNot(NEW_ID, RTLIL::SigSpec(b), RTLIL::SigSpec(inverted_b));
+ insig[i] = inverted_b;
+ }
+
+ //We ARE inverted - bypass it
+ //Don't automatically delete the inverter since other stuff might still use it
+ else
+ insig[i] = srcinv->getPort("\\A");
+ }
+
+ //Cosmetic fixup: If our input is just a scrambled version of one bus, rearrange it
+ //Reductions are all commutative, so there's no point in having them in a weird order
+ bool same_signal = true;
+ RTLIL::Wire* srcwire = insig[0].wire;
+ dict<int, int> seen_bits;
+ for(int i=0; i<GetSize(insig); i++)
+ seen_bits[i] = 0;
+ for(int i=0; i<GetSize(insig); i++)
+ {
+ seen_bits[insig[i].offset] ++;
+ if(insig[i].wire != srcwire)
+ {
+ same_signal = false;
+ break;
+ }
+ }
+ if(same_signal)
+ {
+ //Make sure we've seen every bit exactly once
+ bool every_bit_once = true;
+ for(int i=0; i<GetSize(insig); i++)
+ {
+ if(seen_bits[i] != 1)
+ {
+ every_bit_once = false;
+ break;
+ }
+ }
+
+ //All good? Just use the whole wire as-is without any reordering
+ //We do have to swap MSB to LSB b/c that's the way the reduction cells seem to work?
+ //Unclear on why this isn't sorting properly
+ //TODO: can we do SigChunks instead of single bits if we have subsets of a bus?
+ if(every_bit_once && (GetSize(insig) == srcwire->width) )
+ {
+ log("Rearranging bits\n");
+ RTLIL::SigSpec newsig;
+ for(int i=0; i<GetSize(insig); i++)
+ newsig.append(RTLIL::SigBit(srcwire, GetSize(insig) - i - 1));
+ insig = newsig;
+ insig.sort();
+ }
+ }
+
+ //Push the new input signal back to the reduction (after bypassing/adding inverters)
+ cell->setPort("\\A", insig);
+
+ //Change the cell type
+ if(cell->type == "$reduce_and")
+ cell->type = "$reduce_or";
+ else if(cell->type == "$reduce_or")
+ cell->type = "$reduce_and";
+ //don't change XOR
+
+ //Add an inverter to the output
+ auto inverted_output = cell->getPort("\\Y");
+ auto uninverted_output = m->addWire(NEW_ID);
+ m->addNot(NEW_ID, RTLIL::SigSpec(uninverted_output), inverted_output);
+ cell->setPort("\\Y", uninverted_output);
+}
+
+struct OptDemorganPass : public Pass {
+ OptDemorganPass() : Pass("opt_demorgan", "Optimize reductions with DeMorgan equivalents") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" opt_demorgan [selection]\n");
+ log("\n");
+ log("This pass pushes inverters through $reduce_* cells if this will reduce the\n");
+ log("overall gate count of the circuit\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing OPT_DEMORGAN pass (push inverters through $reduce_* cells).\n");
+
+ int argidx = 0;
+ extra_args(args, argidx, design);
+
+ unsigned int cells_changed = 0;
+ for (auto module : design->selected_modules())
+ {
+ ModIndex index(module);
+ for (auto cell : module->selected_cells())
+ demorgan_worker(index, cell, cells_changed);
+ }
+
+ if(cells_changed)
+ log("Pushed inverters through %u reductions\n", cells_changed);
+ }
+} OptDemorganPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index b62eae28..0ba233c6 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -259,6 +259,29 @@ bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative)
return last_bit_one;
}
+// if the signal has only one bit set, return the index of that bit.
+// otherwise return -1
+int get_onehot_bit_index(RTLIL::SigSpec signal)
+{
+ int bit_index = -1;
+
+ for (int i = 0; i < GetSize(signal); i++)
+ {
+ if (signal[i] == RTLIL::State::S0)
+ continue;
+
+ if (signal[i] != RTLIL::State::S1)
+ return -1;
+
+ if (bit_index != -1)
+ return -1;
+
+ bit_index = i;
+ }
+
+ return bit_index;
+}
+
void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool clkinv)
{
if (!design->selected(module))
@@ -348,19 +371,20 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type.in("$reduce_and", "$_AND_"))
detect_const_and = true;
- if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
+ if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
detect_const_and = true;
if (cell->type.in("$reduce_or", "$reduce_bool", "$_OR_"))
detect_const_or = true;
- if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
+ if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
detect_const_or = true;
if (detect_const_and || detect_const_or)
{
pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool();
- bool found_zero = false, found_one = false, found_inv = false;
+ bool found_zero = false, found_one = false, found_undef = false, found_inv = false, many_conconst = false;
+ SigBit non_const_input = State::Sm;
if (cell->hasPort("\\B")) {
vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector();
@@ -368,12 +392,20 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
for (auto bit : input_bits) {
- if (bit == State::S0)
- found_zero = true;
- if (bit == State::S1)
- found_one = true;
- if (invert_map.count(bit) && input_bits.count(invert_map.at(bit)))
- found_inv = true;
+ if (bit.wire) {
+ if (invert_map.count(bit) && input_bits.count(invert_map.at(bit)))
+ found_inv = true;
+ if (non_const_input != State::Sm)
+ many_conconst = true;
+ non_const_input = many_conconst ? State::Sm : bit;
+ } else {
+ if (bit == State::S0)
+ found_zero = true;
+ else if (bit == State::S1)
+ found_one = true;
+ else
+ found_undef = true;
+ }
}
if (detect_const_and && (found_zero || found_inv)) {
@@ -387,6 +419,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1);
goto next_cell;
}
+
+ if (non_const_input != State::Sm && !found_undef) {
+ cover("opt.opt_expr.and_or_buffer");
+ replace_cell(assign_map, module, cell, "and_or_buffer", "\\Y", non_const_input);
+ goto next_cell;
+ }
}
if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
@@ -411,6 +449,53 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (group_cell_inputs(module, cell, true, assign_map))
goto next_cell;
+ if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" ||
+ cell->type == "$reduce_or" || cell->type == "$reduce_and" || cell->type == "$reduce_bool")
+ {
+ SigBit neutral_bit = cell->type == "$reduce_and" ? State::S1 : State::S0;
+
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec new_sig_a;
+
+ for (auto bit : sig_a)
+ if (bit != neutral_bit) new_sig_a.append(bit);
+
+ if (GetSize(new_sig_a) == 0)
+ new_sig_a.append(neutral_bit);
+
+ if (GetSize(new_sig_a) < GetSize(sig_a)) {
+ cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str());
+ log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a));
+ cell->setPort("\\A", new_sig_a);
+ cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a);
+ did_something = true;
+ }
+ }
+
+ if (cell->type == "$logic_and" || cell->type == "$logic_or")
+ {
+ SigBit neutral_bit = State::S0;
+
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec new_sig_b;
+
+ for (auto bit : sig_b)
+ if (bit != neutral_bit) new_sig_b.append(bit);
+
+ if (GetSize(new_sig_b) == 0)
+ new_sig_b.append(neutral_bit);
+
+ if (GetSize(new_sig_b) < GetSize(sig_b)) {
+ cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str());
+ log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b));
+ cell->setPort("\\B", new_sig_b);
+ cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b);
+ did_something = true;
+ }
+ }
+
if (cell->type == "$reduce_and")
{
RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
@@ -633,6 +718,23 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
+ if (cell->type == "$_TBUF_" || cell->type == "$tribuf") {
+ RTLIL::SigSpec input = cell->getPort(cell->type == "$_TBUF_" ? "\\E" : "\\EN");
+ RTLIL::SigSpec a = cell->getPort("\\A");
+ assign_map.apply(input);
+ assign_map.apply(a);
+ if (input == State::S1)
+ ACTION_DO("\\Y", cell->getPort("\\A"));
+ if (input == State::S0 && !a.is_fully_undef()) {
+ cover("opt.opt_expr.action_" S__LINE__);
+ log("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str());
+ cell->setPort("\\A", SigSpec(State::Sx, GetSize(a)));
+ did_something = true;
+ goto next_cell;
+ }
+ }
+
if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex")
{
RTLIL::SigSpec a = cell->getPort("\\A");
@@ -1167,6 +1269,197 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
+ // remove redundant pairs of bits in ==, ===, !=, and !==
+ // replace cell with const driver if inputs can't be equal
+ if (do_fine && cell->type.in("$eq", "$ne", "$eqx", "$nex"))
+ {
+ pool<pair<SigBit, SigBit>> redundant_cache;
+ mfp<SigBit> contradiction_cache;
+
+ contradiction_cache.promote(State::S0);
+ contradiction_cache.promote(State::S1);
+
+ int a_width = cell->getParam("\\A_WIDTH").as_int();
+ int b_width = cell->getParam("\\B_WIDTH").as_int();
+
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ int width = is_signed ? std::min(a_width, b_width) : std::max(a_width, b_width);
+
+ SigSpec sig_a = cell->getPort("\\A");
+ SigSpec sig_b = cell->getPort("\\B");
+
+ int redundant_bits = 0;
+
+ for (int i = width-1; i >= 0; i--)
+ {
+ SigBit bit_a = i < a_width ? assign_map(sig_a[i]) : State::S0;
+ SigBit bit_b = i < b_width ? assign_map(sig_b[i]) : State::S0;
+
+ if (bit_a != State::Sx && bit_a != State::Sz &&
+ bit_b != State::Sx && bit_b != State::Sz)
+ contradiction_cache.merge(bit_a, bit_b);
+
+ if (bit_b < bit_a)
+ std::swap(bit_a, bit_b);
+
+ pair<SigBit, SigBit> key(bit_a, bit_b);
+
+ if (redundant_cache.count(key)) {
+ if (i < a_width) sig_a.remove(i);
+ if (i < b_width) sig_b.remove(i);
+ redundant_bits++;
+ continue;
+ }
+
+ redundant_cache.insert(key);
+ }
+
+ if (contradiction_cache.find(State::S0) == contradiction_cache.find(State::S1))
+ {
+ SigSpec y_sig = cell->getPort("\\Y");
+ Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig));
+
+ log("Replacing cell `%s' in module `%s' with constant driver %s.\n",
+ log_id(cell), log_id(module), log_signal(y_value));
+
+ module->connect(y_sig, y_value);
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+
+ if (redundant_bits)
+ {
+ log("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
+ redundant_bits, log_id(cell->type), log_id(cell), log_id(module));
+
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\B", sig_b);
+ cell->setParam("\\A_WIDTH", GetSize(sig_a));
+ cell->setParam("\\B_WIDTH", GetSize(sig_b));
+
+ did_something = true;
+ goto next_cell;
+ }
+ }
+
+ // replace a<0 or a>=0 with the top bit of a
+ if (do_fine && (cell->type == "$lt" || cell->type == "$ge" || cell->type == "$gt" || cell->type == "$le"))
+ {
+ //used to decide whether the signal needs to be negated
+ bool is_lt = false;
+
+ //references the variable signal in the comparison
+ RTLIL::SigSpec sigVar;
+
+ //references the constant signal in the comparison
+ RTLIL::SigSpec sigConst;
+
+ // note that this signal must be constant for the optimization
+ // to take place, but it is not checked beforehand.
+ // If new passes are added, this signal must be checked for const-ness
+
+ //width of the variable port
+ int width;
+ int const_width;
+
+ bool var_signed;
+
+ if (cell->type == "$lt" || cell->type == "$ge") {
+ is_lt = cell->type == "$lt" ? 1 : 0;
+ sigVar = cell->getPort("\\A");
+ sigConst = cell->getPort("\\B");
+ width = cell->parameters["\\A_WIDTH"].as_int();
+ const_width = cell->parameters["\\B_WIDTH"].as_int();
+ var_signed = cell->parameters["\\A_SIGNED"].as_bool();
+ } else
+ if (cell->type == "$gt" || cell->type == "$le") {
+ is_lt = cell->type == "$gt" ? 1 : 0;
+ sigVar = cell->getPort("\\B");
+ sigConst = cell->getPort("\\A");
+ width = cell->parameters["\\B_WIDTH"].as_int();
+ const_width = cell->parameters["\\A_WIDTH"].as_int();
+ var_signed = cell->parameters["\\B_SIGNED"].as_bool();
+ } else
+ log_abort();
+
+ // replace a(signed) < 0 with the high bit of a
+ if (sigConst.is_fully_const() && sigConst.is_fully_zero() && var_signed == true)
+ {
+ RTLIL::SigSpec a_prime(RTLIL::State::S0, cell->parameters["\\Y_WIDTH"].as_int());
+ a_prime[0] = sigVar[width - 1];
+ if (is_lt) {
+ log("Replacing %s cell `%s' (implementing X<0) with X[%d]: %s\n",
+ log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
+ module->connect(cell->getPort("\\Y"), a_prime);
+ module->remove(cell);
+ } else {
+ log("Replacing %s cell `%s' (implementing X>=0) with ~X[%d]: %s\n",
+ log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
+ module->addNot(NEW_ID, a_prime, cell->getPort("\\Y"));
+ module->remove(cell);
+ }
+ did_something = true;
+ goto next_cell;
+ } else
+ if (sigConst.is_fully_const() && sigConst.is_fully_def() && var_signed == false)
+ {
+ if (sigConst.is_fully_zero()) {
+ RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
+ if (is_lt) {
+ log("Replacing %s cell `%s' (implementing unsigned X<0) with constant false.\n",
+ log_id(cell->type), log_id(cell));
+ a_prime[0] = RTLIL::State::S0;
+ } else {
+ log("Replacing %s cell `%s' (implementing unsigned X>=0) with constant true.\n",
+ log_id(cell->type), log_id(cell));
+ a_prime[0] = RTLIL::State::S1;
+ }
+ module->connect(cell->getPort("\\Y"), a_prime);
+ module->remove(cell);
+ did_something = true;
+ goto next_cell;
+ }
+
+ int const_bit_set = get_onehot_bit_index(sigConst);
+ if (const_bit_set >= 0 && const_bit_set < width) {
+ int bit_set = const_bit_set;
+ RTLIL::SigSpec a_prime(RTLIL::State::S0, width - bit_set);
+ for (int i = bit_set; i < width; i++) {
+ a_prime[i - bit_set] = sigVar[i];
+ }
+ if (is_lt) {
+ log("Replacing %s cell `%s' (implementing unsigned X<%s) with !X[%d:%d]: %s.\n",
+ log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
+ module->addLogicNot(NEW_ID, a_prime, cell->getPort("\\Y"));
+ } else {
+ log("Replacing %s cell `%s' (implementing unsigned X>=%s) with |X[%d:%d]: %s.\n",
+ log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
+ module->addReduceOr(NEW_ID, a_prime, cell->getPort("\\Y"));
+ }
+ module->remove(cell);
+ did_something = true;
+ goto next_cell;
+ }
+ else if(const_bit_set >= width && const_bit_set >= 0){
+ RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
+ if(is_lt){
+ a_prime[0] = RTLIL::State::S1;
+ log("Replacing %s cell `%s' (implementing unsigned X[%d:0] < %s[%d:0]) with constant 0.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
+ }
+ else{
+ log("Replacing %s cell `%s' (implementing unsigned X[%d:0]>= %s[%d:0]) with constant 1.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
+ }
+ module->connect(cell->getPort("\\Y"), a_prime);
+ module->remove(cell);
+ did_something = true;
+ goto next_cell;
+
+ }
+ }
+ }
+
next_cell:;
#undef ACTION_DO
#undef ACTION_DO_Y
@@ -1177,7 +1470,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
struct OptExprPass : public Pass {
OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1211,7 +1504,7 @@ struct OptExprPass : public Pass {
log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool mux_undef = false;
bool mux_bool = false;
diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc
index 97989d27..eedf8890 100644
--- a/passes/opt/opt_merge.cc
+++ b/passes/opt/opt_merge.cc
@@ -275,13 +275,24 @@ struct OptMergeWorker
ct.cell_types.erase("$pmux");
}
+ ct.cell_types.erase("$tribuf");
+ ct.cell_types.erase("$_TBUF_");
+ ct.cell_types.erase("$anyseq");
+ ct.cell_types.erase("$anyconst");
+ ct.cell_types.erase("$allseq");
+ ct.cell_types.erase("$allconst");
+
log("Finding identical cells in module `%s'.\n", module->name.c_str());
assign_map.set(module);
dff_init_map.set(module);
for (auto &it : module->wires_)
- if (it.second->attributes.count("\\init") != 0)
- dff_init_map.add(it.second, it.second->attributes.at("\\init"));
+ if (it.second->attributes.count("\\init") != 0) {
+ Const initval = it.second->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initval) && i < GetSize(it.second); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ dff_init_map.add(SigBit(it.second, i), initval[i]);
+ }
bool did_something = true;
while (did_something)
@@ -330,7 +341,7 @@ struct OptMergeWorker
struct OptMergePass : public Pass {
OptMergePass() : Pass("opt_merge", "consolidate identical cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -346,7 +357,7 @@ struct OptMergePass : public Pass {
log(" Operate on all cell types, not just built-in types.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing OPT_MERGE pass (detect identical cells).\n");
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index f5ddc2af..87c7ce9b 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -449,7 +449,7 @@ struct OptMuxtreeWorker
struct OptMuxtreePass : public Pass {
OptMuxtreePass() : Pass("opt_muxtree", "eliminate dead trees in multiplexer trees") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -462,7 +462,7 @@ struct OptMuxtreePass : public Pass {
log("This pass only operates on completely selected modules without processes.\n");
log("\n");
}
- virtual void execute(vector<std::string> args, RTLIL::Design *design)
+ void execute(vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
extra_args(args, 1, design);
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index eb9d02ad..d99f1ca6 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -329,7 +329,7 @@ struct OptReduceWorker
struct OptReducePass : public Pass {
OptReducePass() : Pass("opt_reduce", "simplify large MUXes and AND/OR gates") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -350,7 +350,7 @@ struct OptReducePass : public Pass {
log(" alias for -fine\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool do_fine = false;
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index 922f086f..5880254c 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -39,11 +39,201 @@ void remove_init_attr(SigSpec sig)
wbit.wire->attributes.at("\\init")[wbit.offset] = State::Sx;
}
+bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
+{
+ SigSpec sig_set, sig_clr;
+ State pol_set, pol_clr;
+
+ if (cell->hasPort("\\S"))
+ sig_set = cell->getPort("\\S");
+
+ if (cell->hasPort("\\R"))
+ sig_clr = cell->getPort("\\R");
+
+ if (cell->hasPort("\\SET"))
+ sig_set = cell->getPort("\\SET");
+
+ if (cell->hasPort("\\CLR"))
+ sig_clr = cell->getPort("\\CLR");
+
+ log_assert(GetSize(sig_set) == GetSize(sig_clr));
+
+ if (cell->type.substr(0,8) == "$_DFFSR_") {
+ pol_set = cell->type[9] == 'P' ? State::S1 : State::S0;
+ pol_clr = cell->type[10] == 'P' ? State::S1 : State::S0;
+ } else
+ if (cell->type.substr(0,11) == "$_DLATCHSR_") {
+ pol_set = cell->type[12] == 'P' ? State::S1 : State::S0;
+ pol_clr = cell->type[13] == 'P' ? State::S1 : State::S0;
+ } else
+ if (cell->type == "$dffsr" || cell->type == "$dlatchsr") {
+ pol_set = cell->parameters["\\SET_POLARITY"].as_bool() ? State::S1 : State::S0;
+ pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool() ? State::S1 : State::S0;
+ } else
+ log_abort();
+
+ State npol_set = pol_set == State::S0 ? State::S1 : State::S0;
+ State npol_clr = pol_clr == State::S0 ? State::S1 : State::S0;
+
+ SigSpec sig_d = cell->getPort("\\D");
+ SigSpec sig_q = cell->getPort("\\Q");
+
+ bool did_something = false;
+ bool proper_sr = false;
+ bool used_pol_set = false;
+ bool used_pol_clr = false;
+ bool hasreset = false;
+ Const reset_val;
+ SigSpec sig_reset;
+
+ for (int i = 0; i < GetSize(sig_set); i++)
+ {
+ SigBit s = sig_set[i], c = sig_clr[i];
+
+ if (s != npol_set || c != npol_clr)
+ hasreset = true;
+
+ if (s == pol_set || c == pol_clr)
+ {
+ log("Constantly %s Q bit %s for SR cell %s (%s) from module %s.\n",
+ s == pol_set ? "set" : "cleared", log_signal(sig_q[i]),
+ log_id(cell), log_id(cell->type), log_id(mod));
+
+ remove_init_attr(sig_q[i]);
+ mod->connect(sig_q[i], s == pol_set ? State::S1 : State::S0);
+ sig_set.remove(i);
+ sig_clr.remove(i);
+ sig_d.remove(i);
+ sig_q.remove(i--);
+ did_something = true;
+ continue;
+ }
+ if (sig_reset.empty() && s.wire != nullptr) sig_reset = s;
+ if (sig_reset.empty() && c.wire != nullptr) sig_reset = c;
+
+ if (s.wire != nullptr && s != sig_reset) proper_sr = true;
+ if (c.wire != nullptr && c != sig_reset) proper_sr = true;
+
+ if ((s.wire == nullptr) != (c.wire == nullptr)) {
+ if (s.wire != nullptr) used_pol_set = true;
+ if (c.wire != nullptr) used_pol_clr = true;
+ reset_val.bits.push_back(c.wire == nullptr ? State::S1 : State::S0);
+ } else
+ proper_sr = true;
+ }
+
+ if (!hasreset)
+ proper_sr = false;
+
+ if (GetSize(sig_set) == 0)
+ {
+ log("Removing %s (%s) from module %s.\n", log_id(cell), log_id(cell->type), log_id(mod));
+ mod->remove(cell);
+ return true;
+ }
+
+ if (cell->type == "$dffsr" || cell->type == "$dlatchsr")
+ {
+ cell->setParam("\\WIDTH", GetSize(sig_d));
+ cell->setPort("\\SET", sig_set);
+ cell->setPort("\\CLR", sig_clr);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ }
+ else
+ {
+ cell->setPort("\\S", sig_set);
+ cell->setPort("\\R", sig_clr);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ }
+
+ if (proper_sr)
+ return did_something;
+
+ if (used_pol_set && used_pol_clr && pol_set != pol_clr)
+ return did_something;
+
+ if (cell->type == "$dlatchsr")
+ return did_something;
+
+ State unified_pol = used_pol_set ? pol_set : pol_clr;
+
+ if (cell->type == "$dffsr")
+ {
+ if (hasreset)
+ {
+ log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$adff", log_id(mod));
+
+ cell->type = "$adff";
+ cell->setParam("\\ARST_POLARITY", unified_pol);
+ cell->setParam("\\ARST_VALUE", reset_val);
+ cell->setPort("\\ARST", sig_reset);
+
+ cell->unsetParam("\\SET_POLARITY");
+ cell->unsetParam("\\CLR_POLARITY");
+ cell->unsetPort("\\SET");
+ cell->unsetPort("\\CLR");
+
+ return true;
+ }
+ else
+ {
+ log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$dff", log_id(mod));
+
+ cell->type = "$dff";
+ cell->unsetParam("\\SET_POLARITY");
+ cell->unsetParam("\\CLR_POLARITY");
+ cell->unsetPort("\\SET");
+ cell->unsetPort("\\CLR");
+
+ return true;
+ }
+ }
+ else
+ {
+ IdString new_type;
+
+ if (cell->type.substr(0,8) == "$_DFFSR_")
+ new_type = stringf("$_DFF_%c_", cell->type[8]);
+ else if (cell->type.substr(0,11) == "$_DLATCHSR_")
+ new_type = stringf("$_DLATCH_%c_", cell->type[11]);
+ else
+ log_abort();
+
+ log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), log_id(new_type), log_id(mod));
+
+ cell->type = new_type;
+ cell->unsetPort("\\S");
+ cell->unsetPort("\\R");
+
+ return did_something;
+ }
+}
+
bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
{
- SigSpec sig_e = dlatch->getPort("\\EN");
+ SigSpec sig_e;
+ State on_state, off_state;
+
+ if (dlatch->type == "$dlatch") {
+ sig_e = assign_map(dlatch->getPort("\\EN"));
+ on_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S1 : State::S0;
+ off_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S0 : State::S1;
+ } else
+ if (dlatch->type == "$_DLATCH_P_") {
+ sig_e = assign_map(dlatch->getPort("\\E"));
+ on_state = State::S1;
+ off_state = State::S0;
+ } else
+ if (dlatch->type == "$_DLATCH_N_") {
+ sig_e = assign_map(dlatch->getPort("\\E"));
+ on_state = State::S0;
+ off_state = State::S1;
+ } else
+ log_abort();
- if (sig_e == State::S0)
+ if (sig_e == off_state)
{
RTLIL::Const val_init;
for (auto bit : dff_init_map(dlatch->getPort("\\Q")))
@@ -52,7 +242,7 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
goto delete_dlatch;
}
- if (sig_e == State::S1)
+ if (sig_e == on_state)
{
mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D"));
goto delete_dlatch;
@@ -168,7 +358,7 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
goto delete_dff;
}
- if (sig_d == sig_q && (!sig_r.size() || !has_init || val_init == val_rv)) {
+ if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) {
if (sig_r.size())
mod->connect(sig_q, val_rv);
if (has_init)
@@ -176,6 +366,28 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
goto delete_dff;
}
+ if (!sig_r.empty() && sig_r.is_fully_const())
+ {
+ if (sig_r == val_rp || sig_r.is_fully_undef()) {
+ mod->connect(sig_q, val_rv);
+ goto delete_dff;
+ }
+
+ log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
+
+ if (dff->type == "$adff") {
+ dff->type = "$dff";
+ dff->unsetPort("\\ARST");
+ dff->unsetParam("\\ARST_POLARITY");
+ dff->unsetParam("\\ARST_VALUE");
+ return true;
+ }
+
+ log_assert(dff->type.substr(0,6) == "$_DFF_");
+ dff->type = stringf("$_DFF_%c_", + dff->type[6]);
+ dff->unsetPort("\\R");
+ }
+
return false;
delete_dff:
@@ -187,7 +399,7 @@ delete_dff:
struct OptRmdffPass : public Pass {
OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -197,7 +409,7 @@ struct OptRmdffPass : public Pass {
log("a constant driver.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int total_count = 0, total_initdrv = 0;
log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
@@ -221,12 +433,16 @@ struct OptRmdffPass : public Pass {
assign_map.set(module);
dff_init_map.set(module);
+ mux_drivers.clear();
+ init_attributes.clear();
for (auto wire : module->wires())
{
if (wire->attributes.count("\\init") != 0) {
Const initval = wire->attributes.at("\\init");
- dff_init_map.add(wire, initval);
+ for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ dff_init_map.add(SigBit(wire, i), initval[i]);
for (int i = 0; i < GetSize(wire); i++) {
SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
if (mapped_bit.wire) {
@@ -245,6 +461,7 @@ struct OptRmdffPass : public Pass {
mux_drivers.clear();
std::vector<RTLIL::IdString> dff_list;
+ std::vector<RTLIL::IdString> dffsr_list;
std::vector<RTLIL::IdString> dlatch_list;
for (auto cell : module->cells())
{
@@ -262,16 +479,28 @@ struct OptRmdffPass : public Pass {
if (!design->selected(module, cell))
continue;
+ if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
+ "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", "$dffsr",
+ "$_DLATCHSR_NNN_", "$_DLATCHSR_NNP_", "$_DLATCHSR_NPN_", "$_DLATCHSR_NPP_",
+ "$_DLATCHSR_PNN_", "$_DLATCHSR_PNP_", "$_DLATCHSR_PPN_", "$_DLATCHSR_PPP_", "$dlatchsr"))
+ dffsr_list.push_back(cell->name);
+
if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
"$ff", "$dff", "$adff"))
dff_list.push_back(cell->name);
- if (cell->type == "$dlatch")
+ if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
dlatch_list.push_back(cell->name);
}
+ for (auto &id : dffsr_list) {
+ if (module->cell(id) != nullptr &&
+ handle_dffsr(module, module->cells_[id]))
+ total_count++;
+ }
+
for (auto &id : dff_list) {
if (module->cell(id) != nullptr &&
handle_dff(module, module->cells_[id]))
@@ -310,6 +539,7 @@ struct OptRmdffPass : public Pass {
assign_map.clear();
mux_drivers.clear();
+ init_attributes.clear();
if (total_count || total_initdrv)
design->scratchpad_set_bool("opt.did_something", true);
diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc
new file mode 100644
index 00000000..fc1596eb
--- /dev/null
+++ b/passes/opt/rmports.cc
@@ -0,0 +1,187 @@
+/*
+ * 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/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct RmportsPassPass : public Pass {
+ RmportsPassPass() : Pass("rmports", "remove module ports with no connections") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" rmports [selection]\n");
+ log("\n");
+ log("This pass identifies ports in the selected modules which are not used or\n");
+ log("driven and removes them.\n");
+ log("\n");
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing RMPORTS pass (remove ports with no connections).\n");
+
+ size_t argidx = 1;
+ extra_args(args, argidx, design);
+
+ // The set of ports we removed
+ dict<IdString, pool<IdString>> removed_ports;
+
+ // Find all of the unused ports, and remove them from that module
+ auto modules = design->selected_modules();
+ for(auto mod : modules)
+ ScanModule(mod, removed_ports);
+
+ // Remove the unused ports from all instances of those modules
+ for(auto mod : modules)
+ CleanupModule(mod, removed_ports);
+ }
+
+ void CleanupModule(Module *module, dict<IdString, pool<IdString>> &removed_ports)
+ {
+ log("Removing now-unused cell ports in module %s\n", module->name.c_str());
+
+ auto cells = module->cells();
+ for(auto cell : cells)
+ {
+ if(removed_ports.find(cell->type) == removed_ports.end())
+ {
+ // log(" Not touching instance \"%s\" because we didn't remove any ports from module \"%s\"\n",
+ // cell->name.c_str(), cell->type.c_str());
+ continue;
+ }
+
+ auto ports_to_remove = removed_ports[cell->type];
+ for(auto p : ports_to_remove)
+ {
+ log(" Removing port \"%s\" from instance \"%s\"\n",
+ p.c_str(), cell->type.c_str());
+ cell->unsetPort(p);
+ }
+ }
+ }
+
+ void ScanModule(Module* module, dict<IdString, pool<IdString>> &removed_ports)
+ {
+ log("Finding unconnected ports in module %s\n", module->name.c_str());
+
+ pool<IdString> used_ports;
+
+ // See what wires are used.
+ // Start by checking connections between named wires
+ auto &conns = module->connections();
+ for(auto sigsig : conns)
+ {
+ auto s1 = sigsig.first;
+ auto s2 = sigsig.second;
+
+ int len1 = s1.size();
+ int len2 = s2.size();
+ int len = len1;
+ if(len2 < len1)
+ len = len2;
+
+ for(int i=0; i<len; i++)
+ {
+ auto w1 = s1[i].wire;
+ auto w2 = s2[i].wire;
+ if( (w1 == NULL) || (w2 == NULL) )
+ continue;
+
+ //log(" conn %s, %s\n", w1->name.c_str(), w2->name.c_str());
+
+ if( (w1->port_input || w1->port_output) && (used_ports.find(w1->name) == used_ports.end()) )
+ used_ports.insert(w1->name);
+
+ if( (w2->port_input || w2->port_output) && (used_ports.find(w2->name) == used_ports.end()) )
+ used_ports.insert(w2->name);
+ }
+ }
+
+ // Then check connections to cells
+ auto cells = module->cells();
+ for(auto cell : cells)
+ {
+ auto &cconns = cell->connections();
+ for(auto conn : cconns)
+ {
+ for(int i=0; i<conn.second.size(); i++)
+ {
+ auto sig = conn.second[i].wire;
+ if(sig == NULL)
+ continue;
+
+ // log(" sig %s\n", sig->name.c_str());
+ if( (sig->port_input || sig->port_output) && (used_ports.find(sig->name) == used_ports.end()) )
+ used_ports.insert(sig->name);
+ }
+ }
+ }
+
+ // Now that we know what IS used, get rid of anything that isn't in that list
+ pool<IdString> unused_ports;
+ for(auto port : module->ports)
+ {
+ if(used_ports.find(port) != used_ports.end())
+ continue;
+ unused_ports.insert(port);
+ }
+
+ // Print the ports out as we go through them
+ for(auto port : unused_ports)
+ {
+ log(" removing unused port %s\n", port.c_str());
+ removed_ports[module->name].insert(port);
+
+ // Remove from ports list
+ for(size_t i=0; i<module->ports.size(); i++)
+ {
+ if(module->ports[i] == port)
+ {
+ module->ports.erase(module->ports.begin() + i);
+ break;
+ }
+ }
+
+ // Mark the wire as no longer a port
+ auto wire = module->wire(port);
+ wire->port_input = false;
+ wire->port_output = false;
+ wire->port_id = 0;
+ }
+ log("Removed %zu unused ports.\n", unused_ports.size());
+
+ // Re-number all of the wires that DO have ports still on them
+ for(size_t i=0; i<module->ports.size(); i++)
+ {
+ auto port = module->ports[i];
+ auto wire = module->wire(port);
+ wire->port_id = i+1;
+ }
+ }
+
+} RmportsPassPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 22914eaa..b8028082 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -1421,7 +1421,7 @@ struct ShareWorker
struct SharePass : public Pass {
SharePass() : Pass("share", "perform sat-based resource sharing") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1453,7 +1453,7 @@ struct SharePass : public Pass {
log(" Only perform the first N merges, then stop. This is useful for debugging.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
ShareWorkerConfig config;
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 07503fbb..0164f58d 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -353,7 +353,7 @@ struct WreduceWorker
struct WreducePass : public Pass {
WreducePass() : Pass("wreduce", "reduce the word size of operations if possible") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -373,7 +373,7 @@ struct WreducePass : public Pass {
log(" flows that use the 'memory_memx' pass.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, Design *design)
+ void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
WreduceConfig config;
bool opt_memx = false;
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
index d5366f26..ef7cb0f7 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ProcPass : public Pass {
ProcPass() : Pass("proc", "translate processes to netlists") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -57,7 +57,7 @@ struct ProcPass : public Pass {
log(" executed in -ifx mode.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string global_arst;
bool ifxmode = false;
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index 216b00dd..b69eba3f 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -203,7 +203,7 @@ restart_proc_arst:
struct ProcArstPass : public Pass {
ProcArstPass() : Pass("proc_arst", "detect asynchronous resets") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -221,7 +221,7 @@ struct ProcArstPass : public Pass {
log(" in the 'init' attribute on the net.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string global_arst;
bool global_arst_neg = false;
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 7dbabc21..b9e43d1d 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -143,7 +143,7 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)
struct ProcCleanPass : public Pass {
ProcCleanPass() : Pass("proc_clean", "remove empty parts of processes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -153,7 +153,7 @@ struct ProcCleanPass : public Pass {
log("if it contains only empty structures.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int total_count = 0;
log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index 98653dc6..519d35cd 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -322,6 +322,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
}
}
+ SigSpec sig_q = sig;
ce.assign_map.apply(insig);
ce.assign_map.apply(rstval);
ce.assign_map.apply(sig);
@@ -350,13 +351,13 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
else if (!rstval.is_fully_const() && !ce.eval(rstval))
{
log_warning("Async reset value `%s' is not constant!\n", log_signal(rstval));
- gen_dffsr(mod, insig, rstval, sig,
+ gen_dffsr(mod, insig, rstval, sig_q,
sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
sync_edge->signal, sync_level->signal, proc);
}
else
- gen_dff(mod, insig, rstval.as_const(), sig,
+ gen_dff(mod, insig, rstval.as_const(), sig_q,
sync_edge && sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
sync_edge ? sync_edge->signal : SigSpec(),
@@ -369,7 +370,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
struct ProcDffPass : public Pass {
ProcDffPass() : Pass("proc_dff", "extract flip-flops from processes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -379,7 +380,7 @@ struct ProcDffPass : public Pass {
log("d-type flip-flop cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PROC_DFF pass (convert process syncs to FFs).\n");
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
index 6621afd3..d9d5dfbe 100644
--- a/passes/proc/proc_dlatch.cc
+++ b/passes/proc/proc_dlatch.cc
@@ -217,7 +217,7 @@ struct proc_dlatch_db_t
return make_inner(children);
}
- SigBit make_hold(int n)
+ SigBit make_hold(int n, string &src)
{
if (n == true_node)
return State::S1;
@@ -235,20 +235,20 @@ struct proc_dlatch_db_t
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));
+ and_bits.append(module->Not(NEW_ID, rule.signal, false, src));
else
- and_bits.append(module->Eq(NEW_ID, rule.signal, rule.match));
+ and_bits.append(module->Eq(NEW_ID, rule.signal, rule.match, false, src));
}
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));
+ or_bits.append(make_hold(k, src));
+ and_bits.append(module->ReduceOr(NEW_ID, or_bits, false, src));
}
if (GetSize(and_bits) == 2)
- and_bits = module->And(NEW_ID, and_bits[0], and_bits[1]);
+ and_bits = module->And(NEW_ID, and_bits[0], and_bits[1], false, src);
log_assert(GetSize(and_bits) == 1);
rules_sig[n] = and_bits[0];
@@ -340,6 +340,7 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
RTLIL::SigSig latches_bits, nolatches_bits;
dict<SigBit, SigBit> latches_out_in;
dict<SigBit, int> latches_hold;
+ std::string src = proc->get_src_attribute();
for (auto sr : proc->syncs)
{
@@ -405,7 +406,8 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
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);
+ Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n, src)), rhs, lhs);
+ cell->set_src_attribute(src);
db.generated_dlatches.insert(cell);
log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n",
@@ -420,7 +422,7 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
struct ProcDlatchPass : public Pass {
ProcDlatchPass() : Pass("proc_dlatch", "extract latches from processes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -430,7 +432,7 @@ struct ProcDlatchPass : public Pass {
log("d-type latches.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PROC_DLATCH pass (convert process syncs to latches).\n");
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index 0c8fb83d..e2dc07e5 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -102,7 +102,7 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
struct ProcInitPass : public Pass {
ProcInitPass() : Pass("proc_init", "convert initial block to init attributes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -113,7 +113,7 @@ struct ProcInitPass : public Pass {
log("respective wire.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PROC_INIT pass (extract init attributes).\n");
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index 57e131ca..1329c1fe 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -382,7 +382,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode)
struct ProcMuxPass : public Pass {
ProcMuxPass() : Pass("proc_mux", "convert decision trees to multiplexers") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -396,7 +396,7 @@ struct ProcMuxPass : public Pass {
log(" 'case' expressions and 'if' conditions.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool ifxmode = false;
log_header(design, "Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index 5672fb47..7c334e66 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -65,7 +65,7 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
struct ProcRmdeadPass : public Pass {
ProcRmdeadPass() : Pass("proc_rmdead", "eliminate dead trees in decision trees") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -74,7 +74,7 @@ struct ProcRmdeadPass : public Pass {
log("This pass identifies unreachable branches in decision trees and removes them.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n");
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index 6785b750..8ab0280c 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -2,8 +2,10 @@
OBJS += passes/sat/sat.o
OBJS += passes/sat/freduce.o
OBJS += passes/sat/eval.o
+OBJS += passes/sat/sim.o
OBJS += passes/sat/miter.o
OBJS += passes/sat/expose.o
OBJS += passes/sat/assertpmux.o
OBJS += passes/sat/clk2fflogic.o
+OBJS += passes/sat/async2sync.o
diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc
index 63a90767..509cb0ba 100644
--- a/passes/sat/assertpmux.cc
+++ b/passes/sat/assertpmux.cc
@@ -181,7 +181,7 @@ struct AssertpmuxWorker
struct AssertpmuxPass : public Pass {
AssertpmuxPass() : Pass("assertpmux", "convert internal signals to module ports") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -199,7 +199,7 @@ struct AssertpmuxPass : public Pass {
log(" additional constrained and check the $pmux condition always.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_noinit = false;
bool flag_always = false;
diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc
new file mode 100644
index 00000000..c92db711
--- /dev/null
+++ b/passes/sat/async2sync.cc
@@ -0,0 +1,147 @@
+/*
+ * 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 Async2syncPass : public Pass {
+ Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" async2sync [options] [selection]\n");
+ log("\n");
+ log("This command replaces async FF inputs with sync circuits emulating the same\n");
+ log("behavior for when the async signals are actually synchronized to the clock.\n");
+ log("\n");
+ log("This pass assumes negative hold time for the async FF inputs. For example when\n");
+ log("a reset deasserts with the clock edge, then the FF output will still drive the\n");
+ log("reset value in the next cycle regardless of the data-in value at the time of\n");
+ log("the clock edge.\n");
+ log("\n");
+ log("Currently only $adff cells are supported by this pass.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ // bool flag_noinit = false;
+
+ log_header(design, "Executing ASYNC2SYNC pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-noinit") {
+ // flag_noinit = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ dict<SigBit, State> initbits;
+ pool<SigBit> del_initbits;
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init") > 0)
+ {
+ Const initval = wire->attributes.at("\\init");
+ SigSpec initsig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ initbits[initsig[i]] = initval[i];
+ }
+
+ for (auto cell : vector<Cell*>(module->selected_cells()))
+ {
+ if (cell->type.in("$adff"))
+ {
+ // bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool();
+ bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool();
+ Const arst_val = cell->parameters["\\ARST_VALUE"];
+
+ SigSpec sig_clk = cell->getPort("\\CLK");
+ SigSpec sig_arst = cell->getPort("\\ARST");
+ SigSpec sig_d = cell->getPort("\\D");
+ SigSpec sig_q = cell->getPort("\\Q");
+
+ log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(sig_arst), log_signal(sig_d), log_signal(sig_q));
+
+ Const init_val;
+ for (int i = 0; i < GetSize(sig_q); i++) {
+ SigBit bit = sigmap(sig_q[i]);
+ init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
+ del_initbits.insert(bit);
+ }
+
+ Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
+ Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
+ new_q->attributes["\\init"] = init_val;
+
+ if (arst_pol) {
+ module->addMux(NEW_ID, sig_d, arst_val, sig_arst, new_d);
+ module->addMux(NEW_ID, new_q, arst_val, sig_arst, sig_q);
+ } else {
+ module->addMux(NEW_ID, arst_val, sig_d, sig_arst, new_d);
+ module->addMux(NEW_ID, arst_val, new_q, sig_arst, sig_q);
+ }
+
+ cell->setPort("\\D", new_d);
+ cell->setPort("\\Q", new_q);
+ cell->unsetPort("\\ARST");
+ cell->unsetParam("\\ARST_POLARITY");
+ cell->unsetParam("\\ARST_VALUE");
+ cell->type = "$dff";
+ continue;
+ }
+ }
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init") > 0)
+ {
+ bool delete_initattr = true;
+ Const initval = wire->attributes.at("\\init");
+ SigSpec initsig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
+ if (del_initbits.count(initsig[i]) > 0)
+ initval[i] = State::Sx;
+ else if (initval[i] != State::Sx)
+ delete_initattr = false;
+
+ if (delete_initattr)
+ wire->attributes.erase("\\init");
+ else
+ wire->attributes.at("\\init") = initval;
+ }
+ }
+ }
+} Async2syncPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc
index ef6d5dd7..49ec795d 100644
--- a/passes/sat/clk2fflogic.cc
+++ b/passes/sat/clk2fflogic.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct Clk2fflogicPass : public Pass {
Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -36,7 +36,7 @@ struct Clk2fflogicPass : public Pass {
log("multiple clocks.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
// bool flag_noinit = false;
@@ -72,7 +72,88 @@ struct Clk2fflogicPass : public Pass {
for (auto cell : vector<Cell*>(module->selected_cells()))
{
- if (cell->type.in("$dlatch"))
+ if (cell->type.in("$mem"))
+ {
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+ int rd_ports = cell->getParam("\\RD_PORTS").as_int();
+ int wr_ports = cell->getParam("\\WR_PORTS").as_int();
+
+ for (int i = 0; i < rd_ports; i++) {
+ if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool())
+ log_error("Read port %d of memory %s.%s is clocked. This is not supported by \"clk2fflogic\"! "
+ "Call \"memory\" with -nordff to avoid this error.\n", i, log_id(cell), log_id(module));
+ }
+
+ Const wr_clk_en_param = cell->getParam("\\WR_CLK_ENABLE");
+ Const wr_clk_pol_param = cell->getParam("\\WR_CLK_POLARITY");
+
+ SigSpec wr_clk_port = cell->getPort("\\WR_CLK");
+ SigSpec wr_en_port = cell->getPort("\\WR_EN");
+ SigSpec wr_addr_port = cell->getPort("\\WR_ADDR");
+ SigSpec wr_data_port = cell->getPort("\\WR_DATA");
+
+ for (int wport = 0; wport < wr_ports; wport++)
+ {
+ bool clken = wr_clk_en_param[wport] == State::S1;
+ bool clkpol = wr_clk_pol_param[wport] == State::S1;
+
+ if (!clken)
+ continue;
+
+ SigBit clk = wr_clk_port[wport];
+ SigSpec en = wr_en_port.extract(wport*width, width);
+ SigSpec addr = wr_addr_port.extract(wport*abits, abits);
+ SigSpec data = wr_data_port.extract(wport*width, width);
+
+ log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n",
+ wport, log_id(module), log_id(cell), log_signal(clk),
+ log_signal(addr), log_signal(data));
+
+ Wire *past_clk = module->addWire(NEW_ID);
+ past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0;
+ module->addFf(NEW_ID, clk, past_clk);
+
+ SigSpec clock_edge_pattern;
+
+ if (clkpol) {
+ clock_edge_pattern.append_bit(State::S0);
+ clock_edge_pattern.append_bit(State::S1);
+ } else {
+ clock_edge_pattern.append_bit(State::S1);
+ clock_edge_pattern.append_bit(State::S0);
+ }
+
+ SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
+
+ SigSpec en_q = module->addWire(NEW_ID, GetSize(en));
+ module->addFf(NEW_ID, en, en_q);
+
+ SigSpec addr_q = module->addWire(NEW_ID, GetSize(addr));
+ module->addFf(NEW_ID, addr, addr_q);
+
+ SigSpec data_q = module->addWire(NEW_ID, GetSize(data));
+ module->addFf(NEW_ID, data, data_q);
+
+ wr_clk_port[wport] = State::S0;
+ wr_en_port.replace(wport*width, module->Mux(NEW_ID, Const(0, GetSize(en_q)), en_q, clock_edge));
+ wr_addr_port.replace(wport*abits, addr_q);
+ wr_data_port.replace(wport*width, data_q);
+
+ wr_clk_en_param[wport] = State::S0;
+ wr_clk_pol_param[wport] = State::S0;
+ }
+
+ cell->setParam("\\WR_CLK_ENABLE", wr_clk_en_param);
+ cell->setParam("\\WR_CLK_POLARITY", wr_clk_pol_param);
+
+ cell->setPort("\\WR_CLK", wr_clk_port);
+ cell->setPort("\\WR_EN", wr_en_port);
+ cell->setPort("\\WR_ADDR", wr_addr_port);
+ cell->setPort("\\WR_DATA", wr_data_port);
+ }
+
+ if (cell->type.in("$dlatch", "$dlatchsr"))
{
bool enpol = cell->parameters["\\EN_POLARITY"].as_bool();
@@ -87,10 +168,31 @@ struct Clk2fflogicPass : public Pass {
Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
module->addFf(NEW_ID, sig_q, past_q);
- if (enpol)
- module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q);
+ if (cell->type == "$dlatch")
+ {
+ if (enpol)
+ module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q);
+ else
+ module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q);
+ }
else
- module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q);
+ {
+ SigSpec t;
+ if (enpol)
+ t = module->Mux(NEW_ID, past_q, sig_d, sig_en);
+ else
+ t = module->Mux(NEW_ID, sig_d, past_q, sig_en);
+
+ SigSpec s = cell->getPort("\\SET");
+ if (!cell->parameters["\\SET_POLARITY"].as_bool())
+ s = module->Not(NEW_ID, s);
+ t = module->Or(NEW_ID, t, s);
+
+ SigSpec c = cell->getPort("\\CLR");
+ if (cell->parameters["\\CLR_POLARITY"].as_bool())
+ c = module->Not(NEW_ID, c);
+ module->addAnd(NEW_ID, t, c, sig_q);
+ }
Const initval;
bool assign_initval = false;
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index 09f69cc5..008cd2df 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -360,7 +360,7 @@ struct VlogHammerReporter
struct EvalPass : public Pass {
EvalPass() : Pass("eval", "evaluate the circuit given an input") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -383,7 +383,7 @@ struct EvalPass : public Pass {
log(" then all output ports of the current module are used.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<std::pair<std::string, std::string>> sets;
std::vector<std::string> shows, tables;
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index 9427547f..80934548 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -220,7 +220,7 @@ RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width
struct ExposePass : public Pass {
ExposePass() : Pass("expose", "convert internal signals to module ports") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -236,6 +236,10 @@ struct ExposePass : public Pass {
log(" when exposing a wire, create an input/output pair and cut the internal\n");
log(" signal path at that wire.\n");
log("\n");
+ log(" -input\n");
+ log(" when exposing a wire, create an input port and disconnect the internal\n");
+ log(" driver.\n");
+ log("\n");
log(" -shared\n");
log(" only expose those signals that are shared among the selected modules.\n");
log(" this is useful for preparing modules for equivalence checking.\n");
@@ -253,12 +257,13 @@ struct ExposePass : public Pass {
log(" designator for the exposed signal.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool flag_shared = false;
bool flag_evert = false;
bool flag_dff = false;
bool flag_cut = false;
+ bool flag_input = false;
bool flag_evert_dff = false;
std::string sep = ".";
@@ -279,10 +284,14 @@ struct ExposePass : public Pass {
flag_dff = true;
continue;
}
- if (args[argidx] == "-cut") {
+ if (args[argidx] == "-cut" && !flag_input) {
flag_cut = true;
continue;
}
+ if (args[argidx] == "-input" && !flag_cut) {
+ flag_input = true;
+ continue;
+ }
if (args[argidx] == "-evert-dff") {
flag_evert_dff = true;
continue;
@@ -464,16 +473,42 @@ struct ExposePass : public Pass {
continue;
}
- if (!it.second->port_output) {
- it.second->port_output = true;
- log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
+ if (flag_input)
+ {
+ if (!it.second->port_input) {
+ it.second->port_input = true;
+ log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
+ RTLIL::Wire *w = module->addWire(NEW_ID, GetSize(it.second));
+ out_to_in_map.add(it.second, w);
+ }
+ }
+ else
+ {
+ if (!it.second->port_output) {
+ it.second->port_output = true;
+ log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
+ }
+
+ if (flag_cut) {
+ RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width);
+ in_wire->port_input = true;
+ out_to_in_map.add(sigmap(it.second), in_wire);
+ }
}
+ }
- if (flag_cut) {
- RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width);
- in_wire->port_input = true;
- out_to_in_map.add(sigmap(it.second), in_wire);
+ if (flag_input)
+ {
+ for (auto &it : module->cells_) {
+ if (!ct.cell_known(it.second->type))
+ continue;
+ for (auto &conn : it.second->connections_)
+ if (ct.cell_output(it.second->type, conn.first))
+ conn.second = out_to_in_map(sigmap(conn.second));
}
+
+ for (auto &conn : module->connections_)
+ conn.first = out_to_in_map(sigmap(conn.first));
}
if (flag_cut)
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index 77263f6a..f2963163 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -687,7 +687,8 @@ struct FreduceWorker
}
std::map<RTLIL::SigBit, int> bitusage;
- module->rewrite_sigspecs(CountBitUsage(sigmap, bitusage));
+ CountBitUsage bitusage_worker(sigmap, bitusage);
+ module->rewrite_sigspecs(bitusage_worker);
if (!dump_prefix.empty())
dump();
@@ -759,7 +760,7 @@ struct FreduceWorker
struct FreducePass : public Pass {
FreducePass() : Pass("freduce", "perform functional reduction") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -790,7 +791,7 @@ struct FreducePass : public Pass {
log("circuit that is analyzed.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
reduce_counter = 0;
reduce_stop_at = 0;
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index 9e150b60..d37f1b12 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -358,7 +358,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
struct MiterPass : public Pass {
MiterPass() : Pass("miter", "automatically create a miter circuit") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -402,7 +402,7 @@ struct MiterPass : public Pass {
log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
if (args.size() > 1 && args[1] == "-equiv") {
create_miter_equiv(this, args, design);
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index a6ac7afd..695a03e1 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -691,7 +691,6 @@ struct SatHelper
// VCD has some limits on internal (non-display) identifier names, so make legal ones
std::map<std::string, std::string> vcdnames;
- fprintf(f, "$timescale 1ns\n"); // arbitrary time scale since actual clock period is unknown/unimportant
fprintf(f, "$scope module %s $end\n", module->name.c_str());
for (auto &info : modelInfo)
{
@@ -891,7 +890,7 @@ void print_qed()
struct SatPass : public Pass {
SatPass() : Pass("sat", "solve a SAT problem in the circuit") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1058,7 +1057,7 @@ struct SatPass : public Pass {
log(" Like -falsify but do not return an error for timeouts.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::vector<std::pair<std::string, std::string>> sets, sets_init, prove, prove_x;
std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at;
diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc
new file mode 100644
index 00000000..fadffcdb
--- /dev/null
+++ b/passes/sat/sim.cc
@@ -0,0 +1,862 @@
+/*
+ * 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 SimShared
+{
+ bool debug = false;
+ bool hide_internal = true;
+ bool writeback = false;
+ bool zinit = false;
+ int rstlen = 1;
+};
+
+void zinit(State &v)
+{
+ if (v != State::S1)
+ v = State::S0;
+}
+
+void zinit(Const &v)
+{
+ for (auto &bit : v.bits)
+ zinit(bit);
+}
+
+struct SimInstance
+{
+ SimShared *shared;
+
+ Module *module;
+ Cell *instance;
+
+ SimInstance *parent;
+ dict<Cell*, SimInstance*> children;
+
+ SigMap sigmap;
+ dict<SigBit, State> state_nets;
+ dict<SigBit, pool<Cell*>> upd_cells;
+ dict<SigBit, pool<Wire*>> upd_outports;
+
+ pool<SigBit> dirty_bits;
+ pool<Cell*> dirty_cells;
+ pool<SimInstance*, hash_ptr_ops> dirty_children;
+
+ struct ff_state_t
+ {
+ State past_clock;
+ Const past_d;
+ };
+
+ struct mem_state_t
+ {
+ Const past_wr_clk;
+ Const past_wr_en;
+ Const past_wr_addr;
+ Const past_wr_data;
+ Const data;
+ };
+
+ dict<Cell*, ff_state_t> ff_database;
+ dict<Cell*, mem_state_t> mem_database;
+ pool<Cell*> formal_database;
+
+ dict<Wire*, pair<int, Const>> vcd_database;
+
+ SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
+ shared(shared), module(module), instance(instance), parent(parent), sigmap(module)
+ {
+ if (parent) {
+ log_assert(parent->children.count(instance) == 0);
+ parent->children[instance] = this;
+ }
+
+ for (auto wire : module->wires())
+ {
+ SigSpec sig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(sig); i++) {
+ if (state_nets.count(sig[i]) == 0)
+ state_nets[sig[i]] = State::Sx;
+ if (wire->port_output) {
+ upd_outports[sig[i]].insert(wire);
+ dirty_bits.insert(sig[i]);
+ }
+ }
+
+ if (wire->attributes.count("\\init")) {
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1) {
+ state_nets[sig[i]] = initval[i];
+ dirty_bits.insert(sig[i]);
+ }
+ }
+ }
+
+ for (auto cell : module->cells())
+ {
+ Module *mod = module->design->module(cell->type);
+
+ if (mod != nullptr) {
+ dirty_children.insert(new SimInstance(shared, mod, cell, this));
+ }
+
+ for (auto &port : cell->connections()) {
+ if (cell->input(port.first))
+ for (auto bit : sigmap(port.second))
+ upd_cells[bit].insert(cell);
+ }
+
+ if (cell->type.in("$dff")) {
+ ff_state_t ff;
+ ff.past_clock = State::Sx;
+ ff.past_d = Const(State::Sx, cell->getParam("\\WIDTH").as_int());
+ ff_database[cell] = ff;
+ }
+
+ if (cell->type == "$mem")
+ {
+ mem_state_t mem;
+
+ mem.past_wr_clk = Const(State::Sx, GetSize(cell->getPort("\\WR_CLK")));
+ mem.past_wr_en = Const(State::Sx, GetSize(cell->getPort("\\WR_EN")));
+ mem.past_wr_addr = Const(State::Sx, GetSize(cell->getPort("\\WR_ADDR")));
+ mem.past_wr_data = Const(State::Sx, GetSize(cell->getPort("\\WR_DATA")));
+
+ mem.data = cell->getParam("\\INIT");
+ int sz = cell->getParam("\\SIZE").as_int() * cell->getParam("\\WIDTH").as_int();
+
+ if (GetSize(mem.data) > sz)
+ mem.data.bits.resize(sz);
+
+ while (GetSize(mem.data) < sz)
+ mem.data.bits.push_back(State::Sx);
+
+ mem_database[cell] = mem;
+ }
+
+ if (cell->type.in("$assert", "$cover", "$assume")) {
+ formal_database.insert(cell);
+ }
+ }
+
+ if (shared->zinit)
+ {
+ for (auto &it : ff_database)
+ {
+ Cell *cell = it.first;
+ ff_state_t &ff = it.second;
+ zinit(ff.past_d);
+
+ SigSpec qsig = cell->getPort("\\Q");
+ Const qdata = get_state(qsig);
+ zinit(qdata);
+ set_state(qsig, qdata);
+ }
+
+ for (auto &it : mem_database) {
+ mem_state_t &mem = it.second;
+ zinit(mem.past_wr_en);
+ zinit(mem.data);
+ }
+ }
+ }
+
+ ~SimInstance()
+ {
+ for (auto child : children)
+ delete child.second;
+ }
+
+ IdString name() const
+ {
+ if (instance != nullptr)
+ return instance->name;
+ return module->name;
+ }
+
+ std::string hiername() const
+ {
+ if (instance != nullptr)
+ return parent->hiername() + "." + log_id(instance->name);
+
+ return log_id(module->name);
+ }
+
+ Const get_state(SigSpec sig)
+ {
+ Const value;
+
+ for (auto bit : sigmap(sig))
+ if (bit.wire == nullptr)
+ value.bits.push_back(bit.data);
+ else if (state_nets.count(bit))
+ value.bits.push_back(state_nets.at(bit));
+ else
+ value.bits.push_back(State::Sz);
+
+ if (shared->debug)
+ log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
+ return value;
+ }
+
+ bool set_state(SigSpec sig, Const value)
+ {
+ bool did_something = false;
+
+ sig = sigmap(sig);
+ log_assert(GetSize(sig) == GetSize(value));
+
+ for (int i = 0; i < GetSize(sig); i++)
+ if (state_nets.at(sig[i]) != value[i]) {
+ state_nets.at(sig[i]) = value[i];
+ dirty_bits.insert(sig[i]);
+ did_something = true;
+ }
+
+ if (shared->debug)
+ log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
+ return did_something;
+ }
+
+ void update_cell(Cell *cell)
+ {
+ if (ff_database.count(cell))
+ return;
+
+ if (formal_database.count(cell))
+ return;
+
+ if (mem_database.count(cell))
+ {
+ mem_state_t &mem = mem_database.at(cell);
+
+ int num_rd_ports = cell->getParam("\\RD_PORTS").as_int();
+
+ int size = cell->getParam("\\SIZE").as_int();
+ int offset = cell->getParam("\\OFFSET").as_int();
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+
+ if (cell->getParam("\\RD_CLK_ENABLE").as_bool())
+ log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(cell));
+
+ SigSpec rd_addr_sig = cell->getPort("\\RD_ADDR");
+ SigSpec rd_data_sig = cell->getPort("\\RD_DATA");
+
+ for (int port_idx = 0; port_idx < num_rd_ports; port_idx++)
+ {
+ Const addr = get_state(rd_addr_sig.extract(port_idx*abits, abits));
+ Const data = Const(State::Sx, width);
+
+ if (addr.is_fully_def()) {
+ int index = addr.as_int() - offset;
+ if (index >= 0 && index < size)
+ data = mem.data.extract(index*width, width);
+ }
+
+ set_state(rd_data_sig.extract(port_idx*width, width), data);
+ }
+
+ return;
+ }
+
+ if (children.count(cell))
+ {
+ auto child = children.at(cell);
+ for (auto &conn: cell->connections())
+ if (cell->input(conn.first)) {
+ Const value = get_state(conn.second);
+ child->set_state(child->module->wire(conn.first), value);
+ }
+ dirty_children.insert(child);
+ return;
+ }
+
+ if (yosys_celltypes.cell_evaluable(cell->type))
+ {
+ RTLIL::SigSpec sig_a, sig_b, sig_c, sig_d, sig_s, sig_y;
+ bool has_a, has_b, has_c, has_d, has_s, has_y;
+
+ has_a = cell->hasPort("\\A");
+ has_b = cell->hasPort("\\B");
+ has_c = cell->hasPort("\\C");
+ has_d = cell->hasPort("\\D");
+ has_s = cell->hasPort("\\S");
+ has_y = cell->hasPort("\\Y");
+
+ if (has_a) sig_a = cell->getPort("\\A");
+ if (has_b) sig_b = cell->getPort("\\B");
+ if (has_c) sig_c = cell->getPort("\\C");
+ if (has_d) sig_d = cell->getPort("\\D");
+ if (has_s) sig_s = cell->getPort("\\S");
+ if (has_y) sig_y = cell->getPort("\\Y");
+
+ if (shared->debug)
+ log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell), log_id(cell->type));
+
+ // Simple (A -> Y) and (A,B -> Y) cells
+ if (has_a && !has_c && !has_d && !has_s && has_y) {
+ set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b)));
+ return;
+ }
+
+ // (A,B,C -> Y) cells
+ if (has_a && has_b && has_c && !has_d && !has_s && has_y) {
+ set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_c)));
+ return;
+ }
+
+ // (A,B,S -> Y) cells
+ if (has_a && has_b && !has_c && !has_d && has_s && has_y) {
+ set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_s)));
+ return;
+ }
+
+ log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
+ return;
+ }
+
+ log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
+ }
+
+ void update_ph1()
+ {
+ pool<Cell*> queue_cells;
+ pool<Wire*> queue_outports;
+
+ queue_cells.swap(dirty_cells);
+
+ while (1)
+ {
+ for (auto bit : dirty_bits)
+ {
+ if (upd_cells.count(bit))
+ for (auto cell : upd_cells.at(bit))
+ queue_cells.insert(cell);
+
+ if (upd_outports.count(bit) && parent != nullptr)
+ for (auto wire : upd_outports.at(bit))
+ queue_outports.insert(wire);
+ }
+
+ dirty_bits.clear();
+
+ if (!queue_cells.empty())
+ {
+ for (auto cell : queue_cells)
+ update_cell(cell);
+
+ queue_cells.clear();
+ continue;
+ }
+
+ for (auto wire : queue_outports)
+ if (instance->hasPort(wire->name)) {
+ Const value = get_state(wire);
+ parent->set_state(instance->getPort(wire->name), value);
+ }
+
+ queue_outports.clear();
+
+ for (auto child : dirty_children)
+ child->update_ph1();
+
+ dirty_children.clear();
+
+ if (dirty_bits.empty())
+ break;
+ }
+ }
+
+ bool update_ph2()
+ {
+ bool did_something = false;
+
+ for (auto &it : ff_database)
+ {
+ Cell *cell = it.first;
+ ff_state_t &ff = it.second;
+
+ if (cell->type.in("$dff"))
+ {
+ bool clkpol = cell->getParam("\\CLK_POLARITY").as_bool();
+ State current_clock = get_state(cell->getPort("\\CLK"))[0];
+
+ if (clkpol ? (ff.past_clock == State::S1 || current_clock != State::S1) :
+ (ff.past_clock == State::S0 || current_clock != State::S0))
+ continue;
+
+ if (set_state(cell->getPort("\\Q"), ff.past_d))
+ did_something = true;
+ }
+ }
+
+ for (auto &it : mem_database)
+ {
+ Cell *cell = it.first;
+ mem_state_t &mem = it.second;
+
+ int num_wr_ports = cell->getParam("\\WR_PORTS").as_int();
+
+ int size = cell->getParam("\\SIZE").as_int();
+ int offset = cell->getParam("\\OFFSET").as_int();
+ int abits = cell->getParam("\\ABITS").as_int();
+ int width = cell->getParam("\\WIDTH").as_int();
+
+ Const wr_clk_enable = cell->getParam("\\WR_CLK_ENABLE");
+ Const wr_clk_polarity = cell->getParam("\\WR_CLK_POLARITY");
+ Const current_wr_clk = get_state(cell->getPort("\\WR_CLK"));
+
+ for (int port_idx = 0; port_idx < num_wr_ports; port_idx++)
+ {
+ Const addr, data, enable;
+
+ if (wr_clk_enable[port_idx] == State::S0)
+ {
+ addr = get_state(cell->getPort("\\WR_ADDR").extract(port_idx*abits, abits));
+ data = get_state(cell->getPort("\\WR_DATA").extract(port_idx*width, width));
+ enable = get_state(cell->getPort("\\WR_EN").extract(port_idx*width, width));
+ }
+ else
+ {
+ if (wr_clk_polarity[port_idx] == State::S1 ?
+ (mem.past_wr_clk[port_idx] == State::S1 || current_wr_clk[port_idx] != State::S1) :
+ (mem.past_wr_clk[port_idx] == State::S0 || current_wr_clk[port_idx] != State::S0))
+ continue;
+
+ addr = mem.past_wr_addr.extract(port_idx*abits, abits);
+ data = mem.past_wr_data.extract(port_idx*width, width);
+ enable = mem.past_wr_en.extract(port_idx*width, width);
+ }
+
+ if (addr.is_fully_def())
+ {
+ int index = addr.as_int() - offset;
+ if (index >= 0 && index < size)
+ for (int i = 0; i < width; i++)
+ if (enable[i] == State::S1 && mem.data.bits.at(index*width+i) != data[i]) {
+ mem.data.bits.at(index*width+i) = data[i];
+ dirty_cells.insert(cell);
+ did_something = true;
+ }
+ }
+ }
+ }
+
+ for (auto it : children)
+ if (it.second->update_ph2()) {
+ dirty_children.insert(it.second);
+ did_something = true;
+ }
+
+ return did_something;
+ }
+
+ void update_ph3()
+ {
+ for (auto &it : ff_database)
+ {
+ Cell *cell = it.first;
+ ff_state_t &ff = it.second;
+
+ if (cell->type.in("$dff")) {
+ ff.past_clock = get_state(cell->getPort("\\CLK"))[0];
+ ff.past_d = get_state(cell->getPort("\\D"));
+ }
+ }
+
+ for (auto &it : mem_database)
+ {
+ Cell *cell = it.first;
+ mem_state_t &mem = it.second;
+
+ mem.past_wr_clk = get_state(cell->getPort("\\WR_CLK"));
+ mem.past_wr_en = get_state(cell->getPort("\\WR_EN"));
+ mem.past_wr_addr = get_state(cell->getPort("\\WR_ADDR"));
+ mem.past_wr_data = get_state(cell->getPort("\\WR_DATA"));
+ }
+
+ for (auto cell : formal_database)
+ {
+ string label = log_id(cell);
+ if (cell->attributes.count("\\src"))
+ label = cell->attributes.at("\\src").decode_string();
+
+ State a = get_state(cell->getPort("\\A"))[0];
+ State en = get_state(cell->getPort("\\EN"))[0];
+
+ if (cell->type == "$cover" && en == State::S1 && a != State::S1)
+ log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell), label.c_str());
+
+ if (cell->type == "$assume" && en == State::S1 && a != State::S1)
+ log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
+
+ if (cell->type == "$assert" && en == State::S1 && a != State::S1)
+ log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
+ }
+
+ for (auto it : children)
+ it.second->update_ph3();
+ }
+
+ void writeback(pool<Module*> &wbmods)
+ {
+ if (wbmods.count(module))
+ log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module));
+
+ wbmods.insert(module);
+
+ for (auto wire : module->wires())
+ wire->attributes.erase("\\init");
+
+ for (auto &it : ff_database)
+ {
+ Cell *cell = it.first;
+ SigSpec sig_q = cell->getPort("\\Q");
+ Const initval = get_state(sig_q);
+
+ for (int i = 0; i < GetSize(sig_q); i++)
+ {
+ Wire *w = sig_q[i].wire;
+
+ if (w->attributes.count("\\init") == 0)
+ w->attributes["\\init"] = Const(State::Sx, GetSize(w));
+
+ w->attributes["\\init"][sig_q[i].offset] = initval[i];
+ }
+ }
+
+ for (auto &it : mem_database)
+ {
+ Cell *cell = it.first;
+ mem_state_t &mem = it.second;
+ Const initval = mem.data;
+
+ while (GetSize(initval) >= 2) {
+ if (initval[GetSize(initval)-1] != State::Sx) break;
+ if (initval[GetSize(initval)-2] != State::Sx) break;
+ initval.bits.pop_back();
+ }
+
+ cell->setParam("\\INIT", initval);
+ }
+
+ for (auto it : children)
+ it.second->writeback(wbmods);
+ }
+
+ void write_vcd_header(std::ofstream &f, int &id)
+ {
+ f << stringf("$scope module %s $end\n", log_id(name()));
+
+ for (auto wire : module->wires())
+ {
+ if (shared->hide_internal && wire->name[0] == '$')
+ continue;
+
+ f << stringf("$var wire %d n%d %s%s $end\n", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire));
+ vcd_database[wire] = make_pair(id++, Const());
+ }
+
+ for (auto child : children)
+ child.second->write_vcd_header(f, id);
+
+ f << stringf("$upscope $end\n");
+ }
+
+ void write_vcd_step(std::ofstream &f)
+ {
+ for (auto &it : vcd_database)
+ {
+ Wire *wire = it.first;
+ Const value = get_state(wire);
+ int id = it.second.first;
+
+ if (it.second.second == value)
+ continue;
+
+ it.second.second = value;
+
+ f << "b";
+ for (int i = GetSize(value)-1; i >= 0; i--) {
+ switch (value[i]) {
+ case State::S0: f << "0"; break;
+ case State::S1: f << "1"; break;
+ case State::Sx: f << "x"; break;
+ default: f << "z";
+ }
+ }
+
+ f << stringf(" n%d\n", id);
+ }
+
+ for (auto child : children)
+ child.second->write_vcd_step(f);
+ }
+};
+
+struct SimWorker : SimShared
+{
+ SimInstance *top = nullptr;
+ std::ofstream vcdfile;
+ pool<IdString> clock, clockn, reset, resetn;
+
+ ~SimWorker()
+ {
+ delete top;
+ }
+
+ void write_vcd_header()
+ {
+ if (!vcdfile.is_open())
+ return;
+
+ int id = 1;
+ top->write_vcd_header(vcdfile, id);
+
+ vcdfile << stringf("$enddefinitions $end\n");
+ }
+
+ void write_vcd_step(int t)
+ {
+ if (!vcdfile.is_open())
+ return;
+
+ vcdfile << stringf("#%d\n", t);
+ top->write_vcd_step(vcdfile);
+ }
+
+ void update()
+ {
+ while (1)
+ {
+ if (debug)
+ log("\n-- ph1 --\n");
+
+ top->update_ph1();
+
+ if (debug)
+ log("\n-- ph2 --\n");
+
+ if (!top->update_ph2())
+ break;
+ }
+
+ if (debug)
+ log("\n-- ph3 --\n");
+
+ top->update_ph3();
+ }
+
+ void set_inports(pool<IdString> ports, State value)
+ {
+ for (auto portname : ports)
+ {
+ Wire *w = top->module->wire(portname);
+
+ if (w == nullptr)
+ log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
+
+ top->set_state(w, value);
+ }
+ }
+
+ void run(Module *topmod, int numcycles)
+ {
+ log_assert(top == nullptr);
+ top = new SimInstance(this, topmod);
+
+ if (debug)
+ log("\n===== 0 =====\n");
+ else
+ log("Simulating cycle 0.\n");
+
+ set_inports(reset, State::S1);
+ set_inports(resetn, State::S0);
+
+ set_inports(clock, State::Sx);
+ set_inports(clockn, State::Sx);
+
+ update();
+
+ write_vcd_header();
+ write_vcd_step(0);
+
+ for (int cycle = 0; cycle < numcycles; cycle++)
+ {
+ if (debug)
+ log("\n===== %d =====\n", 10*cycle + 5);
+
+ set_inports(clock, State::S0);
+ set_inports(clockn, State::S1);
+
+ update();
+ write_vcd_step(10*cycle + 5);
+
+ if (debug)
+ log("\n===== %d =====\n", 10*cycle + 10);
+ else
+ log("Simulating cycle %d.\n", cycle+1);
+
+ set_inports(clock, State::S1);
+ set_inports(clockn, State::S0);
+
+ if (cycle+1 == rstlen) {
+ set_inports(reset, State::S0);
+ set_inports(resetn, State::S1);
+ }
+
+ update();
+ write_vcd_step(10*cycle + 10);
+ }
+
+ write_vcd_step(10*numcycles + 2);
+
+ if (writeback) {
+ pool<Module*> wbmods;
+ top->writeback(wbmods);
+ }
+ }
+};
+
+struct SimPass : public Pass {
+ SimPass() : Pass("sim", "simulate the circuit") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" sim [options] [top-level]\n");
+ log("\n");
+ log("This command simulates the circuit using the given top-level module.\n");
+ log("\n");
+ log(" -vcd <filename>\n");
+ log(" write the simulation results to the given VCD file\n");
+ log("\n");
+ log(" -clock <portname>\n");
+ log(" name of top-level clock input\n");
+ log("\n");
+ log(" -clockn <portname>\n");
+ log(" name of top-level clock input (inverse polarity)\n");
+ log("\n");
+ log(" -reset <portname>\n");
+ log(" name of top-level reset input (active high)\n");
+ log("\n");
+ log(" -resetn <portname>\n");
+ log(" name of top-level inverted reset input (active low)\n");
+ log("\n");
+ log(" -rstlen <integer>\n");
+ log(" number of cycles reset should stay active (default: 1)\n");
+ log("\n");
+ log(" -zinit\n");
+ log(" zero-initialize all uninitialized regs and memories\n");
+ log("\n");
+ log(" -n <integer>\n");
+ log(" number of cycles to simulate (default: 20)\n");
+ log("\n");
+ log(" -a\n");
+ log(" include all nets in VCD output, nut just those with public names\n");
+ log("\n");
+ log(" -w\n");
+ log(" writeback mode: use final simulation state as new init state\n");
+ log("\n");
+ log(" -d\n");
+ log(" enable debug output\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ SimWorker worker;
+ int numcycles = 20;
+
+ log_header(design, "Executing SIM pass (simulate the circuit).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-vcd" && argidx+1 < args.size()) {
+ worker.vcdfile.open(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-n" && argidx+1 < args.size()) {
+ numcycles = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-rstlen" && argidx+1 < args.size()) {
+ worker.rstlen = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-clock" && argidx+1 < args.size()) {
+ worker.clock.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ if (args[argidx] == "-clockn" && argidx+1 < args.size()) {
+ worker.clockn.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ if (args[argidx] == "-reset" && argidx+1 < args.size()) {
+ worker.reset.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ if (args[argidx] == "-resetn" && argidx+1 < args.size()) {
+ worker.resetn.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ if (args[argidx] == "-a") {
+ worker.hide_internal = false;
+ continue;
+ }
+ if (args[argidx] == "-d") {
+ worker.debug = true;
+ continue;
+ }
+ if (args[argidx] == "-w") {
+ worker.writeback = true;
+ continue;
+ }
+ if (args[argidx] == "-zinit") {
+ worker.zinit = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ Module *top_mod = nullptr;
+
+ if (design->full_selection()) {
+ top_mod = design->top_module();
+ } else {
+ auto mods = design->selected_whole_modules();
+ if (GetSize(mods) != 1)
+ log_cmd_error("Only one top module must be selected.\n");
+ top_mod = mods.front();
+ }
+
+ worker.run(top_mod, numcycles);
+ }
+} SimPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 311a1af9..4faa0ab0 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -16,6 +16,9 @@ ifneq ($(SMALL),1)
OBJS += passes/techmap/iopadmap.o
OBJS += passes/techmap/hilomap.o
OBJS += passes/techmap/extract.o
+OBJS += passes/techmap/extract_fa.o
+OBJS += passes/techmap/extract_counter.o
+OBJS += passes/techmap/extract_reduce.o
OBJS += passes/techmap/alumacc.o
OBJS += passes/techmap/dff2dffe.o
OBJS += passes/techmap/dffinit.o
@@ -32,6 +35,7 @@ OBJS += passes/techmap/insbuf.o
OBJS += passes/techmap/attrmvcp.o
OBJS += passes/techmap/attrmap.o
OBJS += passes/techmap/zinit.o
+OBJS += passes/techmap/dff2dffs.o
endif
GENFILES += passes/techmap/techmap.inc
@@ -54,4 +58,3 @@ yosys-filterlib$(EXE): passes/techmap/filterlib.o
$(Q) mkdir -p $(dir $@)
$(P) $(LD) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS)
endif
-
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index cc79296c..d2d15a4a 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -29,17 +29,17 @@
// 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; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}"
-#define ABC_COMMAND_CTR "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_COMMAND_LUT "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; if; mfs"
-#define ABC_COMMAND_SOP "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; cover {I} {P}"
-#define ABC_COMMAND_DFL "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; map"
-
-#define ABC_FAST_COMMAND_LIB "retime -o {D}; map {D}"
-#define ABC_FAST_COMMAND_CTR "retime -o {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_FAST_COMMAND_LUT "retime -o; if"
-#define ABC_FAST_COMMAND_SOP "retime -o; cover -I {I} -P {P}"
-#define ABC_FAST_COMMAND_DFL "retime -o; map"
+#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
+#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
+#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
+#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
+
+#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
+#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
+#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
+#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@@ -60,6 +60,10 @@
#include "frontends/blif/blifparse.h"
+#ifdef YOSYS_LINK_ABC
+extern "C" int Abc_RealMain(int argc, char *argv[]);
+#endif
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -74,6 +78,8 @@ enum class gate_type_t {
G_NOR,
G_XOR,
G_XNOR,
+ G_ANDNOT,
+ G_ORNOT,
G_MUX,
G_AOI3,
G_OAI3,
@@ -90,6 +96,7 @@ struct gate_t
int in1, in2, in3, in4;
bool is_port;
RTLIL::SigBit bit;
+ RTLIL::State init;
};
bool map_mux4;
@@ -102,10 +109,13 @@ SigMap assign_map;
RTLIL::Module *module;
std::vector<gate_t> signal_list;
std::map<RTLIL::SigBit, int> signal_map;
+std::map<RTLIL::SigBit, RTLIL::State> signal_init;
pool<std::string> enabled_gates;
+bool recover_init;
bool clk_polarity, en_polarity;
RTLIL::SigSpec clk_sig, en_sig;
+dict<int, std::string> pi_map, po_map;
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)
{
@@ -121,6 +131,10 @@ int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1,
gate.in4 = -1;
gate.is_port = false;
gate.bit = bit;
+ if (signal_init.count(bit))
+ gate.init = signal_init.at(bit);
+ else
+ gate.init = State::Sx;
signal_list.push_back(gate);
signal_map[bit] = gate.id;
}
@@ -207,7 +221,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
return;
}
- if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_b = cell->getPort("\\B");
@@ -232,6 +246,10 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
map_signal(sig_y, G(XOR), mapped_a, mapped_b);
else if (cell->type == "$_XNOR_")
map_signal(sig_y, G(XNOR), mapped_a, mapped_b);
+ else if (cell->type == "$_ANDNOT_")
+ map_signal(sig_y, G(ANDNOT), mapped_a, mapped_b);
+ else if (cell->type == "$_ORNOT_")
+ map_signal(sig_y, G(ORNOT), mapped_a, mapped_b);
else
log_abort();
@@ -532,11 +550,13 @@ std::string replace_tempdir(std::string text, std::string tempdir_name, bool sho
}
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));
+ if (selfdir_name != "/") {
+ while (1) {
+ size_t pos = text.find(selfdir_name);
+ if (pos == std::string::npos)
+ break;
+ text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
+ }
}
return text;
@@ -588,6 +608,14 @@ struct abc_output_filter
void next_line(const std::string &line)
{
+ int pi, po;
+ if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) {
+ log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n",
+ pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???",
+ po, po_map.count(po) ? po_map.at(po).c_str() : "???");
+ return;
+ }
+
for (char ch : line)
next_char(ch);
}
@@ -595,7 +623,7 @@ struct abc_output_filter
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
- bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, bool fast_mode,
+ bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode)
{
module = current_module;
@@ -603,11 +631,12 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
signal_map.clear();
signal_list.clear();
+ pi_map.clear();
+ po_map.clear();
+ recover_init = false;
if (clk_str != "$")
{
- assign_map.set(module);
-
clk_polarity = true;
clk_sig = RTLIL::SigSpec();
@@ -615,6 +644,30 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
en_sig = RTLIL::SigSpec();
}
+ if (!clk_str.empty() && clk_str != "$")
+ {
+ if (clk_str.find(',') != std::string::npos) {
+ int pos = clk_str.find(',');
+ std::string en_str = clk_str.substr(pos+1);
+ clk_str = clk_str.substr(0, pos);
+ if (en_str[0] == '!') {
+ en_polarity = false;
+ en_str = en_str.substr(1);
+ }
+ if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
+ en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
+ }
+ if (clk_str[0] == '!') {
+ clk_polarity = false;
+ clk_str = clk_str.substr(1);
+ }
+ if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
+ clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
+ }
+
+ if (dff_mode && clk_sig.empty())
+ log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
+
std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
if (!cleanup)
tempdir_name[0] = tempdir_name[4] = '_';
@@ -652,7 +705,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
all_luts_cost_same = false;
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
if (all_luts_cost_same && !fast_mode)
- abc_script += "; lutpack";
+ abc_script += "; lutpack {S}";
} else if (!liberty_file.empty())
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
else if (sop_mode)
@@ -660,6 +713,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
else
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
+ if (script_file.empty() && !delay_target.empty())
+ for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
+ abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
+
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
@@ -669,6 +726,9 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
+ for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
+ abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
+
abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
abc_script = add_echos_to_abc_cmd(abc_script);
@@ -680,30 +740,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "%s\n", abc_script.c_str());
fclose(f);
- if (!clk_str.empty() && clk_str != "$")
- {
- if (clk_str.find(',') != std::string::npos) {
- int pos = clk_str.find(',');
- std::string en_str = clk_str.substr(pos+1);
- clk_str = clk_str.substr(0, pos);
- if (en_str[0] == '!') {
- en_polarity = false;
- en_str = en_str.substr(1);
- }
- if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
- en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
- }
- if (clk_str[0] == '!') {
- clk_polarity = false;
- clk_str = clk_str.substr(1);
- }
- if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
- clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
- }
-
- if (dff_mode && clk_sig.empty())
- log_error("Clock domain %s not found.\n", clk_str.c_str());
-
if (dff_mode || !clk_str.empty())
{
if (clk_sig.size() == 0)
@@ -749,7 +785,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (!si.is_port || si.type != G(NONE))
continue;
fprintf(f, " n%d", si.id);
- count_input++;
+ pi_map[count_input++] = log_signal(si.bit);
}
if (count_input == 0)
fprintf(f, " dummy_input\n");
@@ -761,7 +797,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (!si.is_port || si.type == G(NONE))
continue;
fprintf(f, " n%d", si.id);
- count_output++;
+ po_map[count_output++] = log_signal(si.bit);
}
fprintf(f, "\n");
@@ -806,6 +842,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
fprintf(f, "00 1\n");
fprintf(f, "11 1\n");
+ } else if (si.type == G(ANDNOT)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "10 1\n");
+ } else if (si.type == G(ORNOT)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "1- 1\n");
+ fprintf(f, "-0 1\n");
} else if (si.type == G(MUX)) {
fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
fprintf(f, "1-0 1\n");
@@ -829,7 +872,11 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "00-- 1\n");
fprintf(f, "--00 1\n");
} else if (si.type == G(FF)) {
- fprintf(f, ".latch n%d n%d\n", si.in1, si.id);
+ if (si.init == State::S0 || si.init == State::S1) {
+ fprintf(f, ".latch n%d n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
+ recover_init = true;
+ } else
+ fprintf(f, ".latch n%d n%d 2\n", si.in1, si.id);
} else if (si.type != G(NONE))
log_abort();
if (si.type != G(NONE))
@@ -851,38 +898,42 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
f = fopen(buffer.c_str(), "wt");
if (f == NULL)
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
- fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
- fprintf(f, "GATE ONE 1 Y=CONST1;\n");
- fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
- fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
+ fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
+ fprintf(f, "GATE ONE 1 Y=CONST1;\n");
+ fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
+ fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
if (enabled_gates.empty() || enabled_gates.count("AND"))
- fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
+ fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
if (enabled_gates.empty() || enabled_gates.count("NAND"))
- fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
+ fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
if (enabled_gates.empty() || enabled_gates.count("OR"))
- fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
+ fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
if (enabled_gates.empty() || enabled_gates.count("NOR"))
- fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
+ fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
if (enabled_gates.empty() || enabled_gates.count("XOR"))
- fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
+ fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
if (enabled_gates.empty() || enabled_gates.count("XNOR"))
- fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
+ fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
+ if (enabled_gates.empty() || enabled_gates.count("ANDNOT"))
+ fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ANDNOT_"));
+ if (enabled_gates.empty() || enabled_gates.count("ORNOT"))
+ fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ORNOT_"));
if (enabled_gates.empty() || enabled_gates.count("AOI3"))
- fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
+ fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
if (enabled_gates.empty() || enabled_gates.count("OAI3"))
- fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
+ fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
if (enabled_gates.empty() || enabled_gates.count("AOI4"))
- fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
+ fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
if (enabled_gates.empty() || enabled_gates.count("OAI4"))
- fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
+ fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
if (enabled_gates.empty() || enabled_gates.count("MUX"))
- fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
if (map_mux4)
- fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*get_cell_cost("$_MUX_"));
if (map_mux8)
- fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*get_cell_cost("$_MUX_"));
if (map_mux16)
- fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_"));
+ fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_"));
fclose(f);
if (!lut_costs.empty()) {
@@ -898,8 +949,24 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
+#ifndef YOSYS_LINK_ABC
abc_output_filter filt(tempdir_name, show_tempdir);
int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
+#else
+ // These needs to be mutable, supposedly due to getopt
+ char *abc_argv[5];
+ string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str());
+ abc_argv[0] = strdup(exe_file.c_str());
+ abc_argv[1] = strdup("-s");
+ abc_argv[2] = strdup("-f");
+ abc_argv[3] = strdup(tmp_script_name.c_str());
+ abc_argv[4] = 0;
+ int ret = Abc_RealMain(4, abc_argv);
+ free(abc_argv[0]);
+ free(abc_argv[1]);
+ free(abc_argv[2]);
+ free(abc_argv[3]);
+#endif
if (ret != 0)
log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
@@ -954,7 +1021,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
design->select(module, cell);
continue;
}
- if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" || c->type == "\\XNOR") {
+ if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" ||
+ c->type == "\\XNOR" || c->type == "\\ANDNOT" || c->type == "\\ORNOT") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
@@ -1130,6 +1198,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
module->connect(conn);
}
+ if (recover_init)
+ for (auto wire : mapped_mod->wires()) {
+ if (wire->attributes.count("\\init")) {
+ Wire *w = module->wires_[remap_name(wire->name)];
+ log_assert(w->attributes.count("\\init") == 0);
+ w->attributes["\\init"] = wire->attributes.at("\\init");
+ }
+ }
+
for (auto &it : cell_stats)
log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
int in_wires = 0, out_wires = 0;
@@ -1171,7 +1248,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
struct AbcPass : public Pass {
AbcPass() : Pass("abc", "use ABC for technology mapping") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1205,7 +1282,7 @@ struct AbcPass : public Pass {
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
log("\n");
log(" for -lut/-luts (only one LUT size):\n");
- log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack").c_str());
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack {S}").c_str());
log("\n");
log(" for -lut/-luts (different LUT sizes):\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
@@ -1253,6 +1330,8 @@ struct AbcPass : public Pass {
log(" -D <picoseconds>\n");
log(" set delay target. the string {D} in the default scripts above is\n");
log(" replaced by this option when used, and an empty string otherwise.\n");
+ log(" this also replaces 'dretime' with 'dretime; retime -o {D}' in the\n");
+ log(" default scripts above.\n");
log("\n");
log(" -I <num>\n");
log(" maximum number of SOP inputs.\n");
@@ -1262,6 +1341,10 @@ struct AbcPass : public Pass {
log(" maximum number of SOP products.\n");
log(" (replaces {P} in the default scripts above)\n");
log("\n");
+ log(" -S <num>\n");
+ log(" maximum number of LUT inputs shared.\n");
+ log(" (replaces {S} in the default scripts above, default: -S 1)\n");
+ log("\n");
log(" -lut <width>\n");
log(" generate netlist using luts of (max) the specified width.\n");
log("\n");
@@ -1283,10 +1366,21 @@ struct AbcPass : public Pass {
// log(" (ignored when used with -liberty or -lut)\n");
// log("\n");
log(" -g type1,type2,...\n");
- log(" Map the the specified list of gate types. Supported gates types are:\n");
- log(" AND, NAND, OR, NOR, XOR, XNOR, MUX, AOI3, OAI3, AOI4, OAI4.\n");
+ log(" Map to the specified list of gate types. Supported gates types are:\n");
+ log(" AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4.\n");
log(" (The NOT gate is always added to this list automatically.)\n");
log("\n");
+ log(" The following aliases can be used to reference common sets of gate types:\n");
+ log(" simple: AND OR XOR MUX\n");
+ log(" cmos2: NAND NOR\n");
+ log(" cmos3: NAND NOR AOI3 OAI3\n");
+ log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n");
+ log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n");
+ log(" aig: AND NAND OR NOR ANDNOT ORNOT\n");
+ log("\n");
+ log(" Prefix a gate type with a '-' to remove it from the list. For example\n");
+ log(" the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.\n");
+ log("\n");
log(" -dff\n");
log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
log(" clock domains are automatically partitioned in clock domains and each\n");
@@ -1316,24 +1410,35 @@ struct AbcPass : public Pass {
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");
- log("This pass does not operate on modules with unprocessed processes in it.\n");
- log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n");
+ log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
+ log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
+ log("ABC on logic snippets extracted from your design. You will not get any useful\n");
+ log("output when passing an ABC script that writes a file. Instead write your full\n");
+ log("design as BLIF file with write_blif and the load that into ABC externally if\n");
+ log("you want to use ABC to convert your design into another format.\n");
log("\n");
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ABC pass (technology mapping using ABC).\n");
log_push();
+ assign_map.clear();
+ signal_list.clear();
+ signal_map.clear();
+ signal_init.clear();
+ pi_map.clear();
+ po_map.clear();
+
#ifdef ABCEXTERNAL
std::string exe_file = ABCEXTERNAL;
#else
std::string exe_file = proc_self_dirname() + "yosys-abc";
#endif
std::string script_file, liberty_file, constr_file, clk_str;
- std::string delay_target, sop_inputs, sop_products;
+ std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
bool show_tempdir = false, sop_mode = false;
vector<int> lut_costs;
@@ -1365,17 +1470,20 @@ struct AbcPass : public Pass {
}
if (arg == "-script" && argidx+1 < args.size()) {
script_file = args[++argidx];
+ rewrite_filename(script_file);
if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
script_file = std::string(pwd) + "/" + script_file;
continue;
}
if (arg == "-liberty" && argidx+1 < args.size()) {
liberty_file = args[++argidx];
+ rewrite_filename(liberty_file);
if (!liberty_file.empty() && !is_absolute_path(liberty_file))
liberty_file = std::string(pwd) + "/" + liberty_file;
continue;
}
if (arg == "-constr" && argidx+1 < args.size()) {
+ rewrite_filename(constr_file);
constr_file = args[++argidx];
if (!constr_file.empty() && !is_absolute_path(constr_file))
constr_file = std::string(pwd) + "/" + constr_file;
@@ -1393,6 +1501,10 @@ struct AbcPass : public Pass {
sop_products = "-P " + args[++argidx];
continue;
}
+ if (arg == "-S" && argidx+1 < args.size()) {
+ lutin_shared = "-S " + args[++argidx];
+ continue;
+ }
if (arg == "-lut" && argidx+1 < args.size()) {
string arg = args[++argidx];
size_t pos = arg.find_first_of(':');
@@ -1445,20 +1557,83 @@ struct AbcPass : public Pass {
}
if (arg == "-g" && argidx+1 < args.size()) {
for (auto g : split_tokens(args[++argidx], ",")) {
+ vector<string> gate_list;
+ bool remove_gates = false;
+ if (GetSize(g) > 0 && g[0] == '-') {
+ remove_gates = true;
+ g = g.substr(1);
+ }
if (g == "AND") goto ok_gate;
if (g == "NAND") goto ok_gate;
if (g == "OR") goto ok_gate;
if (g == "NOR") goto ok_gate;
if (g == "XOR") goto ok_gate;
if (g == "XNOR") goto ok_gate;
+ if (g == "ANDNOT") goto ok_gate;
+ if (g == "ORNOT") goto ok_gate;
if (g == "MUX") goto ok_gate;
if (g == "AOI3") goto ok_gate;
if (g == "OAI3") goto ok_gate;
if (g == "AOI4") goto ok_gate;
if (g == "OAI4") goto ok_gate;
+ if (g == "simple") {
+ gate_list.push_back("AND");
+ gate_list.push_back("OR");
+ gate_list.push_back("XOR");
+ gate_list.push_back("MUX");
+ goto ok_alias;
+ }
+ if (g == "cmos2") {
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ goto ok_alias;
+ }
+ if (g == "cmos3") {
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ goto ok_alias;
+ }
+ if (g == "cmos4") {
+ gate_list.push_back("NAND");
+ gate_list.push_back("NOR");
+ gate_list.push_back("AOI3");
+ gate_list.push_back("OAI3");
+ gate_list.push_back("AOI4");
+ gate_list.push_back("OAI4");
+ goto ok_alias;
+ }
+ if (g == "gates") {
+ gate_list.push_back("AND");
+ gate_list.push_back("NAND");
+ gate_list.push_back("OR");
+ gate_list.push_back("NOR");
+ gate_list.push_back("XOR");
+ gate_list.push_back("XNOR");
+ gate_list.push_back("ANDNOT");
+ gate_list.push_back("ORNOT");
+ goto ok_alias;
+ }
+ if (g == "aig") {
+ gate_list.push_back("AND");
+ gate_list.push_back("NAND");
+ gate_list.push_back("OR");
+ gate_list.push_back("NOR");
+ gate_list.push_back("ANDNOT");
+ gate_list.push_back("ORNOT");
+ goto ok_alias;
+ }
cmd_error(args, argidx, stringf("Unsupported gate type: %s", g.c_str()));
ok_gate:
- enabled_gates.insert(g);
+ gate_list.push_back(g);
+ ok_alias:
+ for (auto gate : gate_list) {
+ if (remove_gates)
+ enabled_gates.erase(gate);
+ else
+ enabled_gates.insert(gate);
+ }
}
continue;
}
@@ -1501,163 +1676,190 @@ struct AbcPass : public Pass {
log_cmd_error("Got -constr but no -liberty!\n");
for (auto mod : design->selected_modules())
- if (mod->processes.size() > 0)
+ {
+ 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_costs, dff_mode, clk_str, keepff,
- delay_target, sop_inputs, sop_products, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
- else
- {
- assign_map.set(mod);
- CellTypes ct(design);
+ continue;
+ }
- std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
- std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
+ assign_map.set(mod);
+ signal_init.clear();
+
+ for (Wire *wire : mod->wires())
+ if (wire->attributes.count("\\init")) {
+ SigSpec initsig = assign_map(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
+ switch (initval[i]) {
+ case State::S0:
+ signal_init[initsig[i]] = State::S0;
+ break;
+ case State::S1:
+ signal_init[initsig[i]] = State::S0;
+ break;
+ default:
+ break;
+ }
+ }
- 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;
+ if (!dff_mode || !clk_str.empty()) {
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
+ delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
+ continue;
+ }
- typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
- std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
- std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
+ CellTypes ct(design);
- 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;
+ std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
+ std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
- 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);
- }
- }
- }
+ 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;
- 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;
+ typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
+ std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
+ std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
- unassigned_cells.erase(cell);
- expand_queue.insert(cell);
- expand_queue_up.insert(cell);
- expand_queue_down.insert(cell);
+ 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;
- assigned_cells[key].push_back(cell);
- assigned_cells_reverse[cell] = key;
+ 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);
+ }
+ }
}
- while (!expand_queue_up.empty() || !expand_queue_down.empty())
+ if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
{
- 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);
- }
- }
+ 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;
- 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);
- }
- }
+ unassigned_cells.erase(cell);
+ expand_queue.insert(cell);
+ expand_queue_up.insert(cell);
+ expand_queue_down.insert(cell);
- 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);
- }
- }
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
+ }
- while (!expand_queue.empty())
+ while (!expand_queue_up.empty() || !expand_queue_down.empty())
+ {
+ if (!expand_queue_up.empty())
{
- RTLIL::Cell *cell = *expand_queue.begin();
+ RTLIL::Cell *cell = *expand_queue_up.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();
- }
+ 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.empty())
- expand_queue.swap(next_expand_queue);
+ 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);
+ }
}
- 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;
+ 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);
}
+ }
- log_header(design, "Summary of detected clock domains:\n");
- for (auto &it : assigned_cells)
- log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
- std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
- std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
-
- for (auto &it : assigned_cells) {
- clk_polarity = std::get<0>(it.first);
- clk_sig = assign_map(std::get<1>(it.first));
- en_polarity = std::get<2>(it.first);
- en_sig = assign_map(std::get<3>(it.first));
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
- keepff, delay_target, sop_inputs, sop_products, fast_mode, it.second, show_tempdir, sop_mode);
- assign_map.set(mod);
+ while (!expand_queue.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue.erase(cell);
+
+ for (auto bit : cell_to_bit.at(cell)) {
+ for (auto c : bit_to_cell[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ }
+ bit_to_cell[bit].clear();
}
+
+ if (expand_queue.empty())
+ expand_queue.swap(next_expand_queue);
+ }
+
+ clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
+ for (auto cell : unassigned_cells) {
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
}
+ log_header(design, "Summary of detected clock domains:\n");
+ for (auto &it : assigned_cells)
+ log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
+ std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
+ std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
+
+ for (auto &it : assigned_cells) {
+ clk_polarity = std::get<0>(it.first);
+ clk_sig = assign_map(std::get<1>(it.first));
+ en_polarity = std::get<2>(it.first);
+ en_sig = assign_map(std::get<3>(it.first));
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
+ keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode);
+ assign_map.set(mod);
+ }
+ }
+
assign_map.clear();
signal_list.clear();
signal_map.clear();
+ signal_init.clear();
+ pi_map.clear();
+ po_map.clear();
log_pop();
}
diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc
index b9ac7ade..35df2ff7 100644
--- a/passes/techmap/aigmap.cc
+++ b/passes/techmap/aigmap.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct AigmapPass : public Pass {
AigmapPass() : Pass("aigmap", "map logic to and-inverter-graph circuit") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" aigmap [options] [selection]\n");
@@ -37,7 +37,7 @@ struct AigmapPass : public Pass {
log(" Enable creation of $_NAND_ cells\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool nand_mode = false;
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index 9f6dd02d..dc7d416b 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -55,19 +55,19 @@ struct AlumaccWorker
RTLIL::SigSpec get_gt() {
if (GetSize(cached_gt) == 0)
- cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()));
+ cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()), false, alu_cell->get_src_attribute());
return cached_gt;
}
RTLIL::SigSpec get_eq() {
if (GetSize(cached_eq) == 0)
- cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"));
+ cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"), false, alu_cell->get_src_attribute());
return cached_eq;
}
RTLIL::SigSpec get_ne() {
if (GetSize(cached_ne) == 0)
- cached_ne = alu_cell->module->Not(NEW_ID, get_eq());
+ cached_ne = alu_cell->module->Not(NEW_ID, get_eq(), false, alu_cell->get_src_attribute());
return cached_ne;
}
@@ -75,7 +75,7 @@ struct AlumaccWorker
if (GetSize(cached_cf) == 0) {
cached_cf = alu_cell->getPort("\\CO");
log_assert(GetSize(cached_cf) >= 1);
- cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1]);
+ cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1], false, alu_cell->get_src_attribute());
}
return cached_cf;
}
@@ -352,10 +352,13 @@ struct AlumaccWorker
{
auto n = it.second;
auto cell = module->addCell(NEW_ID, "$macc");
+
macc_counter++;
log(" creating $macc cell for %s: %s\n", log_id(n->cell), log_id(cell));
+ cell->set_src_attribute(n->cell->get_src_attribute());
+
n->macc.optimize(GetSize(n->y));
n->macc.to_cell(cell);
cell->setPort("\\Y", n->y);
@@ -452,6 +455,7 @@ struct AlumaccWorker
void replace_alu()
{
+ std::string src("");
for (auto &it1 : sig_alu)
for (auto n : it1.second)
{
@@ -475,6 +479,9 @@ struct AlumaccWorker
log("%s%s", i ? ", ": "", log_id(n->cells[i]));
log(": %s\n", log_id(n->alu_cell));
+ if (n->cells.size() > 0)
+ n->alu_cell->set_src_attribute(n->cells[0]->get_src_attribute());
+
n->alu_cell->setPort("\\A", n->a);
n->alu_cell->setPort("\\B", n->b);
n->alu_cell->setPort("\\CI", GetSize(n->c) ? n->c : RTLIL::S0);
@@ -532,7 +539,7 @@ struct AlumaccWorker
struct AlumaccPass : public Pass {
AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -542,7 +549,7 @@ struct AlumaccPass : public Pass {
log("and $macc cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ALUMACC pass (create $alu and $macc cells).\n");
diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc
index dec81d21..0b5576b0 100644
--- a/passes/techmap/attrmap.cc
+++ b/passes/techmap/attrmap.cc
@@ -81,7 +81,7 @@ struct AttrmapAction {
struct AttrmapTocase : AttrmapAction {
string name;
- virtual bool apply(IdString &id, Const&) {
+ bool apply(IdString &id, Const&) YS_OVERRIDE {
if (match_name(name, id, true))
id = RTLIL::escape_id(name);
return true;
@@ -90,7 +90,7 @@ struct AttrmapTocase : AttrmapAction {
struct AttrmapRename : AttrmapAction {
string old_name, new_name;
- virtual bool apply(IdString &id, Const&) {
+ bool apply(IdString &id, Const&) YS_OVERRIDE {
if (match_name(old_name, id))
id = RTLIL::escape_id(new_name);
return true;
@@ -101,7 +101,7 @@ struct AttrmapMap : AttrmapAction {
bool imap;
string old_name, new_name;
string old_value, new_value;
- virtual bool apply(IdString &id, Const &val) {
+ bool apply(IdString &id, Const &val) YS_OVERRIDE {
if (match_name(old_name, id) && match_value(old_value, val, true)) {
id = RTLIL::escape_id(new_name);
val = make_value(new_value);
@@ -112,7 +112,7 @@ struct AttrmapMap : AttrmapAction {
struct AttrmapRemove : AttrmapAction {
string name, value;
- virtual bool apply(IdString &id, Const &val) {
+ bool apply(IdString &id, Const &val) YS_OVERRIDE {
return !(match_name(name, id) && match_value(value, val));
}
};
@@ -144,7 +144,7 @@ void attrmap_apply(string objname, vector<std::unique_ptr<AttrmapAction>> &actio
struct AttrmapPass : public Pass {
AttrmapPass() : Pass("attrmap", "renaming attributes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -179,7 +179,7 @@ struct AttrmapPass : public Pass {
log(" -imap keep=\"false\" keep=0 -remove keep=0\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n");
diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc
index 1537def0..e59aa651 100644
--- a/passes/techmap/attrmvcp.cc
+++ b/passes/techmap/attrmvcp.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct AttrmvcpPass : public Pass {
AttrmvcpPass() : Pass("attrmvcp", "move or copy attributes from wires to driving cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" attrmvcp [options] [selection]\n");
@@ -53,7 +53,7 @@ struct AttrmvcpPass : public Pass {
log(" multiple times.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ATTRMVCP pass (move or copy attributes).\n");
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
index ed4e4576..9f0c7bf6 100644
--- a/passes/techmap/deminout.cc
+++ b/passes/techmap/deminout.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct DeminoutPass : public Pass {
DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" deminout [options] [selection]\n");
@@ -33,7 +33,7 @@ struct DeminoutPass : public Pass {
log("\"Demote\" inout ports to input or output ports, if possible.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n");
@@ -57,7 +57,7 @@ struct DeminoutPass : public Pass {
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
- pool<SigBit> bits_written, bits_used, bits_inout;
+ pool<SigBit> bits_written, bits_used, bits_inout, bits_tribuf;
dict<SigBit, int> bits_numports;
for (auto wire : module->wires())
@@ -82,6 +82,25 @@ struct DeminoutPass : public Pass {
if (cellport_in)
for (auto bit : sigmap(conn.second))
bits_used.insert(bit);
+
+ if (conn.first == "\\Y" && cell->type.in("$mux", "$pmux", "$_MUX_", "$_TBUF_"))
+ {
+ bool tribuf = (cell->type == "$_TBUF_");
+
+ if (!tribuf) {
+ for (auto &c : cell->connections()) {
+ if (!c.first.in("\\A", "\\B"))
+ continue;
+ for (auto b : sigmap(c.second))
+ if (b == State::Sz)
+ tribuf = true;
+ }
+ }
+
+ if (tribuf)
+ for (auto bit : sigmap(conn.second))
+ bits_tribuf.insert(bit);
+ }
}
for (auto wire : module->selected_wires())
@@ -95,10 +114,15 @@ struct DeminoutPass : public Pass {
if (bits_numports[bit] > 1 || bits_inout.count(bit))
new_input = true, new_output = true;
- if (bits_written.count(bit))
+ if (bits_written.count(bit)) {
new_output = true;
- else if (bits_used.count(bit))
- new_input = true;
+ if (bits_tribuf.count(bit))
+ goto tribuf_bit;
+ } else {
+ tribuf_bit:
+ if (bits_used.count(bit))
+ new_input = true;
+ }
}
if (new_input != new_output) {
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
index 1b8920bb..3291f5a4 100644
--- a/passes/techmap/dff2dffe.cc
+++ b/passes/techmap/dff2dffe.cc
@@ -253,7 +253,7 @@ struct Dff2dffeWorker
struct Dff2dffePass : public Pass {
Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -279,11 +279,12 @@ struct Dff2dffePass : public Pass {
log(" -direct-match <pattern>\n");
log(" like -direct for all DFF cell types matching the expression.\n");
log(" this will use $__DFFE_* as <external_gate_type> matching the\n");
- log(" internal gate type $_DFF_*_, except for $_DFF_[NP]_, which is\n");
- log(" converted to $_DFFE_[NP]_.\n");
+ log(" internal gate type $_DFF_*_, and $__DFFSE_* for those matching\n");
+ log(" $_DFFS_*_, except for $_DFF_[NP]_, which is converted to \n");
+ log(" $_DFFE_[NP]_.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
@@ -315,6 +316,15 @@ struct Dff2dffePass : public Pass {
if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict["$_DFF_PN1_"] = "$__DFFE_PN1";
if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict["$_DFF_PP0_"] = "$__DFFE_PP0";
if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict["$_DFF_PP1_"] = "$__DFFE_PP1";
+
+ if (patmatch(pattern, "$__DFFS_NN0_")) found_match = true, direct_dict["$__DFFS_NN0_"] = "$__DFFSE_NN0";
+ if (patmatch(pattern, "$__DFFS_NN1_")) found_match = true, direct_dict["$__DFFS_NN1_"] = "$__DFFSE_NN1";
+ if (patmatch(pattern, "$__DFFS_NP0_")) found_match = true, direct_dict["$__DFFS_NP0_"] = "$__DFFSE_NP0";
+ if (patmatch(pattern, "$__DFFS_NP1_")) found_match = true, direct_dict["$__DFFS_NP1_"] = "$__DFFSE_NP1";
+ if (patmatch(pattern, "$__DFFS_PN0_")) found_match = true, direct_dict["$__DFFS_PN0_"] = "$__DFFSE_PN0";
+ if (patmatch(pattern, "$__DFFS_PN1_")) found_match = true, direct_dict["$__DFFS_PN1_"] = "$__DFFSE_PN1";
+ if (patmatch(pattern, "$__DFFS_PP0_")) found_match = true, direct_dict["$__DFFS_PP0_"] = "$__DFFSE_PP0";
+ if (patmatch(pattern, "$__DFFS_PP1_")) found_match = true, direct_dict["$__DFFS_PP1_"] = "$__DFFSE_PP1";
if (!found_match)
log_cmd_error("No cell types matched pattern '%s'.\n", pattern);
continue;
diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc
new file mode 100644
index 00000000..39a4f6ad
--- /dev/null
+++ b/passes/techmap/dff2dffs.cc
@@ -0,0 +1,142 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 David Shah <dave@ds0.me>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Dff2dffsPass : public Pass {
+ Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { }
+ void help() YS_OVERRIDE
+ {
+ log("\n");
+ log(" dff2dffs [options] [selection]\n");
+ log("\n");
+ log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n");
+ log("dff2dffe for SR over CE priority.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ pool<IdString> dff_types;
+ dff_types.insert("$_DFF_N_");
+ dff_types.insert("$_DFF_P_");
+
+ for (auto module : design->selected_modules())
+ {
+ log("Merging set/reset $_MUX_ cells into DFFs in %s.\n", log_id(module));
+
+ SigMap sigmap(module);
+ dict<SigBit, Cell*> sr_muxes;
+ vector<Cell*> ff_cells;
+
+ for (auto cell : module->selected_cells())
+ {
+ if (dff_types.count(cell->type)) {
+ ff_cells.push_back(cell);
+ continue;
+ }
+
+ if (cell->type != "$_MUX_")
+ continue;
+
+ SigBit bit_a = sigmap(cell->getPort("\\A"));
+ SigBit bit_b = sigmap(cell->getPort("\\B"));
+
+ if (bit_a.wire == nullptr || bit_b.wire == nullptr)
+ sr_muxes[sigmap(cell->getPort("\\Y"))] = cell;
+ }
+
+ for (auto cell : ff_cells)
+ {
+ SigSpec sig_d = cell->getPort("\\D");
+
+ if (GetSize(sig_d) < 1)
+ continue;
+
+ SigBit bit_d = sigmap(sig_d[0]);
+
+ if (sr_muxes.count(bit_d) == 0)
+ continue;
+
+ Cell *mux_cell = sr_muxes.at(bit_d);
+ SigBit bit_a = sigmap(mux_cell->getPort("\\A"));
+ SigBit bit_b = sigmap(mux_cell->getPort("\\B"));
+ SigBit bit_s = sigmap(mux_cell->getPort("\\S"));
+
+ log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
+ log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
+
+ SigBit sr_val, sr_sig;
+ bool invert_sr;
+ sr_sig = bit_s;
+ if (bit_a.wire == nullptr) {
+ bit_d = bit_b;
+ sr_val = bit_a;
+ invert_sr = true;
+ } else {
+ log_assert(bit_b.wire == nullptr);
+ bit_d = bit_a;
+ sr_val = bit_b;
+ invert_sr = false;
+ }
+
+ if (sr_val == State::S1) {
+ if (cell->type == "$_DFF_N_") {
+ if (invert_sr) cell->type = "$__DFFS_NN1_";
+ else cell->type = "$__DFFS_NP1_";
+ } else {
+ log_assert(cell->type == "$_DFF_P_");
+ if (invert_sr) cell->type = "$__DFFS_PN1_";
+ else cell->type = "$__DFFS_PP1_";
+ }
+ } else {
+ if (cell->type == "$_DFF_N_") {
+ if (invert_sr) cell->type = "$__DFFS_NN0_";
+ else cell->type = "$__DFFS_NP0_";
+ } else {
+ log_assert(cell->type == "$_DFF_P_");
+ if (invert_sr) cell->type = "$__DFFS_PN0_";
+ else cell->type = "$__DFFS_PP0_";
+ }
+ }
+ cell->setPort("\\R", sr_sig);
+ cell->setPort("\\D", bit_d);
+ }
+ }
+ }
+} Dff2dffsPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index d737b342..a8eecc97 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct DffinitPass : public Pass {
DffinitPass() : Pass("dffinit", "set INIT param on FF cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -38,15 +38,25 @@ struct DffinitPass : public Pass {
log(" operate on the specified cell type. this option can be used\n");
log(" multiple times.\n");
log("\n");
+ log(" -highlow\n");
+ log(" use the string values \"high\" and \"low\" to represent a single-bit\n");
+ log(" initial value of 1 or 0. (multi-bit values are not supported in this\n");
+ log(" mode.)\n");
+ log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n");
dict<IdString, dict<IdString, IdString>> ff_types;
+ bool highlow_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-highlow") {
+ highlow_mode = true;
+ continue;
+ }
if (args[argidx] == "-ff" && argidx+3 < args.size()) {
IdString cell_name = RTLIL::escape_id(args[++argidx]);
IdString output_port = RTLIL::escape_id(args[++argidx]);
@@ -106,6 +116,16 @@ struct DffinitPass : public Pass {
cleanup_bits.insert(sig[i]);
}
+ if (highlow_mode && GetSize(value) != 0) {
+ if (GetSize(value) != 1)
+ log_error("Multi-bit init value for %s.%s.%s is incompatible with -highlow mode.\n",
+ log_id(module), log_id(cell), log_id(it.second));
+ if (value[0] == State::S1)
+ value = Const("high");
+ else
+ value = Const("low");
+ }
+
log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second),
log_id(it.first), log_signal(sig), log_signal(value));
cell->setParam(it.second, value);
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index c8104fb7..416ed2bd 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -240,6 +240,10 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
if (cell->id != "cell" || cell->args.size() != 1)
continue;
+ LibertyAst *dn = cell->find("dont_use");
+ if (dn != NULL && dn->value == "true")
+ continue;
+
LibertyAst *ff = cell->find("ff");
if (ff == NULL)
continue;
@@ -478,11 +482,15 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
auto cell_type = cell->type;
auto cell_name = cell->name;
auto cell_connections = cell->connections();
+ std::string src = cell->get_src_attribute();
+
module->remove(cell);
cell_mapping &cm = cell_mappings[cell_type];
RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : "\\" + cm.cell_name);
+ new_cell->set_src_attribute(src);
+
bool has_q = false, has_qn = false;
for (auto &port : cm.ports) {
if (port.second == 'Q') has_q = true;
@@ -529,7 +537,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare
struct DfflibmapPass : public Pass {
DfflibmapPass() : Pass("dfflibmap", "technology mapping of flip-flops") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" dfflibmap [-prepare] -liberty <file> [selection]\n");
@@ -545,7 +553,7 @@ struct DfflibmapPass : public Pass {
log("liberty file.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
diff --git a/passes/techmap/dffsr2dff.cc b/passes/techmap/dffsr2dff.cc
index 0d4d5362..086a1d2f 100644
--- a/passes/techmap/dffsr2dff.cc
+++ b/passes/techmap/dffsr2dff.cc
@@ -176,7 +176,7 @@ void adff_worker(SigMap &sigmap, Module *module, Cell *cell)
struct Dffsr2dffPass : public Pass {
Dffsr2dffPass() : Pass("dffsr2dff", "convert DFFSR cells to simpler FF cell types") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -186,7 +186,7 @@ struct Dffsr2dffPass : public Pass {
log("$_DFF_???_) to simpler FF cell types when any of the set/reset inputs is unused.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n");
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index 71e29c60..fff90f13 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -352,7 +352,7 @@ bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
struct ExtractPass : public Pass {
ExtractPass() : Pass("extract", "find subcircuits and replace them with cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -440,7 +440,7 @@ struct ExtractPass : public Pass {
log("See 'help techmap' for a pass that does the opposite thing.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing EXTRACT pass (map subcircuits to cells).\n");
log_push();
diff --git a/techlibs/greenpak4/greenpak4_counters.cc b/passes/techmap/extract_counter.cc
index 998bb73b..a8d0bc83 100644
--- a/techlibs/greenpak4/greenpak4_counters.cc
+++ b/passes/techmap/extract_counter.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2016 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2017 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
@@ -66,11 +66,11 @@ bool is_full_bus(
else if(!other_conns_allowed)
return false;
}
-
+
if( (!found_a) || (!found_b) )
return false;
}
-
+
return true;
}
@@ -83,40 +83,53 @@ bool is_unconnected(const RTLIL::SigSpec& port, ModIndex& index)
if(ports.size() > 1)
return false;
}
-
+
return true;
}
struct CounterExtraction
{
- int width; //counter width
- RTLIL::Wire* rwire; //the register output
- bool has_reset; //true if we have a reset
- RTLIL::SigSpec rst; //reset pin
- int count_value; //value we count from
- RTLIL::SigSpec clk; //clock signal
- RTLIL::SigSpec outsig; //counter output signal
- RTLIL::Cell* count_mux; //counter mux
- RTLIL::Cell* count_reg; //counter register
- RTLIL::Cell* underflow_inv; //inverter reduction for output-underflow detect
+ int width; //counter width
+ RTLIL::Wire* rwire; //the register output
+ bool has_reset; //true if we have a reset
+ bool has_ce; //true if we have a clock enable
+ RTLIL::SigSpec rst; //reset pin
+ bool rst_inverted; //true if reset is active low
+ bool rst_to_max; //true if we reset to max instead of 0
+ int count_value; //value we count from
+ RTLIL::SigSpec ce; //clock signal
+ RTLIL::SigSpec clk; //clock enable, if any
+ RTLIL::SigSpec outsig; //counter output signal
+ RTLIL::Cell* count_mux; //counter mux
+ RTLIL::Cell* count_reg; //counter register
+ RTLIL::Cell* underflow_inv; //inverter reduction for output-underflow detect
+ pool<ModIndex::PortInfo> pouts; //Ports that take a parallel output from us
};
-//attempt to extract a counter centered on the given cell
-int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction& extract)
+//attempt to extract a counter centered on the given adder cell
+//For now we only support DOWN counters.
+//TODO: up/down support
+int counter_tryextract(
+ ModIndex& index,
+ Cell *cell,
+ CounterExtraction& extract,
+ pool<RTLIL::IdString>& parallel_cells,
+ int maxwidth)
{
SigMap& sigmap = index.sigmap;
-
- //GreenPak does not support counters larger than 14 bits so immediately skip anything bigger
+
+ //A counter with less than 2 bits makes no sense
+ //TODO: configurable min threshold
int a_width = cell->getParam("\\A_WIDTH").as_int();
extract.width = a_width;
- if(a_width > 14)
+ if( (a_width < 2) || (a_width > maxwidth) )
return 1;
-
+
//Second input must be a single bit
int b_width = cell->getParam("\\B_WIDTH").as_int();
if(b_width != 1)
return 2;
-
+
//Both inputs must be unsigned, so don't extract anything with a signed input
bool a_sign = cell->getParam("\\A_SIGNED").as_bool();
bool b_sign = cell->getParam("\\B_SIGNED").as_bool();
@@ -128,7 +141,7 @@ int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction
const RTLIL::SigSpec b_port = sigmap(cell->getPort("\\B"));
if(!b_port.is_fully_const() || (b_port.as_int() != 1) )
return 4;
-
+
//BI and CI must be constant 1 as well
const RTLIL::SigSpec bi_port = sigmap(cell->getPort("\\BI"));
if(!bi_port.is_fully_const() || (bi_port.as_int() != 1) )
@@ -136,13 +149,13 @@ int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction
const RTLIL::SigSpec ci_port = sigmap(cell->getPort("\\CI"));
if(!ci_port.is_fully_const() || (ci_port.as_int() != 1) )
return 6;
-
+
//CO and X must be unconnected (exactly one connection to each port)
if(!is_unconnected(sigmap(cell->getPort("\\CO")), index))
return 7;
if(!is_unconnected(sigmap(cell->getPort("\\X")), index))
return 8;
-
+
//Y must have exactly one connection, and it has to be a $mux cell.
//We must have a direct bus connection from our Y to their A.
const RTLIL::SigSpec aluy = sigmap(cell->getPort("\\Y"));
@@ -161,70 +174,152 @@ int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction
if(!underflow.is_fully_const())
return 12;
extract.count_value = underflow.as_int();
-
+
//S connection of the mux must come from an inverter (need not be the only load)
const RTLIL::SigSpec muxsel = sigmap(count_mux->getPort("\\S"));
extract.outsig = muxsel;
pool<Cell*> muxsel_conns = get_other_cells(muxsel, index, count_mux);
Cell* underflow_inv = NULL;
for(auto c : muxsel_conns)
- {
+ {
if(c->type != "$logic_not")
continue;
if(!is_full_bus(muxsel, index, c, "\\Y", count_mux, "\\S", true))
continue;
-
+
underflow_inv = c;
break;
}
if(underflow_inv == NULL)
return 13;
extract.underflow_inv = underflow_inv;
-
- //Y connection of the mux must have exactly one load, the counter's internal register
+
+ //Y connection of the mux must have exactly one load, the counter's internal register, if there's no clock enable
+ //If we have a clock enable, Y drives the B input of a mux. A of that mux must come from our register
const RTLIL::SigSpec muxy = sigmap(count_mux->getPort("\\Y"));
pool<Cell*> muxy_loads = get_other_cells(muxy, index, count_mux);
if(muxy_loads.size() != 1)
return 14;
- Cell* count_reg = *muxy_loads.begin();
+ Cell* muxload = *muxy_loads.begin();
+ Cell* count_reg = muxload;
+ Cell* cemux = NULL;
+ RTLIL::SigSpec cey;
+ if(muxload->type == "$mux")
+ {
+ //This mux is probably a clock enable mux.
+ //Find our count register (should be our only load)
+ cemux = muxload;
+ cey = sigmap(cemux->getPort("\\Y"));
+ pool<Cell*> cey_loads = get_other_cells(cey, index, cemux);
+ if(cey_loads.size() != 1)
+ return 24;
+ count_reg = *cey_loads.begin();
+
+ //Mux should have A driven by count Q, and B by muxy
+ //TODO: if A and B are swapped, CE polarity is inverted
+ if(sigmap(cemux->getPort("\\B")) != muxy)
+ return 24;
+ if(sigmap(cemux->getPort("\\A")) != sigmap(count_reg->getPort("\\Q")))
+ return 24;
+ if(sigmap(cemux->getPort("\\Y")) != sigmap(count_reg->getPort("\\D")))
+ return 24;
+
+ //Select of the mux is our clock enable
+ extract.has_ce = true;
+ extract.ce = sigmap(cemux->getPort("\\S"));
+ }
+ else
+ extract.has_ce = false;
+
extract.count_reg = count_reg;
if(count_reg->type == "$dff")
extract.has_reset = false;
else if(count_reg->type == "$adff")
{
extract.has_reset = true;
-
- //Verify ARST_VALUE is zero and ARST_POLARITY is 1
- //TODO: infer an inverter to make it 1 if necessary, so we can support negative level resets?
- if(count_reg->getParam("\\ARST_POLARITY").as_int() != 1)
- return 22;
- if(count_reg->getParam("\\ARST_VALUE").as_int() != 0)
+
+ //Check polarity of reset - we may have to add an inverter later on!
+ extract.rst_inverted = (count_reg->getParam("\\ARST_POLARITY").as_int() != 1);
+
+ //Verify ARST_VALUE is zero or full scale
+ int rst_value = count_reg->getParam("\\ARST_VALUE").as_int();
+ if(rst_value == 0)
+ extract.rst_to_max = false;
+ else if(rst_value == extract.count_value)
+ extract.rst_to_max = true;
+ else
return 23;
-
+
//Save the reset
extract.rst = sigmap(count_reg->getPort("\\ARST"));
}
//TODO: support synchronous reset
else
return 15;
- if(!is_full_bus(muxy, index, count_mux, "\\Y", count_reg, "\\D"))
+
+ //Sanity check that we use the ALU output properly
+ if(extract.has_ce)
+ {
+ if(!is_full_bus(muxy, index, count_mux, "\\Y", cemux, "\\B"))
+ return 16;
+ if(!is_full_bus(cey, index, cemux, "\\Y", count_reg, "\\D"))
+ return 16;
+ }
+ else if(!is_full_bus(muxy, index, count_mux, "\\Y", count_reg, "\\D"))
return 16;
-
+
//TODO: Verify count_reg CLK_POLARITY is 1
-
+
//Register output must have exactly two loads, the inverter and ALU
- const RTLIL::SigSpec cnout = sigmap(count_reg->getPort("\\Q"));
+ //(unless we have a parallel output!)
+ //If we have a clock enable, 3 is OK
+ const RTLIL::SigSpec qport = count_reg->getPort("\\Q");
+ const RTLIL::SigSpec cnout = sigmap(qport);
pool<Cell*> cnout_loads = get_other_cells(cnout, index, count_reg);
- if(cnout_loads.size() != 2)
- return 17;
+ unsigned int max_loads = 2;
+ if(extract.has_ce)
+ max_loads = 3;
+ if(cnout_loads.size() > max_loads)
+ {
+ for(auto c : cnout_loads)
+ {
+ if(c == underflow_inv)
+ continue;
+ if(c == cell)
+ continue;
+ if(c == muxload)
+ continue;
+
+ //If we specified a limited set of cells for parallel output, check that we only drive them
+ if(!parallel_cells.empty())
+ {
+ //Make sure we're in the whitelist
+ if( parallel_cells.find(c->type) == parallel_cells.end())
+ return 17;
+ }
+
+ //Figure out what port(s) are driven by it
+ //TODO: this can probably be done more efficiently w/o multiple iterations over our whole net?
+ for(auto b : qport)
+ {
+ pool<ModIndex::PortInfo> ports = index.query_ports(b);
+ for(auto x : ports)
+ {
+ if(x.cell != c)
+ continue;
+ extract.pouts.insert(ModIndex::PortInfo(c, x.port, 0));
+ }
+ }
+ }
+ }
if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true))
return 18;
if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true))
return 19;
-
+
//Look up the clock from the register
extract.clk = sigmap(count_reg->getPort("\\CLK"));
-
+
//Register output net must have an INIT attribute equal to the count value
extract.rwire = cnout.as_wire();
if(extract.rwire->attributes.find("\\init") == extract.rwire->attributes.end())
@@ -232,22 +327,25 @@ int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction
int rinit = extract.rwire->attributes["\\init"].as_int();
if(rinit != extract.count_value)
return 21;
-
+
return 0;
}
-void greenpak4_counters_worker(
+void counter_worker(
ModIndex& index,
Cell *cell,
unsigned int& total_counters,
- pool<Cell*>& cells_to_remove)
+ pool<Cell*>& cells_to_remove,
+ pool<pair<Cell*, string>>& cells_to_rename,
+ pool<RTLIL::IdString>& parallel_cells,
+ int maxwidth)
{
SigMap& sigmap = index.sigmap;
-
+
//Core of the counter must be an ALU
if (cell->type != "$alu")
return;
-
+
//A input is the count value. Check if it has COUNT_EXTRACT set.
//If it's not a wire, don't even try
auto port = sigmap(cell->getPort("\\A"));
@@ -268,7 +366,7 @@ void greenpak4_counters_worker(
log_id(a_wire),
count_reg_src.c_str(),
extract_value.c_str());
-
+
if(extract_value == "FORCE")
force_extract = true;
else if(extract_value == "NO")
@@ -280,23 +378,23 @@ void greenpak4_counters_worker(
extract_value.c_str());
}
}
-
+
//If we're explicitly told not to extract, don't infer a counter
if(never_extract)
return;
-
+
//Attempt to extract a counter
CounterExtraction extract;
- int reason = greenpak4_counters_tryextract(index, cell, extract);
-
+ int reason = counter_tryextract(index, cell, extract, parallel_cells, maxwidth);
+
//Nonzero code - we could not find a matchable counter.
//Do nothing, unless extraction was forced in which case give an error
if(reason != 0)
{
- static const char* reasons[24]=
+ static const char* reasons[25]=
{
"no problem", //0
- "counter is larger than 14 bits", //1
+ "counter is too large/small", //1
"counter does not count by one", //2
"counter uses signed math", //3
"counter does not count by one", //4
@@ -312,15 +410,16 @@ void greenpak4_counters_worker(
"Mux output is used outside counter", //14
"Counter reg is not DFF/ADFF", //15
"Counter input is not full bus", //16
- "Count register is used outside counter", //17
+ "Count register is used outside counter, but not by an allowed cell", //17
"Register output is not full bus", //18
"Register output is not full bus", //19
"No init value found", //20
"Underflow value is not equal to init value", //21
- "Reset polarity is not positive", //22
- "Reset is not to zero" //23
+ "RESERVED, not implemented", //22, kept for compatibility but not used anymore
+ "Reset is not to zero or COUNT_TO", //23
+ "Clock enable configuration is unsupported" //24
};
-
+
if(force_extract)
{
log_error(
@@ -330,27 +429,10 @@ void greenpak4_counters_worker(
}
return;
}
-
- //Figure out the final cell type based on the counter size
- string celltype = "\\GP_COUNT8";
- if(extract.width > 8)
- celltype = "\\GP_COUNT14";
-
- //Log it
- total_counters ++;
- string reset_type = "non-resettable";
- if(extract.has_reset)
- {
- //TODO: support other kind of reset
- reset_type = "async resettable";
- }
- log(" Found %d-bit %s down counter (from %d) for register %s declared at %s\n",
- extract.width,
- reset_type.c_str(),
- extract.count_value,
- log_id(extract.rwire->name),
- count_reg_src.c_str());
-
+
+ //Get new cell name
+ string countname = string("$COUNTx$") + log_id(extract.rwire->name.str());
+
//Wipe all of the old connections to the ALU
cell->unsetPort("\\A");
cell->unsetPort("\\B");
@@ -366,77 +448,204 @@ void greenpak4_counters_worker(
cell->unsetParam("\\Y_WIDTH");
//Change the cell type
- cell->type = celltype;
-
+ cell->type = "$__COUNT_";
+
//Hook up resets
if(extract.has_reset)
{
//TODO: support other kinds of reset
cell->setParam("\\RESET_MODE", RTLIL::Const("LEVEL"));
- cell->setPort("\\RST", extract.rst);
+
+ //If the reset is active low, infer an inverter ($__COUNT_ cells always have active high reset)
+ if(extract.rst_inverted)
+ {
+ auto realreset = cell->module->addWire(NEW_ID);
+ cell->module->addNot(NEW_ID, extract.rst, RTLIL::SigSpec(realreset));
+ cell->setPort("\\RST", realreset);
+ }
+ else
+ cell->setPort("\\RST", extract.rst);
}
else
{
cell->setParam("\\RESET_MODE", RTLIL::Const("RISING"));
cell->setPort("\\RST", RTLIL::SigSpec(false));
}
-
+
//Hook up other stuff
- cell->setParam("\\CLKIN_DIVIDE", RTLIL::Const(1));
+ //cell->setParam("\\CLKIN_DIVIDE", RTLIL::Const(1));
cell->setParam("\\COUNT_TO", RTLIL::Const(extract.count_value));
-
+ cell->setParam("\\WIDTH", RTLIL::Const(extract.width));
cell->setPort("\\CLK", extract.clk);
cell->setPort("\\OUT", extract.outsig);
-
+
+ //Hook up clock enable
+ if(extract.has_ce)
+ {
+ cell->setParam("\\HAS_CE", RTLIL::Const(1));
+ cell->setPort("\\CE", extract.ce);
+ }
+ else
+ cell->setParam("\\HAS_CE", RTLIL::Const(0));
+
+ //Hook up hard-wired ports (for now up/down are not supported), default to no parallel output
+ cell->setParam("\\HAS_POUT", RTLIL::Const(0));
+ cell->setParam("\\RESET_TO_MAX", RTLIL::Const(0));
+ cell->setParam("\\DIRECTION", RTLIL::Const("DOWN"));
+ cell->setPort("\\CE", RTLIL::Const(1));
+ cell->setPort("\\UP", RTLIL::Const(0));
+
+ //Hook up any parallel outputs
+ for(auto load : extract.pouts)
+ {
+ log(" Counter has parallel output to cell %s port %s\n", log_id(load.cell->name), log_id(load.port));
+
+ //Find the wire hooked to the old port
+ auto sig = load.cell->getPort(load.port);
+
+ //Connect it to our parallel output
+ //(this is OK to do more than once b/c they all go to the same place)
+ cell->setPort("\\POUT", sig);
+ cell->setParam("\\HAS_POUT", RTLIL::Const(1));
+ }
+
//Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires)
cells_to_remove.insert(extract.count_mux);
cells_to_remove.insert(extract.count_reg);
cells_to_remove.insert(extract.underflow_inv);
+
+ //Log it
+ total_counters ++;
+ string reset_type = "non-resettable";
+ if(extract.has_reset)
+ {
+ if(extract.rst_inverted)
+ reset_type = "negative";
+ else
+ reset_type = "positive";
+
+ //TODO: support other kind of reset
+ reset_type += " async resettable";
+ }
+ log(" Found %d-bit (%s) down counter %s (counting from %d) for register %s, declared at %s\n",
+ extract.width,
+ reset_type.c_str(),
+ countname.c_str(),
+ extract.count_value,
+ log_id(extract.rwire->name),
+ count_reg_src.c_str());
+
+ //Optimize the counter
+ //If we have no parallel output, and we have redundant bits, shrink us
+ if(extract.pouts.empty())
+ {
+ //TODO: Need to update this when we add support for counters with nonzero reset values
+ //to make sure the reset value fits in our bit space too
+
+ //Optimize it
+ int newbits = ceil(log2(extract.count_value));
+ if(extract.width != newbits)
+ {
+ cell->setParam("\\WIDTH", RTLIL::Const(newbits));
+ log(" Optimizing out %d unused high-order bits (new width is %d)\n",
+ extract.width - newbits,
+ newbits);
+ }
+ }
+
+ //Finally, rename the cell
+ cells_to_rename.insert(pair<Cell*, string>(cell, countname));
}
-struct Greenpak4CountersPass : public Pass {
- Greenpak4CountersPass() : Pass("greenpak4_counters", "Extract GreenPak4 counter cells") { }
- virtual void help()
+struct ExtractCounterPass : public Pass {
+ ExtractCounterPass() : Pass("extract_counter", "Extract GreenPak4 counter cells") { }
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" greenpak4_counters [options] [selection]\n");
+ log(" extract_counter [options] [selection]\n");
+ log("\n");
+ log("This pass converts non-resettable or async resettable down counters to\n");
+ log("counter cells. Use a target-specific 'techmap' map file to convert those cells\n");
+ log("to the actual target cells.\n");
+ log("\n");
+ log(" -maxwidth N\n");
+ log(" Only extract counters up to N bits wide\n");
+ log("\n");
+ log(" -pout X,Y,...\n");
+ log(" Only allow parallel output from the counter to the listed cell types\n");
+ log(" (if not specified, parallel outputs are not restricted)\n");
log("\n");
- log("This pass converts non-resettable or async resettable down counters to GreenPak4\n");
- log("counter cells (All other GreenPak4 counter modes must be instantiated manually.)\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- log_header(design, "Executing GREENPAK4_COUNTERS pass (mapping counters to hard IP blocks).\n");
-
+ log_header(design, "Executing EXTRACT_COUNTER pass (find counters in netlist).\n");
+
+ int maxwidth = 64;
size_t argidx;
+ pool<RTLIL::IdString> parallel_cells;
for (argidx = 1; argidx < args.size(); argidx++)
{
- // if (args[argidx] == "-v") {
- // continue;
- // }
- break;
+ if (args[argidx] == "-pout")
+ {
+ if(argidx + 1 >= args.size())
+ {
+ log_error("extract_counter -pout requires an argument\n");
+ return;
+ }
+
+ std::string pouts = args[++argidx];
+ std::string tmp;
+ for(size_t i=0; i<pouts.length(); i++)
+ {
+ if(pouts[i] == ',')
+ {
+ parallel_cells.insert(RTLIL::escape_id(tmp));
+ tmp = "";
+ }
+ else
+ tmp += pouts[i];
+ }
+ parallel_cells.insert(RTLIL::escape_id(tmp));
+ continue;
+ }
+
+ if (args[argidx] == "-maxwidth" && argidx+1 < args.size())
+ {
+ maxwidth = atoi(args[++argidx].c_str());
+ continue;
+ }
}
extra_args(args, argidx, design);
-
+
//Extract all of the counters we could find
unsigned int total_counters = 0;
for (auto module : design->selected_modules())
{
pool<Cell*> cells_to_remove;
-
+ pool<pair<Cell*, string>> cells_to_rename;
+
ModIndex index(module);
for (auto cell : module->selected_cells())
- greenpak4_counters_worker(index, cell, total_counters, cells_to_remove);
-
+ counter_worker(index, cell, total_counters, cells_to_remove, cells_to_rename, parallel_cells, maxwidth);
+
for(auto cell : cells_to_remove)
+ {
+ //log("Removing cell %s\n", log_id(cell->name));
module->remove(cell);
+ }
+
+ for(auto cpair : cells_to_rename)
+ {
+ //log("Renaming cell %s to %s\n", log_id(cpair.first->name), cpair.second.c_str());
+ module->rename(cpair.first, cpair.second);
+ }
}
-
+
if(total_counters)
log("Extracted %u counters\n", total_counters);
}
-} Greenpak4CountersPass;
+} ExtractCounterPass;
PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc
new file mode 100644
index 00000000..9e6dc0d2
--- /dev/null
+++ b/passes/techmap/extract_fa.cc
@@ -0,0 +1,605 @@
+/*
+ * 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/consteval.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ExtractFaConfig
+{
+ bool enable_fa = false;
+ bool enable_ha = false;
+ bool verbose = false;
+ int maxdepth = 20;
+ int maxbreadth = 6;
+};
+
+// http://svn.clifford.at/handicraft/2016/bindec/bindec.c
+int bindec(unsigned char v)
+{
+ int r = v & 1;
+ r += (~((v & 2) - 1)) & 10;
+ r += (~((v & 4) - 1)) & 100;
+ r += (~((v & 8) - 1)) & 1000;
+ r += (~((v & 16) - 1)) & 10000;
+ r += (~((v & 32) - 1)) & 100000;
+ r += (~((v & 64) - 1)) & 1000000;
+ r += (~((v & 128) - 1)) & 10000000;
+ return r;
+}
+
+struct ExtractFaWorker
+{
+ const ExtractFaConfig &config;
+ Module *module;
+ ConstEval ce;
+ SigMap &sigmap;
+
+ dict<SigBit, Cell*> driver;
+ pool<SigBit> handled_bits;
+
+ const int xor2_func = 0x6, xnor2_func = 0x9;
+ const int xor3_func = 0x96, xnor3_func = 0x69;
+
+ pool<tuple<SigBit, SigBit>> xorxnor2;
+ pool<tuple<SigBit, SigBit, SigBit>> xorxnor3;
+
+ dict<tuple<SigBit, SigBit>, dict<int, pool<SigBit>>> func2;
+ dict<tuple<SigBit, SigBit, SigBit>, dict<int, pool<SigBit>>> func3;
+
+ int count_func2;
+ int count_func3;
+
+ struct func2_and_info_t {
+ bool inv_a, inv_b, inv_y;
+ };
+
+ struct func3_maj_info_t {
+ bool inv_a, inv_b, inv_c, inv_y;
+ };
+
+ dict<int, func2_and_info_t> func2_and_info;
+ dict<int, func3_maj_info_t> func3_maj_info;
+
+ ExtractFaWorker(const ExtractFaConfig &config, Module *module) :
+ config(config), module(module), ce(module), sigmap(ce.assign_map)
+ {
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type.in( "$_BUF_", "$_NOT_", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_",
+ "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_",
+ "$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
+ {
+ SigBit y = sigmap(SigBit(cell->getPort("\\Y")));
+ log_assert(driver.count(y) == 0);
+ driver[y] = cell;
+ }
+ }
+
+ for (int ia = 0; ia < 2; ia++)
+ for (int ib = 0; ib < 2; ib++)
+ {
+ func2_and_info_t f2i;
+
+ f2i.inv_a = ia;
+ f2i.inv_b = ib;
+ f2i.inv_y = false;
+
+ int func = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ bool a = (i & 1) ? !f2i.inv_a : f2i.inv_a;
+ bool b = (i & 2) ? !f2i.inv_b : f2i.inv_b;
+ if (a && b) func |= 1 << i;
+ }
+
+ log_assert(func2_and_info.count(func) == 0);
+ func2_and_info[func] = f2i;
+
+ f2i.inv_y = true;
+ func ^= 15;
+
+ log_assert(func2_and_info.count(func) == 0);
+ func2_and_info[func] = f2i;
+ }
+
+ for (int ia = 0; ia < 2; ia++)
+ for (int ib = 0; ib < 2; ib++)
+ for (int ic = 0; ic < 2; ic++)
+ {
+ func3_maj_info_t f3i;
+
+ f3i.inv_a = ia;
+ f3i.inv_b = ib;
+ f3i.inv_c = ic;
+ f3i.inv_y = false;
+
+ int func = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ bool a = (i & 1) ? !f3i.inv_a : f3i.inv_a;
+ bool b = (i & 2) ? !f3i.inv_b : f3i.inv_b;
+ bool c = (i & 4) ? !f3i.inv_c : f3i.inv_c;
+ if ((a && b) || (a && c) || (b &&c)) func |= 1 << i;
+ }
+
+ log_assert(func3_maj_info.count(func) == 0);
+ func3_maj_info[func] = f3i;
+
+ // f3i.inv_y = true;
+ // func ^= 255;
+
+ // log_assert(func3_maj_info.count(func) == 0);
+ // func3_maj_info[func] = f3i;
+ }
+ }
+
+ void check_partition(SigBit root, pool<SigBit> &leaves)
+ {
+ if (config.enable_ha && GetSize(leaves) == 2)
+ {
+ leaves.sort();
+
+ SigBit A = SigSpec(leaves)[0];
+ SigBit B = SigSpec(leaves)[1];
+
+ int func = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ bool a_value = (i & 1) != 0;
+ bool b_value = (i & 2) != 0;
+
+ ce.push();
+ ce.set(A, a_value ? State::S1 : State::S0);
+ ce.set(B, b_value ? State::S1 : State::S0);
+
+ SigSpec sig = root;
+
+ if (!ce.eval(sig))
+ log_abort();
+
+ if (sig == State::S1)
+ func |= 1 << i;
+
+ ce.pop();
+ }
+
+ // log("%04d %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(root));
+
+ if (func == xor2_func || func == xnor2_func)
+ xorxnor2.insert(tuple<SigBit, SigBit>(A, B));
+
+ count_func2++;
+ func2[tuple<SigBit, SigBit>(A, B)][func].insert(root);
+ }
+
+ if (config.enable_fa && GetSize(leaves) == 3)
+ {
+ leaves.sort();
+
+ SigBit A = SigSpec(leaves)[0];
+ SigBit B = SigSpec(leaves)[1];
+ SigBit C = SigSpec(leaves)[2];
+
+ int func = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ bool a_value = (i & 1) != 0;
+ bool b_value = (i & 2) != 0;
+ bool c_value = (i & 4) != 0;
+
+ ce.push();
+ ce.set(A, a_value ? State::S1 : State::S0);
+ ce.set(B, b_value ? State::S1 : State::S0);
+ ce.set(C, c_value ? State::S1 : State::S0);
+
+ SigSpec sig = root;
+
+ if (!ce.eval(sig))
+ log_abort();
+
+ if (sig == State::S1)
+ func |= 1 << i;
+
+ ce.pop();
+ }
+
+ // log("%08d %s %s %s -> %s\n", bindec(func), log_signal(A), log_signal(B), log_signal(C), log_signal(root));
+
+ if (func == xor3_func || func == xnor3_func)
+ xorxnor3.insert(tuple<SigBit, SigBit, SigBit>(A, B, C));
+
+ count_func3++;
+ func3[tuple<SigBit, SigBit, SigBit>(A, B, C)][func].insert(root);
+ }
+ }
+
+ void find_partitions(SigBit root, pool<SigBit> &leaves, pool<pool<SigBit>> &cache, int maxdepth, int maxbreadth)
+ {
+ if (cache.count(leaves))
+ return;
+
+ // log("%*s[%d] %s:", 20-maxdepth, "", maxdepth, log_signal(root));
+ // for (auto bit : leaves)
+ // log(" %s", log_signal(bit));
+ // log("\n");
+
+ cache.insert(leaves);
+ check_partition(root, leaves);
+
+ if (maxdepth == 0)
+ return;
+
+ for (SigBit bit : leaves)
+ {
+ if (driver.count(bit) == 0)
+ continue;
+
+ Cell *cell = driver.at(bit);
+ pool<SigBit> new_leaves = leaves;
+
+ new_leaves.erase(bit);
+ if (cell->hasPort("\\A")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\A"))));
+ if (cell->hasPort("\\B")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\B"))));
+ if (cell->hasPort("\\C")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\C"))));
+ if (cell->hasPort("\\D")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\D"))));
+
+ if (GetSize(new_leaves) > maxbreadth)
+ continue;
+
+ find_partitions(root, new_leaves, cache, maxdepth-1, maxbreadth);
+ }
+ }
+
+ void assign_new_driver(SigBit bit, SigBit new_driver)
+ {
+ Cell *cell = driver.at(bit);
+ if (sigmap(cell->getPort("\\Y")) == bit) {
+ cell->setPort("\\Y", module->addWire(NEW_ID));
+ module->connect(bit, new_driver);
+ }
+ }
+
+ void run()
+ {
+ log("Extracting full/half adders from %s:\n", log_id(module));
+
+ for (auto it : driver)
+ {
+ if (it.second->type.in("$_BUF_", "$_NOT_"))
+ continue;
+
+ SigBit root = it.first;
+ pool<SigBit> leaves = { root };
+ pool<pool<SigBit>> cache;
+
+ if (config.verbose)
+ log(" checking %s\n", log_signal(it.first));
+
+ count_func2 = 0;
+ count_func3 = 0;
+
+ find_partitions(root, leaves, cache, config.maxdepth, config.maxbreadth);
+
+ if (config.verbose && count_func2 > 0)
+ log(" extracted %d two-input functions\n", count_func2);
+
+ if (config.verbose && count_func3 > 0)
+ log(" extracted %d three-input functions\n", count_func3);
+ }
+
+ for (auto &key : xorxnor3)
+ {
+ SigBit A = get<0>(key);
+ SigBit B = get<1>(key);
+ SigBit C = get<2>(key);
+
+ log(" 3-Input XOR/XNOR %s %s %s:\n", log_signal(A), log_signal(B), log_signal(C));
+
+ for (auto &it : func3.at(key))
+ {
+ if (it.first != xor3_func && it.first != xnor3_func)
+ continue;
+
+ log(" %08d ->", bindec(it.first));
+ for (auto bit : it.second)
+ log(" %s", log_signal(bit));
+ log("\n");
+ }
+
+ dict<int, tuple<SigBit, SigBit, Cell*>> facache;
+
+ for (auto &it : func3_maj_info)
+ {
+ int func = it.first;
+ auto f3i = it.second;
+
+ if (func3.at(key).count(func) == 0)
+ continue;
+
+ if (func3.at(key).count(xor3_func) == 0 && func3.at(key).count(xnor3_func) != 0) {
+ f3i.inv_a = !f3i.inv_a;
+ f3i.inv_b = !f3i.inv_b;
+ f3i.inv_c = !f3i.inv_c;
+ f3i.inv_y = !f3i.inv_y;
+ }
+
+ if (!f3i.inv_a && !f3i.inv_b && !f3i.inv_c && !f3i.inv_y) {
+ log(" Majority without inversions:\n");
+ } else {
+ log(" Majority with inverted");
+ if (f3i.inv_a) log(" A");
+ if (f3i.inv_b) log(" B");
+ if (f3i.inv_c) log(" C");
+ if (f3i.inv_y) log(" Y");
+ log(":\n");
+ }
+
+ log(" %08d ->", bindec(func));
+ for (auto bit : func3.at(key).at(func))
+ log(" %s", log_signal(bit));
+ log("\n");
+
+ int fakey = 0;
+ if (f3i.inv_a) fakey |= 1;
+ if (f3i.inv_b) fakey |= 2;
+ if (f3i.inv_c) fakey |= 4;
+
+ int fakey_inv = fakey ^ 7;
+ bool invert_xy = false;
+ SigBit X, Y;
+
+ if (facache.count(fakey))
+ {
+ auto &fa = facache.at(fakey);
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ if (facache.count(fakey_inv))
+ {
+ auto &fa = facache.at(fakey_inv);
+ invert_xy = true;
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ {
+ Cell *cell = module->addCell(NEW_ID, "$fa");
+ cell->setParam("\\WIDTH", 1);
+
+ log(" Created $fa cell %s.\n", log_id(cell));
+
+ cell->setPort("\\A", f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
+ cell->setPort("\\B", f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
+ cell->setPort("\\C", f3i.inv_c ? module->NotGate(NEW_ID, C) : C);
+
+ X = module->addWire(NEW_ID);
+ Y = module->addWire(NEW_ID);
+
+ cell->setPort("\\X", X);
+ cell->setPort("\\Y", Y);
+
+ facache[fakey] = make_tuple(X, Y, cell);
+ }
+
+ if (func3.at(key).count(xor3_func)) {
+ SigBit YY = invert_xy ? module->NotGate(NEW_ID, Y) : Y;
+ for (auto bit : func3.at(key).at(xor3_func))
+ assign_new_driver(bit, YY);
+ }
+
+ if (func3.at(key).count(xnor3_func)) {
+ SigBit YY = invert_xy ? Y : module->NotGate(NEW_ID, Y);
+ for (auto bit : func3.at(key).at(xnor3_func))
+ assign_new_driver(bit, YY);
+ }
+
+ SigBit XX = invert_xy != f3i.inv_y ? module->NotGate(NEW_ID, X) : X;
+
+ for (auto bit : func3.at(key).at(func))
+ assign_new_driver(bit, XX);
+ }
+ }
+
+ for (auto &key : xorxnor2)
+ {
+ SigBit A = get<0>(key);
+ SigBit B = get<1>(key);
+
+ log(" 2-Input XOR/XNOR %s %s:\n", log_signal(A), log_signal(B));
+
+ for (auto &it : func2.at(key))
+ {
+ if (it.first != xor2_func && it.first != xnor2_func)
+ continue;
+
+ log(" %04d ->", bindec(it.first));
+ for (auto bit : it.second)
+ log(" %s", log_signal(bit));
+ log("\n");
+ }
+
+ dict<int, tuple<SigBit, SigBit, Cell*>> facache;
+
+ for (auto &it : func2_and_info)
+ {
+ int func = it.first;
+ auto &f2i = it.second;
+
+ if (func2.at(key).count(func) == 0)
+ continue;
+
+ if (!f2i.inv_a && !f2i.inv_b && !f2i.inv_y) {
+ log(" AND without inversions:\n");
+ } else {
+ log(" AND with inverted");
+ if (f2i.inv_a) log(" A");
+ if (f2i.inv_b) log(" B");
+ if (f2i.inv_y) log(" Y");
+ log(":\n");
+ }
+
+ log(" %04d ->", bindec(func));
+ for (auto bit : func2.at(key).at(func))
+ log(" %s", log_signal(bit));
+ log("\n");
+
+ int fakey = 0;
+ if (f2i.inv_a) fakey |= 1;
+ if (f2i.inv_b) fakey |= 2;
+
+ int fakey_inv = fakey ^ 3;
+ bool invert_xy = false;
+ SigBit X, Y;
+
+ if (facache.count(fakey))
+ {
+ auto &fa = facache.at(fakey);
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ if (facache.count(fakey_inv))
+ {
+ auto &fa = facache.at(fakey_inv);
+ invert_xy = true;
+ X = get<0>(fa);
+ Y = get<1>(fa);
+ log(" Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+ }
+ else
+ {
+ Cell *cell = module->addCell(NEW_ID, "$fa");
+ cell->setParam("\\WIDTH", 1);
+
+ log(" Created $fa cell %s.\n", log_id(cell));
+
+ cell->setPort("\\A", f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
+ cell->setPort("\\B", f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
+ cell->setPort("\\C", State::S0);
+
+ X = module->addWire(NEW_ID);
+ Y = module->addWire(NEW_ID);
+
+ cell->setPort("\\X", X);
+ cell->setPort("\\Y", Y);
+ }
+
+ if (func2.at(key).count(xor2_func)) {
+ SigBit YY = invert_xy ? module->NotGate(NEW_ID, Y) : Y;
+ for (auto bit : func2.at(key).at(xor2_func))
+ assign_new_driver(bit, YY);
+ }
+
+ if (func2.at(key).count(xnor2_func)) {
+ SigBit YY = invert_xy ? Y : module->NotGate(NEW_ID, Y);
+ for (auto bit : func2.at(key).at(xnor2_func))
+ assign_new_driver(bit, YY);
+ }
+
+ SigBit XX = invert_xy != f2i.inv_y ? module->NotGate(NEW_ID, X) : X;
+
+ for (auto bit : func2.at(key).at(func))
+ assign_new_driver(bit, XX);
+ }
+ }
+ }
+};
+
+struct ExtractFaPass : public Pass {
+ ExtractFaPass() : Pass("extract_fa", "find and extract full/half adders") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" extract_fa [options] [selection]\n");
+ log("\n");
+ log("This pass extracts full/half adders from a gate-level design.\n");
+ log("\n");
+ log(" -fa, -ha\n");
+ log(" Enable cell types (fa=full adder, ha=half adder)\n");
+ log(" All types are enabled if none of this options is used\n");
+ log("\n");
+ log(" -d <int>\n");
+ log(" Set maximum depth for extracted logic cones (default=20)\n");
+ log("\n");
+ log(" -b <int>\n");
+ log(" Set maximum breadth for extracted logic cones (default=6)\n");
+ log("\n");
+ log(" -v\n");
+ log(" Verbose output\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ ExtractFaConfig config;
+
+ log_header(design, "Executing EXTRACT_FA pass (find and extract full/half adders).\n");
+ log_push();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-fa") {
+ config.enable_fa = true;
+ continue;
+ }
+ if (args[argidx] == "-ha") {
+ config.enable_ha = true;
+ continue;
+ }
+ if (args[argidx] == "-v") {
+ config.verbose = true;
+ continue;
+ }
+ if (args[argidx] == "-d" && argidx+2 < args.size()) {
+ config.maxdepth = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-b" && argidx+2 < args.size()) {
+ config.maxbreadth = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!config.enable_fa && !config.enable_ha) {
+ config.enable_fa = true;
+ config.enable_ha = true;
+ }
+
+ for (auto module : design->selected_modules())
+ {
+ ExtractFaWorker worker(config, module);
+ worker.run();
+ }
+
+ log_pop();
+ }
+} ExtractFaPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc
new file mode 100644
index 00000000..a77bbc0b
--- /dev/null
+++ b/passes/techmap/extract_reduce.cc
@@ -0,0 +1,324 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2017 Robert Ou <rqou@robertou.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include <deque>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ExtractReducePass : public Pass
+{
+ enum GateType {
+ And,
+ Or,
+ Xor
+ };
+
+ ExtractReducePass() : Pass("extract_reduce", "converts gate chains into $reduce_* cells") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" extract_reduce [options] [selection]\n");
+ log("\n");
+ log("converts gate chains into $reduce_* cells\n");
+ log("\n");
+ log("This command finds chains of $_AND_, $_OR_, and $_XOR_ cells and replaces them\n");
+ log("with their corresponding $reduce_* cells. Because this command only operates on\n");
+ log("these cell types, it is recommended to map the design to only these cell types\n");
+ log("using the `abc -g` command. Note that, in some cases, it may be more effective\n");
+ log("to map the design to only $_AND_ cells, run extract_reduce, map the remaining\n");
+ log("parts of the design to AND/OR/XOR cells, and run extract_reduce a second time.\n");
+ log("\n");
+ log(" -allow-off-chain\n");
+ log(" Allows matching of cells that have loads outside the chain. These cells\n");
+ log(" will be replicated and folded into the $reduce_* cell, but the original\n");
+ log(" cell will remain, driving its original loads.\n");
+ log("\n");
+ }
+
+ inline bool IsRightType(Cell* cell, GateType gt)
+ {
+ return (cell->type == "$_AND_" && gt == GateType::And) ||
+ (cell->type == "$_OR_" && gt == GateType::Or) ||
+ (cell->type == "$_XOR_" && gt == GateType::Xor);
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing EXTRACT_REDUCE pass.\n");
+ log_push();
+
+ size_t argidx;
+ bool allow_off_chain = false;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-allow-off-chain")
+ {
+ allow_off_chain = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+
+ // Index all of the nets in the module
+ dict<SigBit, Cell*> sig_to_driver;
+ dict<SigBit, pool<Cell*>> sig_to_sink;
+ for (auto cell : module->selected_cells())
+ {
+ for (auto &conn : cell->connections())
+ {
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sig_to_driver[bit] = cell;
+
+ if (cell->input(conn.first))
+ {
+ for (auto bit : sigmap(conn.second))
+ {
+ if (sig_to_sink.count(bit) == 0)
+ sig_to_sink[bit] = pool<Cell*>();
+ sig_to_sink[bit].insert(cell);
+ }
+ }
+ }
+ }
+
+ // Need to check if any wires connect to module ports
+ pool<SigBit> port_sigs;
+ for (auto wire : module->selected_wires())
+ if (wire->port_input || wire->port_output)
+ for (auto bit : sigmap(wire))
+ port_sigs.insert(bit);
+
+ // Actual logic starts here
+ pool<Cell*> consumed_cells;
+ for (auto cell : module->selected_cells())
+ {
+ if (consumed_cells.count(cell))
+ continue;
+
+ GateType gt;
+
+ if (cell->type == "$_AND_")
+ gt = GateType::And;
+ else if (cell->type == "$_OR_")
+ gt = GateType::Or;
+ else if (cell->type == "$_XOR_")
+ gt = GateType::Xor;
+ else
+ continue;
+
+ log("Working on cell %s...\n", cell->name.c_str());
+
+ // If looking for a single chain, follow linearly to the sink
+ pool<Cell*> sinks;
+ if(!allow_off_chain)
+ {
+ Cell* head_cell = cell;
+ Cell* x = cell;
+ while (true)
+ {
+ if(!IsRightType(x, gt))
+ break;
+
+ head_cell = x;
+
+ auto y = sigmap(x->getPort("\\Y"));
+ log_assert(y.size() == 1);
+
+ // Should only continue if there is one fanout back into a cell (not to a port)
+ if (sig_to_sink[y[0]].size() != 1)
+ break;
+
+ x = *sig_to_sink[y[0]].begin();
+ }
+
+ sinks.insert(head_cell);
+ }
+
+ //If off-chain loads are allowed, we have to do a wider traversal to see what the longest chain is
+ else
+ {
+ //BFS, following all chains until they hit a cell of a different type
+ //Pick the longest one
+ auto y = sigmap(cell->getPort("\\Y"));
+ pool<Cell*> current_loads = sig_to_sink[y];
+ pool<Cell*> next_loads;
+
+ while(!current_loads.empty())
+ {
+ //Find each sink and see what they are
+ for(auto x : current_loads)
+ {
+ //Not one of our gates? Don't follow any further
+ //(but add the originating cell to the list of sinks)
+ if(!IsRightType(x, gt))
+ {
+ sinks.insert(cell);
+ continue;
+ }
+
+ //If this signal drives a port, add it to the sinks
+ //(even though it may not be the end of a chain)
+ if(port_sigs.count(x) && !consumed_cells.count(x))
+ sinks.insert(x);
+
+ //It's a match, search everything out from it
+ auto& next = sig_to_sink[x];
+ for(auto z : next)
+ next_loads.insert(z);
+ }
+
+ //If we couldn't find any downstream loads, stop.
+ //Create a reduction for each of the max-length chains we found
+ if(next_loads.empty())
+ {
+ for(auto s : current_loads)
+ {
+ //Not one of our gates? Don't follow any further
+ if(!IsRightType(s, gt))
+ continue;
+
+ sinks.insert(s);
+ }
+ break;
+ }
+
+ //Otherwise, continue down the chain
+ current_loads = next_loads;
+ next_loads.clear();
+ }
+ }
+
+ //We have our list, go act on it
+ for(auto head_cell : sinks)
+ {
+ log(" Head cell is %s\n", head_cell->name.c_str());
+
+ //Avoid duplication if we already were covered
+ if(consumed_cells.count(head_cell))
+ continue;
+
+ pool<Cell*> cur_supercell;
+ std::deque<Cell*> bfs_queue = {head_cell};
+ while (bfs_queue.size())
+ {
+ Cell* x = bfs_queue.front();
+ bfs_queue.pop_front();
+
+ cur_supercell.insert(x);
+
+ auto a = sigmap(x->getPort("\\A"));
+ log_assert(a.size() == 1);
+
+ // Must have only one sink unless we're going off chain
+ // XXX: Check that it is indeed this node?
+ if( allow_off_chain || (sig_to_sink[a[0]].size() + port_sigs.count(a[0]) == 1) )
+ {
+ Cell* cell_a = sig_to_driver[a[0]];
+ if(cell_a && IsRightType(cell_a, gt))
+ {
+ // The cell here is the correct type, and it's definitely driving
+ // this current cell.
+ bfs_queue.push_back(cell_a);
+ }
+ }
+
+ auto b = sigmap(x->getPort("\\B"));
+ log_assert(b.size() == 1);
+
+ // Must have only one sink
+ // XXX: Check that it is indeed this node?
+ if( allow_off_chain || (sig_to_sink[b[0]].size() + port_sigs.count(b[0]) == 1) )
+ {
+ Cell* cell_b = sig_to_driver[b[0]];
+ if(cell_b && IsRightType(cell_b, gt))
+ {
+ // The cell here is the correct type, and it's definitely driving only
+ // this current cell.
+ bfs_queue.push_back(cell_b);
+ }
+ }
+ }
+
+ log(" Cells:\n");
+ for (auto x : cur_supercell)
+ log(" %s\n", x->name.c_str());
+
+ if (cur_supercell.size() > 1)
+ {
+ // Worth it to create reduce cell
+ log(" Creating $reduce_* cell!\n");
+
+ pool<SigBit> input_pool;
+ pool<SigBit> input_pool_intermed;
+ for (auto x : cur_supercell)
+ {
+ input_pool.insert(sigmap(x->getPort("\\A"))[0]);
+ input_pool.insert(sigmap(x->getPort("\\B"))[0]);
+ input_pool_intermed.insert(sigmap(x->getPort("\\Y"))[0]);
+ }
+ SigSpec input;
+ for (auto b : input_pool)
+ if (input_pool_intermed.count(b) == 0)
+ input.append_bit(b);
+
+ SigBit output = sigmap(head_cell->getPort("\\Y")[0]);
+
+ auto new_reduce_cell = module->addCell(NEW_ID,
+ gt == GateType::And ? "$reduce_and" :
+ gt == GateType::Or ? "$reduce_or" :
+ gt == GateType::Xor ? "$reduce_xor" : "");
+ new_reduce_cell->setParam("\\A_SIGNED", 0);
+ new_reduce_cell->setParam("\\A_WIDTH", input.size());
+ new_reduce_cell->setParam("\\Y_WIDTH", 1);
+ new_reduce_cell->setPort("\\A", input);
+ new_reduce_cell->setPort("\\Y", output);
+
+ if(allow_off_chain)
+ consumed_cells.insert(head_cell);
+ else
+ {
+ for (auto x : cur_supercell)
+ consumed_cells.insert(x);
+ }
+ }
+ }
+ }
+
+ // Remove all of the head cells, since we supplant them.
+ // Do not remove the upstream cells since some might still be in use ("clean" will get rid of unused ones)
+ for (auto cell : consumed_cells)
+ module->remove(cell);
+ }
+
+ log_pop();
+ }
+} ExtractReducePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index 82cecac2..9ec651ae 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -55,7 +55,7 @@ void hilomap_worker(RTLIL::SigSpec &sig)
struct HilomapPass : public Pass {
HilomapPass() : Pass("hilomap", "technology mapping of constant hi- and/or lo-drivers") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" hilomap [options] [selection]\n");
@@ -74,7 +74,7 @@ struct HilomapPass : public Pass {
log(" each constant bit.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing HILOMAP pass (mapping to constant drivers).\n");
diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc
index aa81468d..2173049b 100644
--- a/passes/techmap/insbuf.cc
+++ b/passes/techmap/insbuf.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct InsbufPass : public Pass {
InsbufPass() : Pass("insbuf", "insert buffer cells for connected wires") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" insbuf [options] [selection]\n");
@@ -37,7 +37,7 @@ struct InsbufPass : public Pass {
log(" call to \"clean\" will remove all $_BUF_ in the design.)\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing INSBUF pass (insert buffer cells for connected wires).\n");
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 4acbf7c0..efcc082d 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -34,7 +34,7 @@ void split_portname_pair(std::string &port1, std::string &port2)
struct IopadmapPass : public Pass {
IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" iopadmap [options] [selection]\n");
@@ -78,7 +78,7 @@ struct IopadmapPass : public Pass {
log("Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
@@ -146,11 +146,37 @@ struct IopadmapPass : public Pass {
for (auto module : design->selected_modules())
{
dict<IdString, pool<int>> skip_wires;
+ pool<SigBit> skip_wire_bits;
+ SigMap sigmap(module);
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4))))
+ skip_wire_bits.insert(bit);
+ }
if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
{
- SigMap sigmap(module);
dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits;
+ pool<pair<IdString, IdString>> norewrites;
+ SigMap rewrites;
for (auto cell : module->cells())
if (cell->type == "$_TBUF_") {
@@ -177,6 +203,9 @@ struct IopadmapPass : public Pass {
if (tbuf_bits.count(mapped_wire_bit) == 0)
continue;
+ if (skip_wire_bits.count(mapped_wire_bit))
+ continue;
+
auto &tbuf_cache = tbuf_bits.at(mapped_wire_bit);
Cell *tbuf_cell = module->cell(tbuf_cache.first);
@@ -219,6 +248,9 @@ struct IopadmapPass : public Pass {
module->remove(tbuf_cell);
skip_wires[wire->name].insert(i);
+
+ norewrites.insert(make_pair(cell->name, RTLIL::escape_id(tinoutpad_portname4)));
+ rewrites.add(sigmap(wire_bit), owire);
continue;
}
@@ -256,6 +288,22 @@ struct IopadmapPass : public Pass {
}
}
}
+
+ if (GetSize(norewrites))
+ {
+ for (auto cell : module->cells())
+ for (auto port : cell->connections())
+ {
+ if (norewrites.count(make_pair(cell->name, port.first)))
+ continue;
+
+ SigSpec orig_sig = sigmap(port.second);
+ SigSpec new_sig = rewrites(orig_sig);
+
+ if (orig_sig != new_sig)
+ cell->setPort(port.first, new_sig);
+ }
+ }
}
for (auto wire : module->selected_wires())
@@ -272,6 +320,13 @@ struct IopadmapPass : public Pass {
skip_bit_indices = skip_wires.at(wire->name);
}
+ for (int i = 0; i < GetSize(wire); i++)
+ if (skip_wire_bits.count(sigmap(SigBit(wire, i))))
+ skip_bit_indices.insert(i);
+
+ if (GetSize(wire) == GetSize(skip_bit_indices))
+ continue;
+
if (wire->port_input && !wire->port_output) {
if (inpad_celltype.empty()) {
log("Don't map input port %s.%s: Missing option -inpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index d5254c02..d3b1ff02 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -100,8 +100,15 @@ int LibertyParser::lexer(std::string &str)
break;
}
f.unget();
- // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
- return 'v';
+ if (str == "+" || str == "-") {
+ /* Single operator is not an identifier */
+ // fprintf(stderr, "LEX: char >>%s<<\n", str.c_str());
+ return str[0];
+ }
+ else {
+ // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
+ return 'v';
+ }
}
if (c == '"') {
@@ -191,6 +198,19 @@ LibertyAst *LibertyParser::parse()
tok = lexer(ast->value);
if (tok != 'v')
error();
+ tok = lexer(str);
+ while (tok == '+' || tok == '-' || tok == '*' || tok == '/') {
+ ast->value += tok;
+ tok = lexer(str);
+ if (tok != 'v')
+ error();
+ ast->value += str;
+ tok = lexer(str);
+ }
+ if (tok == ';')
+ break;
+ else
+ error();
continue;
}
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index 2bb0bd8b..d32bbff1 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -56,7 +56,7 @@ int lut2mux(Cell *cell)
struct Lut2muxPass : public Pass {
Lut2muxPass() : Pass("lut2mux", "convert $lut to $_MUX_") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -65,7 +65,7 @@ struct Lut2muxPass : public Pass {
log("This pass converts $lut cells to $_MUX_ gates.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n");
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index 32569d07..3e8e59e6 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -365,7 +365,7 @@ PRIVATE_NAMESPACE_BEGIN
struct MaccmapPass : public Pass {
MaccmapPass() : Pass("maccmap", "mapping macc cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -375,7 +375,7 @@ struct MaccmapPass : public Pass {
log("is used then the $macc cell is mapped to $add, $sub, etc. cells instead.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool unmap_mode = false;
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index 1dc64958..12da9ed0 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -561,7 +561,7 @@ struct MuxcoverWorker
struct MuxcoverPass : public Pass {
MuxcoverPass() : Pass("muxcover", "cover trees of MUX cells with wider MUXes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -579,7 +579,7 @@ struct MuxcoverPass : public Pass {
log(" less efficient than the original circuit.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing MUXCOVER pass (mapping to wider MUXes).\n");
diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc
index 6fcdf82b..cc765d89 100644
--- a/passes/techmap/nlutmap.cc
+++ b/passes/techmap/nlutmap.cc
@@ -92,7 +92,7 @@ struct NlutmapWorker
for (auto bit : sigmap(conn.second))
bit_lut_count[bit]++;
}
-
+
for (auto &cand : candidate_ratings)
{
for (auto &conn : cand.first->connections())
@@ -129,7 +129,7 @@ struct NlutmapWorker
struct NlutmapPass : public Pass {
NlutmapPass() : Pass("nlutmap", "map to LUTs of different sizes") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -149,7 +149,7 @@ struct NlutmapPass : public Pass {
log("to generic logic gates ($_AND_, etc.).\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
NlutmapConfig config;
diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc
index c626dbcc..b7a22dc3 100644
--- a/passes/techmap/pmuxtree.cc
+++ b/passes/techmap/pmuxtree.cc
@@ -67,7 +67,7 @@ static SigSpec recursive_mux_generator(Module *module, const SigSpec &sig_data,
struct PmuxtreePass : public Pass {
PmuxtreePass() : Pass("pmuxtree", "transform $pmux cells to trees of $mux cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -76,7 +76,7 @@ struct PmuxtreePass : public Pass {
log("This pass transforms $pmux cells to a trees of $mux cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PMUXTREE pass.\n");
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index 6936b499..f20863ba 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -391,7 +391,7 @@ struct ShregmapWorker
struct ShregmapPass : public Pass {
ShregmapPass() : Pass("shregmap", "map shift registers") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -449,7 +449,7 @@ struct ShregmapPass : public Pass {
log(" map to greenpak4 shift registers.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
ShregmapOptions opts;
string clkpol, enpol;
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index c6b932bd..660b6060 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -575,7 +575,7 @@ PRIVATE_NAMESPACE_BEGIN
struct SimplemapPass : public Pass {
SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -590,7 +590,7 @@ struct SimplemapPass : public Pass {
log(" $sr, $ff, $dff, $dffsr, $adff, $dlatch\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
extra_args(args, 1, design);
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 6784f48c..d0e5e223 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -171,18 +171,15 @@ struct TechmapWorker
}
std::string orig_cell_name;
- pool<string> extra_src_attrs;
+ pool<string> extra_src_attrs = cell->get_strpool_attribute("\\src");
- if (!flatten_mode)
- {
+ if (!flatten_mode) {
for (auto &it : tpl->cells_)
if (it.first == "\\_TECHMAP_REPLACE_") {
orig_cell_name = cell->name.str();
module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str());
break;
}
-
- extra_src_attrs = cell->get_strpool_attribute("\\src");
}
dict<IdString, IdString> memory_renames;
@@ -247,6 +244,9 @@ struct TechmapWorker
continue;
}
+ if (GetSize(it.second) == 0)
+ continue;
+
RTLIL::Wire *w = tpl->wires_.at(portname);
RTLIL::SigSig c, extra_connect;
@@ -305,10 +305,15 @@ struct TechmapWorker
// approach that yields nicer outputs:
// replace internal wires that are connected to external wires
- if (w->port_output)
+ if (w->port_output && !w->port_input) {
port_signal_map.add(c.second, c.first);
- else
+ } else
+ if (!w->port_output && w->port_input) {
port_signal_map.add(c.first, c.second);
+ } else {
+ module->connect(c);
+ extra_connect = SigSig();
+ }
for (auto &attr : w->attributes) {
if (attr.first == "\\src")
@@ -322,8 +327,9 @@ struct TechmapWorker
for (auto &it : tpl->cells_)
{
std::string c_name = it.second->name.str();
+ bool techmap_replace_cell = (!flatten_mode) && (c_name == "\\_TECHMAP_REPLACE_");
- if (!flatten_mode && c_name == "\\_TECHMAP_REPLACE_")
+ if (techmap_replace_cell)
c_name = orig_cell_name;
else
apply_prefix(cell->name.str(), c_name);
@@ -353,6 +359,11 @@ struct TechmapWorker
if (c->attributes.count("\\src"))
c->add_strpool_attribute("\\src", extra_src_attrs);
+
+ if (techmap_replace_cell)
+ for (auto attr : cell->attributes)
+ if (!c->attributes.count(attr.first))
+ c->attributes[attr.first] = attr.second;
}
for (auto &it : tpl->connections()) {
@@ -451,6 +462,7 @@ struct TechmapWorker
bool mapped_cell = false;
std::string cell_type = cell->type.str();
+
if (in_recursion && cell_type.substr(0, 2) == "\\$")
cell_type = cell_type.substr(1);
@@ -498,6 +510,8 @@ struct TechmapWorker
extmapper_module = extmapper_design->addModule(m_name);
RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell);
+ extmapper_cell->set_src_attribute(cell->get_src_attribute());
+
int port_counter = 1;
for (auto &c : extmapper_cell->connections_) {
RTLIL::Wire *w = extmapper_module->addWire(c.first, GetSize(c.second));
@@ -877,7 +891,7 @@ struct TechmapWorker
struct TechmapPass : public Pass {
TechmapPass() : Pass("techmap", "generic technology mapper") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -919,7 +933,7 @@ struct TechmapPass : public Pass {
log(" -D <define>, -I <incdir>\n");
log(" this options are passed as-is to the Verilog frontend for loading the\n");
log(" map file. Note that the Verilog frontend is also called with the\n");
- log(" '-ignore_redef' option set.\n");
+ log(" '-nooverwrite' option set.\n");
log("\n");
log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
log("match cells with a type that match the text value of this attribute. Otherwise\n");
@@ -1000,7 +1014,7 @@ struct TechmapPass : public Pass {
log("constant value.\n");
log("\n");
log("A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name\n");
- log("of the cell that is being replaced.\n");
+ log("and attributes of the cell that is being replaced.\n");
log("\n");
log("See 'help extract' for a pass that does the opposite thing.\n");
log("\n");
@@ -1008,7 +1022,7 @@ struct TechmapPass : public Pass {
log("essentially techmap but using the design itself as map library).\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing TECHMAP pass (map to technology primitives).\n");
log_push();
@@ -1017,7 +1031,7 @@ struct TechmapPass : public Pass {
simplemap_get_mappers(worker.simplemap_mappers);
std::vector<std::string> map_files;
- std::string verilog_frontend = "verilog -ignore_redef";
+ std::string verilog_frontend = "verilog -nooverwrite";
int max_iter = -1;
size_t argidx;
@@ -1076,6 +1090,7 @@ struct TechmapPass : public Pass {
std::ifstream f;
rewrite_filename(fn);
f.open(fn.c_str());
+ yosys_input_files.insert(fn);
if (f.fail())
log_cmd_error("Can't open map file `%s'\n", fn.c_str());
Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
@@ -1126,7 +1141,7 @@ struct TechmapPass : public Pass {
struct FlattenPass : public Pass {
FlattenPass() : Pass("flatten", "flatten design") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -1140,7 +1155,7 @@ struct FlattenPass : public Pass {
log("flattened by this command.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FLATTEN pass (flatten design).\n");
log_push();
diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc
index 03629082..587cb903 100644
--- a/passes/techmap/tribuf.cc
+++ b/passes/techmap/tribuf.cc
@@ -139,7 +139,7 @@ struct TribufWorker {
struct TribufPass : public Pass {
TribufPass() : Pass("tribuf", "infer tri-state buffers") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -156,7 +156,7 @@ struct TribufPass : public Pass {
log(" to non-tristate logic. this option implies -merge.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
TribufConfig config;
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
index a577e123..b46147fb 100644
--- a/passes/techmap/zinit.cc
+++ b/passes/techmap/zinit.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct ZinitPass : public Pass {
ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -37,7 +37,7 @@ struct ZinitPass : public Pass {
log(" also add zero initialization to uninitialized FFs\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool all_mode = false;
diff --git a/passes/tests/test_abcloop.cc b/passes/tests/test_abcloop.cc
index 09cb4195..5d5466af 100644
--- a/passes/tests/test_abcloop.cc
+++ b/passes/tests/test_abcloop.cc
@@ -244,7 +244,7 @@ static void test_abcloop()
struct TestAbcloopPass : public Pass {
TestAbcloopPass() : Pass("test_abcloop", "automatically test handling of loops in abc command") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -259,7 +259,7 @@ struct TestAbcloopPass : public Pass {
log(" use this value as rng seed value (default = unix time).\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
int num_iter = 100;
xorshift32_state = 0;
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
index cb31056f..bfb1d664 100644
--- a/passes/tests/test_autotb.cc
+++ b/passes/tests/test_autotb.cc
@@ -324,7 +324,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s
struct TestAutotbBackend : public Backend {
TestAutotbBackend() : Backend("=test_autotb", "generate simple test benches") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -349,7 +349,7 @@ struct TestAutotbBackend : public Backend {
log(" number of iterations the test bench should run (default = 1000)\n");
log("\n");
}
- virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int num_iter = 1000;
int seed = 0;
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index 049c2053..e360b5ed 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -652,7 +652,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
struct TestCellPass : public Pass {
TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -712,7 +712,7 @@ struct TestCellPass : public Pass {
log(" create a Verilog test bench to test simlib and write_verilog\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
{
int num_iter = 100;
std::string techmap_cmd = "techmap -assert";
@@ -852,8 +852,6 @@ struct TestCellPass : public Pass {
// cell_types["$slice"] = "A";
// cell_types["$concat"] = "A";
- // cell_types["$assert"] = "A";
- // cell_types["$assume"] = "A";
cell_types["$lut"] = "*";
cell_types["$sop"] = "*";
diff --git a/techlibs/achronix/Makefile.inc b/techlibs/achronix/Makefile.inc
new file mode 100755
index 00000000..994cf001
--- /dev/null
+++ b/techlibs/achronix/Makefile.inc
@@ -0,0 +1,6 @@
+
+OBJS += techlibs/achronix/synth_achronix.o
+
+$(eval $(call add_share_file,share/achronix/speedster22i/,techlibs/achronix/speedster22i/cells_sim.v))
+$(eval $(call add_share_file,share/achronix/speedster22i/,techlibs/achronix/speedster22i/cells_map.v))
+
diff --git a/techlibs/achronix/speedster22i/cells_arith.v b/techlibs/achronix/speedster22i/cells_arith.v
new file mode 100755
index 00000000..e2194cbd
--- /dev/null
+++ b/techlibs/achronix/speedster22i/cells_arith.v
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ */
+
+// NOTE: This is still WIP.
+(* techmap_celltype = "$alu" *)
+module _80_altera_max10_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;
+ output CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$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:0] C = {CO, CI};
+ wire [Y_WIDTH+1:0] COx;
+ wire [Y_WIDTH+1:0] C = {COx, CI};
+
+ /* Start implementation */
+ (* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b0000_0000_1010_1010), .sum_lutc_input("cin")) carry_start (.cout(COx[0]), .dataa(C[0]), .datab(1'b1), .datac(1'b1), .datad(1'b1));
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
+ if(i==Y_WIDTH-1) begin
+ (* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b1111_0000_1110_0000), .sum_lutc_input("cin")) carry_end (.combout(COx[Y_WIDTH]), .dataa(1'b1), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[Y_WIDTH]));
+ assign CO = COx[Y_WIDTH];
+ end
+ else
+ fiftyfivenm_lcell_comb #(.lut_mask(16'b1001_0110_1110_1000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(COx[i+1]), .dataa(AA[i]), .datab(BB[i]), .datac(1'b1), .datad(1'b1), .cin(C[i+1]));
+ end: slice
+ endgenerate
+ /* End implementation */
+ assign X = AA ^ BB;
+
+endmodule
diff --git a/techlibs/achronix/speedster22i/cells_map.v b/techlibs/achronix/speedster22i/cells_map.v
new file mode 100755
index 00000000..95f5d59c
--- /dev/null
+++ b/techlibs/achronix/speedster22i/cells_map.v
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ *
+ */
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Achronix eFPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board/custom chip.
+
+// > Input/Output buffers <
+// Input buffer map
+module \$__inpad (input I, output O);
+ PADIN _TECHMAP_REPLACE_ (.padout(O), .padin(I));
+endmodule
+// Output buffer map
+module \$__outpad (input I, output O);
+ PADOUT _TECHMAP_REPLACE_ (.padout(O), .padin(I), .oe(1'b1));
+endmodule
+// > end buffers <
+
+// > Look-Up table <
+// > VT: I still think Achronix folks would have choosen a better \
+// > logic architecture.
+// LUT Map
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+ input [WIDTH-1:0] A;
+ output Y;
+ generate
+ if (WIDTH == 1) begin
+ // VT: This is not consistent and ACE will complain: assign Y = ~A[0];
+ LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_
+ (.dout(Y), .din0(A[0]), .din1(1'b0), .din2(1'b0), .din3(1'b0));
+ end else
+ if (WIDTH == 2) begin
+ LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_
+ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(1'b0), .din3(1'b0));
+ end else
+ if(WIDTH == 3) begin
+ LUT4 #(.lut_function({2{LUT}})) _TECHMAP_REPLACE_
+ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(1'b0));
+ end else
+ if(WIDTH == 4) begin
+ LUT4 #(.lut_function(LUT)) _TECHMAP_REPLACE_
+ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(A[3]));
+ end else
+ wire _TECHMAP_FAIL_ = 1;
+ endgenerate
+endmodule
+// > end LUT <
+
+// > Flops <
+// DFF flop
+module \$_DFF_P_ (input D, C, output Q);
+ DFF _TECHMAP_REPLACE_
+ (.q(Q), .d(D), .ck(C));
+endmodule
+
diff --git a/techlibs/achronix/speedster22i/cells_sim.v b/techlibs/achronix/speedster22i/cells_sim.v
new file mode 100755
index 00000000..da23fed7
--- /dev/null
+++ b/techlibs/achronix/speedster22i/cells_sim.v
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ *
+ */
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Achronix eFPGA technology sim models. User must first simulate the generated \
+// > netlist before going to test it on board/custom chip.
+// > Changelog: 1) Removed unused VCC/GND modules
+// > 2) Altera comments here (?). Removed.
+// > 3) Reusing LUT sim model, removed wrong wires and parameters.
+
+module PADIN (output padout, input padin);
+ assign padout = padin;
+endmodule
+
+module PADOUT (output padout, input padin, input oe);
+ assign padout = padin;
+ assign oe = oe;
+endmodule
+
+module LUT4 (output dout,
+ input din0, din1, din2, din3);
+
+parameter [15:0] lut_function = 16'hFFFF;
+reg combout_rt;
+wire dataa_w;
+wire datab_w;
+wire datac_w;
+wire datad_w;
+
+assign dataa_w = din0;
+assign datab_w = din1;
+assign datac_w = din2;
+assign datad_w = din3;
+
+function lut_data;
+input [15:0] mask;
+input dataa, datab, datac, datad;
+reg [7:0] s3;
+reg [3:0] s2;
+reg [1:0] s1;
+ begin
+ s3 = datad ? mask[15:8] : mask[7:0];
+ s2 = datac ? s3[7:4] : s3[3:0];
+ s1 = datab ? s2[3:2] : s2[1:0];
+ lut_data = dataa ? s1[1] : s1[0];
+ end
+endfunction
+
+always @(dataa_w or datab_w or datac_w or datad_w or cin_w) begin
+ combout_rt = lut_data(lut_function, dataa_w, datab_w,
+ datac_w, datad_w);
+end
+assign dout = combout_rt & 1'b1;
+endmodule
+
+module DFF (output q,
+ input d, ck);
+ reg q;
+ always @(posedge ck)
+ q <= d;
+
+endmodule
+
+
+
diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc
new file mode 100755
index 00000000..92b10781
--- /dev/null
+++ b/techlibs/achronix/synth_achronix.cc
@@ -0,0 +1,188 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SynthAchronixPass : public ScriptPass {
+ SynthAchronixPass() : ScriptPass("synth_achronix", "synthesis for Acrhonix Speedster22i FPGAs.") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_achronix [options]\n");
+ log("\n");
+ log("This command runs synthesis for Achronix Speedster eFPGAs. This work is still experimental.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module (default='top')\n");
+ log("\n");
+ log(" -vout <file>\n");
+ log(" write the design to the specified Verilog netlist file. writing of an\n");
+ log(" output file is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log(" -retime\n");
+ log(" run 'abc' with -dff option\n");
+ log("\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
+
+ string top_opt, family_opt, vout_file;
+ bool retime, flatten;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ vout_file = "";
+ retime = false;
+ flatten = true;
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_opt = "-top " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-vout" && argidx+1 < args.size()) {
+ vout_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
+ if (args[argidx] == "-flatten") {
+ flatten = true;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This comannd only operates on fully selected designs!\n");
+
+ log_header(design, "Executing SYNTH_ACHRONIX pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ void script() YS_OVERRIDE
+ {
+ if (check_label("begin"))
+ {
+ run("read_verilog -sv -lib +/achronix/speedster22i/cells_sim.v");
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
+
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
+ {
+ run("proc");
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
+ }
+
+ if (check_label("coarse"))
+ {
+ run("synth -run coarse");
+ }
+
+ if (check_label("fine"))
+ {
+ run("opt -fast -mux_undef -undriven -fine -full");
+ run("memory_map");
+ run("opt -undriven -fine");
+ run("dffsr2dff");
+ run("dff2dffe -direct-match $_DFF_*");
+ run("opt -fine");
+ run("techmap -map +/techmap.v");
+ run("opt -full");
+ run("clean -purge");
+ run("setundef -undriven -zero");
+ if (retime || help_mode)
+ run("abc -markgroups -dff", "(only if -retime)");
+ }
+
+ if (check_label("map_luts"))
+ {
+ run("abc -lut 4" + string(retime ? " -dff" : ""));
+ run("clean");
+ }
+
+ if (check_label("map_cells"))
+ {
+ run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I");
+ run("techmap -map +/achronix/speedster22i/cells_map.v");
+ // VT: not done yet run("dffinit -highlow -ff DFF q power_up");
+ run("clean -purge");
+ }
+
+ if (check_label("check"))
+ {
+ run("hierarchy -check");
+ run("stat");
+ run("check -noinit");
+ }
+
+ if (check_label("vout"))
+ {
+ if (!vout_file.empty() || help_mode)
+ run(stringf("write_verilog -nodec -attr2comment -defparam -renameprefix syn_ %s",
+ help_mode ? "<file-name>" : vout_file.c_str()));
+ }
+ }
+} SynthAchronixPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc
index 236d6c55..ab961ac0 100644
--- a/techlibs/common/Makefile.inc
+++ b/techlibs/common/Makefile.inc
@@ -24,5 +24,6 @@ $(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/pmux2mux.v))
$(eval $(call add_share_file,share,techlibs/common/adff2dff.v))
+$(eval $(call add_share_file,share,techlibs/common/dff2ff.v))
$(eval $(call add_share_file,share,techlibs/common/cells.lib))
diff --git a/techlibs/common/dff2ff.v b/techlibs/common/dff2ff.v
new file mode 100644
index 00000000..2dc4d20d
--- /dev/null
+++ b/techlibs/common/dff2ff.v
@@ -0,0 +1,14 @@
+(* techmap_celltype = "$dff" *)
+module dff2ff (CLK, D, Q);
+ parameter WIDTH = 1;
+ parameter CLK_POLARITY = 1;
+
+ input CLK;
+ input [WIDTH-1:0] D;
+ output reg [WIDTH-1:0] Q;
+
+ wire [1023:0] _TECHMAP_DO_ = "proc;;";
+
+ always @($global_clock)
+ Q <= D;
+endmodule
diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc
index 71534983..897f37db 100644
--- a/techlibs/common/prep.cc
+++ b/techlibs/common/prep.cc
@@ -29,7 +29,7 @@ struct PrepPass : public ScriptPass
{
PrepPass() : ScriptPass("prep", "generic synthesis script") { }
- virtual void help() YS_OVERRIDE
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -55,15 +55,16 @@ struct PrepPass : public ScriptPass
log("\n");
log(" -memx\n");
log(" simulate verilog simulation behavior for out-of-bounds memory accesses\n");
- log(" using the 'memory_memx' pass. This option implies -nordff.\n");
+ log(" using the 'memory_memx' pass.\n");
log("\n");
log(" -nomem\n");
log(" do not run any of the memory_* passes\n");
log("\n");
- log(" -nordff\n");
- log(" passed to 'memory_dff'. prohibits merging of FFs into memory read ports\n");
+ log(" -rdff\n");
+ log(" do not pass -nordff to 'memory_dff'. This enables merging of FFs into\n");
+ log(" memory read ports.\n");
log("\n");
- log(" -nokeepdc\n");
+ log(" -nokeepdc\n");
log(" do not call opt_* with -keepdc\n");
log("\n");
log(" -run <from_label>[:<to_label>]\n");
@@ -77,13 +78,12 @@ struct PrepPass : public ScriptPass
log("\n");
}
- string top_module, fsm_opts, memory_opts;
- bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc;
+ string top_module, fsm_opts;
+ bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc, nordff;
- virtual void clear_flags() YS_OVERRIDE
+ void clear_flags() YS_OVERRIDE
{
top_module.clear();
- memory_opts.clear();
autotop = false;
flatten = false;
@@ -91,9 +91,10 @@ struct PrepPass : public ScriptPass
memxmode = false;
nomemmode = false;
nokeepdc = false;
+ nordff = true;
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
@@ -129,7 +130,6 @@ struct PrepPass : public ScriptPass
}
if (args[argidx] == "-memx") {
memxmode = true;
- memory_opts += " -nordff";
continue;
}
if (args[argidx] == "-nomem") {
@@ -137,7 +137,11 @@ struct PrepPass : public ScriptPass
continue;
}
if (args[argidx] == "-nordff") {
- memory_opts += " -nordff";
+ nordff = true;
+ continue;
+ }
+ if (args[argidx] == "-rdff") {
+ nordff = false;
continue;
}
if (args[argidx] == "-nokeepdc") {
@@ -159,7 +163,7 @@ struct PrepPass : public ScriptPass
log_pop();
}
- virtual void script() YS_OVERRIDE
+ void script() YS_OVERRIDE
{
if (check_label("begin"))
@@ -196,7 +200,7 @@ struct PrepPass : public ScriptPass
run(memxmode ? "wreduce -memx" : "wreduce");
}
if (!nomemmode) {
- run("memory_dff" + (help_mode ? " [-nordff]" : memory_opts));
+ run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : ""));
if (help_mode || memxmode)
run("memory_memx", "(if -memx)");
run("opt_clean");
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index e770c545..937512e7 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -175,6 +175,44 @@ endmodule
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//-
+//- $_ANDNOT_ (A, B, Y)
+//-
+//- A 2-input AND-NOT gate.
+//-
+//- Truth table: A B | Y
+//- -----+---
+//- 0 0 | 0
+//- 0 1 | 0
+//- 1 0 | 1
+//- 1 1 | 0
+//-
+module \$_ANDNOT_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = A & (~B);
+endmodule
+
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//- $_ORNOT_ (A, B, Y)
+//-
+//- A 2-input OR-NOT gate.
+//-
+//- Truth table: A B | Y
+//- -----+---
+//- 0 0 | 1
+//- 0 1 | 0
+//- 1 0 | 1
+//- 1 1 | 1
+//-
+module \$_ORNOT_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = A | (~B);
+endmodule
+
+// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
//- $_MUX_ (A, B, S, Y)
//-
//- A 2-input MUX gate.
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 2c4db1ac..8e43fe05 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -1305,6 +1305,30 @@ endmodule
// --------------------------------------------------------
+module \$live (A, EN);
+
+input A, EN;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$fair (A, EN);
+
+input A, EN;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$cover (A, EN);
+
+input A, EN;
+
+endmodule
+
+// --------------------------------------------------------
+
module \$initstate (Y);
output reg Y = 1;
@@ -1346,6 +1370,30 @@ endmodule
// --------------------------------------------------------
+module \$allconst (Y);
+
+parameter WIDTH = 0;
+
+output [WIDTH-1:0] Y;
+
+assign Y = 'bx;
+
+endmodule
+
+// --------------------------------------------------------
+
+module \$allseq (Y);
+
+parameter WIDTH = 0;
+
+output [WIDTH-1:0] Y;
+
+assign Y = 'bx;
+
+endmodule
+
+// --------------------------------------------------------
+
module \$equiv (A, B, Y);
input A, B;
diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc
index 11ebe533..efb21475 100644
--- a/techlibs/common/synth.cc
+++ b/techlibs/common/synth.cc
@@ -29,7 +29,7 @@ struct SynthPass : public ScriptPass
{
SynthPass() : ScriptPass("synth", "generic synthesis script") { }
- virtual void help() YS_OVERRIDE
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -64,6 +64,9 @@ struct SynthPass : public ScriptPass
log(" -nordff\n");
log(" passed to 'memory'. prohibits merging of FFs into memory read ports\n");
log("\n");
+ log(" -noshare\n");
+ log(" do not run SAT-based resource sharing\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");
@@ -76,9 +79,9 @@ struct SynthPass : public ScriptPass
}
string top_module, fsm_opts, memory_opts;
- bool autotop, flatten, noalumacc, nofsm, noabc;
+ bool autotop, flatten, noalumacc, nofsm, noabc, noshare;
- virtual void clear_flags() YS_OVERRIDE
+ void clear_flags() YS_OVERRIDE
{
top_module.clear();
fsm_opts.clear();
@@ -89,9 +92,10 @@ struct SynthPass : public ScriptPass
noalumacc = false;
nofsm = false;
noabc = false;
+ noshare = false;
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
clear_flags();
@@ -142,6 +146,10 @@ struct SynthPass : public ScriptPass
memory_opts += " -nordff";
continue;
}
+ if (args[argidx] == "-noshare") {
+ noshare = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -157,7 +165,7 @@ struct SynthPass : public ScriptPass
log_pop();
}
- virtual void script() YS_OVERRIDE
+ void script() YS_OVERRIDE
{
if (check_label("begin"))
{
@@ -186,7 +194,8 @@ struct SynthPass : public ScriptPass
run("wreduce");
if (!noalumacc)
run("alumacc");
- run("share");
+ if (!noshare)
+ run("share");
run("opt");
if (!nofsm)
run("fsm" + fsm_opts);
diff --git a/techlibs/coolrunner2/Makefile.inc b/techlibs/coolrunner2/Makefile.inc
new file mode 100644
index 00000000..d62c9960
--- /dev/null
+++ b/techlibs/coolrunner2/Makefile.inc
@@ -0,0 +1,8 @@
+
+OBJS += techlibs/coolrunner2/synth_coolrunner2.o
+OBJS += techlibs/coolrunner2/coolrunner2_sop.o
+
+$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_latch.v))
+$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_sim.v))
+$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/tff_extract.v))
+$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/xc2_dff.lib))
diff --git a/techlibs/coolrunner2/cells_latch.v b/techlibs/coolrunner2/cells_latch.v
new file mode 100644
index 00000000..f1e19da3
--- /dev/null
+++ b/techlibs/coolrunner2/cells_latch.v
@@ -0,0 +1,19 @@
+module $_DLATCH_P_(input E, input D, output Q);
+ LDCP _TECHMAP_REPLACE_ (
+ .D(D),
+ .G(E),
+ .Q(Q),
+ .PRE(1'b0),
+ .CLR(1'b0)
+ );
+endmodule
+
+module $_DLATCH_N_(input E, input D, output Q);
+ LDCP_N _TECHMAP_REPLACE_ (
+ .D(D),
+ .G(E),
+ .Q(Q),
+ .PRE(1'b0),
+ .CLR(1'b0)
+ );
+endmodule
diff --git a/techlibs/coolrunner2/cells_sim.v b/techlibs/coolrunner2/cells_sim.v
new file mode 100644
index 00000000..562fb1ef
--- /dev/null
+++ b/techlibs/coolrunner2/cells_sim.v
@@ -0,0 +1,310 @@
+module IBUF(input I, output O);
+ assign O = I;
+endmodule
+
+module IOBUFE(input I, input E, output O, inout IO);
+ assign O = IO;
+ assign IO = E ? I : 1'bz;
+endmodule
+
+module ANDTERM(IN, IN_B, OUT);
+ parameter TRUE_INP = 0;
+ parameter COMP_INP = 0;
+
+ input [TRUE_INP-1:0] IN;
+ input [COMP_INP-1:0] IN_B;
+ output reg OUT;
+
+ integer i;
+
+ always @(*) begin
+ OUT = 1;
+ for (i = 0; i < TRUE_INP; i=i+1)
+ OUT = OUT & IN[i];
+ for (i = 0; i < COMP_INP; i=i+1)
+ OUT = OUT & ~IN_B[i];
+ end
+endmodule
+
+module ORTERM(IN, OUT);
+ parameter WIDTH = 0;
+
+ input [WIDTH-1:0] IN;
+ output reg OUT;
+
+ integer i;
+
+ always @(*) begin
+ OUT = 0;
+ for (i = 0; i < WIDTH; i=i+1) begin
+ OUT = OUT | IN[i];
+ end
+ end
+endmodule
+
+module MACROCELL_XOR(IN_PTC, IN_ORTERM, OUT);
+ parameter INVERT_OUT = 0;
+
+ input IN_PTC;
+ input IN_ORTERM;
+ output wire OUT;
+
+ wire xor_intermed;
+
+ assign OUT = INVERT_OUT ? ~xor_intermed : xor_intermed;
+ assign xor_intermed = IN_ORTERM ^ IN_PTC;
+endmodule
+
+module FDCP (C, PRE, CLR, D, Q);
+ parameter INIT = 0;
+
+ input C, PRE, CLR, D;
+ output reg Q;
+
+ initial begin
+ Q <= INIT;
+ end
+
+ always @(posedge C, posedge PRE, posedge CLR) begin
+ if (CLR == 1)
+ Q <= 0;
+ else if (PRE == 1)
+ Q <= 1;
+ else
+ Q <= D;
+ end
+endmodule
+
+module FDCP_N (C, PRE, CLR, D, Q);
+ parameter INIT = 0;
+
+ input C, PRE, CLR, D;
+ output reg Q;
+
+ initial begin
+ Q <= INIT;
+ end
+
+ always @(negedge C, posedge PRE, posedge CLR) begin
+ if (CLR == 1)
+ Q <= 0;
+ else if (PRE == 1)
+ Q <= 1;
+ else
+ Q <= D;
+ end
+endmodule
+
+module LDCP (G, PRE, CLR, D, Q);
+ parameter INIT = 0;
+
+ input G, PRE, CLR, D;
+ output reg Q;
+
+ initial begin
+ Q <= INIT;
+ end
+
+ always @* begin
+ if (CLR == 1)
+ Q <= 0;
+ else if (G == 1)
+ Q <= D;
+ else if (PRE == 1)
+ Q <= 1;
+ end
+endmodule
+
+module LDCP_N (G, PRE, CLR, D, Q);
+ parameter INIT = 0;
+
+ input G, PRE, CLR, D;
+ output reg Q;
+
+ initial begin
+ Q <= INIT;
+ end
+
+ always @* begin
+ if (CLR == 1)
+ Q <= 0;
+ else if (G == 0)
+ Q <= D;
+ else if (PRE == 1)
+ Q <= 1;
+ end
+endmodule
+
+module BUFG(I, O);
+ input I;
+ output O;
+
+ assign O = I;
+endmodule
+
+module BUFGSR(I, O);
+ parameter INVERT = 0;
+
+ input I;
+ output O;
+
+ assign O = INVERT ? ~I : I;
+endmodule
+
+module BUFGTS(I, O);
+ parameter INVERT = 0;
+
+ input I;
+ output O;
+
+ assign O = INVERT ? ~I : I;
+endmodule
+
+module FDDCP (C, PRE, CLR, D, Q);
+ parameter INIT = 0;
+
+ input C, PRE, CLR, D;
+ output reg Q;
+
+ initial begin
+ Q <= INIT;
+ end
+
+ always @(posedge C, negedge C, posedge PRE, posedge CLR) begin
+ if (CLR == 1)
+ Q <= 0;
+ else if (PRE == 1)
+ Q <= 1;
+ else
+ Q <= D;
+ end
+endmodule
+
+module FTCP (C, PRE, CLR, T, Q);
+ parameter INIT = 0;
+
+ input C, PRE, CLR, T;
+ output wire Q;
+ reg Q_;
+
+ initial begin
+ Q_ <= INIT;
+ end
+
+ always @(posedge C, posedge PRE, posedge CLR) begin
+ if (CLR == 1)
+ Q_ <= 0;
+ else if (PRE == 1)
+ Q_ <= 1;
+ else if (T == 1)
+ Q_ <= ~Q_;
+ end
+
+ assign Q = Q_;
+endmodule
+
+module FTCP_N (C, PRE, CLR, T, Q);
+ parameter INIT = 0;
+
+ input C, PRE, CLR, T;
+ output wire Q;
+ reg Q_;
+
+ initial begin
+ Q_ <= INIT;
+ end
+
+ always @(negedge C, posedge PRE, posedge CLR) begin
+ if (CLR == 1)
+ Q_ <= 0;
+ else if (PRE == 1)
+ Q_ <= 1;
+ else if (T == 1)
+ Q_ <= ~Q_;
+ end
+
+ assign Q = Q_;
+endmodule
+
+module FTDCP (C, PRE, CLR, T, Q);
+ parameter INIT = 0;
+
+ input C, PRE, CLR, T;
+ output wire Q;
+ reg Q_;
+
+ initial begin
+ Q_ <= INIT;
+ end
+
+ always @(posedge C, negedge C, posedge PRE, posedge CLR) begin
+ if (CLR == 1)
+ Q_ <= 0;
+ else if (PRE == 1)
+ Q_ <= 1;
+ else if (T == 1)
+ Q_ <= ~Q_;
+ end
+
+ assign Q = Q_;
+endmodule
+
+module FDCPE (C, PRE, CLR, D, Q, CE);
+ parameter INIT = 0;
+
+ input C, PRE, CLR, D, CE;
+ output reg Q;
+
+ initial begin
+ Q <= INIT;
+ end
+
+ always @(posedge C, posedge PRE, posedge CLR) begin
+ if (CLR == 1)
+ Q <= 0;
+ else if (PRE == 1)
+ Q <= 1;
+ else if (CE == 1)
+ Q <= D;
+ end
+endmodule
+
+module FDCPE_N (C, PRE, CLR, D, Q, CE);
+ parameter INIT = 0;
+
+ input C, PRE, CLR, D, CE;
+ output reg Q;
+
+ initial begin
+ Q <= INIT;
+ end
+
+ always @(negedge C, posedge PRE, posedge CLR) begin
+ if (CLR == 1)
+ Q <= 0;
+ else if (PRE == 1)
+ Q <= 1;
+ else if (CE == 1)
+ Q <= D;
+ end
+endmodule
+
+module FDDCPE (C, PRE, CLR, D, Q, CE);
+ parameter INIT = 0;
+
+ input C, PRE, CLR, D, CE;
+ output reg Q;
+
+ initial begin
+ Q <= INIT;
+ end
+
+ always @(posedge C, negedge C, posedge PRE, posedge CLR) begin
+ if (CLR == 1)
+ Q <= 0;
+ else if (PRE == 1)
+ Q <= 1;
+ else if (CE == 1)
+ Q <= D;
+ end
+endmodule
diff --git a/techlibs/coolrunner2/coolrunner2_sop.cc b/techlibs/coolrunner2/coolrunner2_sop.cc
new file mode 100644
index 00000000..48da0d8a
--- /dev/null
+++ b/techlibs/coolrunner2/coolrunner2_sop.cc
@@ -0,0 +1,320 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2017 Robert Ou <rqou@robertou.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Coolrunner2SopPass : public Pass {
+ Coolrunner2SopPass() : Pass("coolrunner2_sop", "break $sop cells into ANDTERM/ORTERM cells") { }
+ void help() YS_OVERRIDE
+ {
+ log("\n");
+ log(" coolrunner2_sop [options] [selection]\n");
+ log("\n");
+ log("Break $sop cells into ANDTERM/ORTERM cells.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing COOLRUNNER2_SOP pass (break $sop cells into ANDTERM/ORTERM cells).\n");
+ extra_args(args, 1, design);
+
+ for (auto module : design->selected_modules())
+ {
+ pool<Cell*> cells_to_remove;
+ SigMap sigmap(module);
+
+ // Find all the $_NOT_ cells
+ dict<SigBit, tuple<SigBit, Cell*>> not_cells;
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "$_NOT_")
+ {
+ auto not_input = sigmap(cell->getPort("\\A")[0]);
+ auto not_output = sigmap(cell->getPort("\\Y")[0]);
+ not_cells[not_input] = tuple<SigBit, Cell*>(not_output, cell);
+ }
+ }
+
+ // Find wires that need to become special product terms
+ dict<SigBit, pool<tuple<Cell*, std::string>>> special_pterms_no_inv;
+ dict<SigBit, pool<tuple<Cell*, std::string>>> special_pterms_inv;
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
+ cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
+ cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE" ||
+ cell->type == "\\LDCP" || cell->type == "\\LDCP_N")
+ {
+ if (cell->hasPort("\\PRE"))
+ special_pterms_no_inv[sigmap(cell->getPort("\\PRE")[0])].insert(
+ tuple<Cell*, const char *>(cell, "\\PRE"));
+ if (cell->hasPort("\\CLR"))
+ special_pterms_no_inv[sigmap(cell->getPort("\\CLR")[0])].insert(
+ tuple<Cell*, const char *>(cell, "\\CLR"));
+ if (cell->hasPort("\\CE"))
+ special_pterms_no_inv[sigmap(cell->getPort("\\CE")[0])].insert(
+ tuple<Cell*, const char *>(cell, "\\CE"));
+
+ if (cell->hasPort("\\C"))
+ special_pterms_inv[sigmap(cell->getPort("\\C")[0])].insert(
+ tuple<Cell*, const char *>(cell, "\\C"));
+ if (cell->hasPort("\\G"))
+ special_pterms_inv[sigmap(cell->getPort("\\G")[0])].insert(
+ tuple<Cell*, const char *>(cell, "\\G"));
+ }
+ }
+
+ // Process $sop cells
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "$sop")
+ {
+ // Read the inputs/outputs/parameters of the $sop cell
+ auto sop_inputs = sigmap(cell->getPort("\\A"));
+ auto sop_output = sigmap(cell->getPort("\\Y"))[0];
+ auto sop_depth = cell->getParam("\\DEPTH").as_int();
+ auto sop_width = cell->getParam("\\WIDTH").as_int();
+ auto sop_table = cell->getParam("\\TABLE");
+
+ // Check for a $_NOT_ at the output
+ bool has_invert = false;
+ if (not_cells.count(sop_output))
+ {
+ auto not_cell = not_cells.at(sop_output);
+
+ has_invert = true;
+ sop_output = std::get<0>(not_cell);
+
+ // remove the $_NOT_ cell because it gets folded into the xor
+ cells_to_remove.insert(std::get<1>(not_cell));
+ }
+
+ // Check for special P-term usage
+ bool is_special_pterm = false;
+ bool special_pterm_can_invert = false;
+ if (special_pterms_no_inv.count(sop_output) || special_pterms_inv.count(sop_output))
+ {
+ is_special_pterm = true;
+ if (!special_pterms_no_inv[sop_output].size())
+ special_pterm_can_invert = true;
+ }
+
+ // Construct AND cells
+ pool<SigBit> intermed_wires;
+ for (int i = 0; i < sop_depth; i++) {
+ // Wire for the output
+ auto and_out = module->addWire(NEW_ID);
+ intermed_wires.insert(and_out);
+
+ // Signals for the inputs
+ pool<SigBit> and_in_true;
+ pool<SigBit> and_in_comp;
+ for (int j = 0; j < sop_width; j++)
+ {
+ if (sop_table[2 * (i * sop_width + j) + 0])
+ {
+ and_in_comp.insert(sop_inputs[j]);
+ }
+ if (sop_table[2 * (i * sop_width + j) + 1])
+ {
+ and_in_true.insert(sop_inputs[j]);
+ }
+ }
+
+ // Construct the cell
+ auto and_cell = module->addCell(NEW_ID, "\\ANDTERM");
+ and_cell->setParam("\\TRUE_INP", GetSize(and_in_true));
+ and_cell->setParam("\\COMP_INP", GetSize(and_in_comp));
+ and_cell->setPort("\\OUT", and_out);
+ and_cell->setPort("\\IN", and_in_true);
+ and_cell->setPort("\\IN_B", and_in_comp);
+ }
+
+ if (sop_depth == 1)
+ {
+ // If there is only one term, don't construct an OR cell. Directly construct the XOR gate
+ auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR");
+ xor_cell->setParam("\\INVERT_OUT", has_invert);
+ xor_cell->setPort("\\IN_PTC", *intermed_wires.begin());
+ xor_cell->setPort("\\OUT", sop_output);
+
+ // Special P-term handling
+ if (is_special_pterm)
+ {
+ if (!has_invert || special_pterm_can_invert)
+ {
+ // Can connect the P-term directly to the special term sinks
+ for (auto x : special_pterms_inv[sop_output])
+ std::get<0>(x)->setPort(std::get<1>(x), *intermed_wires.begin());
+ for (auto x : special_pterms_no_inv[sop_output])
+ std::get<0>(x)->setPort(std::get<1>(x), *intermed_wires.begin());
+ }
+
+ if (has_invert)
+ {
+ if (special_pterm_can_invert)
+ {
+ log_assert(special_pterms_no_inv[sop_output].size() == 0);
+
+ for (auto x : special_pterms_inv[sop_output])
+ {
+ auto cell = std::get<0>(x);
+ // Need to invert the polarity of the cell
+ if (cell->type == "\\FDCP") cell->type = "\\FDCP_N";
+ else if (cell->type == "\\FDCP_N") cell->type = "\\FDCP";
+ else if (cell->type == "\\FTCP") cell->type = "\\FTCP_N";
+ else if (cell->type == "\\FTCP_N") cell->type = "\\FTCP";
+ else if (cell->type == "\\FDCPE") cell->type = "\\FDCPE_N";
+ else if (cell->type == "\\FDCPE_N") cell->type = "\\FDCPE";
+ else if (cell->type == "\\LDCP") cell->type = "\\LDCP_N";
+ else if (cell->type == "\\LDCP_N") cell->type = "\\LDCP";
+ else log_assert(!"Internal error! Bad cell type!");
+ }
+ }
+ else
+ {
+ // Need to construct a feed-through term
+ auto feedthrough_out = module->addWire(NEW_ID);
+ auto feedthrough_cell = module->addCell(NEW_ID, "\\ANDTERM");
+ feedthrough_cell->setParam("\\TRUE_INP", 1);
+ feedthrough_cell->setParam("\\COMP_INP", 0);
+ feedthrough_cell->setPort("\\OUT", feedthrough_out);
+ feedthrough_cell->setPort("\\IN", sop_output);
+ feedthrough_cell->setPort("\\IN_B", SigSpec());
+
+ for (auto x : special_pterms_inv[sop_output])
+ std::get<0>(x)->setPort(std::get<1>(x), feedthrough_out);
+ for (auto x : special_pterms_no_inv[sop_output])
+ std::get<0>(x)->setPort(std::get<1>(x), feedthrough_out);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Wire from OR to XOR
+ auto or_to_xor_wire = module->addWire(NEW_ID);
+
+ // Construct the OR cell
+ auto or_cell = module->addCell(NEW_ID, "\\ORTERM");
+ or_cell->setParam("\\WIDTH", sop_depth);
+ or_cell->setPort("\\IN", intermed_wires);
+ or_cell->setPort("\\OUT", or_to_xor_wire);
+
+ // Construct the XOR cell
+ auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR");
+ xor_cell->setParam("\\INVERT_OUT", has_invert);
+ xor_cell->setPort("\\IN_ORTERM", or_to_xor_wire);
+ xor_cell->setPort("\\OUT", sop_output);
+
+ if (is_special_pterm)
+ {
+ // Need to construct a feed-through term
+ auto feedthrough_out = module->addWire(NEW_ID);
+ auto feedthrough_cell = module->addCell(NEW_ID, "\\ANDTERM");
+ feedthrough_cell->setParam("\\TRUE_INP", 1);
+ feedthrough_cell->setParam("\\COMP_INP", 0);
+ feedthrough_cell->setPort("\\OUT", feedthrough_out);
+ feedthrough_cell->setPort("\\IN", sop_output);
+ feedthrough_cell->setPort("\\IN_B", SigSpec());
+
+ for (auto x : special_pterms_inv[sop_output])
+ std::get<0>(x)->setPort(std::get<1>(x), feedthrough_out);
+ for (auto x : special_pterms_no_inv[sop_output])
+ std::get<0>(x)->setPort(std::get<1>(x), feedthrough_out);
+ }
+ }
+
+ // Finally, remove the $sop cell
+ cells_to_remove.insert(cell);
+ }
+ }
+
+ // In some cases we can get a FF feeding straight into an FF. This is not possible, so we need to insert
+ // some AND/XOR cells in the middle to make it actually work.
+
+ // Find all the FF outputs
+ pool<SigBit> sig_fed_by_ff;
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
+ cell->type == "\\LDCP" || cell->type == "\\LDCP_N" ||
+ cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
+ cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE")
+ {
+ auto output = sigmap(cell->getPort("\\Q")[0]);
+ sig_fed_by_ff.insert(output);
+ }
+ }
+
+ // Look at all the FF inputs
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
+ cell->type == "\\LDCP" || cell->type == "\\LDCP_N" ||
+ cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
+ cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE")
+ {
+ SigBit input;
+ if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP")
+ input = sigmap(cell->getPort("\\T")[0]);
+ else
+ input = sigmap(cell->getPort("\\D")[0]);
+
+ if (sig_fed_by_ff[input])
+ {
+ printf("Buffering input to \"%s\"\n", cell->name.c_str());
+
+ auto and_to_xor_wire = module->addWire(NEW_ID);
+ auto xor_to_ff_wire = module->addWire(NEW_ID);
+
+ auto and_cell = module->addCell(NEW_ID, "\\ANDTERM");
+ and_cell->setParam("\\TRUE_INP", 1);
+ and_cell->setParam("\\COMP_INP", 0);
+ and_cell->setPort("\\OUT", and_to_xor_wire);
+ and_cell->setPort("\\IN", input);
+ and_cell->setPort("\\IN_B", SigSpec());
+
+ auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR");
+ xor_cell->setParam("\\INVERT_OUT", false);
+ xor_cell->setPort("\\IN_PTC", and_to_xor_wire);
+ xor_cell->setPort("\\OUT", xor_to_ff_wire);
+
+ if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP")
+ cell->setPort("\\T", xor_to_ff_wire);
+ else
+ cell->setPort("\\D", xor_to_ff_wire);
+ }
+ }
+ }
+
+ // Actually do the removal now that we aren't iterating
+ for (auto cell : cells_to_remove)
+ {
+ module->remove(cell);
+ }
+ }
+ }
+} Coolrunner2SopPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc
new file mode 100644
index 00000000..a5dac356
--- /dev/null
+++ b/techlibs/coolrunner2/synth_coolrunner2.cc
@@ -0,0 +1,202 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2017 Robert Ou <rqou@robertou.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SynthCoolrunner2Pass : public ScriptPass
+{
+ SynthCoolrunner2Pass() : ScriptPass("synth_coolrunner2", "synthesis for Xilinx Coolrunner-II CPLDs") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_coolrunner2 [options]\n");
+ log("\n");
+ log("This command runs synthesis for Coolrunner-II CPLDs. This work is experimental.\n");
+ log("It is intended to be used with https://github.com/azonenberg/openfpga as the\n");
+ log("place-and-route.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module (default='top')\n");
+ log("\n");
+ log(" -json <file>\n");
+ log(" write the design to the specified JSON file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log(" -retime\n");
+ log(" run 'abc' with -dff option\n");
+ log("\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
+
+ string top_opt, json_file;
+ bool flatten, retime;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ json_file = "";
+ flatten = true;
+ retime = false;
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_opt = "-top " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-json" && argidx+1 < args.size()) {
+ json_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This comannd only operates on fully selected designs!\n");
+
+ log_header(design, "Executing SYNTH_COOLRUNNER2 pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ void script() YS_OVERRIDE
+ {
+ if (check_label("begin"))
+ {
+ run("read_verilog -lib +/coolrunner2/cells_sim.v");
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
+
+ if (check_label("flatten", "(unless -noflatten)") && flatten)
+ {
+ run("proc");
+ run("flatten");
+ run("tribuf -logic");
+ }
+
+ if (check_label("coarse"))
+ {
+ run("synth -run coarse");
+ }
+
+ if (check_label("fine"))
+ {
+ run("opt -fast -full");
+ run("techmap");
+ run("techmap -map +/coolrunner2/cells_latch.v");
+ run("dfflibmap -prepare -liberty +/coolrunner2/xc2_dff.lib");
+ }
+
+ if (check_label("map_tff"))
+ {
+ // This is quite hacky. By telling abc that it can only use AND and XOR gates, abc will try and use XOR
+ // gates "whenever possible." This will hopefully cause toggle flip-flop structures to turn into an XOR
+ // connected to a D flip-flop. We then match on these and convert them into XC2 TFF cells.
+ run("abc -g AND,XOR");
+ run("clean");
+ run("extract -map +/coolrunner2/tff_extract.v");
+ }
+
+ if (check_label("map_pla"))
+ {
+ run("abc -sop -I 40 -P 56");
+ run("clean");
+ }
+
+ if (check_label("map_cells"))
+ {
+ run("dfflibmap -liberty +/coolrunner2/xc2_dff.lib");
+ run("dffinit -ff FDCP Q INIT");
+ run("dffinit -ff FDCP_N Q INIT");
+ run("dffinit -ff FTCP Q INIT");
+ run("dffinit -ff FTCP_N Q INIT");
+ run("dffinit -ff LDCP Q INIT");
+ run("dffinit -ff LDCP_N Q INIT");
+ run("coolrunner2_sop");
+ run("iopadmap -bits -inpad IBUF O:I -outpad IOBUFE I:IO -inoutpad IOBUFE O:IO -toutpad IOBUFE E:I:IO -tinoutpad IOBUFE E:O:I:IO");
+ run("attrmvcp -attr src -attr LOC t:IOBUFE n:*");
+ run("attrmvcp -attr src -attr LOC -driven t:IBUF n:*");
+ run("splitnets");
+ run("clean");
+ }
+
+ if (check_label("check"))
+ {
+ run("hierarchy -check");
+ run("stat");
+ run("check -noinit");
+ }
+
+ if (check_label("json"))
+ {
+ if (!json_file.empty() || help_mode)
+ run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
+ }
+
+ log_pop();
+ }
+} SynthCoolrunner2Pass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/coolrunner2/tff_extract.v b/techlibs/coolrunner2/tff_extract.v
new file mode 100644
index 00000000..b4237dd1
--- /dev/null
+++ b/techlibs/coolrunner2/tff_extract.v
@@ -0,0 +1,41 @@
+module FTCP (C, PRE, CLR, T, Q);
+ input C, PRE, CLR, T;
+ output wire Q;
+
+ wire xorout;
+
+ $_XOR_ xorgate (
+ .A(T),
+ .B(Q),
+ .Y(xorout),
+ );
+
+ $_DFFSR_PPP_ dff (
+ .C(C),
+ .D(xorout),
+ .Q(Q),
+ .S(PRE),
+ .R(CLR),
+ );
+endmodule
+
+module FTCP_N (C, PRE, CLR, T, Q);
+ input C, PRE, CLR, T;
+ output wire Q;
+
+ wire xorout;
+
+ $_XOR_ xorgate (
+ .A(T),
+ .B(Q),
+ .Y(xorout),
+ );
+
+ $_DFFSR_NPP_ dff (
+ .C(C),
+ .D(xorout),
+ .Q(Q),
+ .S(PRE),
+ .R(CLR),
+ );
+endmodule
diff --git a/techlibs/coolrunner2/xc2_dff.lib b/techlibs/coolrunner2/xc2_dff.lib
new file mode 100644
index 00000000..b578493a
--- /dev/null
+++ b/techlibs/coolrunner2/xc2_dff.lib
@@ -0,0 +1,31 @@
+library(xc2_dff) {
+ cell(FDCP) {
+ area: 1;
+ ff("IQ", "IQN") { clocked_on: C;
+ next_state: D;
+ clear: "CLR";
+ preset: "PRE"; }
+ pin(C) { direction: input;
+ clock: true; }
+ pin(D) { direction: input; }
+ pin(Q) { direction: output;
+ function: "IQ"; }
+ pin(CLR) { direction: input; }
+ pin(PRE) { direction: input; }
+ }
+
+ cell(FDCP_N) {
+ area: 1;
+ ff("IQ", "IQN") { clocked_on: "!C";
+ next_state: D;
+ clear: "CLR";
+ preset: "PRE"; }
+ pin(C) { direction: input;
+ clock: true; }
+ pin(D) { direction: input; }
+ pin(Q) { direction: output;
+ function: "IQ"; }
+ pin(CLR) { direction: input; }
+ pin(PRE) { direction: input; }
+ }
+}
diff --git a/techlibs/easic/Makefile.inc b/techlibs/easic/Makefile.inc
new file mode 100644
index 00000000..fb05a8a8
--- /dev/null
+++ b/techlibs/easic/Makefile.inc
@@ -0,0 +1,3 @@
+
+OBJS += techlibs/easic/synth_easic.o
+
diff --git a/techlibs/easic/synth_easic.cc b/techlibs/easic/synth_easic.cc
new file mode 100644
index 00000000..b5ed93be
--- /dev/null
+++ b/techlibs/easic/synth_easic.cc
@@ -0,0 +1,188 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SynthEasicPass : public ScriptPass
+{
+ SynthEasicPass() : ScriptPass("synth_easic", "synthesis for eASIC platform") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_easic [options]\n");
+ log("\n");
+ log("This command runs synthesis for eASIC platform.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module\n");
+ log("\n");
+ log(" -vlog <file>\n");
+ log(" write the design to the specified structural Verilog file. writing of\n");
+ log(" an output file is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -etools <path>\n");
+ log(" set path to the eTools installation. (default=/opt/eTools)\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log(" -retime\n");
+ log(" run 'abc' with -dff option\n");
+ log("\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
+
+ string top_opt, vlog_file, etools_path;
+ bool flatten, retime;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ vlog_file = "";
+ etools_path = "/opt/eTools";
+ flatten = true;
+ retime = false;
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_opt = "-top " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-vlog" && argidx+1 < args.size()) {
+ vlog_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-etools" && argidx+1 < args.size()) {
+ etools_path = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This comannd only operates on fully selected designs!\n");
+
+ log_header(design, "Executing SYNTH_EASIC pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ void script() YS_OVERRIDE
+ {
+ string phys_clk_lib = stringf("%s/data_ruby28/design_libs/logical/timing/gp/n3x_phys_clk_0v893ff125c.lib", etools_path.c_str());
+ string logic_lut_lib = stringf("%s/data_ruby28/design_libs/logical/timing/gp/n3x_logic_lut_0v893ff125c.lib", etools_path.c_str());
+
+ if (check_label("begin"))
+ {
+ run(stringf("read_liberty -lib %s", help_mode ? "<etools_phys_clk_lib>" : phys_clk_lib.c_str()));
+ run(stringf("read_liberty -lib %s", help_mode ? "<etools_logic_lut_lib>" : logic_lut_lib.c_str()));
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
+
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
+ {
+ run("proc");
+ run("flatten");
+ }
+
+ if (check_label("coarse"))
+ {
+ run("synth -run coarse");
+ }
+
+ if (check_label("fine"))
+ {
+ run("opt -fast -mux_undef -undriven -fine");
+ run("memory_map");
+ run("opt -undriven -fine");
+ run("techmap");
+ run("opt -fast");
+ if (retime || help_mode) {
+ run("abc -dff", " (only if -retime)");
+ run("opt_clean", "(only if -retime)");
+ }
+ }
+
+ if (check_label("map"))
+ {
+ run(stringf("dfflibmap -liberty %s", help_mode ? "<etools_phys_clk_lib>" : phys_clk_lib.c_str()));
+ run(stringf("abc -liberty %s", help_mode ? "<etools_logic_lut_lib>" : logic_lut_lib.c_str()));
+ run("opt_clean");
+ }
+
+ if (check_label("check"))
+ {
+ run("hierarchy -check");
+ run("stat");
+ run("check -noinit");
+ }
+
+ if (check_label("vlog"))
+ {
+ if (!vlog_file.empty() || help_mode)
+ run(stringf("write_verilog -noexpr -attr2comment %s", help_mode ? "<file-name>" : vlog_file.c_str()));
+ }
+ }
+} SynthEasicPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc
new file mode 100644
index 00000000..9d324734
--- /dev/null
+++ b/techlibs/ecp5/Makefile.inc
@@ -0,0 +1,8 @@
+
+OBJS += techlibs/ecp5/synth_ecp5.o
+
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/drams_map.v))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dram.txt))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v
new file mode 100644
index 00000000..1094c5f8
--- /dev/null
+++ b/techlibs/ecp5/arith_map.v
@@ -0,0 +1,79 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 David Shah <dave@ds0.me>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+(* techmap_celltype = "$alu" *)
+module _80_ecp5_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));
+
+ function integer round_up2;
+ input integer N;
+ begin
+ round_up2 = ((N + 1) / 2) * 2;
+ end
+ endfunction
+
+ localparam Y_WIDTH2 = round_up2(Y_WIDTH);
+
+ wire [Y_WIDTH2-1:0] AA = A_buf;
+ wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf;
+ wire [Y_WIDTH2-1:0] C = {CO, CI};
+ wire [Y_WIDTH2-1:0] FCO, Y1;
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice
+ CCU2C #(
+ .INIT0(16'b0110011010101010),
+ .INIT1(16'b0110011010101010),
+ .INJECT1_0("NO"),
+ .INJECT1_1("NO")
+ ) ccu2c_i (
+ .CIN(C[i]),
+ .A0(AA[i]), .B0(BB[i]), .C0(1'b0), .D0(1'b1),
+ .A1(AA[i+1]), .B1(BB[i+1]), .C1(1'b0), .D1(1'b1),
+ .S0(Y[i]), .S1(Y1[i]),
+ .COUT(FCO[i])
+ );
+
+ assign CO[i] = (AA[i] && BB[i]) || (C[i] && (AA[i] || BB[i]));
+ if (i+1 < Y_WIDTH) begin
+ assign CO[i+1] = FCO[i];
+ assign Y[i+1] = Y1[i];
+ end
+ end endgenerate
+
+ assign X = AA ^ BB;
+endmodule
diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
new file mode 100644
index 00000000..48162a4d
--- /dev/null
+++ b/techlibs/ecp5/cells_map.v
@@ -0,0 +1,135 @@
+module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+
+module \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+module \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+
+module \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+module \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+
+module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFSE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+`ifndef NO_LUT
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+
+ input [WIDTH-1:0] A;
+ output Y;
+
+ generate
+ if (WIDTH == 1) begin
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[0]), .B(1'b0), .C(1'b0), .D(1'b0));
+ end else
+ if (WIDTH == 2) begin
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[0]), .B(A[1]), .C(1'b0), .D(1'b0));
+ end else
+ if (WIDTH == 3) begin
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(1'b0));
+ end else
+ if (WIDTH == 4) begin
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ `ifndef NO_PFUMUX
+ end else
+ if (WIDTH == 5) begin
+ wire f0, f1;
+ LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y));
+ end else
+ if (WIDTH == 6) begin
+ wire f0, f1, f2, f3, g0, g1;
+ LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
+ PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
+ L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y));
+ end else
+ if (WIDTH == 7) begin
+ wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1;
+ LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
+ PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
+ PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2));
+ PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3));
+ L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0));
+ L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1));
+ L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y));
+ `endif
+ end else begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ endgenerate
+endmodule
+`endif
diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
new file mode 100644
index 00000000..1700694e
--- /dev/null
+++ b/techlibs/ecp5/cells_sim.v
@@ -0,0 +1,448 @@
+// ---------------------------------------
+
+module LUT4(input A, B, C, D, output Z);
+ parameter [15:0] INIT = 16'h0000;
+ wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0];
+ wire [3:0] s2 = C ? s3[ 7:4] : s3[3:0];
+ wire [1:0] s1 = B ? s2[ 3:2] : s2[1:0];
+ assign Z = A ? s1[1] : s1[0];
+endmodule
+
+// ---------------------------------------
+
+module L6MUX21 (input D0, D1, SD, output Z);
+ assign Z = SD ? D1 : D0;
+endmodule
+
+// ---------------------------------------
+
+module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
+ output S0, S1, COUT);
+
+ parameter [15:0] INIT0 = 16'h0000;
+ parameter [15:0] INIT1 = 16'h0000;
+ parameter INJECT1_0 = "YES";
+ parameter INJECT1_1 = "YES";
+
+ // First half
+ wire LUT4_0, LUT2_0;
+ LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0));
+ LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0));
+
+ wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN;
+ assign S0 = LUT4_0 ^ gated_cin_0;
+
+ wire gated_lut2_0 = (INJECT1_0 == "YES") ? 1'b0 : LUT2_0;
+ wire cout_0 = (~LUT4_0 & gated_lut2_0) | (LUT4_0 & CIN);
+
+ // Second half
+ wire LUT4_1, LUT2_1;
+ LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1));
+ LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1));
+
+ wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0;
+ assign S1 = LUT4_1 ^ gated_cin_1;
+
+ wire gated_lut2_1 = (INJECT1_1 == "YES") ? 1'b0 : LUT2_1;
+ assign COUT = (~LUT4_1 & gated_lut2_1) | (LUT4_1 & cout_0);
+
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_RAM16X2 (
+ input DI0, DI1,
+ input WAD0, WAD1, WAD2, WAD3,
+ input WRE, WCK,
+ input RAD0, RAD1, RAD2, RAD3,
+ output DO0, DO1
+);
+ parameter WCKMUX = "WCK";
+ parameter WREMUX = "WRE";
+ parameter INITVAL_0 = 16'h0000;
+ parameter INITVAL_1 = 16'h0000;
+
+ reg [1:0] mem[15:0];
+
+ integer i;
+ initial begin
+ for (i = 0; i < 16; i = i + 1)
+ mem[i] <= {INITVAL_1[i], INITVAL_0[i]};
+ end
+
+ wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK;
+
+ reg muxwre;
+ always @(*)
+ case (WREMUX)
+ "1": muxwre = 1'b1;
+ "0": muxwre = 1'b0;
+ "INV": muxwre = ~WRE;
+ default: muxwre = WRE;
+ endcase
+
+
+ always @(posedge muxwck)
+ if (muxwre)
+ mem[{WAD3, WAD2, WAD1, WAD0}] <= {DI1, DI0};
+
+ assign {DO1, DO0} = mem[{RAD3, RAD2, RAD1, RAD0}];
+endmodule
+
+// ---------------------------------------
+
+module PFUMX (input ALUT, BLUT, C0, output Z);
+ assign Z = C0 ? ALUT : BLUT;
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_DPR16X4 (
+ input [3:0] DI,
+ input [3:0] WAD,
+ input WRE, WCK,
+ input [3:0] RAD,
+ output [3:0] DO
+);
+ parameter WCKMUX = "WCK";
+ parameter WREMUX = "WRE";
+ parameter [63:0] INITVAL = 64'h0000000000000000;
+
+ reg [3:0] mem[15:0];
+
+ integer i;
+ initial begin
+ for (i = 0; i < 16; i = i + 1)
+ mem[i] <= {INITVAL[i+3], INITVAL[i+2], INITVAL[i+1], INITVAL[i]};
+ end
+
+ wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK;
+
+ reg muxwre;
+ always @(*)
+ case (WREMUX)
+ "1": muxwre = 1'b1;
+ "0": muxwre = 1'b0;
+ "INV": muxwre = ~WRE;
+ default: muxwre = WRE;
+ endcase
+
+ always @(posedge muxwck)
+ if (muxwre)
+ mem[WAD] <= DI;
+
+ assign DO = mem[RAD];
+endmodule
+
+// ---------------------------------------
+
+module DPR16X4C (
+ input [3:0] DI,
+ input WCK, WRE,
+ input [3:0] RAD,
+ input [3:0] WAD,
+ output [3:0] DO
+);
+ // For legacy Lattice compatibility, INITIVAL is a hex
+ // string rather than a numeric parameter
+ parameter INITVAL = "0x0000000000000000";
+
+ function [63:0] convert_initval;
+ input [143:0] hex_initval;
+ reg done;
+ reg [63:0] temp;
+ reg [7:0] char;
+ integer i;
+ begin
+ done = 1'b0;
+ temp = 0;
+ for (i = 0; i < 16; i = i + 1) begin
+ if (!done) begin
+ char = hex_initval[8*i +: 8];
+ if (char == "x") begin
+ done = 1'b1;
+ end else begin
+ if (char >= "0" && char <= "9")
+ temp[4*i +: 4] = char - "0";
+ else if (char >= "A" && char <= "F")
+ temp[4*i +: 4] = 10 + char - "A";
+ else if (char >= "a" && char <= "f")
+ temp[4*i +: 4] = 10 + char - "a";
+ end
+ end
+ end
+ convert_initval = temp;
+ end
+ endfunction
+
+ localparam conv_initval = convert_initval(INITVAL);
+
+ reg [3:0] ram[0:15];
+ integer i;
+ initial begin
+ for (i = 0; i < 15; i = i + 1) begin
+ ram[i] <= conv_initval[4*i +: 4];
+ end
+ end
+
+ always @(posedge WCK)
+ if (WRE)
+ ram[WAD] <= DI;
+
+ assign DO = ram[RAD];
+
+endmodule
+
+// ---------------------------------------
+
+module LUT2(input A, B, output Z);
+ parameter [3:0] INIT = 4'h0;
+ wire [1:0] s1 = B ? INIT[ 3:2] : INIT[1:0];
+ assign Z = A ? s1[1] : s1[0];
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q);
+ parameter GSR = "ENABLED";
+ parameter [127:0] CEMUX = "1";
+ parameter CLKMUX = "CLK";
+ parameter LSRMUX = "LSR";
+ parameter SRMODE = "LSR_OVER_CE";
+ parameter REGSET = "RESET";
+
+ reg muxce;
+ always @(*)
+ case (CEMUX)
+ "1": muxce = 1'b1;
+ "0": muxce = 1'b0;
+ "INV": muxce = ~CE;
+ default: muxce = CE;
+ endcase
+
+ wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
+ wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
+
+ localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0;
+
+ initial Q = srval;
+
+ generate
+ if (SRMODE == "ASYNC") begin
+ always @(posedge muxclk, posedge muxlsr)
+ if (muxlsr)
+ Q <= srval;
+ else if (muxce)
+ Q <= DI;
+ end else begin
+ always @(posedge muxclk)
+ if (muxlsr)
+ Q <= srval;
+ else if (muxce)
+ Q <= DI;
+ end
+ endgenerate
+endmodule
+
+// ---------------------------------------
+
+module OBZ(input I, T, output O);
+assign O = T ? 1'bz : I;
+endmodule
+
+// ---------------------------------------
+
+module IB(input I, output O);
+assign O = I;
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_IO(
+ inout B,
+ input I,
+ input T,
+ output O
+);
+ parameter DIR = "INPUT";
+
+ generate
+ if (DIR == "INPUT") begin
+ assign B = 1'bz;
+ assign O = B;
+ end else if (DIR == "OUTPUT") begin
+ assign B = T ? 1'bz : I;
+ assign O = 1'bx;
+ end else if (DIR == "INOUT") begin
+ assign B = T ? 1'bz : I;
+ assign O = B;
+ end else begin
+ ERROR_UNKNOWN_IO_MODE error();
+ end
+ endgenerate
+
+endmodule
+
+// ---------------------------------------
+
+module OB(input I, output O);
+assign O = I;
+endmodule
+
+// ---------------------------------------
+
+module BB(input I, T, output O, inout B);
+assign B = T ? 1'bz : I;
+assign O = B;
+endmodule
+
+// ---------------------------------------
+
+module INV(input A, output Z);
+ assign Z = !A;
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_SLICE(
+ input A0, B0, C0, D0,
+ input A1, B1, C1, D1,
+ input M0, M1,
+ input FCI, FXA, FXB,
+
+ input CLK, LSR, CE,
+ input DI0, DI1,
+
+ input WD0, WD1,
+ input WAD0, WAD1, WAD2, WAD3,
+ input WRE, WCK,
+
+ output F0, Q0,
+ output F1, Q1,
+ output FCO, OFX0, OFX1,
+
+ output WDO0, WDO1, WDO2, WDO3,
+ output WADO0, WADO1, WADO2, WADO3
+);
+
+ parameter MODE = "LOGIC";
+ parameter GSR = "ENABLED";
+ parameter SRMODE = "LSR_OVER_CE";
+ parameter [127:0] CEMUX = "1";
+ parameter CLKMUX = "CLK";
+ parameter LSRMUX = "LSR";
+ parameter LUT0_INITVAL = 16'h0000;
+ parameter LUT1_INITVAL = 16'h0000;
+ parameter REG0_SD = "0";
+ parameter REG1_SD = "0";
+ parameter REG0_REGSET = "RESET";
+ parameter REG1_REGSET = "RESET";
+ parameter [127:0] CCU2_INJECT1_0 = "NO";
+ parameter [127:0] CCU2_INJECT1_1 = "NO";
+ parameter WREMUX = "WRE";
+
+ function [15:0] permute_initval;
+ input [15:0] initval;
+ integer i;
+ begin
+ for (i = 0; i < 16; i = i + 1) begin
+ permute_initval[{i[0], i[2], i[1], i[3]}] = initval[i];
+ end
+ end
+ endfunction
+
+ generate
+ if (MODE == "LOGIC") begin
+ // LUTs
+ LUT4 #(
+ .INIT(LUT0_INITVAL)
+ ) lut4_0 (
+ .A(A0), .B(B0), .C(C0), .D(D0),
+ .Z(F0)
+ );
+ LUT4 #(
+ .INIT(LUT1_INITVAL)
+ ) lut4_1 (
+ .A(A1), .B(B1), .C(C1), .D(D1),
+ .Z(F1)
+ );
+ // LUT expansion muxes
+ PFUMX lut5_mux (.ALUT(F1), .BLUT(F0), .C0(M0), .Z(OFX0));
+ L6MUX21 lutx_mux (.D0(FXA), .D1(FXB), .SD(M1), .Z(OFX1));
+ end else if (MODE == "CCU2") begin
+ CCU2C #(
+ .INIT0(LUT0_INITVAL),
+ .INIT1(LUT1_INITVAL),
+ .INJECT1_0(CCU2_INJECT1_0),
+ .INJECT1_1(CCU2_INJECT1_1)
+ ) ccu2c_i (
+ .CIN(FCI),
+ .A0(A0), .B0(B0), .C0(C0), .D0(D0),
+ .A1(A1), .B1(B1), .C1(C1), .D1(D1),
+ .S0(F0), .S1(F1),
+ .COUT(FCO)
+ );
+ end else if (MODE == "RAMW") begin
+ assign WDO0 = C1;
+ assign WDO1 = A1;
+ assign WDO2 = D1;
+ assign WDO3 = B1;
+ assign WADO0 = D0;
+ assign WADO1 = B0;
+ assign WADO2 = C0;
+ assign WADO3 = A0;
+ end else if (MODE == "DPRAM") begin
+ TRELLIS_RAM16X2 #(
+ .INITVAL_0(permute_initval(LUT0_INITVAL)),
+ .INITVAL_1(permute_initval(LUT1_INITVAL)),
+ .WREMUX(WREMUX)
+ ) ram_i (
+ .DI0(WD0), .DI1(WD1),
+ .WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3),
+ .WRE(WRE), .WCK(WCK),
+ .RAD0(D0), .RAD1(B0), .RAD2(C0), .RAD3(A0),
+ .DO0(F0), .DO1(F1)
+ );
+ // TODO: confirm RAD and INITVAL ordering
+ // DPRAM mode contract?
+ always @(*) begin
+ assert(A0==A1);
+ assert(B0==B1);
+ assert(C0==C1);
+ assert(D0==D1);
+ end
+ end else begin
+ ERROR_UNKNOWN_SLICE_MODE error();
+ end
+ endgenerate
+
+ // FF input selection muxes
+ wire muxdi0 = (REG0_SD == "1") ? DI0 : M0;
+ wire muxdi1 = (REG1_SD == "1") ? DI1 : M1;
+ // Flipflops
+ TRELLIS_FF #(
+ .GSR(GSR),
+ .CEMUX(CEMUX),
+ .CLKMUX(CLKMUX),
+ .LSRMUX(LSRMUX),
+ .SRMODE(SRMODE),
+ .REGSET(REG0_REGSET)
+ ) ff_0 (
+ .CLK(CLK), .LSR(LSR), .CE(CE),
+ .DI(muxdi0),
+ .Q(Q0)
+ );
+ TRELLIS_FF #(
+ .GSR(GSR),
+ .CEMUX(CEMUX),
+ .CLKMUX(CLKMUX),
+ .LSRMUX(LSRMUX),
+ .SRMODE(SRMODE),
+ .REGSET(REG1_REGSET)
+ ) ff_1 (
+ .CLK(CLK), .LSR(LSR), .CE(CE),
+ .DI(muxdi1),
+ .Q(Q1)
+ );
+endmodule
+
diff --git a/techlibs/ecp5/dram.txt b/techlibs/ecp5/dram.txt
new file mode 100644
index 00000000..b3252fa9
--- /dev/null
+++ b/techlibs/ecp5/dram.txt
@@ -0,0 +1,16 @@
+bram $__TRELLIS_DPR16X4
+ init 1
+ abits 4
+ dbits 4
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 2
+endbram
+
+match $__TRELLIS_DPR16X4
+ make_outreg
+endmatch
diff --git a/techlibs/ecp5/drams_map.v b/techlibs/ecp5/drams_map.v
new file mode 100644
index 00000000..3b3de831
--- /dev/null
+++ b/techlibs/ecp5/drams_map.v
@@ -0,0 +1,28 @@
+module \$__TRELLIS_DPR16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter [63:0] INIT = 64'bx;
+ parameter CLKPOL2 = 1;
+ input CLK1;
+
+ input [3:0] A1ADDR;
+ output [3:0] A1DATA;
+
+ input [3:0] B1ADDR;
+ input [3:0] B1DATA;
+ input B1EN;
+
+ localparam WCKMUX = CLKPOL2 ? "WCK" : "INV";
+
+ TRELLIS_DPR16X4 #(
+ .INITVAL(INIT),
+ .WCKMUX(WCKMUX),
+ .WREMUX("WRE")
+ ) _TECHMAP_REPLACE_ (
+ .RAD(A1ADDR),
+ .DO(A1DATA),
+
+ .WAD(B1ADDR),
+ .DI(B1DATA),
+ .WCK(CLK1),
+ .WRE(B1EN)
+ );
+endmodule
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc
new file mode 100644
index 00000000..a13dd8d4
--- /dev/null
+++ b/techlibs/ecp5/synth_ecp5.cc
@@ -0,0 +1,331 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 Clifford Wolf <dave@ds0.me>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SynthEcp5Pass : public ScriptPass
+{
+ SynthEcp5Pass() : ScriptPass("synth_ecp5", "synthesis for ECP5 FPGAs") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_ecp5 [options]\n");
+ log("\n");
+ log("This command runs synthesis for ECP5 FPGAs.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module\n");
+ log("\n");
+ log(" -blif <file>\n");
+ log(" write the design to the specified BLIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -edif <file>\n");
+ log(" write the design to the specified EDIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -json <file>\n");
+ log(" write the design to the specified JSON file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log(" -retime\n");
+ log(" run 'abc' with -dff option\n");
+ log("\n");
+ log(" -noccu2\n");
+ log(" do not use CCU2 cells in output netlist\n");
+ log("\n");
+ log(" -nodffe\n");
+ log(" do not use flipflops with CE in output netlist\n");
+ log("\n");
+ log(" -nobram\n");
+ log(" do not use BRAM cells in output netlist\n");
+ log("\n");
+ log(" -nodram\n");
+ log(" do not use distributed RAM cells in output netlist\n");
+ log("\n");
+ log(" -nomux\n");
+ log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
+ log("\n");
+ log(" -abc2\n");
+ log(" run two passes of 'abc' for slightly improved logic density\n");
+ log("\n");
+ log(" -vpr\n");
+ log(" generate an output netlist (and BLIF file) suitable for VPR\n");
+ log(" (this feature is experimental and incomplete)\n");
+ log("\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
+
+ string top_opt, blif_file, edif_file, json_file;
+ bool noccu2, nodffe, nobram, nodram, nomux, flatten, retime, abc2, vpr;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ blif_file = "";
+ edif_file = "";
+ json_file = "";
+ noccu2 = false;
+ nodffe = false;
+ nobram = false;
+ nodram = false;
+ nomux = false;
+ flatten = true;
+ retime = false;
+ abc2 = false;
+ vpr = false;
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_opt = "-top " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-blif" && argidx+1 < args.size()) {
+ blif_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-edif" && argidx+1 < args.size()) {
+ edif_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-json" && argidx+1 < args.size()) {
+ json_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
+ if (args[argidx] == "-flatten") {
+ flatten = true;
+ continue;
+ }
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
+ if (args[argidx] == "-noccu2") {
+ noccu2 = true;
+ continue;
+ }
+ if (args[argidx] == "-nodffe") {
+ nodffe = true;
+ continue;
+ }
+ if (args[argidx] == "-nobram") {
+ nobram = true;
+ continue;
+ }
+ if (args[argidx] == "-nodram") {
+ nodram = true;
+ continue;
+ }
+ if (args[argidx] == "-nomux") {
+ nomux = true;
+ continue;
+ }
+ if (args[argidx] == "-abc2") {
+ abc2 = true;
+ continue;
+ }
+ if (args[argidx] == "-vpr") {
+ vpr = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This comannd only operates on fully selected designs!\n");
+
+ log_header(design, "Executing SYNTH_ECP5 pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ void script() YS_OVERRIDE
+ {
+ if (check_label("begin"))
+ {
+ run("read_verilog -lib +/ecp5/cells_sim.v");
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
+
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
+ {
+ run("proc");
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
+ }
+
+ if (check_label("coarse"))
+ {
+ run("synth -run coarse");
+ }
+
+ if (!nobram && check_label("bram", "(skip if -nobram)"))
+ {
+ //TODO
+#if 0
+ run("memory_bram -rules +/ecp5/brams.txt");
+ run("techmap -map +/ecp5/brams_map.v");
+#endif
+ }
+
+ if (!nodram && check_label("dram", "(skip if -nodram)"))
+ {
+ run("memory_bram -rules +/ecp5/dram.txt");
+ run("techmap -map +/ecp5/drams_map.v");
+ }
+
+ if (check_label("fine"))
+ {
+ run("opt -fast -mux_undef -undriven -fine");
+ run("memory_map");
+ run("opt -undriven -fine");
+ if (noccu2)
+ run("techmap");
+ else
+ run("techmap -map +/techmap.v -map +/ecp5/arith_map.v");
+ if (retime || help_mode)
+ run("abc -dff", "(only if -retime)");
+ }
+
+ if (check_label("map_ffs"))
+ {
+ run("dffsr2dff");
+ run("dff2dffs");
+ run("opt_clean");
+ if (!nodffe)
+ run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
+ run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
+ run("opt_expr -mux_undef");
+ run("simplemap");
+ // TODO
+#if 0
+ run("ecp5_ffinit");
+#endif
+ }
+
+ if (check_label("map_luts"))
+ {
+ if (abc2 || help_mode) {
+ run("abc", " (only if -abc2)");
+ }
+ //TODO
+#if 0
+ run("techmap -map +/ecp5/latches_map.v");
+#endif
+ if (nomux)
+ run("abc -lut 4");
+ else
+ run("abc -lut 4:7");
+ run("clean");
+ }
+
+ if (check_label("map_cells"))
+ {
+ if (vpr)
+ run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
+ else
+ run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)");
+
+ run("clean");
+ }
+
+ if (check_label("check"))
+ {
+ run("hierarchy -check");
+ run("stat");
+ run("check -noinit");
+ }
+
+ if (check_label("blif"))
+ {
+ if (!blif_file.empty() || help_mode) {
+ if (vpr || help_mode) {
+ run(stringf("opt_clean -purge"),
+ " (vpr mode)");
+ run(stringf("write_blif -attr -cname -conn -param %s",
+ help_mode ? "<file-name>" : blif_file.c_str()),
+ " (vpr mode)");
+ }
+ if (!vpr)
+ run(stringf("write_blif -gates -attr -param %s",
+ help_mode ? "<file-name>" : blif_file.c_str()),
+ " (non-vpr mode)");
+ }
+ }
+
+ if (check_label("edif"))
+ {
+ if (!edif_file.empty() || help_mode)
+ run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
+ }
+
+ if (check_label("json"))
+ {
+ if (!json_file.empty() || help_mode)
+ run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
+ }
+ }
+} SynthEcp5Pass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v
index 3a09c157..94794262 100644
--- a/techlibs/gowin/cells_sim.v
+++ b/techlibs/gowin/cells_sim.v
@@ -1,51 +1,59 @@
module LUT1(output F, input I0);
- parameter [1:0] INIT = 0;
- assign F = I0 ? INIT[1] : INIT[0];
+ parameter [1:0] INIT = 0;
+ assign F = I0 ? INIT[1] : INIT[0];
endmodule
module LUT2(output F, input I0, I1);
- parameter [3:0] INIT = 0;
- wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0];
- assign F = I0 ? s1[1] : s1[0];
+ parameter [3:0] INIT = 0;
+ wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0];
+ assign F = I0 ? s1[1] : s1[0];
endmodule
module LUT3(output F, 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 F = I0 ? s1[1] : s1[0];
+ 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 F = I0 ? s1[1] : s1[0];
endmodule
module LUT4(output F, 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 F = I0 ? s1[1] : s1[0];
+ 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 F = I0 ? s1[1] : s1[0];
endmodule
module DFF (output reg Q, input CLK, D);
- always @(posedge C)
+ parameter [0:0] INIT = 1'b0;
+ initial Q = INIT;
+ always @(posedge CLK)
Q <= D;
endmodule
module DFFN (output reg Q, input CLK, D);
- always @(negedge C)
+ parameter [0:0] INIT = 1'b0;
+ initial Q = INIT;
+ always @(negedge CLK)
Q <= D;
endmodule
module VCC(output V);
- assign V = 1;
+ assign V = 1;
endmodule
module GND(output G);
- assign G = 0;
+ assign G = 0;
endmodule
module IBUF(output O, input I);
- assign O = I;
+ assign O = I;
endmodule
module OBUF(output O, input I);
- assign O = I;
+ assign O = I;
+endmodule
+
+module GSR (input GSRI);
+ wire GSRO = GSRI;
endmodule
diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc
index 129ab839..793f345b 100644
--- a/techlibs/gowin/synth_gowin.cc
+++ b/techlibs/gowin/synth_gowin.cc
@@ -29,7 +29,7 @@ struct SynthGowinPass : public ScriptPass
{
SynthGowinPass() : ScriptPass("synth_gowin", "synthesis for Gowin FPGAs") { }
- virtual void help() YS_OVERRIDE
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -61,14 +61,14 @@ struct SynthGowinPass : public ScriptPass
string top_opt, vout_file;
bool retime;
- virtual void clear_flags() YS_OVERRIDE
+ void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
vout_file = "";
retime = false;
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
clear_flags();
@@ -111,7 +111,7 @@ struct SynthGowinPass : public ScriptPass
log_pop();
}
- virtual void script() YS_OVERRIDE
+ void script() YS_OVERRIDE
{
if (check_label("begin"))
{
@@ -169,7 +169,7 @@ struct SynthGowinPass : public ScriptPass
if (check_label("vout"))
{
if (!vout_file.empty() || help_mode)
- run(stringf("write_verilog -attr2comment -defparam -renameprefix gen %s",
+ run(stringf("write_verilog -nodec -attr2comment -defparam -renameprefix gen %s",
help_mode ? "<file-name>" : vout_file.c_str()));
}
}
diff --git a/techlibs/greenpak4/Makefile.inc b/techlibs/greenpak4/Makefile.inc
index 1c9871e2..b43fb751 100644
--- a/techlibs/greenpak4/Makefile.inc
+++ b/techlibs/greenpak4/Makefile.inc
@@ -1,8 +1,12 @@
OBJS += techlibs/greenpak4/synth_greenpak4.o
-OBJS += techlibs/greenpak4/greenpak4_counters.o
OBJS += techlibs/greenpak4/greenpak4_dffinv.o
+$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_blackbox.v))
+$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_latch.v))
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_map.v))
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim.v))
+$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim_ams.v))
+$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim_digital.v))
+$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim_wip.v))
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/gp_dff.lib))
diff --git a/techlibs/greenpak4/cells_blackbox.v b/techlibs/greenpak4/cells_blackbox.v
new file mode 100644
index 00000000..1895b90d
--- /dev/null
+++ b/techlibs/greenpak4/cells_blackbox.v
@@ -0,0 +1,18 @@
+module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP);
+
+ input wire CE;
+ input wire CLK;
+ output reg OUT;
+ output reg[WIDTH-1:0] POUT;
+ input wire RST;
+ input wire UP;
+
+ parameter COUNT_TO = 1;
+ parameter RESET_MODE = "RISING";
+ parameter RESET_TO_MAX = "1";
+ parameter HAS_POUT = 0;
+ parameter HAS_CE = 0;
+ parameter WIDTH = 8;
+ parameter DIRECTION = "DOWN";
+
+endmodule
diff --git a/techlibs/greenpak4/cells_latch.v b/techlibs/greenpak4/cells_latch.v
new file mode 100644
index 00000000..2ccdd203
--- /dev/null
+++ b/techlibs/greenpak4/cells_latch.v
@@ -0,0 +1,15 @@
+module $_DLATCH_P_(input E, input D, output Q);
+ GP_DLATCH _TECHMAP_REPLACE_ (
+ .D(D),
+ .nCLK(!E),
+ .Q(Q)
+ );
+endmodule
+
+module $_DLATCH_N_(input E, input D, output Q);
+ GP_DLATCH _TECHMAP_REPLACE_ (
+ .D(D),
+ .nCLK(E),
+ .Q(Q)
+ );
+endmodule
diff --git a/techlibs/greenpak4/cells_map.v b/techlibs/greenpak4/cells_map.v
index 111a77a1..b971a51f 100644
--- a/techlibs/greenpak4/cells_map.v
+++ b/techlibs/greenpak4/cells_map.v
@@ -50,6 +50,58 @@ module GP_DFFRI(input D, CLK, nRST, output reg nQ);
);
endmodule
+module GP_DLATCHS(input D, nCLK, nSET, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ GP_DLATCHSR #(
+ .INIT(INIT),
+ .SRMODE(1'b1),
+ ) _TECHMAP_REPLACE_ (
+ .D(D),
+ .nCLK(nCLK),
+ .nSR(nSET),
+ .Q(Q)
+ );
+endmodule
+
+module GP_DLATCHR(input D, nCLK, nRST, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ GP_DLATCHSR #(
+ .INIT(INIT),
+ .SRMODE(1'b0),
+ ) _TECHMAP_REPLACE_ (
+ .D(D),
+ .nCLK(nCLK),
+ .nSR(nRST),
+ .Q(Q)
+ );
+endmodule
+
+module GP_DLATCHSI(input D, nCLK, nSET, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ GP_DLATCHSRI #(
+ .INIT(INIT),
+ .SRMODE(1'b1),
+ ) _TECHMAP_REPLACE_ (
+ .D(D),
+ .nCLK(nCLK),
+ .nSR(nSET),
+ .nQ(nQ)
+ );
+endmodule
+
+module GP_DLATCHRI(input D, nCLK, nRST, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ GP_DLATCHSRI #(
+ .INIT(INIT),
+ .SRMODE(1'b0),
+ ) _TECHMAP_REPLACE_ (
+ .D(D),
+ .nCLK(nCLK),
+ .nSR(nRST),
+ .nQ(nQ)
+ );
+endmodule
+
module GP_OBUFT(input IN, input OE, output OUT);
GP_IOBUF _TECHMAP_REPLACE_ (
.IN(IN),
@@ -92,3 +144,116 @@ module \$lut (A, Y);
end
endgenerate
endmodule
+
+module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP);
+
+ input wire CE;
+ input wire CLK;
+ output reg OUT;
+ output reg[WIDTH-1:0] POUT;
+ input wire RST;
+ input wire UP;
+
+ parameter COUNT_TO = 1;
+ parameter RESET_MODE = "RISING";
+ parameter RESET_TO_MAX = 0;
+ parameter HAS_POUT = 0;
+ parameter HAS_CE = 0;
+ parameter WIDTH = 8;
+ parameter DIRECTION = "DOWN";
+
+ //If we have a DIRECTION other than DOWN fail... GP_COUNTx_ADV is not supported yet
+ if(DIRECTION != "DOWN") begin
+ initial begin
+ $display("ERROR: \$__COUNT_ support for GP_COUNTx_ADV is not yet implemented. This counter should never have been extracted (bug in extract_counter pass?).");
+ $finish;
+ end
+ end
+
+ //If counter is more than 14 bits wide, complain (also shouldn't happen)
+ else if(WIDTH > 14) begin
+ initial begin
+ $display("ERROR: \$__COUNT_ support for cascaded counters is not yet implemented. This counter should never have been extracted (bug in extract_counter pass?).");
+ $finish;
+ end
+ end
+
+ //If counter is more than 8 bits wide and has parallel output, we have a problem
+ else if(WIDTH > 8 && HAS_POUT) begin
+ initial begin
+ $display("ERROR: \$__COUNT_ support for 9-14 bit counters with parallel output is not yet implemented. This counter should never have been extracted (bug in extract_counter pass?).");
+ $finish;
+ end
+ end
+
+ //Looks like a legal counter! Do something with it
+ else if(WIDTH <= 8) begin
+ if(HAS_CE) begin
+ wire ce_not;
+ GP_INV ceinv(
+ .IN(CE),
+ .OUT(ce_not)
+ );
+ GP_COUNT8_ADV #(
+ .COUNT_TO(COUNT_TO),
+ .RESET_MODE(RESET_MODE),
+ .RESET_VALUE(RESET_TO_MAX ? "COUNT_TO" : "ZERO"),
+ .CLKIN_DIVIDE(1)
+ ) _TECHMAP_REPLACE_ (
+ .CLK(CLK),
+ .RST(RST),
+ .OUT(OUT),
+ .UP(1'b0), //always count down for now
+ .KEEP(ce_not),
+ .POUT(POUT)
+ );
+ end
+ else begin
+ GP_COUNT8 #(
+ .COUNT_TO(COUNT_TO),
+ .RESET_MODE(RESET_MODE),
+ .CLKIN_DIVIDE(1)
+ ) _TECHMAP_REPLACE_ (
+ .CLK(CLK),
+ .RST(RST),
+ .OUT(OUT),
+ .POUT(POUT)
+ );
+ end
+ end
+
+ else begin
+ if(HAS_CE) begin
+ wire ce_not;
+ GP_INV ceinv(
+ .IN(CE),
+ .OUT(ce_not)
+ );
+ GP_COUNT14_ADV #(
+ .COUNT_TO(COUNT_TO),
+ .RESET_MODE(RESET_TO_MAX ? "COUNT_TO" : "ZERO"),
+ .RESET_VALUE("COUNT_TO"),
+ .CLKIN_DIVIDE(1)
+ ) _TECHMAP_REPLACE_ (
+ .CLK(CLK),
+ .RST(RST),
+ .OUT(OUT),
+ .UP(1'b0), //always count down for now
+ .KEEP(ce_not),
+ .POUT(POUT)
+ );
+ end
+ else begin
+ GP_COUNT14 #(
+ .COUNT_TO(COUNT_TO),
+ .RESET_MODE(RESET_MODE),
+ .CLKIN_DIVIDE(1)
+ ) _TECHMAP_REPLACE_ (
+ .CLK(CLK),
+ .RST(RST),
+ .OUT(OUT)
+ );
+ end
+ end
+
+endmodule
diff --git a/techlibs/greenpak4/cells_sim.v b/techlibs/greenpak4/cells_sim.v
index 80746be0..221bee69 100644
--- a/techlibs/greenpak4/cells_sim.v
+++ b/techlibs/greenpak4/cells_sim.v
@@ -1,461 +1,5 @@
`timescale 1ns/1ps
-module GP_2LUT(input IN0, IN1, output OUT);
- parameter [3:0] INIT = 0;
- assign OUT = INIT[{IN1, IN0}];
-endmodule
-
-module GP_3LUT(input IN0, IN1, IN2, output OUT);
- parameter [7:0] INIT = 0;
- assign OUT = INIT[{IN2, IN1, IN0}];
-endmodule
-
-module GP_4LUT(input IN0, IN1, IN2, IN3, output OUT);
- parameter [15:0] INIT = 0;
- assign OUT = INIT[{IN3, IN2, IN1, IN0}];
-endmodule
-
-module GP_ABUF(input wire IN, output wire OUT);
-
- assign OUT = IN;
-
- //cannot simulate mixed signal IP
-
-endmodule
-
-module GP_ACMP(input wire PWREN, input wire VIN, input wire VREF, output reg OUT);
-
- parameter BANDWIDTH = "HIGH";
- parameter VIN_ATTEN = 1;
- parameter VIN_ISRC_EN = 0;
- parameter HYSTERESIS = 0;
-
- initial OUT = 0;
-
- //cannot simulate mixed signal IP
-
-endmodule
-
-module GP_BANDGAP(output reg OK);
- parameter AUTO_PWRDN = 1;
- parameter CHOPPER_EN = 1;
- parameter OUT_DELAY = 100;
-
- //cannot simulate mixed signal IP
-
-endmodule
-
-module GP_COUNT8(input CLK, input wire RST, output reg OUT);
-
- parameter RESET_MODE = "RISING";
-
- parameter COUNT_TO = 8'h1;
- parameter CLKIN_DIVIDE = 1;
-
- //more complex hard IP blocks are not supported for simulation yet
-
- reg[7:0] count = COUNT_TO;
-
- //Combinatorially output whenever we wrap low
- always @(*) begin
- OUT <= (count == 8'h0);
- end
-
- //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
- //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
- //Datasheet seems to indicate that reset is asynchronous, but for now we model as sync due to Yosys issues...
- always @(posedge CLK) begin
-
- count <= count - 1'd1;
-
- if(count == 0)
- count <= COUNT_TO;
-
- /*
- if((RESET_MODE == "RISING") && RST)
- count <= 0;
- if((RESET_MODE == "FALLING") && !RST)
- count <= 0;
- if((RESET_MODE == "BOTH") && RST)
- count <= 0;
- */
- end
-
-endmodule
-
-module GP_COUNT14(input CLK, input wire RST, output reg OUT);
-
- parameter RESET_MODE = "RISING";
-
- parameter COUNT_TO = 14'h1;
- parameter CLKIN_DIVIDE = 1;
-
- //more complex hard IP blocks are not supported for simulation yet
-
-endmodule
-
-module GP_COUNT8_ADV(input CLK, input RST, output reg OUT,
- input UP, input KEEP);
-
- parameter RESET_MODE = "RISING";
- parameter RESET_VALUE = "ZERO";
-
- parameter COUNT_TO = 8'h1;
- parameter CLKIN_DIVIDE = 1;
-
- //more complex hard IP blocks are not supported for simulation yet
-
-endmodule
-
-module GP_COUNT14_ADV(input CLK, input RST, output reg OUT,
- input UP, input KEEP);
-
- parameter RESET_MODE = "RISING";
- parameter RESET_VALUE = "ZERO";
-
- parameter COUNT_TO = 14'h1;
- parameter CLKIN_DIVIDE = 1;
-
- //more complex hard IP blocks are not supported for simulation yet
-
-endmodule
-
-module GP_DAC(input[7:0] DIN, input wire VREF, output reg VOUT);
-
- initial VOUT = 0;
-
- //analog hard IP is not supported for simulation
-
-endmodule
-
-module GP_DELAY(input IN, output reg OUT);
-
- parameter DELAY_STEPS = 1;
- parameter GLITCH_FILTER = 0;
-
- initial OUT = 0;
-
- generate
-
- //TODO: These delays are PTV dependent! For now, hard code 3v3 timing
- //Change simulation-mode delay depending on global Vdd range (how to specify this?)
- always @(*) begin
- case(DELAY_STEPS)
- 1: #166 OUT = IN;
- 2: #318 OUT = IN;
- 2: #471 OUT = IN;
- 3: #622 OUT = IN;
- default: begin
- $display("ERROR: GP_DELAY must have DELAY_STEPS in range [1,4]");
- $finish;
- end
- endcase
- end
-
- endgenerate
-
-endmodule
-
-module GP_DFF(input D, CLK, output reg Q);
- parameter [0:0] INIT = 1'bx;
- initial Q = INIT;
- always @(posedge CLK) begin
- Q <= D;
- end
-endmodule
-
-module GP_DFFI(input D, CLK, output reg nQ);
- parameter [0:0] INIT = 1'bx;
- initial nQ = INIT;
- always @(posedge CLK) begin
- nQ <= ~D;
- end
-endmodule
-
-module GP_DFFR(input D, CLK, nRST, output reg Q);
- parameter [0:0] INIT = 1'bx;
- initial Q = INIT;
- always @(posedge CLK, negedge nRST) begin
- if (!nRST)
- Q <= 1'b0;
- else
- Q <= D;
- end
-endmodule
-
-module GP_DFFRI(input D, CLK, nRST, output reg nQ);
- parameter [0:0] INIT = 1'bx;
- initial nQ = INIT;
- always @(posedge CLK, negedge nRST) begin
- if (!nRST)
- nQ <= 1'b1;
- else
- nQ <= ~D;
- end
-endmodule
-
-module GP_DFFS(input D, CLK, nSET, output reg Q);
- parameter [0:0] INIT = 1'bx;
- initial Q = INIT;
- always @(posedge CLK, negedge nSET) begin
- if (!nSET)
- Q <= 1'b1;
- else
- Q <= D;
- end
-endmodule
-
-module GP_DFFSI(input D, CLK, nSET, output reg nQ);
- parameter [0:0] INIT = 1'bx;
- initial nQ = INIT;
- always @(posedge CLK, negedge nSET) begin
- if (!nSET)
- nQ <= 1'b0;
- else
- nQ <= ~D;
- end
-endmodule
-
-module GP_DFFSR(input D, CLK, nSR, output reg Q);
- parameter [0:0] INIT = 1'bx;
- parameter [0:0] SRMODE = 1'bx;
- initial Q = INIT;
- always @(posedge CLK, negedge nSR) begin
- if (!nSR)
- Q <= SRMODE;
- else
- Q <= D;
- end
-endmodule
-
-module GP_DFFSRI(input D, CLK, nSR, output reg nQ);
- parameter [0:0] INIT = 1'bx;
- parameter [0:0] SRMODE = 1'bx;
- initial nQ = INIT;
- always @(posedge CLK, negedge nSR) begin
- if (!nSR)
- nQ <= ~SRMODE;
- else
- nQ <= ~D;
- end
-endmodule
-
-module GP_EDGEDET(input IN, output reg OUT);
-
- parameter EDGE_DIRECTION = "RISING";
- parameter DELAY_STEPS = 1;
- parameter GLITCH_FILTER = 0;
-
- //not implemented for simulation
-
-endmodule
-
-module GP_IBUF(input IN, output OUT);
- assign OUT = IN;
-endmodule
-
-module GP_IOBUF(input IN, input OE, output OUT, inout IO);
- assign OUT = IO;
- assign IO = OE ? IN : 1'bz;
-endmodule
-
-module GP_INV(input IN, output OUT);
- assign OUT = ~IN;
-endmodule
-
-module GP_LFOSC(input PWRDN, output reg CLKOUT);
-
- parameter PWRDN_EN = 0;
- parameter AUTO_PWRDN = 0;
- parameter OUT_DIV = 1;
-
- initial CLKOUT = 0;
-
- //auto powerdown not implemented for simulation
- //output dividers not implemented for simulation
-
- always begin
- if(PWRDN)
- CLKOUT = 0;
- else begin
- //half period of 1730 Hz
- #289017;
- CLKOUT = ~CLKOUT;
- end
- end
-
-endmodule
-
-module GP_OBUF(input IN, output OUT);
- assign OUT = IN;
-endmodule
-
-module GP_OBUFT(input IN, input OE, output OUT);
- assign OUT = OE ? IN : 1'bz;
-endmodule
-
-module GP_PGA(input wire VIN_P, input wire VIN_N, input wire VIN_SEL, output reg VOUT);
-
- parameter GAIN = 1;
- parameter INPUT_MODE = "SINGLE";
-
- initial VOUT = 0;
-
- //cannot simulate mixed signal IP
-
-endmodule
-
-module GP_PGEN(input wire nRST, input wire CLK, output reg OUT);
- initial OUT = 0;
- parameter PATTERN_DATA = 16'h0;
- parameter PATTERN_LEN = 5'd16;
-
- reg[3:0] count = 0;
- always @(posedge CLK) begin
- if(!nRST)
- OUT <= PATTERN_DATA[0];
-
- else begin
- count <= count + 1;
- OUT <= PATTERN_DATA[count];
-
- if( (count + 1) == PATTERN_LEN)
- count <= 0;
- end
- end
-
-endmodule
-
-module GP_POR(output reg RST_DONE);
- parameter POR_TIME = 500;
-
- initial begin
- RST_DONE = 0;
-
- if(POR_TIME == 4)
- #4000;
- else if(POR_TIME == 500)
- #500000;
- else begin
- $display("ERROR: bad POR_TIME for GP_POR cell");
- $finish;
- end
-
- RST_DONE = 1;
-
- end
-
-endmodule
-
-module GP_RCOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC);
-
- parameter PWRDN_EN = 0;
- parameter AUTO_PWRDN = 0;
- parameter HARDIP_DIV = 1;
- parameter FABRIC_DIV = 1;
- parameter OSC_FREQ = "25k";
-
- initial CLKOUT_HARDIP = 0;
- initial CLKOUT_FABRIC = 0;
-
- //output dividers not implemented for simulation
- //auto powerdown not implemented for simulation
-
- always begin
- if(PWRDN) begin
- CLKOUT_HARDIP = 0;
- CLKOUT_FABRIC = 0;
- end
- else begin
-
- if(OSC_FREQ == "25k") begin
- //half period of 25 kHz
- #20000;
- end
-
- else begin
- //half period of 2 MHz
- #250;
- end
-
- CLKOUT_HARDIP = ~CLKOUT_HARDIP;
- CLKOUT_FABRIC = ~CLKOUT_FABRIC;
- end
- end
-
-endmodule
-
-module GP_RINGOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC);
-
- parameter PWRDN_EN = 0;
- parameter AUTO_PWRDN = 0;
- parameter HARDIP_DIV = 1;
- parameter FABRIC_DIV = 1;
-
- initial CLKOUT_HARDIP = 0;
- initial CLKOUT_FABRIC = 0;
-
- //output dividers not implemented for simulation
- //auto powerdown not implemented for simulation
-
- always begin
- if(PWRDN) begin
- CLKOUT_HARDIP = 0;
- CLKOUT_FABRIC = 0;
- end
- else begin
- //half period of 27 MHz
- #18.518;
- CLKOUT_HARDIP = ~CLKOUT_HARDIP;
- CLKOUT_FABRIC = ~CLKOUT_FABRIC;
- end
- end
-
-endmodule
-
-module GP_SHREG(input nRST, input CLK, input IN, output OUTA, output OUTB);
-
- parameter OUTA_TAP = 1;
- parameter OUTA_INVERT = 0;
- parameter OUTB_TAP = 1;
-
- reg[15:0] shreg = 0;
-
- always @(posedge CLK, negedge nRST) begin
-
- if(!nRST)
- shreg = 0;
-
- else
- shreg <= {shreg[14:0], IN};
-
- end
-
- assign OUTA = (OUTA_INVERT) ? ~shreg[OUTA_TAP - 1] : shreg[OUTA_TAP - 1];
- assign OUTB = shreg[OUTB_TAP - 1];
-
-endmodule
-
-//keep constraint needed to prevent optimization since we have no outputs
-(* keep *)
-module GP_SYSRESET(input RST);
- parameter RESET_MODE = "EDGE";
- parameter EDGE_SPEED = 4;
-
- //cannot simulate whole system reset
-
-endmodule
-
-module GP_VDD(output OUT);
- assign OUT = 1;
-endmodule
-
-module GP_VREF(input VIN, output reg VOUT);
- parameter VIN_DIV = 1;
- parameter VREF = 0;
- //cannot simulate mixed signal IP
-endmodule
-
-module GP_VSS(output OUT);
- assign OUT = 0;
-endmodule
+`include "cells_sim_ams.v"
+`include "cells_sim_digital.v"
+`include "cells_sim_wip.v"
diff --git a/techlibs/greenpak4/cells_sim_ams.v b/techlibs/greenpak4/cells_sim_ams.v
new file mode 100644
index 00000000..7f8b3de3
--- /dev/null
+++ b/techlibs/greenpak4/cells_sim_ams.v
@@ -0,0 +1,110 @@
+`timescale 1ns/1ps
+
+/*
+ This file contains analog / mixed signal cells, or other things that are not possible to fully model
+ in behavioral Verilog.
+
+ It also contains some stuff like oscillators that use non-synthesizeable constructs such as delays.
+ TODO: do we want a third file for those cells?
+ */
+
+module GP_ABUF(input wire IN, output wire OUT);
+
+ assign OUT = IN;
+
+ //must be 1, 5, 20, 50
+ //values >1 only available with Vdd > 2.7V
+ parameter BANDWIDTH_KHZ = 1;
+
+endmodule
+
+module GP_ACMP(input wire PWREN, input wire VIN, input wire VREF, output reg OUT);
+
+ parameter BANDWIDTH = "HIGH";
+ parameter VIN_ATTEN = 1;
+ parameter VIN_ISRC_EN = 0;
+ parameter HYSTERESIS = 0;
+
+ initial OUT = 0;
+
+endmodule
+
+module GP_BANDGAP(output reg OK);
+ parameter AUTO_PWRDN = 1;
+ parameter CHOPPER_EN = 1;
+ parameter OUT_DELAY = 100;
+
+endmodule
+
+module GP_DAC(input[7:0] DIN, input wire VREF, output reg VOUT);
+
+ initial VOUT = 0;
+
+ //analog hard IP is not supported for simulation
+
+endmodule
+
+module GP_LFOSC(input PWRDN, output reg CLKOUT);
+
+ parameter PWRDN_EN = 0;
+ parameter AUTO_PWRDN = 0;
+ parameter OUT_DIV = 1;
+
+ initial CLKOUT = 0;
+
+ //auto powerdown not implemented for simulation
+ //output dividers not implemented for simulation
+
+ always begin
+ if(PWRDN)
+ CLKOUT = 0;
+ else begin
+ //half period of 1730 Hz
+ #289017;
+ CLKOUT = ~CLKOUT;
+ end
+ end
+
+endmodule
+
+module GP_PGA(input wire VIN_P, input wire VIN_N, input wire VIN_SEL, output reg VOUT);
+
+ parameter GAIN = 1;
+ parameter INPUT_MODE = "SINGLE";
+
+ initial VOUT = 0;
+
+ //cannot simulate mixed signal IP
+
+endmodule
+
+module GP_PWRDET(output reg VDD_LOW);
+ initial VDD_LOW = 0;
+endmodule
+
+module GP_VREF(input VIN, output reg VOUT);
+ parameter VIN_DIV = 1;
+ parameter VREF = 0;
+ //cannot simulate mixed signal IP
+endmodule
+
+module GP_POR(output reg RST_DONE);
+ parameter POR_TIME = 500;
+
+ initial begin
+ RST_DONE = 0;
+
+ if(POR_TIME == 4)
+ #4000;
+ else if(POR_TIME == 500)
+ #500000;
+ else begin
+ $display("ERROR: bad POR_TIME for GP_POR cell");
+ $finish;
+ end
+
+ RST_DONE = 1;
+
+ end
+
+endmodule
diff --git a/techlibs/greenpak4/cells_sim_digital.v b/techlibs/greenpak4/cells_sim_digital.v
new file mode 100644
index 00000000..43d35d08
--- /dev/null
+++ b/techlibs/greenpak4/cells_sim_digital.v
@@ -0,0 +1,794 @@
+`timescale 1ns/1ps
+
+/*
+ This file contains simulation models for GreenPAK cells which are possible to fully model using synthesizeable
+ behavioral Verilog constructs only.
+ */
+
+module GP_2LUT(input IN0, IN1, output OUT);
+ parameter [3:0] INIT = 0;
+ assign OUT = INIT[{IN1, IN0}];
+endmodule
+
+module GP_3LUT(input IN0, IN1, IN2, output OUT);
+ parameter [7:0] INIT = 0;
+ assign OUT = INIT[{IN2, IN1, IN0}];
+endmodule
+
+module GP_4LUT(
+ input wire IN0,
+ input wire IN1,
+ input wire IN2,
+ input wire IN3,
+ output wire OUT);
+
+ parameter [15:0] INIT = 0;
+ assign OUT = INIT[{IN3, IN2, IN1, IN0}];
+endmodule
+
+module GP_CLKBUF(input wire IN, output wire OUT);
+ assign OUT = IN;
+endmodule
+
+module GP_COUNT14(input CLK, input wire RST, output reg OUT);
+
+ parameter RESET_MODE = "RISING";
+
+ parameter COUNT_TO = 14'h1;
+ parameter CLKIN_DIVIDE = 1;
+
+ reg[13:0] count = COUNT_TO;
+
+ initial begin
+ if(CLKIN_DIVIDE != 1) begin
+ $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented");
+ $finish;
+ end
+ end
+
+ //Combinatorially output underflow flag whenever we wrap low
+ always @(*) begin
+ OUT <= (count == 14'h0);
+ end
+
+ //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
+ //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
+ generate
+ case(RESET_MODE)
+
+ "RISING": begin
+ always @(posedge CLK, posedge RST) begin
+ if(RST)
+ count <= 0;
+ else begin
+ count <= count - 1'd1;
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+ end
+ end
+
+ "FALLING": begin
+ always @(posedge CLK, negedge RST) begin
+ if(!RST)
+ count <= 0;
+ else begin
+ count <= count - 1'd1;
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+ end
+ end
+
+ "BOTH": begin
+ initial begin
+ $display("Both-edge reset mode for GP_COUNT14 not implemented");
+ $finish;
+ end
+ end
+
+ "LEVEL": begin
+ always @(posedge CLK, posedge RST) begin
+ if(RST)
+ count <= 0;
+
+ else begin
+ count <= count - 1'd1;
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+ end
+ end
+
+ default: begin
+ initial begin
+ $display("Invalid RESET_MODE on GP_COUNT14");
+ $finish;
+ end
+ end
+
+ endcase
+ endgenerate
+
+endmodule
+
+module GP_COUNT14_ADV(input CLK, input RST, output reg OUT,
+ input UP, input KEEP, output reg[7:0] POUT);
+
+ parameter RESET_MODE = "RISING";
+ parameter RESET_VALUE = "ZERO";
+
+ parameter COUNT_TO = 14'h1;
+ parameter CLKIN_DIVIDE = 1;
+
+ initial begin
+ if(CLKIN_DIVIDE != 1) begin
+ $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented");
+ $finish;
+ end
+ end
+
+ reg[13:0] count = COUNT_TO;
+
+ //Combinatorially output underflow flag whenever we wrap low
+ always @(*) begin
+ if(UP)
+ OUT <= (count == 14'h3fff);
+ else
+ OUT <= (count == 14'h0);
+ POUT <= count[7:0];
+ end
+
+ //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
+ //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
+ generate
+ case(RESET_MODE)
+
+ "RISING": begin
+ always @(posedge CLK, posedge RST) begin
+
+ //Resets
+ if(RST) begin
+ if(RESET_VALUE == "ZERO")
+ count <= 0;
+ else
+ count <= COUNT_TO;
+ end
+
+ else if(KEEP) begin
+ end
+ else if(UP) begin
+ count <= count + 1'd1;
+ if(count == 14'h3fff)
+ count <= COUNT_TO;
+ end
+ else begin
+ count <= count - 1'd1;
+
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+
+ end
+ end
+
+ "FALLING": begin
+ always @(posedge CLK, negedge RST) begin
+
+ //Resets
+ if(!RST) begin
+ if(RESET_VALUE == "ZERO")
+ count <= 0;
+ else
+ count <= COUNT_TO;
+ end
+
+ else if(KEEP) begin
+ end
+ else if(UP) begin
+ count <= count + 1'd1;
+ if(count == 14'h3fff)
+ count <= COUNT_TO;
+ end
+ else begin
+ count <= count - 1'd1;
+
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+
+ end
+ end
+
+ "BOTH": begin
+ initial begin
+ $display("Both-edge reset mode for GP_COUNT14_ADV not implemented");
+ $finish;
+ end
+ end
+
+ "LEVEL": begin
+ always @(posedge CLK, posedge RST) begin
+
+ //Resets
+ if(RST) begin
+ if(RESET_VALUE == "ZERO")
+ count <= 0;
+ else
+ count <= COUNT_TO;
+ end
+
+ else begin
+
+ if(KEEP) begin
+ end
+ else if(UP) begin
+ count <= count + 1'd1;
+ if(count == 14'h3fff)
+ count <= COUNT_TO;
+ end
+ else begin
+ count <= count - 1'd1;
+
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+
+ end
+
+ end
+ end
+
+ default: begin
+ initial begin
+ $display("Invalid RESET_MODE on GP_COUNT14_ADV");
+ $finish;
+ end
+ end
+
+ endcase
+ endgenerate
+
+endmodule
+
+module GP_COUNT8_ADV(input CLK, input RST, output reg OUT,
+ input UP, input KEEP, output reg[7:0] POUT);
+
+ parameter RESET_MODE = "RISING";
+ parameter RESET_VALUE = "ZERO";
+
+ parameter COUNT_TO = 8'h1;
+ parameter CLKIN_DIVIDE = 1;
+
+ reg[7:0] count = COUNT_TO;
+
+ initial begin
+ if(CLKIN_DIVIDE != 1) begin
+ $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented");
+ $finish;
+ end
+ end
+
+ //Combinatorially output underflow flag whenever we wrap low
+ always @(*) begin
+ if(UP)
+ OUT <= (count == 8'hff);
+ else
+ OUT <= (count == 8'h0);
+ POUT <= count;
+ end
+
+ //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
+ //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
+ generate
+ case(RESET_MODE)
+
+ "RISING": begin
+ always @(posedge CLK, posedge RST) begin
+
+ //Resets
+ if(RST) begin
+ if(RESET_VALUE == "ZERO")
+ count <= 0;
+ else
+ count <= COUNT_TO;
+ end
+
+ //Main counter
+ else if(KEEP) begin
+ end
+ else if(UP) begin
+ count <= count + 1'd1;
+ if(count == 8'hff)
+ count <= COUNT_TO;
+ end
+ else begin
+ count <= count - 1'd1;
+
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+
+ end
+ end
+
+ "FALLING": begin
+ always @(posedge CLK, negedge RST) begin
+
+ //Resets
+ if(!RST) begin
+ if(RESET_VALUE == "ZERO")
+ count <= 0;
+ else
+ count <= COUNT_TO;
+ end
+
+ //Main counter
+ else if(KEEP) begin
+ end
+ else if(UP) begin
+ count <= count + 1'd1;
+ if(count == 8'hff)
+ count <= COUNT_TO;
+ end
+ else begin
+ count <= count - 1'd1;
+
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+
+ end
+ end
+
+ "BOTH": begin
+ initial begin
+ $display("Both-edge reset mode for GP_COUNT8_ADV not implemented");
+ $finish;
+ end
+ end
+
+ "LEVEL": begin
+ always @(posedge CLK, posedge RST) begin
+
+ //Resets
+ if(RST) begin
+ if(RESET_VALUE == "ZERO")
+ count <= 0;
+ else
+ count <= COUNT_TO;
+ end
+
+ else begin
+
+ if(KEEP) begin
+ end
+ else if(UP) begin
+ count <= count + 1'd1;
+ if(count == 8'hff)
+ count <= COUNT_TO;
+ end
+ else begin
+ count <= count - 1'd1;
+
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+ end
+
+ end
+ end
+
+ default: begin
+ initial begin
+ $display("Invalid RESET_MODE on GP_COUNT8_ADV");
+ $finish;
+ end
+ end
+
+ endcase
+ endgenerate
+
+endmodule
+
+module GP_COUNT8(
+ input wire CLK,
+ input wire RST,
+ output reg OUT,
+ output reg[7:0] POUT);
+
+ parameter RESET_MODE = "RISING";
+
+ parameter COUNT_TO = 8'h1;
+ parameter CLKIN_DIVIDE = 1;
+
+ initial begin
+ if(CLKIN_DIVIDE != 1) begin
+ $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented");
+ $finish;
+ end
+ end
+
+ reg[7:0] count = COUNT_TO;
+
+ //Combinatorially output underflow flag whenever we wrap low
+ always @(*) begin
+ OUT <= (count == 8'h0);
+ POUT <= count;
+ end
+
+ //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
+ //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
+ generate
+ case(RESET_MODE)
+
+ "RISING": begin
+ always @(posedge CLK, posedge RST) begin
+ if(RST)
+ count <= 0;
+ else begin
+ count <= count - 1'd1;
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+ end
+ end
+
+ "FALLING": begin
+ always @(posedge CLK, negedge RST) begin
+ if(!RST)
+ count <= 0;
+ else begin
+ count <= count - 1'd1;
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+ end
+ end
+
+ "BOTH": begin
+ initial begin
+ $display("Both-edge reset mode for GP_COUNT8 not implemented");
+ $finish;
+ end
+ end
+
+ "LEVEL": begin
+ always @(posedge CLK, posedge RST) begin
+ if(RST)
+ count <= 0;
+
+ else begin
+ count <= count - 1'd1;
+ if(count == 0)
+ count <= COUNT_TO;
+ end
+ end
+ end
+
+ default: begin
+ initial begin
+ $display("Invalid RESET_MODE on GP_COUNT8");
+ $finish;
+ end
+ end
+
+ endcase
+ endgenerate
+
+endmodule
+
+module GP_DCMPREF(output reg[7:0]OUT);
+ parameter[7:0] REF_VAL = 8'h00;
+ initial OUT = REF_VAL;
+endmodule
+
+module GP_DCMPMUX(input[1:0] SEL, input[7:0] IN0, input[7:0] IN1, input[7:0] IN2, input[7:0] IN3, output reg[7:0] OUTA, output reg[7:0] OUTB);
+
+ always @(*) begin
+ case(SEL)
+ 2'd00: begin
+ OUTA <= IN0;
+ OUTB <= IN3;
+ end
+
+ 2'd01: begin
+ OUTA <= IN1;
+ OUTB <= IN2;
+ end
+
+ 2'd02: begin
+ OUTA <= IN2;
+ OUTB <= IN1;
+ end
+
+ 2'd03: begin
+ OUTA <= IN3;
+ OUTB <= IN0;
+ end
+
+ endcase
+ end
+endmodule
+
+module GP_DELAY(input IN, output reg OUT);
+
+ parameter DELAY_STEPS = 1;
+ parameter GLITCH_FILTER = 0;
+
+ initial OUT = 0;
+
+ generate
+
+ if(GLITCH_FILTER) begin
+ initial begin
+ $display("ERROR: GP_DELAY glitch filter mode not implemented");
+ $finish;
+ end
+ end
+
+ //TODO: These delays are PTV dependent! For now, hard code 3v3 timing
+ //Change simulation-mode delay depending on global Vdd range (how to specify this?)
+ always @(*) begin
+ case(DELAY_STEPS)
+ 1: #166 OUT = IN;
+ 2: #318 OUT = IN;
+ 2: #471 OUT = IN;
+ 3: #622 OUT = IN;
+ default: begin
+ $display("ERROR: GP_DELAY must have DELAY_STEPS in range [1,4]");
+ $finish;
+ end
+ endcase
+ end
+
+ endgenerate
+
+endmodule
+
+module GP_DFF(input D, CLK, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ initial Q = INIT;
+ always @(posedge CLK) begin
+ Q <= D;
+ end
+endmodule
+
+module GP_DFFI(input D, CLK, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ initial nQ = INIT;
+ always @(posedge CLK) begin
+ nQ <= ~D;
+ end
+endmodule
+
+module GP_DFFR(input D, CLK, nRST, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ initial Q = INIT;
+ always @(posedge CLK, negedge nRST) begin
+ if (!nRST)
+ Q <= 1'b0;
+ else
+ Q <= D;
+ end
+endmodule
+
+module GP_DFFRI(input D, CLK, nRST, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ initial nQ = INIT;
+ always @(posedge CLK, negedge nRST) begin
+ if (!nRST)
+ nQ <= 1'b1;
+ else
+ nQ <= ~D;
+ end
+endmodule
+
+module GP_DFFS(input D, CLK, nSET, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ initial Q = INIT;
+ always @(posedge CLK, negedge nSET) begin
+ if (!nSET)
+ Q <= 1'b1;
+ else
+ Q <= D;
+ end
+endmodule
+
+module GP_DFFSI(input D, CLK, nSET, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ initial nQ = INIT;
+ always @(posedge CLK, negedge nSET) begin
+ if (!nSET)
+ nQ <= 1'b0;
+ else
+ nQ <= ~D;
+ end
+endmodule
+
+module GP_DFFSR(input D, CLK, nSR, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ parameter [0:0] SRMODE = 1'bx;
+ initial Q = INIT;
+ always @(posedge CLK, negedge nSR) begin
+ if (!nSR)
+ Q <= SRMODE;
+ else
+ Q <= D;
+ end
+endmodule
+
+module GP_DFFSRI(input D, CLK, nSR, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ parameter [0:0] SRMODE = 1'bx;
+ initial nQ = INIT;
+ always @(posedge CLK, negedge nSR) begin
+ if (!nSR)
+ nQ <= ~SRMODE;
+ else
+ nQ <= ~D;
+ end
+endmodule
+
+module GP_DLATCH(input D, input nCLK, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ initial Q = INIT;
+ always @(*) begin
+ if(!nCLK)
+ Q <= D;
+ end
+endmodule
+
+module GP_DLATCHI(input D, input nCLK, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ initial nQ = INIT;
+ always @(*) begin
+ if(!nCLK)
+ nQ <= ~D;
+ end
+endmodule
+
+module GP_DLATCHR(input D, input nCLK, input nRST, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ initial Q = INIT;
+ always @(*) begin
+ if(!nRST)
+ Q <= 1'b0;
+ else if(!nCLK)
+ Q <= D;
+ end
+endmodule
+
+module GP_DLATCHRI(input D, input nCLK, input nRST, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ initial nQ = INIT;
+ always @(*) begin
+ if(!nRST)
+ nQ <= 1'b1;
+ else if(!nCLK)
+ nQ <= ~D;
+ end
+endmodule
+
+module GP_DLATCHS(input D, input nCLK, input nSET, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ initial Q = INIT;
+ always @(*) begin
+ if(!nSET)
+ Q <= 1'b1;
+ else if(!nCLK)
+ Q <= D;
+ end
+endmodule
+
+module GP_DLATCHSI(input D, input nCLK, input nSET, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ initial nQ = INIT;
+ always @(*) begin
+ if(!nSET)
+ nQ <= 1'b0;
+ else if(!nCLK)
+ nQ <= ~D;
+ end
+endmodule
+
+module GP_DLATCHSR(input D, input nCLK, input nSR, output reg Q);
+ parameter [0:0] INIT = 1'bx;
+ parameter[0:0] SRMODE = 1'bx;
+ initial Q = INIT;
+ always @(*) begin
+ if(!nSR)
+ Q <= SRMODE;
+ else if(!nCLK)
+ Q <= D;
+ end
+endmodule
+
+module GP_DLATCHSRI(input D, input nCLK, input nSR, output reg nQ);
+ parameter [0:0] INIT = 1'bx;
+ parameter[0:0] SRMODE = 1'bx;
+ initial nQ = INIT;
+ always @(*) begin
+ if(!nSR)
+ nQ <= ~SRMODE;
+ else if(!nCLK)
+ nQ <= ~D;
+ end
+endmodule
+
+module GP_IBUF(input IN, output OUT);
+ assign OUT = IN;
+endmodule
+
+module GP_IOBUF(input IN, input OE, output OUT, inout IO);
+ assign OUT = IO;
+ assign IO = OE ? IN : 1'bz;
+endmodule
+
+module GP_INV(input IN, output OUT);
+ assign OUT = ~IN;
+endmodule
+
+module GP_OBUF(input IN, output OUT);
+ assign OUT = IN;
+endmodule
+
+module GP_OBUFT(input IN, input OE, output OUT);
+ assign OUT = OE ? IN : 1'bz;
+endmodule
+
+module GP_PGEN(input wire nRST, input wire CLK, output reg OUT);
+ initial OUT = 0;
+ parameter PATTERN_DATA = 16'h0;
+ parameter PATTERN_LEN = 5'd16;
+
+ localparam COUNT_MAX = PATTERN_LEN - 1'h1;
+
+ reg[3:0] count = 0;
+ always @(posedge CLK, negedge nRST) begin
+
+ if(!nRST)
+ count <= 0;
+
+ else begin
+ count <= count - 1'h1;
+ if(count == 0)
+ count <= COUNT_MAX;
+ end
+ end
+
+ always @(*)
+ OUT = PATTERN_DATA[count];
+
+endmodule
+
+module GP_SHREG(input nRST, input CLK, input IN, output OUTA, output OUTB);
+
+ parameter OUTA_TAP = 1;
+ parameter OUTA_INVERT = 0;
+ parameter OUTB_TAP = 1;
+
+ reg[15:0] shreg = 0;
+
+ always @(posedge CLK, negedge nRST) begin
+
+ if(!nRST)
+ shreg = 0;
+
+ else
+ shreg <= {shreg[14:0], IN};
+
+ end
+
+ assign OUTA = (OUTA_INVERT) ? ~shreg[OUTA_TAP - 1] : shreg[OUTA_TAP - 1];
+ assign OUTB = shreg[OUTB_TAP - 1];
+
+endmodule
+
+module GP_VDD(output OUT);
+ assign OUT = 1;
+endmodule
+
+module GP_VSS(output OUT);
+ assign OUT = 0;
+endmodule
diff --git a/techlibs/greenpak4/cells_sim_wip.v b/techlibs/greenpak4/cells_sim_wip.v
new file mode 100644
index 00000000..5261b12d
--- /dev/null
+++ b/techlibs/greenpak4/cells_sim_wip.v
@@ -0,0 +1,136 @@
+
+//Cells still in this file have INCOMPLETE simulation models, need to finish them
+
+module GP_DCMP(input[7:0] INP, input[7:0] INN, input CLK, input PWRDN, output reg GREATER, output reg EQUAL);
+ parameter PWRDN_SYNC = 1'b0;
+ parameter CLK_EDGE = "RISING";
+ parameter GREATER_OR_EQUAL = 1'b0;
+
+ //TODO implement power-down mode
+
+ initial GREATER = 0;
+ initial EQUAL = 0;
+
+ wire clk_minv = (CLK_EDGE == "RISING") ? CLK : ~CLK;
+ always @(posedge clk_minv) begin
+ if(GREATER_OR_EQUAL)
+ GREATER <= (INP >= INN);
+ else
+ GREATER <= (INP > INN);
+
+ EQUAL <= (INP == INN);
+ end
+
+endmodule
+
+module GP_EDGEDET(input IN, output reg OUT);
+
+ parameter EDGE_DIRECTION = "RISING";
+ parameter DELAY_STEPS = 1;
+ parameter GLITCH_FILTER = 0;
+
+ //not implemented for simulation
+
+endmodule
+
+module GP_RCOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC);
+
+ parameter PWRDN_EN = 0;
+ parameter AUTO_PWRDN = 0;
+ parameter HARDIP_DIV = 1;
+ parameter FABRIC_DIV = 1;
+ parameter OSC_FREQ = "25k";
+
+ initial CLKOUT_HARDIP = 0;
+ initial CLKOUT_FABRIC = 0;
+
+ //output dividers not implemented for simulation
+ //auto powerdown not implemented for simulation
+
+ always begin
+ if(PWRDN) begin
+ CLKOUT_HARDIP = 0;
+ CLKOUT_FABRIC = 0;
+ end
+ else begin
+
+ if(OSC_FREQ == "25k") begin
+ //half period of 25 kHz
+ #20000;
+ end
+
+ else begin
+ //half period of 2 MHz
+ #250;
+ end
+
+ CLKOUT_HARDIP = ~CLKOUT_HARDIP;
+ CLKOUT_FABRIC = ~CLKOUT_FABRIC;
+ end
+ end
+
+endmodule
+
+module GP_RINGOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC);
+
+ parameter PWRDN_EN = 0;
+ parameter AUTO_PWRDN = 0;
+ parameter HARDIP_DIV = 1;
+ parameter FABRIC_DIV = 1;
+
+ initial CLKOUT_HARDIP = 0;
+ initial CLKOUT_FABRIC = 0;
+
+ //output dividers not implemented for simulation
+ //auto powerdown not implemented for simulation
+
+ always begin
+ if(PWRDN) begin
+ CLKOUT_HARDIP = 0;
+ CLKOUT_FABRIC = 0;
+ end
+ else begin
+ //half period of 27 MHz
+ #18.518;
+ CLKOUT_HARDIP = ~CLKOUT_HARDIP;
+ CLKOUT_FABRIC = ~CLKOUT_FABRIC;
+ end
+ end
+
+endmodule
+
+module GP_SPI(
+ input SCK,
+ inout SDAT,
+ input CSN,
+ input[7:0] TXD_HIGH,
+ input[7:0] TXD_LOW,
+ output reg[7:0] RXD_HIGH,
+ output reg[7:0] RXD_LOW,
+ output reg INT);
+
+ initial RXD_HIGH = 0;
+ initial RXD_LOW = 0;
+ initial INT = 0;
+
+ parameter DATA_WIDTH = 8; //byte or word width
+ parameter SPI_CPHA = 0; //SPI clock phase
+ parameter SPI_CPOL = 0; //SPI clock polarity
+ parameter DIRECTION = "INPUT"; //SPI data direction (either input to chip or output to host)
+ //parallel output to fabric not yet implemented
+
+ //TODO: write sim model
+ //TODO: SPI SDIO control... can we use ADC output while SPI is input??
+ //TODO: clock sync
+
+endmodule
+
+//keep constraint needed to prevent optimization since we have no outputs
+(* keep *)
+module GP_SYSRESET(input RST);
+ parameter RESET_MODE = "EDGE";
+ parameter EDGE_SPEED = 4;
+
+ //cannot simulate whole system reset
+
+endmodule
diff --git a/techlibs/greenpak4/greenpak4_dffinv.cc b/techlibs/greenpak4/greenpak4_dffinv.cc
index ff63958e..d57e978a 100644
--- a/techlibs/greenpak4/greenpak4_dffinv.cc
+++ b/techlibs/greenpak4/greenpak4_dffinv.cc
@@ -26,6 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
void invert_gp_dff(Cell *cell, bool invert_input)
{
string cell_type = cell->type.str();
+ bool cell_type_latch = cell_type.find("LATCH") != string::npos;
bool cell_type_i = cell_type.find('I') != string::npos;
bool cell_type_r = cell_type.find('R') != string::npos;
bool cell_type_s = cell_type.find('S') != string::npos;
@@ -79,25 +80,28 @@ void invert_gp_dff(Cell *cell, bool invert_input)
cell_type_i = true;
}
- cell->type = stringf("\\GP_DFF%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : "");
+ if(cell_type_latch)
+ cell->type = stringf("\\GP_DLATCH%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : "");
+ else
+ cell->type = stringf("\\GP_DFF%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : "");
log("Merged %s inverter into cell %s.%s: %s -> %s\n", invert_input ? "input" : "output",
log_id(cell->module), log_id(cell), cell_type.c_str()+1, log_id(cell->type));
}
struct Greenpak4DffInvPass : public Pass {
- Greenpak4DffInvPass() : Pass("greenpak4_dffinv", "merge greenpak4 inverters and DFFs") { }
- virtual void help()
+ Greenpak4DffInvPass() : Pass("greenpak4_dffinv", "merge greenpak4 inverters and DFF/latches") { }
+ void help() YS_OVERRIDE
{
log("\n");
log(" greenpak4_dffinv [options] [selection]\n");
log("\n");
- log("Merge GP_INV cells with GP_DFF* cells.\n");
+ log("Merge GP_INV cells with GP_DFF* and GP_DLATCH* cells.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
- log_header(design, "Executing GREENPAK4_DFFINV pass (merge synchronous set/reset into FF cells).\n");
+ log_header(design, "Executing GREENPAK4_DFFINV pass (merge input/output inverters into FF/latch cells).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -120,6 +124,15 @@ struct Greenpak4DffInvPass : public Pass {
gp_dff_types.insert("\\GP_DFFSR");
gp_dff_types.insert("\\GP_DFFSRI");
+ gp_dff_types.insert("\\GP_DLATCH");
+ gp_dff_types.insert("\\GP_DLATCHI");
+ gp_dff_types.insert("\\GP_DLATCHR");
+ gp_dff_types.insert("\\GP_DLATCHRI");
+ gp_dff_types.insert("\\GP_DLATCHS");
+ gp_dff_types.insert("\\GP_DLATCHSI");
+ gp_dff_types.insert("\\GP_DLATCHSR");
+ gp_dff_types.insert("\\GP_DLATCHSRI");
+
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
diff --git a/techlibs/greenpak4/synth_greenpak4.cc b/techlibs/greenpak4/synth_greenpak4.cc
index 10e2a149..b91d5273 100644
--- a/techlibs/greenpak4/synth_greenpak4.cc
+++ b/techlibs/greenpak4/synth_greenpak4.cc
@@ -29,13 +29,15 @@ struct SynthGreenPAK4Pass : public ScriptPass
{
SynthGreenPAK4Pass() : ScriptPass("synth_greenpak4", "synthesis for GreenPAK4 FPGAs") { }
- virtual void help() YS_OVERRIDE
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" synth_greenpak4 [options]\n");
log("\n");
log("This command runs synthesis for GreenPAK4 FPGAs. This work is experimental.\n");
+ log("It is intended to be used with https://github.com/azonenberg/openfpga as the\n");
+ log("place-and-route.\n");
log("\n");
log(" -top <module>\n");
log(" use the specified module as top module (default='top')\n");
@@ -68,7 +70,7 @@ struct SynthGreenPAK4Pass : public ScriptPass
string top_opt, part, json_file;
bool flatten, retime;
- virtual void clear_flags() YS_OVERRIDE
+ void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
part = "SLG46621V";
@@ -77,7 +79,7 @@ struct SynthGreenPAK4Pass : public ScriptPass
retime = false;
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
clear_flags();
@@ -131,7 +133,7 @@ struct SynthGreenPAK4Pass : public ScriptPass
log_pop();
}
- virtual void script() YS_OVERRIDE
+ void script() YS_OVERRIDE
{
if (check_label("begin"))
{
@@ -153,12 +155,13 @@ struct SynthGreenPAK4Pass : public ScriptPass
if (check_label("fine"))
{
- run("greenpak4_counters");
+ run("extract_counter -pout GP_DCMP,GP_DAC -maxwidth 14");
run("clean");
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
run("techmap");
+ run("techmap -map +/greenpak4/cells_latch.v");
run("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib");
run("opt -fast");
if (retime || help_mode)
@@ -201,8 +204,6 @@ struct SynthGreenPAK4Pass : public ScriptPass
if (!json_file.empty() || help_mode)
run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
}
-
- log_pop();
}
} SynthGreenPAK4Pass;
diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v
index 0227ffad..d0ddfd02 100644
--- a/techlibs/ice40/cells_map.v
+++ b/techlibs/ice40/cells_map.v
@@ -27,6 +27,7 @@ module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (
module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
+`ifndef NO_LUT
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
@@ -55,3 +56,4 @@ module \$lut (A, Y);
end
endgenerate
endmodule
+`endif
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index 7778b551..9f73aeb0 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -1,6 +1,6 @@
-`define SB_DFF_REG reg Q = 0;
-// `define SB_DFF_REG reg Q;
+`define SB_DFF_REG reg Q = 0
+// `define SB_DFF_REG reg Q
// SiliconBlue IO Cells
@@ -132,21 +132,18 @@ endmodule
// Positive Edge SiliconBlue FF Cells
-module SB_DFF (output Q, input C, D);
- `SB_DFF_REG
+module SB_DFF (output `SB_DFF_REG, input C, D);
always @(posedge C)
Q <= D;
endmodule
-module SB_DFFE (output Q, input C, E, D);
- `SB_DFF_REG
+module SB_DFFE (output `SB_DFF_REG, input C, E, D);
always @(posedge C)
if (E)
Q <= D;
endmodule
-module SB_DFFSR (output Q, input C, R, D);
- `SB_DFF_REG
+module SB_DFFSR (output `SB_DFF_REG, input C, R, D);
always @(posedge C)
if (R)
Q <= 0;
@@ -154,8 +151,7 @@ module SB_DFFSR (output Q, input C, R, D);
Q <= D;
endmodule
-module SB_DFFR (output Q, input C, R, D);
- `SB_DFF_REG
+module SB_DFFR (output `SB_DFF_REG, input C, R, D);
always @(posedge C, posedge R)
if (R)
Q <= 0;
@@ -163,8 +159,7 @@ module SB_DFFR (output Q, input C, R, D);
Q <= D;
endmodule
-module SB_DFFSS (output Q, input C, S, D);
- `SB_DFF_REG
+module SB_DFFSS (output `SB_DFF_REG, input C, S, D);
always @(posedge C)
if (S)
Q <= 1;
@@ -172,8 +167,7 @@ module SB_DFFSS (output Q, input C, S, D);
Q <= D;
endmodule
-module SB_DFFS (output Q, input C, S, D);
- `SB_DFF_REG
+module SB_DFFS (output `SB_DFF_REG, input C, S, D);
always @(posedge C, posedge S)
if (S)
Q <= 1;
@@ -181,8 +175,7 @@ module SB_DFFS (output Q, input C, S, D);
Q <= D;
endmodule
-module SB_DFFESR (output Q, input C, E, R, D);
- `SB_DFF_REG
+module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D);
always @(posedge C)
if (E) begin
if (R)
@@ -192,8 +185,7 @@ module SB_DFFESR (output Q, input C, E, R, D);
end
endmodule
-module SB_DFFER (output Q, input C, E, R, D);
- `SB_DFF_REG
+module SB_DFFER (output `SB_DFF_REG, input C, E, R, D);
always @(posedge C, posedge R)
if (R)
Q <= 0;
@@ -201,8 +193,7 @@ module SB_DFFER (output Q, input C, E, R, D);
Q <= D;
endmodule
-module SB_DFFESS (output Q, input C, E, S, D);
- `SB_DFF_REG
+module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D);
always @(posedge C)
if (E) begin
if (S)
@@ -212,8 +203,7 @@ module SB_DFFESS (output Q, input C, E, S, D);
end
endmodule
-module SB_DFFES (output Q, input C, E, S, D);
- `SB_DFF_REG
+module SB_DFFES (output `SB_DFF_REG, input C, E, S, D);
always @(posedge C, posedge S)
if (S)
Q <= 1;
@@ -223,21 +213,18 @@ endmodule
// Negative Edge SiliconBlue FF Cells
-module SB_DFFN (output Q, input C, D);
- `SB_DFF_REG
+module SB_DFFN (output `SB_DFF_REG, input C, D);
always @(negedge C)
Q <= D;
endmodule
-module SB_DFFNE (output Q, input C, E, D);
- `SB_DFF_REG
+module SB_DFFNE (output `SB_DFF_REG, input C, E, D);
always @(negedge C)
if (E)
Q <= D;
endmodule
-module SB_DFFNSR (output Q, input C, R, D);
- `SB_DFF_REG
+module SB_DFFNSR (output `SB_DFF_REG, input C, R, D);
always @(negedge C)
if (R)
Q <= 0;
@@ -245,8 +232,7 @@ module SB_DFFNSR (output Q, input C, R, D);
Q <= D;
endmodule
-module SB_DFFNR (output Q, input C, R, D);
- `SB_DFF_REG
+module SB_DFFNR (output `SB_DFF_REG, input C, R, D);
always @(negedge C, posedge R)
if (R)
Q <= 0;
@@ -254,8 +240,7 @@ module SB_DFFNR (output Q, input C, R, D);
Q <= D;
endmodule
-module SB_DFFNSS (output Q, input C, S, D);
- `SB_DFF_REG
+module SB_DFFNSS (output `SB_DFF_REG, input C, S, D);
always @(negedge C)
if (S)
Q <= 1;
@@ -263,8 +248,7 @@ module SB_DFFNSS (output Q, input C, S, D);
Q <= D;
endmodule
-module SB_DFFNS (output Q, input C, S, D);
- `SB_DFF_REG
+module SB_DFFNS (output `SB_DFF_REG, input C, S, D);
always @(negedge C, posedge S)
if (S)
Q <= 1;
@@ -272,8 +256,7 @@ module SB_DFFNS (output Q, input C, S, D);
Q <= D;
endmodule
-module SB_DFFNESR (output Q, input C, E, R, D);
- `SB_DFF_REG
+module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D);
always @(negedge C)
if (E) begin
if (R)
@@ -283,8 +266,7 @@ module SB_DFFNESR (output Q, input C, E, R, D);
end
endmodule
-module SB_DFFNER (output Q, input C, E, R, D);
- `SB_DFF_REG
+module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D);
always @(negedge C, posedge R)
if (R)
Q <= 0;
@@ -292,8 +274,7 @@ module SB_DFFNER (output Q, input C, E, R, D);
Q <= D;
endmodule
-module SB_DFFNESS (output Q, input C, E, S, D);
- `SB_DFF_REG
+module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D);
always @(negedge C)
if (E) begin
if (S)
@@ -303,8 +284,7 @@ module SB_DFFNESS (output Q, input C, E, S, D);
end
endmodule
-module SB_DFFNES (output Q, input C, E, S, D);
- `SB_DFF_REG
+module SB_DFFNES (output `SB_DFF_REG, input C, E, S, D);
always @(negedge C, posedge S)
if (S)
Q <= 1;
@@ -677,7 +657,12 @@ module ICESTORM_LC (
parameter [0:0] SET_NORESET = 0;
parameter [0:0] ASYNC_SR = 0;
- wire COUT = CARRY_ENABLE ? (I1 && I2) || ((I1 || I2) && CIN) : 1'bx;
+ parameter [0:0] CIN_CONST = 0;
+ parameter [0:0] CIN_SET = 0;
+
+ wire mux_cin = CIN_CONST ? CIN_SET : CIN;
+
+ assign COUT = CARRY_ENABLE ? (I1 && I2) || ((I1 || I2) && mux_cin) : 1'bx;
wire [7:0] lut_s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
wire [3:0] lut_s2 = I2 ? lut_s3[ 7:4] : lut_s3[3:0];
@@ -881,3 +866,368 @@ module SB_WARMBOOT (
input S0
);
endmodule
+
+// UltraPlus feature cells
+(* blackbox *)
+module SB_MAC16 (
+ input CLK,
+ input CE,
+ input [15:0] C,
+ input [15:0] A,
+ input [15:0] B,
+ input [15:0] D,
+ input AHOLD,
+ input BHOLD,
+ input CHOLD,
+ input DHOLD,
+ input IRSTTOP,
+ input IRSTBOT,
+ input ORSTTOP,
+ input ORSTBOT,
+ input OLOADTOP,
+ input OLOADBOT,
+ input ADDSUBTOP,
+ input ADDSUBBOT,
+ input OHOLDTOP,
+ input OHOLDBOT,
+ input CI,
+ input ACCUMCI,
+ input SIGNEXTIN,
+ output [31:0] O,
+ output CO,
+ output ACCUMCO,
+ output SIGNEXTOUT
+);
+parameter NEG_TRIGGER = 1'b0;
+parameter C_REG = 1'b0;
+parameter A_REG = 1'b0;
+parameter B_REG = 1'b0;
+parameter D_REG = 1'b0;
+parameter TOP_8x8_MULT_REG = 1'b0;
+parameter BOT_8x8_MULT_REG = 1'b0;
+parameter PIPELINE_16x16_MULT_REG1 = 1'b0;
+parameter PIPELINE_16x16_MULT_REG2 = 1'b0;
+parameter TOPOUTPUT_SELECT = 2'b00;
+parameter TOPADDSUB_LOWERINPUT = 2'b00;
+parameter TOPADDSUB_UPPERINPUT = 1'b0;
+parameter TOPADDSUB_CARRYSELECT = 2'b00;
+parameter BOTOUTPUT_SELECT = 2'b00;
+parameter BOTADDSUB_LOWERINPUT = 2'b00;
+parameter BOTADDSUB_UPPERINPUT = 1'b0;
+parameter BOTADDSUB_CARRYSELECT = 2'b00;
+parameter MODE_8x8 = 1'b0;
+parameter A_SIGNED = 1'b0;
+parameter B_SIGNED = 1'b0;
+endmodule
+
+(* blackbox *)
+module SB_SPRAM256KA(
+ input [13:0] ADDRESS,
+ input [15:0] DATAIN,
+ input [3:0] MASKWREN,
+ input WREN,
+ input CHIPSELECT,
+ input CLOCK,
+ input STANDBY,
+ input SLEEP,
+ input POWEROFF,
+ output [15:0] DATAOUT
+);
+endmodule
+
+(* blackbox *)
+module SB_HFOSC(
+ input CLKHFPU,
+ input CLKHFEN,
+ output CLKHF
+);
+parameter CLKHF_DIV = "0b00";
+endmodule
+
+(* blackbox *)
+module SB_LFOSC(
+ input CLKLFPU,
+ input CLKLFEN,
+ output CLKLF
+);
+endmodule
+
+(* blackbox *)
+module SB_RGBA_DRV(
+ input CURREN,
+ input RGBLEDEN,
+ input RGB0PWM,
+ input RGB1PWM,
+ input RGB2PWM,
+ output RGB0,
+ output RGB1,
+ output RGB2
+);
+parameter CURRENT_MODE = "0b0";
+parameter RGB0_CURRENT = "0b000000";
+parameter RGB1_CURRENT = "0b000000";
+parameter RGB2_CURRENT = "0b000000";
+endmodule
+
+(* blackbox *)
+module SB_I2C(
+ input SBCLKI,
+ input SBRWI,
+ input SBSTBI,
+ input SBADRI7,
+ input SBADRI6,
+ input SBADRI5,
+ input SBADRI4,
+ input SBADRI3,
+ input SBADRI2,
+ input SBADRI1,
+ input SBADRI0,
+ input SBDATI7,
+ input SBDATI6,
+ input SBDATI5,
+ input SBDATI4,
+ input SBDATI3,
+ input SBDATI2,
+ input SBDATI1,
+ input SBDATI0,
+ input SCLI,
+ input SDAI,
+ output SBDATO7,
+ output SBDATO6,
+ output SBDATO5,
+ output SBDATO4,
+ output SBDATO3,
+ output SBDATO2,
+ output SBDATO1,
+ output SBDATO0,
+ output SBACKO,
+ output I2CIRQ,
+ output I2CWKUP,
+ output SCLO, //inout in the SB verilog library, but output in the VHDL and PDF libs and seemingly in the HW itself
+ output SCLOE,
+ output SDAO,
+ output SDAOE
+);
+parameter I2C_SLAVE_INIT_ADDR = "0b1111100001";
+parameter BUS_ADDR74 = "0b0001";
+endmodule
+
+(* blackbox *)
+module SB_SPI (
+ input SBCLKI,
+ input SBRWI,
+ input SBSTBI,
+ input SBADRI7,
+ input SBADRI6,
+ input SBADRI5,
+ input SBADRI4,
+ input SBADRI3,
+ input SBADRI2,
+ input SBADRI1,
+ input SBADRI0,
+ input SBDATI7,
+ input SBDATI6,
+ input SBDATI5,
+ input SBDATI4,
+ input SBDATI3,
+ input SBDATI2,
+ input SBDATI1,
+ input SBDATI0,
+ input MI,
+ input SI,
+ input SCKI,
+ input SCSNI,
+ output SBDATO7,
+ output SBDATO6,
+ output SBDATO5,
+ output SBDATO4,
+ output SBDATO3,
+ output SBDATO2,
+ output SBDATO1,
+ output SBDATO0,
+ output SBACKO,
+ output SPIIRQ,
+ output SPIWKUP,
+ output SO,
+ output SOE,
+ output MO,
+ output MOE,
+ output SCKO, //inout in the SB verilog library, but output in the VHDL and PDF libs and seemingly in the HW itself
+ output SCKOE,
+ output MCSNO3,
+ output MCSNO2,
+ output MCSNO1,
+ output MCSNO0,
+ output MCSNOE3,
+ output MCSNOE2,
+ output MCSNOE1,
+ output MCSNOE0
+);
+parameter BUS_ADDR74 = "0b0000";
+endmodule
+
+(* blackbox *)
+module SB_LEDDA_IP(
+ input LEDDCS,
+ input LEDDCLK,
+ input LEDDDAT7,
+ input LEDDDAT6,
+ input LEDDDAT5,
+ input LEDDDAT4,
+ input LEDDDAT3,
+ input LEDDDAT2,
+ input LEDDDAT1,
+ input LEDDDAT0,
+ input LEDDADDR3,
+ input LEDDADDR2,
+ input LEDDADDR1,
+ input LEDDADDR0,
+ input LEDDDEN,
+ input LEDDEXE,
+ input LEDDRST,
+ output PWMOUT0,
+ output PWMOUT1,
+ output PWMOUT2,
+ output LEDDON
+);
+endmodule
+
+(* blackbox *)
+module SB_FILTER_50NS(
+ input FILTERIN,
+ output FILTEROUT
+);
+endmodule
+
+module SB_IO_I3C (
+ inout PACKAGE_PIN,
+ input LATCH_INPUT_VALUE,
+ input CLOCK_ENABLE,
+ input INPUT_CLK,
+ input OUTPUT_CLK,
+ input OUTPUT_ENABLE,
+ input D_OUT_0,
+ input D_OUT_1,
+ output D_IN_0,
+ output D_IN_1,
+ input PU_ENB,
+ input WEAK_PU_ENB
+);
+ parameter [5:0] PIN_TYPE = 6'b000000;
+ parameter [0:0] PULLUP = 1'b0;
+ parameter [0:0] WEAK_PULLUP = 1'b0;
+ parameter [0:0] NEG_TRIGGER = 1'b0;
+ parameter IO_STANDARD = "SB_LVCMOS";
+
+`ifndef BLACKBOX
+ reg dout, din_0, din_1;
+ reg din_q_0, din_q_1;
+ reg dout_q_0, dout_q_1;
+ reg outena_q;
+
+ generate if (!NEG_TRIGGER) begin
+ always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN;
+ always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN;
+ always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0;
+ always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1;
+ always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE;
+ end else begin
+ always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN;
+ always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN;
+ always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0;
+ always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1;
+ always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE;
+ end endgenerate
+
+ always @* begin
+ if (!PIN_TYPE[1] || !LATCH_INPUT_VALUE)
+ din_0 = PIN_TYPE[0] ? PACKAGE_PIN : din_q_0;
+ din_1 = din_q_1;
+ end
+
+ // work around simulation glitches on dout in DDR mode
+ reg outclk_delayed_1;
+ reg outclk_delayed_2;
+ always @* outclk_delayed_1 <= OUTPUT_CLK;
+ always @* outclk_delayed_2 <= outclk_delayed_1;
+
+ always @* begin
+ if (PIN_TYPE[3])
+ dout = PIN_TYPE[2] ? !dout_q_0 : D_OUT_0;
+ else
+ dout = (outclk_delayed_2 ^ NEG_TRIGGER) || PIN_TYPE[2] ? dout_q_0 : dout_q_1;
+ end
+
+ assign D_IN_0 = din_0, D_IN_1 = din_1;
+
+ generate
+ if (PIN_TYPE[5:4] == 2'b01) assign PACKAGE_PIN = dout;
+ if (PIN_TYPE[5:4] == 2'b10) assign PACKAGE_PIN = OUTPUT_ENABLE ? dout : 1'bz;
+ if (PIN_TYPE[5:4] == 2'b11) assign PACKAGE_PIN = outena_q ? dout : 1'bz;
+ endgenerate
+`endif
+endmodule
+
+module SB_IO_OD (
+ inout PACKAGEPIN,
+ input LATCHINPUTVALUE,
+ input CLOCKENABLE,
+ input INPUTCLK,
+ input OUTPUTCLK,
+ input OUTPUTENABLE,
+ input DOUT1,
+ input DOUT0,
+ output DIN1,
+ output DIN0
+);
+ parameter [5:0] PIN_TYPE = 6'b000000;
+ parameter [0:0] NEG_TRIGGER = 1'b0;
+
+`ifndef BLACKBOX
+ reg dout, din_0, din_1;
+ reg din_q_0, din_q_1;
+ reg dout_q_0, dout_q_1;
+ reg outena_q;
+
+ generate if (!NEG_TRIGGER) begin
+ always @(posedge INPUTCLK) if (CLOCKENABLE) din_q_0 <= PACKAGEPIN;
+ always @(negedge INPUTCLK) if (CLOCKENABLE) din_q_1 <= PACKAGEPIN;
+ always @(posedge OUTPUTCLK) if (CLOCKENABLE) dout_q_0 <= DOUT0;
+ always @(negedge OUTPUTCLK) if (CLOCKENABLE) dout_q_1 <= DOUT1;
+ always @(posedge OUTPUTCLK) if (CLOCKENABLE) outena_q <= OUTPUTENABLE;
+ end else begin
+ always @(negedge INPUTCLK) if (CLOCKENABLE) din_q_0 <= PACKAGEPIN;
+ always @(posedge INPUTCLK) if (CLOCKENABLE) din_q_1 <= PACKAGEPIN;
+ always @(negedge OUTPUTCLK) if (CLOCKENABLE) dout_q_0 <= DOUT0;
+ always @(posedge OUTPUTCLK) if (CLOCKENABLE) dout_q_1 <= DOUT1;
+ always @(negedge OUTPUTCLK) if (CLOCKENABLE) outena_q <= OUTPUTENABLE;
+ end endgenerate
+
+ always @* begin
+ if (!PIN_TYPE[1] || !LATCHINPUTVALUE)
+ din_0 = PIN_TYPE[0] ? PACKAGEPIN : din_q_0;
+ din_1 = din_q_1;
+ end
+
+ // work around simulation glitches on dout in DDR mode
+ reg outclk_delayed_1;
+ reg outclk_delayed_2;
+ always @* outclk_delayed_1 <= OUTPUTCLK;
+ always @* outclk_delayed_2 <= outclk_delayed_1;
+
+ always @* begin
+ if (PIN_TYPE[3])
+ dout = PIN_TYPE[2] ? !dout_q_0 : DOUT0;
+ else
+ dout = (outclk_delayed_2 ^ NEG_TRIGGER) || PIN_TYPE[2] ? dout_q_0 : dout_q_1;
+ end
+
+ assign DIN0 = din_0, DIN1 = din_1;
+
+ generate
+ if (PIN_TYPE[5:4] == 2'b01) assign PACKAGEPIN = dout ? 1'bz : 1'b0;
+ if (PIN_TYPE[5:4] == 2'b10) assign PACKAGEPIN = OUTPUTENABLE ? (dout ? 1'bz : 1'b0) : 1'bz;
+ if (PIN_TYPE[5:4] == 2'b11) assign PACKAGEPIN = outena_q ? (dout ? 1'bz : 1'b0) : 1'bz;
+ endgenerate
+`endif
+endmodule
diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc
index c914b20e..3089d893 100644
--- a/techlibs/ice40/ice40_ffinit.cc
+++ b/techlibs/ice40/ice40_ffinit.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct Ice40FfinitPass : public Pass {
Ice40FfinitPass() : Pass("ice40_ffinit", "iCE40: handle FF init values") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -35,7 +35,7 @@ struct Ice40FfinitPass : public Pass {
log("nonzero init values.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ICE40_FFINIT pass (implement FF init values).\n");
diff --git a/techlibs/ice40/ice40_ffssr.cc b/techlibs/ice40/ice40_ffssr.cc
index 9afbc0fc..668df09d 100644
--- a/techlibs/ice40/ice40_ffssr.cc
+++ b/techlibs/ice40/ice40_ffssr.cc
@@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN
struct Ice40FfssrPass : public Pass {
Ice40FfssrPass() : Pass("ice40_ffssr", "iCE40: merge synchronous set/reset into FF cells") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
log("\n");
log(" ice40_ffssr [options] [selection]\n");
@@ -33,7 +33,7 @@ struct Ice40FfssrPass : public Pass {
log("Merge synchronous set/reset $_MUX_ cells into iCE40 FFs.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n");
diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc
index ae72f5d6..16274005 100644
--- a/techlibs/ice40/ice40_opt.cc
+++ b/techlibs/ice40/ice40_opt.cc
@@ -26,6 +26,13 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+static SigBit get_bit_or_zero(const SigSpec &sig)
+{
+ if (GetSize(sig) == 0)
+ return State::S0;
+ return sig[0];
+}
+
static void run_ice40_opts(Module *module, bool unlut_mode)
{
pool<SigBit> optimized_co;
@@ -45,7 +52,11 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
SigSpec non_const_inputs, replacement_output;
int count_zeros = 0, count_ones = 0;
- SigBit inbit[3] = {cell->getPort("\\I0"), cell->getPort("\\I1"), cell->getPort("\\CI")};
+ SigBit inbit[3] = {
+ get_bit_or_zero(cell->getPort("\\I0")),
+ get_bit_or_zero(cell->getPort("\\I1")),
+ get_bit_or_zero(cell->getPort("\\CI"))
+ };
for (int i = 0; i < 3; i++)
if (inbit[i].wire == nullptr) {
if (inbit[i] == State::S1)
@@ -63,8 +74,8 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
replacement_output = non_const_inputs;
if (GetSize(replacement_output)) {
- optimized_co.insert(sigmap(cell->getPort("\\CO")));
- module->connect(cell->getPort("\\CO"), replacement_output);
+ optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
+ module->connect(cell->getPort("\\CO")[0], replacement_output);
module->design->scratchpad_set_bool("opt.did_something", true);
log("Optimized away SB_CARRY cell %s.%s: CO=%s\n",
log_id(module), log_id(cell), log_signal(replacement_output));
@@ -78,10 +89,10 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
{
SigSpec inbits;
- inbits.append(cell->getPort("\\I0"));
- inbits.append(cell->getPort("\\I1"));
- inbits.append(cell->getPort("\\I2"));
- inbits.append(cell->getPort("\\I3"));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I0")));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I1")));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I2")));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
sigmap.apply(inbits);
if (unlut_mode)
@@ -104,8 +115,13 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
cell->setParam("\\LUT", cell->getParam("\\LUT_INIT"));
cell->unsetParam("\\LUT_INIT");
- cell->setPort("\\A", SigSpec({cell->getPort("\\I3"), cell->getPort("\\I2"), cell->getPort("\\I1"), cell->getPort("\\I0")}));
- cell->setPort("\\Y", cell->getPort("\\O"));
+ cell->setPort("\\A", SigSpec({
+ get_bit_or_zero(cell->getPort("\\I3")),
+ get_bit_or_zero(cell->getPort("\\I2")),
+ get_bit_or_zero(cell->getPort("\\I1")),
+ get_bit_or_zero(cell->getPort("\\I0"))
+ }));
+ cell->setPort("\\Y", cell->getPort("\\O")[0]);
cell->unsetPort("\\I0");
cell->unsetPort("\\I1");
cell->unsetPort("\\I2");
@@ -120,7 +136,7 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
struct Ice40OptPass : public Pass {
Ice40OptPass() : Pass("ice40_opt", "iCE40: perform simple optimizations") { }
- virtual void help()
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -140,7 +156,7 @@ struct Ice40OptPass : public Pass {
log("mapped SB_LUT4 cells back to logic.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string opt_expr_args = "-mux_undef -undriven";
bool unlut_mode = false;
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index 2533d3af..b0687e5e 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -29,7 +29,7 @@ struct SynthIce40Pass : public ScriptPass
{
SynthIce40Pass() : ScriptPass("synth_ice40", "synthesis for iCE40 FPGAs") { }
- virtual void help() YS_OVERRIDE
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -38,14 +38,18 @@ struct SynthIce40Pass : public ScriptPass
log("This command runs synthesis for iCE40 FPGAs.\n");
log("\n");
log(" -top <module>\n");
- log(" use the specified module as top module (default='top')\n");
+ log(" use the specified module as top module\n");
log("\n");
log(" -blif <file>\n");
log(" write the design to the specified BLIF file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
log(" -edif <file>\n");
- log(" write the design to the specified edif file. writing of an output file\n");
+ log(" write the design to the specified EDIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -json <file>\n");
+ log(" write the design to the specified JSON file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
log(" -run <from_label>:<to_label>\n");
@@ -62,34 +66,44 @@ struct SynthIce40Pass : public ScriptPass
log(" -nocarry\n");
log(" do not use SB_CARRY cells in output netlist\n");
log("\n");
+ log(" -nodffe\n");
+ log(" do not use SB_DFFE* cells in output netlist\n");
+ log("\n");
log(" -nobram\n");
log(" do not use SB_RAM40_4K* cells in output netlist\n");
log("\n");
log(" -abc2\n");
log(" run two passes of 'abc' for slightly improved logic density\n");
log("\n");
+ log(" -vpr\n");
+ log(" generate an output netlist (and BLIF file) suitable for VPR\n");
+ log(" (this feature is experimental and incomplete)\n");
+ log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
- string top_opt, blif_file, edif_file;
- bool nocarry, nobram, flatten, retime, abc2;
+ string top_opt, blif_file, edif_file, json_file;
+ bool nocarry, nodffe, nobram, flatten, retime, abc2, vpr;
- virtual void clear_flags() YS_OVERRIDE
+ void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
blif_file = "";
edif_file = "";
+ json_file = "";
nocarry = false;
+ nodffe = false;
nobram = false;
flatten = true;
retime = false;
abc2 = false;
+ vpr = false;
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
clear_flags();
@@ -109,6 +123,10 @@ struct SynthIce40Pass : public ScriptPass
edif_file = args[++argidx];
continue;
}
+ if (args[argidx] == "-json" && argidx+1 < args.size()) {
+ json_file = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-run" && argidx+1 < args.size()) {
size_t pos = args[argidx+1].find(':');
if (pos == std::string::npos)
@@ -133,6 +151,10 @@ struct SynthIce40Pass : public ScriptPass
nocarry = true;
continue;
}
+ if (args[argidx] == "-nodffe") {
+ nodffe = true;
+ continue;
+ }
if (args[argidx] == "-nobram") {
nobram = true;
continue;
@@ -141,6 +163,10 @@ struct SynthIce40Pass : public ScriptPass
abc2 = true;
continue;
}
+ if (args[argidx] == "-vpr") {
+ vpr = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -156,7 +182,7 @@ struct SynthIce40Pass : public ScriptPass
log_pop();
}
- virtual void script() YS_OVERRIDE
+ void script() YS_OVERRIDE
{
if (check_label("begin"))
{
@@ -200,8 +226,9 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("map_ffs"))
{
run("dffsr2dff");
- run("dff2dffe -direct-match $_DFF_*");
- run("techmap -map +/ice40/cells_map.v");
+ if (!nodffe)
+ run("dff2dffe -direct-match $_DFF_*");
+ run("techmap -D NO_LUT -map +/ice40/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
run("ice40_ffinit");
@@ -222,7 +249,11 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("map_cells"))
{
- run("techmap -map +/ice40/cells_map.v");
+ if (vpr)
+ run("techmap -D NO_LUT -map +/ice40/cells_map.v");
+ else
+ run("techmap -map +/ice40/cells_map.v", "(with -D NO_LUT in vpr mode)");
+
run("clean");
}
@@ -235,8 +266,19 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("blif"))
{
- if (!blif_file.empty() || help_mode)
- run(stringf("write_blif -gates -attr -param %s", help_mode ? "<file-name>" : blif_file.c_str()));
+ if (!blif_file.empty() || help_mode) {
+ if (vpr || help_mode) {
+ run(stringf("opt_clean -purge"),
+ " (vpr mode)");
+ run(stringf("write_blif -attr -cname -conn -param %s",
+ help_mode ? "<file-name>" : blif_file.c_str()),
+ " (vpr mode)");
+ }
+ if (!vpr)
+ run(stringf("write_blif -gates -attr -param %s",
+ help_mode ? "<file-name>" : blif_file.c_str()),
+ " (non-vpr mode)");
+ }
}
if (check_label("edif"))
@@ -244,6 +286,12 @@ struct SynthIce40Pass : public ScriptPass
if (!edif_file.empty() || help_mode)
run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
}
+
+ if (check_label("json"))
+ {
+ if (!json_file.empty() || help_mode)
+ run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
+ }
}
} SynthIce40Pass;
diff --git a/techlibs/intel/Makefile.inc b/techlibs/intel/Makefile.inc
new file mode 100644
index 00000000..ec7cea37
--- /dev/null
+++ b/techlibs/intel/Makefile.inc
@@ -0,0 +1,24 @@
+
+OBJS += techlibs/intel/synth_intel.o
+
+$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/m9k_bb.v))
+$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/altpll_bb.v))
+$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams.txt))
+$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map.v))
+$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/cells_sim.v))
+$(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/cells_sim.v))
+$(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_sim.v))
+$(eval $(call add_share_file,share/intel/cyclone10,techlibs/intel/cyclone10/cells_sim.v))
+$(eval $(call add_share_file,share/intel/cycloneiv,techlibs/intel/cycloneiv/cells_sim.v))
+$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/cells_sim.v))
+$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/cells_map.v))
+$(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/cells_map.v))
+$(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_map.v))
+$(eval $(call add_share_file,share/intel/cyclone10,techlibs/intel/cyclone10/cells_map.v))
+$(eval $(call add_share_file,share/intel/cycloneiv,techlibs/intel/cycloneiv/cells_map.v))
+$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/cells_map.v))
+#$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/arith_map.v))
+#$(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/arith_map.v))
+#$(eval $(call add_share_file,share/intel/cycloneiv,techlibs/intel/cycloneiv/arith_map.v))
+#$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/arith_map.v))
+
diff --git a/techlibs/intel/a10gx/cells_arith.v b/techlibs/intel/a10gx/cells_arith.v
new file mode 100644
index 00000000..89fb4561
--- /dev/null
+++ b/techlibs/intel/a10gx/cells_arith.v
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ */
+
+// NOTE: This is still WIP.
+(* techmap_celltype = "$alu" *)
+module _80_altera_a10gx_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;
+ output CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$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:0] C = {CO, CI};
+ wire [Y_WIDTH+1:0] COx;
+ wire [Y_WIDTH+1:0] C = {COx, CI};
+
+ /* Start implementation */
+ (* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b0000_0000_1010_1010), .sum_lutc_input("cin")) carry_start (.cout(COx[0]), .dataa(C[0]), .datab(1'b1), .datac(1'b1), .datad(1'b1));
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
+ if(i==Y_WIDTH-1) begin
+ (* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b1111_0000_1110_0000), .sum_lutc_input("cin")) carry_end (.combout(COx[Y_WIDTH]), .dataa(1'b1), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[Y_WIDTH]));
+ assign CO = COx[Y_WIDTH];
+ end
+ else
+ fiftyfivenm_lcell_comb #(.lut_mask(16'b1001_0110_1110_1000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(COx[i+1]), .dataa(AA[i]), .datab(BB[i]), .datac(1'b1), .datad(1'b1), .cin(C[i+1]));
+ end: slice
+ endgenerate
+ /* End implementation */
+ assign X = AA ^ BB;
+
+endmodule
diff --git a/techlibs/intel/a10gx/cells_map.v b/techlibs/intel/a10gx/cells_map.v
new file mode 100644
index 00000000..1430e855
--- /dev/null
+++ b/techlibs/intel/a10gx/cells_map.v
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ */
+// Input buffer map
+module \$__inpad (input I, output O);
+ twentynm_io_ibuf _TECHMAP_REPLACE_ (.o(O), .i(I), .ibar(1'b0));
+endmodule
+
+// Output buffer map
+module \$__outpad (input I, output O);
+ twentynm_io_obuf _TECHMAP_REPLACE_ (.o(O), .i(I), .oe(1'b1));
+endmodule
+
+// LUT Map
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+ input [WIDTH-1:0] A;
+ output Y;
+ generate
+ if (WIDTH == 1) begin
+ assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
+ end else
+ if (WIDTH == 2) begin
+ twentynm_lcell_comb #(.lut_mask({16{LUT}}), .shared_arith("off"), .extended_lut("off"))
+ _TECHMAP_REPLACE_ (.combout(Y), .dataa(A[0]), .datab(A[1]), .datac(1'b1),.datad(1'b1), .datae(1'b1), .dataf(1'b1), .datag(1'b1));
+ end /*else
+ if(WIDTH == 3) begin
+ fiftyfivenm_lcell_comb #(.lut_mask({2{LUT}}), .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y), .dataa(A[0]), .datab(A[1]), .datac(A[2]),.datad(1'b1));
+ end else
+ if(WIDTH == 4) begin
+ fiftyfivenm_lcell_comb #(.lut_mask(LUT), .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y), .dataa(A[0]), .datab(A[1]), .datac(A[2]),.datad(A[3]));
+ end*/ else
+ wire _TECHMAP_FAIL_ = 1;
+ endgenerate
+endmodule //
+
+
diff --git a/techlibs/intel/a10gx/cells_sim.v b/techlibs/intel/a10gx/cells_sim.v
new file mode 100644
index 00000000..e892b377
--- /dev/null
+++ b/techlibs/intel/a10gx/cells_sim.v
@@ -0,0 +1,59 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+module VCC (output V);
+ assign V = 1'b1;
+endmodule // VCC
+
+module GND (output G);
+ assign G = 1'b0;
+endmodule // GND
+
+/* Altera Arria 10 GX devices Input Buffer Primitive */
+module twentynm_io_ibuf (output o, input i, input ibar);
+ assign ibar = ibar;
+ assign o = i;
+endmodule // twentynm_io_ibuf
+
+/* Altera Arria 10 GX devices Output Buffer Primitive */
+module twentynm_io_obuf (output o, input i, input oe);
+ assign o = i;
+ assign oe = oe;
+endmodule // twentynm_io_obuf
+
+/* Altera Arria 10 GX LUT Primitive */
+module twentynm_lcell_comb (output combout, cout, sumout,
+ input dataa, datab, datac, datad,
+ input datae, dataf, datag, cin,
+ input sharein);
+
+parameter lut_mask = 64'hFFFFFFFFFFFFFFFF;
+parameter dont_touch = "off";
+parameter lpm_type = "twentynm_lcell_comb";
+parameter shared_arith = "off";
+parameter extended_lut = "off";
+
+// TODO: This is still WIP
+initial begin
+ $display("Simulation model is still under investigation\n");
+end
+
+endmodule // twentynm_lcell_comb
+
+
+
diff --git a/techlibs/intel/common/altpll_bb.v b/techlibs/intel/common/altpll_bb.v
new file mode 100644
index 00000000..d2e6a364
--- /dev/null
+++ b/techlibs/intel/common/altpll_bb.v
@@ -0,0 +1,366 @@
+/*
+ * 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.
+ *
+ */
+/* No clearbox model */
+`ifdef NO_CLEARBOX
+(* blackbox *)
+module altpll
+ ( inclk,
+ fbin,
+ pllena,
+ clkswitch,
+ areset,
+ pfdena,
+ clkena,
+ extclkena,
+ scanclk,
+ scanaclr,
+ scanclkena,
+ scanread,
+ scanwrite,
+ scandata,
+ phasecounterselect,
+ phaseupdown,
+ phasestep,
+ configupdate,
+ fbmimicbidir,
+ clk,
+ extclk,
+ clkbad,
+ enable0,
+ enable1,
+ activeclock,
+ clkloss,
+ locked,
+ scandataout,
+ scandone,
+ sclkout0,
+ sclkout1,
+ phasedone,
+ vcooverrange,
+ vcounderrange,
+ fbout,
+ fref,
+ icdrclk,
+ c0,
+ c1,
+ c2,
+ c3,
+ c4);
+
+ parameter intended_device_family = "MAX 10";
+ parameter operation_mode = "NORMAL";
+ parameter pll_type = "AUTO";
+ parameter qualify_conf_done = "OFF";
+ parameter compensate_clock = "CLK0";
+ parameter scan_chain = "LONG";
+ parameter primary_clock = "inclk0";
+ parameter inclk0_input_frequency = 1000;
+ parameter inclk1_input_frequency = 0;
+ parameter gate_lock_signal = "NO";
+ parameter gate_lock_counter = 0;
+ parameter lock_high = 1;
+ parameter lock_low = 0;
+ parameter valid_lock_multiplier = 1;
+ parameter invalid_lock_multiplier = 5;
+ parameter switch_over_type = "AUTO";
+ parameter switch_over_on_lossclk = "OFF" ;
+ parameter switch_over_on_gated_lock = "OFF" ;
+ parameter enable_switch_over_counter = "OFF";
+ parameter switch_over_counter = 0;
+ parameter feedback_source = "EXTCLK0" ;
+ parameter bandwidth = 0;
+ parameter bandwidth_type = "UNUSED";
+ parameter lpm_hint = "UNUSED";
+ parameter spread_frequency = 0;
+ parameter down_spread = "0.0";
+ parameter self_reset_on_gated_loss_lock = "OFF";
+ parameter self_reset_on_loss_lock = "OFF";
+ parameter lock_window_ui = "0.05";
+ parameter width_clock = 6;
+ parameter width_phasecounterselect = 4;
+ parameter charge_pump_current_bits = 9999;
+ parameter loop_filter_c_bits = 9999;
+ parameter loop_filter_r_bits = 9999;
+ parameter scan_chain_mif_file = "UNUSED";
+ parameter clk9_multiply_by = 1;
+ parameter clk8_multiply_by = 1;
+ parameter clk7_multiply_by = 1;
+ parameter clk6_multiply_by = 1;
+ parameter clk5_multiply_by = 1;
+ parameter clk4_multiply_by = 1;
+ parameter clk3_multiply_by = 1;
+ parameter clk2_multiply_by = 1;
+ parameter clk1_multiply_by = 1;
+ parameter clk0_multiply_by = 1;
+ parameter clk9_divide_by = 1;
+ parameter clk8_divide_by = 1;
+ parameter clk7_divide_by = 1;
+ parameter clk6_divide_by = 1;
+ parameter clk5_divide_by = 1;
+ parameter clk4_divide_by = 1;
+ parameter clk3_divide_by = 1;
+ parameter clk2_divide_by = 1;
+ parameter clk1_divide_by = 1;
+ parameter clk0_divide_by = 1;
+ parameter clk9_phase_shift = "0";
+ parameter clk8_phase_shift = "0";
+ parameter clk7_phase_shift = "0";
+ parameter clk6_phase_shift = "0";
+ parameter clk5_phase_shift = "0";
+ parameter clk4_phase_shift = "0";
+ parameter clk3_phase_shift = "0";
+ parameter clk2_phase_shift = "0";
+ parameter clk1_phase_shift = "0";
+ parameter clk0_phase_shift = "0";
+
+ parameter clk9_duty_cycle = 50;
+ parameter clk8_duty_cycle = 50;
+ parameter clk7_duty_cycle = 50;
+ parameter clk6_duty_cycle = 50;
+ parameter clk5_duty_cycle = 50;
+ parameter clk4_duty_cycle = 50;
+ parameter clk3_duty_cycle = 50;
+ parameter clk2_duty_cycle = 50;
+ parameter clk1_duty_cycle = 50;
+ parameter clk0_duty_cycle = 50;
+
+ parameter clk9_use_even_counter_mode = "OFF";
+ parameter clk8_use_even_counter_mode = "OFF";
+ parameter clk7_use_even_counter_mode = "OFF";
+ parameter clk6_use_even_counter_mode = "OFF";
+ parameter clk5_use_even_counter_mode = "OFF";
+ parameter clk4_use_even_counter_mode = "OFF";
+ parameter clk3_use_even_counter_mode = "OFF";
+ parameter clk2_use_even_counter_mode = "OFF";
+ parameter clk1_use_even_counter_mode = "OFF";
+ parameter clk0_use_even_counter_mode = "OFF";
+ parameter clk9_use_even_counter_value = "OFF";
+ parameter clk8_use_even_counter_value = "OFF";
+ parameter clk7_use_even_counter_value = "OFF";
+ parameter clk6_use_even_counter_value = "OFF";
+ parameter clk5_use_even_counter_value = "OFF";
+ parameter clk4_use_even_counter_value = "OFF";
+ parameter clk3_use_even_counter_value = "OFF";
+ parameter clk2_use_even_counter_value = "OFF";
+ parameter clk1_use_even_counter_value = "OFF";
+ parameter clk0_use_even_counter_value = "OFF";
+
+ parameter clk2_output_frequency = 0;
+ parameter clk1_output_frequency = 0;
+ parameter clk0_output_frequency = 0;
+
+ parameter vco_min = 0;
+ parameter vco_max = 0;
+ parameter vco_center = 0;
+ parameter pfd_min = 0;
+ parameter pfd_max = 0;
+ parameter m_initial = 1;
+ parameter m = 0;
+ parameter n = 1;
+ parameter m2 = 1;
+ parameter n2 = 1;
+ parameter ss = 0;
+ parameter l0_high = 1;
+ parameter l1_high = 1;
+ parameter g0_high = 1;
+ parameter g1_high = 1;
+ parameter g2_high = 1;
+ parameter g3_high = 1;
+ parameter e0_high = 1;
+ parameter e1_high = 1;
+ parameter e2_high = 1;
+ parameter e3_high = 1;
+ parameter l0_low = 1;
+ parameter l1_low = 1;
+ parameter g0_low = 1;
+ parameter g1_low = 1;
+ parameter g2_low = 1;
+ parameter g3_low = 1;
+ parameter e0_low = 1;
+ parameter e1_low = 1;
+ parameter e2_low = 1;
+ parameter e3_low = 1;
+ parameter l0_initial = 1;
+ parameter l1_initial = 1;
+ parameter g0_initial = 1;
+ parameter g1_initial = 1;
+ parameter g2_initial = 1;
+ parameter g3_initial = 1;
+ parameter e0_initial = 1;
+ parameter e1_initial = 1;
+ parameter e2_initial = 1;
+ parameter e3_initial = 1;
+ parameter l0_mode = "bypass";
+ parameter l1_mode = "bypass";
+ parameter g0_mode = "bypass";
+ parameter g1_mode = "bypass";
+ parameter g2_mode = "bypass";
+ parameter g3_mode = "bypass";
+ parameter e0_mode = "bypass";
+ parameter e1_mode = "bypass";
+ parameter e2_mode = "bypass";
+ parameter e3_mode = "bypass";
+ parameter l0_ph = 0;
+ parameter l1_ph = 0;
+ parameter g0_ph = 0;
+ parameter g1_ph = 0;
+ parameter g2_ph = 0;
+ parameter g3_ph = 0;
+ parameter e0_ph = 0;
+ parameter e1_ph = 0;
+ parameter e2_ph = 0;
+ parameter e3_ph = 0;
+ parameter m_ph = 0;
+ parameter l0_time_delay = 0;
+ parameter l1_time_delay = 0;
+ parameter g0_time_delay = 0;
+ parameter g1_time_delay = 0;
+ parameter g2_time_delay = 0;
+ parameter g3_time_delay = 0;
+ parameter e0_time_delay = 0;
+ parameter e1_time_delay = 0;
+ parameter e2_time_delay = 0;
+ parameter e3_time_delay = 0;
+ parameter m_time_delay = 0;
+ parameter n_time_delay = 0;
+ parameter extclk3_counter = "e3" ;
+ parameter extclk2_counter = "e2" ;
+ parameter extclk1_counter = "e1" ;
+ parameter extclk0_counter = "e0" ;
+ parameter clk9_counter = "c9" ;
+ parameter clk8_counter = "c8" ;
+ parameter clk7_counter = "c7" ;
+ parameter clk6_counter = "c6" ;
+ parameter clk5_counter = "l1" ;
+ parameter clk4_counter = "l0" ;
+ parameter clk3_counter = "g3" ;
+ parameter clk2_counter = "g2" ;
+ parameter clk1_counter = "g1" ;
+ parameter clk0_counter = "g0" ;
+ parameter enable0_counter = "l0";
+ parameter enable1_counter = "l0";
+ parameter charge_pump_current = 2;
+ parameter loop_filter_r = "1.0";
+ parameter loop_filter_c = 5;
+ parameter vco_post_scale = 0;
+ parameter vco_frequency_control = "AUTO";
+ parameter vco_phase_shift_step = 0;
+ parameter lpm_type = "altpll";
+
+ parameter port_clkena0 = "PORT_CONNECTIVITY";
+ parameter port_clkena1 = "PORT_CONNECTIVITY";
+ parameter port_clkena2 = "PORT_CONNECTIVITY";
+ parameter port_clkena3 = "PORT_CONNECTIVITY";
+ parameter port_clkena4 = "PORT_CONNECTIVITY";
+ parameter port_clkena5 = "PORT_CONNECTIVITY";
+ parameter port_extclkena0 = "PORT_CONNECTIVITY";
+ parameter port_extclkena1 = "PORT_CONNECTIVITY";
+ parameter port_extclkena2 = "PORT_CONNECTIVITY";
+ parameter port_extclkena3 = "PORT_CONNECTIVITY";
+ parameter port_extclk0 = "PORT_CONNECTIVITY";
+ parameter port_extclk1 = "PORT_CONNECTIVITY";
+ parameter port_extclk2 = "PORT_CONNECTIVITY";
+ parameter port_extclk3 = "PORT_CONNECTIVITY";
+ parameter port_clk0 = "PORT_CONNECTIVITY";
+ parameter port_clk1 = "PORT_CONNECTIVITY";
+ parameter port_clk2 = "PORT_CONNECTIVITY";
+ parameter port_clk3 = "PORT_CONNECTIVITY";
+ parameter port_clk4 = "PORT_CONNECTIVITY";
+ parameter port_clk5 = "PORT_CONNECTIVITY";
+ parameter port_clk6 = "PORT_CONNECTIVITY";
+ parameter port_clk7 = "PORT_CONNECTIVITY";
+ parameter port_clk8 = "PORT_CONNECTIVITY";
+ parameter port_clk9 = "PORT_CONNECTIVITY";
+ parameter port_scandata = "PORT_CONNECTIVITY";
+ parameter port_scandataout = "PORT_CONNECTIVITY";
+ parameter port_scandone = "PORT_CONNECTIVITY";
+ parameter port_sclkout1 = "PORT_CONNECTIVITY";
+ parameter port_sclkout0 = "PORT_CONNECTIVITY";
+ parameter port_clkbad0 = "PORT_CONNECTIVITY";
+ parameter port_clkbad1 = "PORT_CONNECTIVITY";
+ parameter port_activeclock = "PORT_CONNECTIVITY";
+ parameter port_clkloss = "PORT_CONNECTIVITY";
+ parameter port_inclk1 = "PORT_CONNECTIVITY";
+ parameter port_inclk0 = "PORT_CONNECTIVITY";
+ parameter port_fbin = "PORT_CONNECTIVITY";
+ parameter port_fbout = "PORT_CONNECTIVITY";
+ parameter port_pllena = "PORT_CONNECTIVITY";
+ parameter port_clkswitch = "PORT_CONNECTIVITY";
+ parameter port_areset = "PORT_CONNECTIVITY";
+ parameter port_pfdena = "PORT_CONNECTIVITY";
+ parameter port_scanclk = "PORT_CONNECTIVITY";
+ parameter port_scanaclr = "PORT_CONNECTIVITY";
+ parameter port_scanread = "PORT_CONNECTIVITY";
+ parameter port_scanwrite = "PORT_CONNECTIVITY";
+ parameter port_enable0 = "PORT_CONNECTIVITY";
+ parameter port_enable1 = "PORT_CONNECTIVITY";
+ parameter port_locked = "PORT_CONNECTIVITY";
+ parameter port_configupdate = "PORT_CONNECTIVITY";
+ parameter port_phasecounterselect = "PORT_CONNECTIVITY";
+ parameter port_phasedone = "PORT_CONNECTIVITY";
+ parameter port_phasestep = "PORT_CONNECTIVITY";
+ parameter port_phaseupdown = "PORT_CONNECTIVITY";
+ parameter port_vcooverrange = "PORT_CONNECTIVITY";
+ parameter port_vcounderrange = "PORT_CONNECTIVITY";
+ parameter port_scanclkena = "PORT_CONNECTIVITY";
+ parameter using_fbmimicbidir_port = "ON";
+
+ input [1:0] inclk;
+ input fbin;
+ input pllena;
+ input clkswitch;
+ input areset;
+ input pfdena;
+ input clkena;
+ input extclkena;
+ input scanclk;
+ input scanaclr;
+ input scanclkena;
+ input scanread;
+ input scanwrite;
+ input scandata;
+ input phasecounterselect;
+ input phaseupdown;
+ input phasestep;
+ input configupdate;
+ inout fbmimicbidir;
+
+
+ output [width_clock-1:0] clk;
+ output [3:0] extclk;
+ output [1:0] clkbad;
+ output enable0;
+ output enable1;
+ output activeclock;
+ output clkloss;
+ output locked;
+ output scandataout;
+ output scandone;
+ output sclkout0;
+ output sclkout1;
+ output phasedone;
+ output vcooverrange;
+ output vcounderrange;
+ output fbout;
+ output fref;
+ output icdrclk;
+ output c0, c1, c2, c3, c4;
+
+endmodule // altpll
+`endif
diff --git a/techlibs/intel/common/brams.txt b/techlibs/intel/common/brams.txt
new file mode 100644
index 00000000..3bf21afc
--- /dev/null
+++ b/techlibs/intel/common/brams.txt
@@ -0,0 +1,33 @@
+bram $__M9K_ALTSYNCRAM_SINGLEPORT_FULL
+ init 1
+ abits 13 @M1
+ dbits 1 @M1
+ abits 12 @M2
+ dbits 2 @M2
+ abits 11 @M3
+ dbits 4 @M3
+ abits 10 @M4
+ dbits 8 @M4
+ abits 10 @M5
+ dbits 9 @M5
+ abits 9 @M6
+ dbits 16 @M6
+ abits 9 @M7
+ dbits 18 @M7
+ abits 8 @M8
+ dbits 32 @M8
+ abits 8 @M9
+ dbits 36 @M9
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 1 1
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+match $__M9K_ALTSYNCRAM_SINGLEPORT_FULL
+ min efficiency 2
+ make_transp
+endmatch
diff --git a/techlibs/intel/common/brams_map.v b/techlibs/intel/common/brams_map.v
new file mode 100644
index 00000000..fae4af2a
--- /dev/null
+++ b/techlibs/intel/common/brams_map.v
@@ -0,0 +1,93 @@
+module \$__M9K_ALTSYNCRAM_SINGLEPORT_FULL (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+
+ parameter CFG_ABITS = 8;
+ parameter CFG_DBITS = 36;
+ parameter ABITS = "1";
+ parameter DBITS = "1";
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+
+ input CLK2;
+ input CLK3;
+ //Read data
+ output [CFG_DBITS-1:0] A1DATA;
+ input [CFG_ABITS-1:0] A1ADDR;
+ input A1EN;
+ //Write data
+ output [CFG_DBITS-1:0] B1DATA;
+ input [CFG_ABITS-1:0] B1ADDR;
+ input B1EN;
+
+ wire [CFG_DBITS-1:0] B1DATA_t;
+
+ localparam MODE = CFG_DBITS == 1 ? 1:
+ CFG_DBITS == 2 ? 2:
+ CFG_DBITS == 4 ? 3:
+ CFG_DBITS == 8 ? 4:
+ CFG_DBITS == 9 ? 5:
+ CFG_DBITS == 16 ? 6:
+ CFG_DBITS == 18 ? 7:
+ CFG_DBITS == 32 ? 8:
+ CFG_DBITS == 36 ? 9:
+ 'bx;
+
+ localparam NUMWORDS = CFG_DBITS == 1 ? 8192:
+ CFG_DBITS == 2 ? 4096:
+ CFG_DBITS == 4 ? 2048:
+ CFG_DBITS == 8 ? 1024:
+ CFG_DBITS == 9 ? 1024:
+ CFG_DBITS == 16 ? 512:
+ CFG_DBITS == 18 ? 512:
+ CFG_DBITS == 32 ? 256:
+ CFG_DBITS == 36 ? 256:
+ 'bx;
+
+ altsyncram #(.clock_enable_input_b ("ALTERNATE" ),
+ .clock_enable_input_a ("ALTERNATE" ),
+ .clock_enable_output_b ("NORMAL" ),
+ .clock_enable_output_a ("NORMAL" ),
+ .wrcontrol_aclr_a ("NONE" ),
+ .indata_aclr_a ("NONE" ),
+ .address_aclr_a ("NONE" ),
+ .outdata_aclr_a ("NONE" ),
+ .outdata_reg_a ("UNREGISTERED"),
+ .operation_mode ("SINGLE_PORT" ),
+ .intended_device_family ("CYCLONE IVE" ),
+ .outdata_reg_a ("UNREGISTERED"),
+ .lpm_type ("altsyncram" ),
+ .init_type ("unused" ),
+ .ram_block_type ("AUTO" ),
+ .lpm_hint ("ENABLE_RUNTIME_MOD=NO"), // Forced value
+ .power_up_uninitialized ("FALSE"),
+ .read_during_write_mode_port_a ("NEW_DATA_NO_NBE_READ"), // Forced value
+ .width_byteena_a (1), // Forced value
+ .numwords_b ( NUMWORDS ),
+ .numwords_a ( NUMWORDS ),
+ .widthad_b ( CFG_ABITS ),
+ .width_b ( CFG_DBITS ),
+ .widthad_a ( CFG_ABITS ),
+ .width_a ( CFG_DBITS )
+ ) _TECHMAP_REPLACE_ (
+ .data_a(B1DATA),
+ .address_a(B1ADDR),
+ .wren_a(B1EN),
+ .rden_a(A1EN),
+ .q_a(A1DATA),
+ .data_b(1'b0),
+ .address_b(0),
+ .wren_b(1'b0),
+ .rden_b(1'b0),
+ .q_b(1'b0),
+ .clock0(CLK2),
+ .clock1(1'b1), // Unused in single port mode
+ .clocken0(1'b1),
+ .clocken1(1'b1),
+ .clocken2(1'b1),
+ .clocken3(1'b1),
+ .aclr0(1'b0),
+ .aclr1(1'b0),
+ .addressstall_a(1'b0),
+ .addressstall_b(1'b0));
+
+endmodule
+
diff --git a/techlibs/intel/common/m9k_bb.v b/techlibs/intel/common/m9k_bb.v
new file mode 100644
index 00000000..b18a752f
--- /dev/null
+++ b/techlibs/intel/common/m9k_bb.v
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ */
+(* blackbox *)
+module altsyncram(data_a, address_a, wren_a, rden_a, q_a, data_b, address_b, wren_b, rden_b,
+ q_b, clock0, clock1, clocken0, clocken1, clocken2, clocken3, aclr0, aclr1,
+ addressstall_a, addressstall_b);
+
+ parameter clock_enable_input_b = "ALTERNATE";
+ parameter clock_enable_input_a = "ALTERNATE";
+ parameter clock_enable_output_b = "NORMAL";
+ parameter clock_enable_output_a = "NORMAL";
+ parameter wrcontrol_aclr_a = "NONE";
+ parameter indata_aclr_a = "NONE";
+ parameter address_aclr_a = "NONE";
+ parameter outdata_aclr_a = "NONE";
+ parameter outdata_reg_a = "UNREGISTERED";
+ parameter operation_mode = "SINGLE_PORT";
+ parameter intended_device_family = "MAX 10 FPGA";
+ parameter outdata_reg_a = "UNREGISTERED";
+ parameter lpm_type = "altsyncram";
+ parameter init_type = "unused";
+ parameter ram_block_type = "AUTO";
+ parameter lpm_hint = "ENABLE_RUNTIME_MOD=NO";
+ parameter power_up_uninitialized = "FALSE";
+ parameter read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ";
+ parameter width_byteena_a = 1;
+ parameter numwords_b = 0;
+ parameter numwords_a = 0;
+ parameter widthad_b = 1;
+ parameter width_b = 1;
+ parameter widthad_a = 1;
+ parameter width_a = 1;
+
+ // Port A declarations
+ output [35:0] q_a;
+ input [35:0] data_a;
+ input [7:0] address_a;
+ input wren_a;
+ input rden_a;
+ // Port B declarations
+ output [35:0] q_b;
+ input [35:0] data_b;
+ input [7:0] address_b;
+ input wren_b;
+ input rden_b;
+ // Control signals
+ input clock0, clock1;
+ input clocken0, clocken1, clocken2, clocken3;
+ input aclr0, aclr1;
+ input addressstall_a;
+ input addressstall_b;
+ // TODO: Implement the correct simulation model
+
+endmodule // altsyncram
diff --git a/techlibs/intel/cyclone10/cells_arith.v b/techlibs/intel/cyclone10/cells_arith.v
new file mode 100644
index 00000000..5ae8d6ce
--- /dev/null
+++ b/techlibs/intel/cyclone10/cells_arith.v
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ */
+
+// NOTE: This is still WIP.
+(* techmap_celltype = "$alu" *)
+module _80_altera_a10gx_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;
+ output CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$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:0] C = {CO, CI};
+ wire [Y_WIDTH+1:0] COx;
+ wire [Y_WIDTH+1:0] C = {COx, CI};
+
+ /* Start implementation */
+ (* keep *) cyclone10lp_lcell_comb #(.lut_mask(16'b0000_0000_1010_1010), .sum_lutc_input("cin")) carry_start (.cout(COx[0]), .dataa(C[0]), .datab(1'b1), .datac(1'b1), .datad(1'b1));
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
+ if(i==Y_WIDTH-1) begin
+ (* keep *) cyclone10lp_lcell_comb #(.lut_mask(16'b1111_0000_1110_0000), .sum_lutc_input("cin")) carry_end (.combout(COx[Y_WIDTH]), .dataa(1'b1), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[Y_WIDTH]));
+ assign CO = COx[Y_WIDTH];
+ end
+ else
+ cyclone10lp_lcell_comb #(.lut_mask(16'b1001_0110_1110_1000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(COx[i+1]), .dataa(AA[i]), .datab(BB[i]), .datac(1'b1), .datad(1'b1), .cin(C[i+1]));
+ end: slice
+ endgenerate
+ /* End implementation */
+ assign X = AA ^ BB;
+
+endmodule
diff --git a/techlibs/intel/cyclone10/cells_map.v b/techlibs/intel/cyclone10/cells_map.v
new file mode 100644
index 00000000..c2f6f403
--- /dev/null
+++ b/techlibs/intel/cyclone10/cells_map.v
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ *
+ */
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+
+// Normal mode DFF negedge clk, negedge reset
+module \$_DFF_N_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Normal mode DFF
+module \$_DFF_P_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+// Async Active Low Reset DFF
+module \$_DFF_PN0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Async Active High Reset DFF
+module \$_DFF_PP0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire R_i = ~ R;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+module \$__DFFE_PP0 (input D, C, E, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire E_i = ~ E;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+endmodule
+
+// Input buffer map
+module \$__inpad (input I, output O);
+ cyclone10lp_io_ibuf _TECHMAP_REPLACE_ (.o(O), .i(I), .ibar(1'b0));
+endmodule
+
+// Output buffer map
+module \$__outpad (input I, output O);
+ cyclone10lp_io_obuf _TECHMAP_REPLACE_ (.o(O), .i(I), .oe(1'b1));
+endmodule
+
+// LUT Map
+/* 0 -> datac
+ 1 -> cin */
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+ input [WIDTH-1:0] A;
+ output Y;
+ generate
+ if (WIDTH == 1) begin
+ assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
+ end else
+ if (WIDTH == 2) begin
+ cyclone10lp_lcell_comb #(.lut_mask({4{LUT}}),
+ .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(1'b1),
+ .datad(1'b1));
+ end else
+ if(WIDTH == 3) begin
+ cyclone10lp_lcell_comb #(.lut_mask({2{LUT}}),
+ .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(A[2]),
+ .datad(1'b1));
+ end else
+ if(WIDTH == 4) begin
+ cyclone10lp_lcell_comb #(.lut_mask(LUT),
+ .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(A[2]),
+ .datad(A[3]));
+ end else
+ wire _TECHMAP_FAIL_ = 1;
+ endgenerate
+
+endmodule
+
+
diff --git a/techlibs/intel/cyclone10/cells_sim.v b/techlibs/intel/cyclone10/cells_sim.v
new file mode 100644
index 00000000..f5a8aee2
--- /dev/null
+++ b/techlibs/intel/cyclone10/cells_sim.v
@@ -0,0 +1,137 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+module VCC (output V);
+ assign V = 1'b1;
+endmodule // VCC
+
+module GND (output G);
+ assign G = 1'b0;
+endmodule // GND
+
+/* Altera Cyclone 10 LP devices Input Buffer Primitive */
+module cyclone10lp_io_ibuf
+ (output o, input i, input ibar);
+ assign ibar = ibar;
+ assign o = i;
+endmodule // cyclone10lp_io_ibuf
+
+/* Altera Cyclone 10 LP devices Output Buffer Primitive */
+module cyclone10lp_io_obuf
+ (output o, input i, input oe);
+ assign o = i;
+ assign oe = oe;
+endmodule // cyclone10lp_io_obuf
+
+/* Altera Cyclone IV (E) 4-input non-fracturable LUT Primitive */
+module cyclone10lp_lcell_comb
+ (output combout, cout,
+ input dataa, datab, datac, datad, cin);
+
+ /* Internal parameters which define the behaviour
+ of the LUT primitive.
+ lut_mask define the lut function, can be expressed in 16-digit bin or hex.
+ sum_lutc_input define the type of LUT (combinational | arithmetic).
+ dont_touch for retiming || carry options.
+ lpm_type for WYSIWYG */
+
+ parameter lut_mask = 16'hFFFF;
+ parameter dont_touch = "off";
+ parameter lpm_type = "cyclone10lp_lcell_comb";
+ parameter sum_lutc_input = "datac";
+
+ reg [1:0] lut_type;
+ reg cout_rt;
+ reg combout_rt;
+ wire dataa_w;
+ wire datab_w;
+ wire datac_w;
+ wire datad_w;
+ wire cin_w;
+
+ assign dataa_w = dataa;
+ assign datab_w = datab;
+ assign datac_w = datac;
+ assign datad_w = datad;
+
+ function lut_data;
+ input [15:0] mask;
+ input dataa, datab, datac, datad;
+ reg [7:0] s3;
+ reg [3:0] s2;
+ reg [1:0] s1;
+ begin
+ s3 = datad ? mask[15:8] : mask[7:0];
+ s2 = datac ? s3[7:4] : s3[3:0];
+ s1 = datab ? s2[3:2] : s2[1:0];
+ lut_data = dataa ? s1[1] : s1[0];
+ end
+
+ endfunction
+
+ initial begin
+ if (sum_lutc_input == "datac") lut_type = 0;
+ else
+ if (sum_lutc_input == "cin") lut_type = 1;
+ else begin
+ $error("Error in sum_lutc_input. Parameter %s is not a valid value.\n", sum_lutc_input);
+ $finish();
+ end
+ end
+
+ always @(dataa_w or datab_w or datac_w or datad_w or cin_w) begin
+ if (lut_type == 0) begin // logic function
+ combout_rt = lut_data(lut_mask, dataa_w, datab_w,
+ datac_w, datad_w);
+ end
+ else if (lut_type == 1) begin // arithmetic function
+ combout_rt = lut_data(lut_mask, dataa_w, datab_w,
+ cin_w, datad_w);
+ end
+ cout_rt = lut_data(lut_mask, dataa_w, datab_w, cin_w, 'b0);
+ end
+
+ assign combout = combout_rt & 1'b1;
+ assign cout = cout_rt & 1'b1;
+
+endmodule // cyclone10lp_lcell_comb
+
+/* Altera D Flip-Flop Primitive */
+module dffeas
+ (output q,
+ input d, clk, clrn, prn, ena,
+ input asdata, aload, sclr, sload);
+
+ // Timing simulation is not covered
+ parameter power_up="dontcare";
+ parameter is_wysiwyg="false";
+
+ reg q_tmp;
+ wire reset;
+ reg [7:0] debug_net;
+
+ assign reset = (prn && sclr && ~clrn && ena);
+ assign q = q_tmp & 1'b1;
+
+ always @(posedge clk, posedge aload) begin
+ if(reset) q_tmp <= 0;
+ else q_tmp <= d;
+ end
+ assign q = q_tmp;
+
+endmodule // dffeas
diff --git a/techlibs/intel/cycloneiv/cells_arith.v b/techlibs/intel/cycloneiv/cells_arith.v
new file mode 100644
index 00000000..010a4b5d
--- /dev/null
+++ b/techlibs/intel/cycloneiv/cells_arith.v
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ *
+ */
+
+// NOTE: This is still WIP.
+(* techmap_celltype = "$alu" *)
+/* Uncomment this for LCU????
+module _80_cycloneiv_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;
+ output CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
+ //wire [Y_WIDTH:0] C = {CO, CI};
+ wire [Y_WIDTH+1:0] COx;
+ wire [Y_WIDTH+1:0] C = {COx, CI};
+
+ /* Start implementation */
+ //cycloneiv_lcell_comb #(.lut_mask(16'b0000_0000_1010_1010), .sum_lutc_input("cin")) carry_start (.cout(COx[0]), .dataa(C[0]), .datab(1'b1), .datac(1'b1), .datad(1'b1));
+ /*
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
+ if(i==Y_WIDTH-1)
+ (* keep *) cycloneiv_lcell_comb #(.lut_mask(16'b1111_0000_1110_0000), .sum_lutc_input("cin")) carry_end (.combout(CO), .dataa(1'b1), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[Y_WIDTH]));
+ //assign CO = COx[Y_WIDTH];
+ else
+ cycloneiv_lcell_comb #(.lut_mask(16'b1001_0110_1110_1000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(COx[i+1]), .dataa(AA[i]), .datab(BB[i]), .datac(1'b1), .datad(1'b1), .cin(C[i+1]));
+ end: slice
+ endgenerate
+ /* End implementation */
+ /*assign X = AA ^ BB;
+
+endmodule*/
+module _80_cycloneiv_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:0] CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH < 6;
+
+ 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:0] C = {CO, CI};
+
+ cycloneiv_lcell_comb #(.lut_mask(16'b0110_0110_1000_1000), .sum_lutc_input("cin")) carry_start (.cout(CO[0]), .dataa(BB[0]), .datab(1'b1), .datac(1'b1), .datad(1'b1));
+ genvar i;
+ generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice
+ cycloneiv_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i]));
+ end endgenerate
+
+ assign X = AA ^ BB;
+endmodule
diff --git a/techlibs/intel/cycloneiv/cells_map.v b/techlibs/intel/cycloneiv/cells_map.v
new file mode 100644
index 00000000..19148843
--- /dev/null
+++ b/techlibs/intel/cycloneiv/cells_map.v
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ *
+ */
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+
+// Normal mode DFF negedge clk, negedge reset
+module \$_DFF_N_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Normal mode DFF
+module \$_DFF_P_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+// Async Active Low Reset DFF
+module \$_DFF_PN0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Async Active High Reset DFF
+module \$_DFF_PP0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire R_i = ~ R;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+module \$__DFFE_PP0 (input D, C, E, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire E_i = ~ E;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+endmodule
+
+// Input buffer map
+module \$__inpad (input I, output O);
+ cycloneiv_io_ibuf _TECHMAP_REPLACE_ (.o(O), .i(I), .ibar(1'b0));
+endmodule
+
+// Output buffer map
+module \$__outpad (input I, output O);
+ cycloneiv_io_obuf _TECHMAP_REPLACE_ (.o(O), .i(I), .oe(1'b1));
+endmodule
+
+// LUT Map
+/* 0 -> datac
+ 1 -> cin */
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+ input [WIDTH-1:0] A;
+ output Y;
+ generate
+ if (WIDTH == 1) begin
+ assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
+ end else
+ if (WIDTH == 2) begin
+ cycloneiv_lcell_comb #(.lut_mask({4{LUT}}), .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y), .dataa(A[0]), .datab(A[1]), .datac(1'b1),.datad(1'b1));
+ end else
+ if(WIDTH == 3) begin
+ cycloneiv_lcell_comb #(.lut_mask({2{LUT}}), .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y), .dataa(A[0]), .datab(A[1]), .datac(A[2]),.datad(1'b1));
+ end else
+ if(WIDTH == 4) begin
+ cycloneiv_lcell_comb #(.lut_mask(LUT), .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y), .dataa(A[0]), .datab(A[1]), .datac(A[2]),.datad(A[3]));
+ end else
+ wire _TECHMAP_FAIL_ = 1;
+ endgenerate
+endmodule //
+
+
diff --git a/techlibs/intel/cycloneiv/cells_sim.v b/techlibs/intel/cycloneiv/cells_sim.v
new file mode 100644
index 00000000..2af2ab99
--- /dev/null
+++ b/techlibs/intel/cycloneiv/cells_sim.v
@@ -0,0 +1,299 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+module VCC (output V);
+ assign V = 1'b1;
+endmodule // VCC
+
+module GND (output G);
+ assign G = 1'b0;
+endmodule // GND
+
+/* Altera Cyclone IV (GX) devices Input Buffer Primitive */
+module cycloneiv_io_ibuf
+ (output o, input i, input ibar);
+ assign ibar = ibar;
+ assign o = i;
+endmodule // fiftyfivenm_io_ibuf
+
+/* Altera Cyclone IV (GX) devices Output Buffer Primitive */
+module cycloneiv_io_obuf
+ (output o, input i, input oe);
+ assign o = i;
+ assign oe = oe;
+endmodule // fiftyfivenm_io_obuf
+
+/* Altera Cyclone IV (GX) 4-input non-fracturable LUT Primitive */
+module cycloneiv_lcell_comb
+ (output combout, cout,
+ input dataa, datab, datac, datad, cin);
+
+ /* Internal parameters which define the behaviour
+ of the LUT primitive.
+ lut_mask define the lut function, can be expressed in 16-digit bin or hex.
+ sum_lutc_input define the type of LUT (combinational | arithmetic).
+ dont_touch for retiming || carry options.
+ lpm_type for WYSIWYG */
+
+ parameter lut_mask = 16'hFFFF;
+ parameter dont_touch = "off";
+ parameter lpm_type = "cycloneiv_lcell_comb";
+ parameter sum_lutc_input = "datac";
+
+ reg [1:0] lut_type;
+ reg cout_rt;
+ reg combout_rt;
+ wire dataa_w;
+ wire datab_w;
+ wire datac_w;
+ wire datad_w;
+ wire cin_w;
+
+ assign dataa_w = dataa;
+ assign datab_w = datab;
+ assign datac_w = datac;
+ assign datad_w = datad;
+
+ function lut_data;
+ input [15:0] mask;
+ input dataa, datab, datac, datad;
+ reg [7:0] s3;
+ reg [3:0] s2;
+ reg [1:0] s1;
+ begin
+ s3 = datad ? mask[15:8] : mask[7:0];
+ s2 = datac ? s3[7:4] : s3[3:0];
+ s1 = datab ? s2[3:2] : s2[1:0];
+ lut_data = dataa ? s1[1] : s1[0];
+ end
+
+ endfunction
+
+ initial begin
+ if (sum_lutc_input == "datac") lut_type = 0;
+ else
+ if (sum_lutc_input == "cin") lut_type = 1;
+ else begin
+ $error("Error in sum_lutc_input. Parameter %s is not a valid value.\n", sum_lutc_input);
+ $finish();
+ end
+ end
+
+ always @(dataa_w or datab_w or datac_w or datad_w or cin_w) begin
+ if (lut_type == 0) begin // logic function
+ combout_rt = lut_data(lut_mask, dataa_w, datab_w,
+ datac_w, datad_w);
+ end
+ else if (lut_type == 1) begin // arithmetic function
+ combout_rt = lut_data(lut_mask, dataa_w, datab_w,
+ cin_w, datad_w);
+ end
+ cout_rt = lut_data(lut_mask, dataa_w, datab_w, cin_w, 'b0);
+ end
+
+ assign combout = combout_rt & 1'b1;
+ assign cout = cout_rt & 1'b1;
+
+endmodule // cycloneiv_lcell_comb
+
+/* Altera D Flip-Flop Primitive */
+module dffeas
+ (output q,
+ input d, clk, clrn, prn, ena,
+ input asdata, aload, sclr, sload);
+
+ // Timing simulation is not covered
+ parameter power_up="dontcare";
+ parameter is_wysiwyg="false";
+
+ reg q_tmp;
+ wire reset;
+ reg [7:0] debug_net;
+
+ assign reset = (prn && sclr && ~clrn && ena);
+ assign q = q_tmp & 1'b1;
+
+ always @(posedge clk, posedge aload) begin
+ if(reset) q_tmp <= 0;
+ else q_tmp <= d;
+ end
+ assign q = q_tmp;
+
+endmodule // dffeas
+
+/* Cyclone IV GX altpll clearbox model */
+(* blackbox *)
+module cycloneiv_pll
+ (inclk,
+ fbin,
+ fbout,
+ clkswitch,
+ areset,
+ pfdena,
+ scanclk,
+ scandata,
+ scanclkena,
+ configupdate,
+ clk,
+ phasecounterselect,
+ phaseupdown,
+ phasestep,
+ clkbad,
+ activeclock,
+ locked,
+ scandataout,
+ scandone,
+ phasedone,
+ vcooverrange,
+ vcounderrange,
+ fref,
+ icdrclk);
+
+ parameter operation_mode = "normal";
+ parameter pll_type = "auto";
+ parameter compensate_clock = "clock0";
+ parameter inclk0_input_frequency = 0;
+ parameter inclk1_input_frequency = 0;
+ parameter self_reset_on_loss_lock = "off";
+ parameter switch_over_type = "auto";
+ parameter switch_over_counter = 1;
+ parameter enable_switch_over_counter = "off";
+ parameter bandwidth = 0;
+ parameter bandwidth_type = "auto";
+ parameter use_dc_coupling = "false";
+ parameter lock_high = 0;
+ parameter lock_low = 0;
+ parameter lock_window_ui = "0.05";
+ parameter test_bypass_lock_detect = "off";
+ parameter clk0_output_frequency = 0;
+ parameter clk0_multiply_by = 0;
+ parameter clk0_divide_by = 0;
+ parameter clk0_phase_shift = "0";
+ parameter clk0_duty_cycle = 50;
+ parameter clk1_output_frequency = 0;
+ parameter clk1_multiply_by = 0;
+ parameter clk1_divide_by = 0;
+ parameter clk1_phase_shift = "0";
+ parameter clk1_duty_cycle = 50;
+ parameter clk2_output_frequency = 0;
+ parameter clk2_multiply_by = 0;
+ parameter clk2_divide_by = 0;
+ parameter clk2_phase_shift = "0";
+ parameter clk2_duty_cycle = 50;
+ parameter clk3_output_frequency = 0;
+ parameter clk3_multiply_by = 0;
+ parameter clk3_divide_by = 0;
+ parameter clk3_phase_shift = "0";
+ parameter clk3_duty_cycle = 50;
+ parameter clk4_output_frequency = 0;
+ parameter clk4_multiply_by = 0;
+ parameter clk4_divide_by = 0;
+ parameter clk4_phase_shift = "0";
+ parameter clk4_duty_cycle = 50;
+ parameter pfd_min = 0;
+ parameter pfd_max = 0;
+ parameter vco_min = 0;
+ parameter vco_max = 0;
+ parameter vco_center = 0;
+ // Advanced user parameters
+ parameter m_initial = 1;
+ parameter m = 0;
+ parameter n = 1;
+ parameter c0_high = 1;
+ parameter c0_low = 1;
+ parameter c0_initial = 1;
+ parameter c0_mode = "bypass";
+ parameter c0_ph = 0;
+ parameter c1_high = 1;
+ parameter c1_low = 1;
+ parameter c1_initial = 1;
+ parameter c1_mode = "bypass";
+ parameter c1_ph = 0;
+ parameter c2_high = 1;
+ parameter c2_low = 1;
+ parameter c2_initial = 1;
+ parameter c2_mode = "bypass";
+ parameter c2_ph = 0;
+ parameter c3_high = 1;
+ parameter c3_low = 1;
+ parameter c3_initial = 1;
+ parameter c3_mode = "bypass";
+ parameter c3_ph = 0;
+ parameter c4_high = 1;
+ parameter c4_low = 1;
+ parameter c4_initial = 1;
+ parameter c4_mode = "bypass";
+ parameter c4_ph = 0;
+ parameter m_ph = 0;
+ parameter clk0_counter = "unused";
+ parameter clk1_counter = "unused";
+ parameter clk2_counter = "unused";
+ parameter clk3_counter = "unused";
+ parameter clk4_counter = "unused";
+ parameter c1_use_casc_in = "off";
+ parameter c2_use_casc_in = "off";
+ parameter c3_use_casc_in = "off";
+ parameter c4_use_casc_in = "off";
+ parameter m_test_source = -1;
+ parameter c0_test_source = -1;
+ parameter c1_test_source = -1;
+ parameter c2_test_source = -1;
+ parameter c3_test_source = -1;
+ parameter c4_test_source = -1;
+ parameter vco_multiply_by = 0;
+ parameter vco_divide_by = 0;
+ parameter vco_post_scale = 1;
+ parameter vco_frequency_control = "auto";
+ parameter vco_phase_shift_step = 0;
+ parameter charge_pump_current = 10;
+ parameter loop_filter_r = "1.0";
+ parameter loop_filter_c = 0;
+ parameter pll_compensation_delay = 0;
+ parameter lpm_type = "cycloneiv_pll";
+ parameter phase_counter_select_width = 3;
+
+ input [1:0] inclk;
+ input fbin;
+ input clkswitch;
+ input areset;
+ input pfdena;
+ input [phase_counter_select_width - 1:0] phasecounterselect;
+ input phaseupdown;
+ input phasestep;
+ input scanclk;
+ input scanclkena;
+ input scandata;
+ input configupdate;
+
+ output [4:0] clk;
+ output [1:0] clkbad;
+ output activeclock;
+ output locked;
+ output scandataout;
+ output scandone;
+ output fbout;
+ output phasedone;
+ output vcooverrange;
+ output vcounderrange;
+ output fref;
+ output icdrclk;
+
+endmodule // cycloneive_pll
+
+
diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v
new file mode 100644
index 00000000..b3a11272
--- /dev/null
+++ b/techlibs/intel/cycloneive/arith_map.v
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ *
+ */
+/* TODO: Describe the following mode */
+module fa
+ (input a_c,
+ input b_c,
+ input cin_c,
+ output cout_t,
+ output sum_x);
+
+ wire a_c;
+ wire b_c;
+ wire cout_t;
+ wire cin_c;
+ wire sum_x;
+ wire VCC;
+
+ assign VCC = 1'b1;
+
+ cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x),
+ .dataa(a_c),
+ .datab(b_c),
+ .datac(cin_c),
+ .datad(VCC));
+ defparam syn__05_.lut_mask = 16'b1001011010010110;
+ defparam syn__05_.sum_lutc_input = "datac";
+
+ cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t),
+ .dataa(cin_c),
+ .datab(b_c),
+ .datac(a_c),
+ .datad(VCC));
+ defparam syn__06_.lut_mask = 16'b1110000011100000;
+ defparam syn__06_.sum_lutc_input = "datac";
+
+endmodule // fa
+
+module f_stage();
+
+endmodule // f_stage
+
+module f_end();
+
+endmodule // f_end
+
+module _80_cycloneive_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:0] CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH < 5;
+
+ 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:0] C = {CO, CI};
+
+ fa f0 (.a_c(AA[0]),
+ .b_c(BB[0]),
+ .cin_c(C[0]),
+ .cout_t(C0[1]),
+ .sum_x(Y[0]));
+
+ genvar i;
+ generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice
+ cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i]));
+ end endgenerate
+
+ assign X = AA ^ BB;
+
+endmodule
diff --git a/techlibs/intel/cycloneive/cells_map.v b/techlibs/intel/cycloneive/cells_map.v
new file mode 100644
index 00000000..abeb92ee
--- /dev/null
+++ b/techlibs/intel/cycloneive/cells_map.v
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ *
+ */
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+
+// Normal mode DFF negedge clk, negedge reset
+module \$_DFF_N_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Normal mode DFF
+module \$_DFF_P_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+// Async Active Low Reset DFF
+module \$_DFF_PN0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Async Active High Reset DFF
+module \$_DFF_PP0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire R_i = ~ R;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+module \$__DFFE_PP0 (input D, C, E, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire E_i = ~ E;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+endmodule
+
+// Input buffer map
+module \$__inpad (input I, output O);
+ cycloneive_io_ibuf _TECHMAP_REPLACE_ (.o(O), .i(I), .ibar(1'b0));
+endmodule
+
+// Output buffer map
+module \$__outpad (input I, output O);
+ cycloneive_io_obuf _TECHMAP_REPLACE_ (.o(O), .i(I), .oe(1'b1));
+endmodule
+
+// LUT Map
+/* 0 -> datac
+ 1 -> cin */
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+ input [WIDTH-1:0] A;
+ output Y;
+ generate
+ if (WIDTH == 1) begin
+ assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
+ end else
+ if (WIDTH == 2) begin
+ cycloneive_lcell_comb #(.lut_mask({4{LUT}}),
+ .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(1'b1),
+ .datad(1'b1));
+ end else
+ if(WIDTH == 3) begin
+ cycloneive_lcell_comb #(.lut_mask({2{LUT}}),
+ .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(A[2]),
+ .datad(1'b1));
+ end else
+ if(WIDTH == 4) begin
+ cycloneive_lcell_comb #(.lut_mask(LUT),
+ .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(A[2]),
+ .datad(A[3]));
+ end else
+ wire _TECHMAP_FAIL_ = 1;
+ endgenerate
+
+endmodule
+
+
diff --git a/techlibs/intel/cycloneive/cells_sim.v b/techlibs/intel/cycloneive/cells_sim.v
new file mode 100644
index 00000000..f17b86fd
--- /dev/null
+++ b/techlibs/intel/cycloneive/cells_sim.v
@@ -0,0 +1,292 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+module VCC (output V);
+ assign V = 1'b1;
+endmodule // VCC
+
+module GND (output G);
+ assign G = 1'b0;
+endmodule // GND
+
+/* Altera Cyclone IV (E) devices Input Buffer Primitive */
+module cycloneive_io_ibuf
+ (output o, input i, input ibar);
+ assign ibar = ibar;
+ assign o = i;
+endmodule // fiftyfivenm_io_ibuf
+
+/* Altera Cyclone IV (E) devices Output Buffer Primitive */
+module cycloneive_io_obuf
+ (output o, input i, input oe);
+ assign o = i;
+ assign oe = oe;
+endmodule // fiftyfivenm_io_obuf
+
+/* Altera Cyclone IV (E) 4-input non-fracturable LUT Primitive */
+module cycloneive_lcell_comb
+ (output combout, cout,
+ input dataa, datab, datac, datad, cin);
+
+ /* Internal parameters which define the behaviour
+ of the LUT primitive.
+ lut_mask define the lut function, can be expressed in 16-digit bin or hex.
+ sum_lutc_input define the type of LUT (combinational | arithmetic).
+ dont_touch for retiming || carry options.
+ lpm_type for WYSIWYG */
+
+ parameter lut_mask = 16'hFFFF;
+ parameter dont_touch = "off";
+ parameter lpm_type = "cycloneive_lcell_comb";
+ parameter sum_lutc_input = "datac";
+
+ reg [1:0] lut_type;
+ reg cout_rt;
+ reg combout_rt;
+ wire dataa_w;
+ wire datab_w;
+ wire datac_w;
+ wire datad_w;
+ wire cin_w;
+
+ assign dataa_w = dataa;
+ assign datab_w = datab;
+ assign datac_w = datac;
+ assign datad_w = datad;
+
+ function lut_data;
+ input [15:0] mask;
+ input dataa, datab, datac, datad;
+ reg [7:0] s3;
+ reg [3:0] s2;
+ reg [1:0] s1;
+ begin
+ s3 = datad ? mask[15:8] : mask[7:0];
+ s2 = datac ? s3[7:4] : s3[3:0];
+ s1 = datab ? s2[3:2] : s2[1:0];
+ lut_data = dataa ? s1[1] : s1[0];
+ end
+
+ endfunction
+
+ initial begin
+ if (sum_lutc_input == "datac") lut_type = 0;
+ else
+ if (sum_lutc_input == "cin") lut_type = 1;
+ else begin
+ $error("Error in sum_lutc_input. Parameter %s is not a valid value.\n", sum_lutc_input);
+ $finish();
+ end
+ end
+
+ always @(dataa_w or datab_w or datac_w or datad_w or cin_w) begin
+ if (lut_type == 0) begin // logic function
+ combout_rt = lut_data(lut_mask, dataa_w, datab_w,
+ datac_w, datad_w);
+ end
+ else if (lut_type == 1) begin // arithmetic function
+ combout_rt = lut_data(lut_mask, dataa_w, datab_w,
+ cin_w, datad_w);
+ end
+ cout_rt = lut_data(lut_mask, dataa_w, datab_w, cin_w, 'b0);
+ end
+
+ assign combout = combout_rt & 1'b1;
+ assign cout = cout_rt & 1'b1;
+
+endmodule // cycloneive_lcell_comb
+
+/* Altera D Flip-Flop Primitive */
+module dffeas
+ (output q,
+ input d, clk, clrn, prn, ena,
+ input asdata, aload, sclr, sload);
+
+ // Timing simulation is not covered
+ parameter power_up="dontcare";
+ parameter is_wysiwyg="false";
+
+ reg q_tmp;
+ wire reset;
+ reg [7:0] debug_net;
+
+ assign reset = (prn && sclr && ~clrn && ena);
+ assign q = q_tmp & 1'b1;
+
+ always @(posedge clk, posedge aload) begin
+ if(reset) q_tmp <= 0;
+ else q_tmp <= d;
+ end
+ assign q = q_tmp;
+
+endmodule // dffeas
+
+/* Cyclone IV E altpll clearbox model */
+(* blackbox *)
+module cycloneive_pll
+ (inclk,
+ fbin,
+ fbout,
+ clkswitch,
+ areset,
+ pfdena,
+ scanclk,
+ scandata,
+ scanclkena,
+ configupdate,
+ clk,
+ phasecounterselect,
+ phaseupdown,
+ phasestep,
+ clkbad,
+ activeclock,
+ locked,
+ scandataout,
+ scandone,
+ phasedone,
+ vcooverrange,
+ vcounderrange);
+
+ parameter operation_mode = "normal";
+ parameter pll_type = "auto";
+ parameter compensate_clock = "clock0";
+ parameter inclk0_input_frequency = 0;
+ parameter inclk1_input_frequency = 0;
+ parameter self_reset_on_loss_lock = "off";
+ parameter switch_over_type = "auto";
+ parameter switch_over_counter = 1;
+ parameter enable_switch_over_counter = "off";
+ parameter bandwidth = 0;
+ parameter bandwidth_type = "auto";
+ parameter use_dc_coupling = "false";
+ parameter lock_high = 0;
+ parameter lock_low = 0;
+ parameter lock_window_ui = "0.05";
+ parameter test_bypass_lock_detect = "off";
+ parameter clk0_output_frequency = 0;
+ parameter clk0_multiply_by = 0;
+ parameter clk0_divide_by = 0;
+ parameter clk0_phase_shift = "0";
+ parameter clk0_duty_cycle = 50;
+ parameter clk1_output_frequency = 0;
+ parameter clk1_multiply_by = 0;
+ parameter clk1_divide_by = 0;
+ parameter clk1_phase_shift = "0";
+ parameter clk1_duty_cycle = 50;
+ parameter clk2_output_frequency = 0;
+ parameter clk2_multiply_by = 0;
+ parameter clk2_divide_by = 0;
+ parameter clk2_phase_shift = "0";
+ parameter clk2_duty_cycle = 50;
+ parameter clk3_output_frequency = 0;
+ parameter clk3_multiply_by = 0;
+ parameter clk3_divide_by = 0;
+ parameter clk3_phase_shift = "0";
+ parameter clk3_duty_cycle = 50;
+ parameter clk4_output_frequency = 0;
+ parameter clk4_multiply_by = 0;
+ parameter clk4_divide_by = 0;
+ parameter clk4_phase_shift = "0";
+ parameter clk4_duty_cycle = 50;
+ parameter pfd_min = 0;
+ parameter pfd_max = 0;
+ parameter vco_min = 0;
+ parameter vco_max = 0;
+ parameter vco_center = 0;
+ // Advanced user parameters
+ parameter m_initial = 1;
+ parameter m = 0;
+ parameter n = 1;
+ parameter c0_high = 1;
+ parameter c0_low = 1;
+ parameter c0_initial = 1;
+ parameter c0_mode = "bypass";
+ parameter c0_ph = 0;
+ parameter c1_high = 1;
+ parameter c1_low = 1;
+ parameter c1_initial = 1;
+ parameter c1_mode = "bypass";
+ parameter c1_ph = 0;
+ parameter c2_high = 1;
+ parameter c2_low = 1;
+ parameter c2_initial = 1;
+ parameter c2_mode = "bypass";
+ parameter c2_ph = 0;
+ parameter c3_high = 1;
+ parameter c3_low = 1;
+ parameter c3_initial = 1;
+ parameter c3_mode = "bypass";
+ parameter c3_ph = 0;
+ parameter c4_high = 1;
+ parameter c4_low = 1;
+ parameter c4_initial = 1;
+ parameter c4_mode = "bypass";
+ parameter c4_ph = 0;
+ parameter m_ph = 0;
+ parameter clk0_counter = "unused";
+ parameter clk1_counter = "unused";
+ parameter clk2_counter = "unused";
+ parameter clk3_counter = "unused";
+ parameter clk4_counter = "unused";
+ parameter c1_use_casc_in = "off";
+ parameter c2_use_casc_in = "off";
+ parameter c3_use_casc_in = "off";
+ parameter c4_use_casc_in = "off";
+ parameter m_test_source = -1;
+ parameter c0_test_source = -1;
+ parameter c1_test_source = -1;
+ parameter c2_test_source = -1;
+ parameter c3_test_source = -1;
+ parameter c4_test_source = -1;
+ parameter vco_multiply_by = 0;
+ parameter vco_divide_by = 0;
+ parameter vco_post_scale = 1;
+ parameter vco_frequency_control = "auto";
+ parameter vco_phase_shift_step = 0;
+ parameter charge_pump_current = 10;
+ parameter loop_filter_r = "1.0";
+ parameter loop_filter_c = 0;
+ parameter pll_compensation_delay = 0;
+ parameter lpm_type = "cycloneive_pll";
+ parameter phase_counter_select_width = 3;
+
+ input [1:0] inclk;
+ input fbin;
+ input clkswitch;
+ input areset;
+ input pfdena;
+ input [phase_counter_select_width - 1:0] phasecounterselect;
+ input phaseupdown;
+ input phasestep;
+ input scanclk;
+ input scanclkena;
+ input scandata;
+ input configupdate;
+
+ output [4:0] clk;
+ output [1:0] clkbad;
+ output activeclock;
+ output locked;
+ output scandataout;
+ output scandone;
+ output fbout;
+ output phasedone;
+ output vcooverrange;
+ output vcounderrange;
+
+endmodule // cycloneive_pll
diff --git a/techlibs/intel/cyclonev/cells_arith.v b/techlibs/intel/cyclonev/cells_arith.v
new file mode 100644
index 00000000..89fb4561
--- /dev/null
+++ b/techlibs/intel/cyclonev/cells_arith.v
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ */
+
+// NOTE: This is still WIP.
+(* techmap_celltype = "$alu" *)
+module _80_altera_a10gx_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;
+ output CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$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:0] C = {CO, CI};
+ wire [Y_WIDTH+1:0] COx;
+ wire [Y_WIDTH+1:0] C = {COx, CI};
+
+ /* Start implementation */
+ (* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b0000_0000_1010_1010), .sum_lutc_input("cin")) carry_start (.cout(COx[0]), .dataa(C[0]), .datab(1'b1), .datac(1'b1), .datad(1'b1));
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
+ if(i==Y_WIDTH-1) begin
+ (* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b1111_0000_1110_0000), .sum_lutc_input("cin")) carry_end (.combout(COx[Y_WIDTH]), .dataa(1'b1), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[Y_WIDTH]));
+ assign CO = COx[Y_WIDTH];
+ end
+ else
+ fiftyfivenm_lcell_comb #(.lut_mask(16'b1001_0110_1110_1000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(COx[i+1]), .dataa(AA[i]), .datab(BB[i]), .datac(1'b1), .datad(1'b1), .cin(C[i+1]));
+ end: slice
+ endgenerate
+ /* End implementation */
+ assign X = AA ^ BB;
+
+endmodule
diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v
new file mode 100644
index 00000000..bd60d4e1
--- /dev/null
+++ b/techlibs/intel/cyclonev/cells_map.v
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ *
+ */
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+// 2) Cyclone V 7-input LUT function was wrong implemented. Removed abc option to map this function \
+// and added the explanation in this file instead. Such function needs to be implemented.
+
+// Normal mode DFF negedge clk, negedge reset
+module \$_DFF_N_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Normal mode DFF
+module \$_DFF_P_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+// Async Active Low Reset DFF
+module \$_DFF_PN0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Async Active High Reset DFF
+module \$_DFF_PP0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire R_i = ~ R;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+module \$__DFFE_PP0 (input D, C, E, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire E_i = ~ E;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+endmodule
+
+// Input buffer map
+module \$__inpad (input I, output O);
+ cyclonev_io_ibuf _TECHMAP_REPLACE_ (.o(O), .i(I), .ibar(1'b0));
+endmodule
+
+// Output buffer map
+module \$__outpad (input I, output O);
+ cyclonev_io_obuf _TECHMAP_REPLACE_ (.o(O), .i(I), .oe(1'b1));
+endmodule
+
+// LUT Map
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+ input [WIDTH-1:0] A;
+ output Y;
+ wire VCC;
+ wire GND;
+ assign {VCC,GND} = {1'b1,1'b0};
+
+ generate
+ if (WIDTH == 1) begin
+ assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
+ end
+ else
+ if (WIDTH == 2) begin
+ cyclonev_lcell_comb #(.lut_mask({16{LUT}}), .shared_arith("off"), .extended_lut("off"))
+ _TECHMAP_REPLACE_
+ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(VCC),
+ .datad(VCC),
+ .datae(VCC),
+ .dataf(VCC),
+ .datag(VCC));
+ end
+ else
+ if(WIDTH == 3) begin
+ cyclonev_lcell_comb #(.lut_mask({8{LUT}}), .shared_arith("off"), .extended_lut("off"))
+ _TECHMAP_REPLACE_
+ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(A[2]),
+ .datad(VCC),
+ .datae(VCC),
+ .dataf(VCC),
+ .datag(VCC));
+ end
+ else
+ if(WIDTH == 4) begin
+ cyclonev_lcell_comb #(.lut_mask({4{LUT}}), .shared_arith("off"), .extended_lut("off"))
+ _TECHMAP_REPLACE_
+ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(A[2]),
+ .datad(A[3]),
+ .datae(VCC),
+ .dataf(VCC),
+ .datag(VCC));
+ end
+ else
+ if(WIDTH == 5) begin
+ cyclonev_lcell_comb #(.lut_mask({2{LUT}}), .shared_arith("off"), .extended_lut("off"))
+ _TECHMAP_REPLACE_
+ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(A[2]),
+ .datad(A[3]),
+ .datae(A[4]),
+ .dataf(VCC),
+ .datag(VCC));
+ end
+ else
+ if(WIDTH == 6) begin
+ cyclonev_lcell_comb #(.lut_mask(LUT), .shared_arith("off"), .extended_lut("off"))
+ _TECHMAP_REPLACE_
+ (.combout(Y),
+ .dataa(A[0]),
+ .datab(A[1]),
+ .datac(A[2]),
+ .datad(A[3]),
+ .datae(A[4]),
+ .dataf(A[5]),
+ .datag(VCC));
+ end
+ /*else
+ if(WIDTH == 7) begin
+ TODO: There's not a just 7-input function on Cyclone V, see the following note:
+ **Extended LUT Mode**
+ Use extended LUT mode to implement a specific set of 7-input functions. The set must
+ be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs.
+ [source](Device Interfaces and Integration Basics for Cyclone V Devices).
+ end*/
+ else
+ wire _TECHMAP_FAIL_ = 1;
+ endgenerate
+endmodule // lut
+
+
diff --git a/techlibs/intel/cyclonev/cells_sim.v b/techlibs/intel/cyclonev/cells_sim.v
new file mode 100644
index 00000000..5ecdabcf
--- /dev/null
+++ b/techlibs/intel/cyclonev/cells_sim.v
@@ -0,0 +1,144 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+module VCC (output V);
+ assign V = 1'b1;
+endmodule // VCC
+
+module GND (output G);
+ assign G = 1'b0;
+endmodule // GND
+
+/* Altera Cyclone V devices Input Buffer Primitive */
+module cyclonev_io_ibuf
+ (output o, input i, input ibar);
+ assign ibar = ibar;
+ assign o = i;
+endmodule // cyclonev_io_ibuf
+
+/* Altera Cyclone V devices Output Buffer Primitive */
+module cyclonev_io_obuf
+ (output o, input i, input oe);
+ assign o = i;
+ assign oe = oe;
+endmodule // cyclonev_io_obuf
+
+/* Altera Cyclone V LUT Primitive */
+module cyclonev_lcell_comb
+ (output combout, cout, sumout, shareout,
+ input dataa, datab, datac, datad,
+ input datae, dataf, datag, cin,
+ input sharein);
+
+ parameter lut_mask = 64'hFFFFFFFFFFFFFFFF;
+ parameter dont_touch = "off";
+ parameter lpm_type = "cyclonev_lcell_comb";
+ parameter shared_arith = "off";
+ parameter extended_lut = "off";
+
+ // Internal variables
+ // Sub mask for fragmented LUTs
+ wire [15:0] mask_a, mask_b, mask_c, mask_d;
+ // Independant output for fragmented LUTs
+ wire output_0, output_1, output_2, output_3;
+ // Extended mode uses mux to define the output
+ wire mux_0, mux_1;
+ // Input for hold the shared LUT mode value
+ wire shared_lut_alm;
+
+ // Simulation model of 4-input LUT
+ function lut4;
+ input [15:0] mask;
+ input dataa, datab, datac, datad;
+ reg [7:0] s3;
+ reg [3:0] s2;
+ reg [1:0] s1;
+ begin
+ s3 = datad ? mask[15:8] : mask[7:0];
+ s2 = datac ? s3[7:4] : s3[3:0];
+ s1 = datab ? s2[3:2] : s2[1:0];
+ lut4 = dataa ? s1[1] : s1[0];
+ end
+ endfunction // lut4
+
+ // Simulation model of 5-input LUT
+ function lut5;
+ input [31:0] mask; // wp-01003.pdf, page 3: "a 5-LUT can be built with two 4-LUTs and a multiplexer.
+ input dataa, datab, datac, datad, datae;
+ reg upper_lut_value;
+ reg lower_lut_value;
+ begin
+ upper_lut_value = lut4(mask[31:16], dataa, datab, datac, datad);
+ lower_lut_value = lut4(mask[15:0], dataa, datab, datac, datad);
+ lut5 = (datae) ? upper_mask_value : lower_mask_value;
+ end
+ endfunction // lut5
+
+ // Simulation model of 6-input LUT
+ function lut6;
+ input [63:0] mask;
+ input dataa, datab, datac, datad, datae, dataf;
+ reg upper_lut_value;
+ reg lower_lut_value;
+ begin
+ upper_lut_value = lut5(mask[63:32], dataa, datab, datac, datad, datae);
+ lower_lut_value = lut5(mask[31:0], dataa, datab, datac, datad, datae);
+ lut6 = (dataf) ? upper_mask_value : lower_mask_value;
+ end
+ endfunction // lut6
+
+ assign {mask_a, mask_b, mask_c, mask_d} = {lut_mask[15:0], lut_mask[31:16], lut_mask[47:32], lut_mask[63:48]};
+
+ always @(*) begin
+ if(extended_lut == "on")
+ shared_lut_alm = datag;
+ else
+ shared_lut_alm = datac;
+ // Build the ALM behaviour
+ out_0 = lut4(mask_a, dataa, datab, datac, datad);
+ out_1 = lut4(mask_b, dataa, datab, shared_lut_alm, datad);
+ out_2 = lut4(mask_c, dataa, datab, datac, datad);
+ out_3 = lut4(mask_d, dataa, datab, shared_lut_alm, datad);
+ end
+endmodule // cyclonev_lcell_comb
+
+
+/* Altera D Flip-Flop Primitive */
+module dffeas
+ (output q,
+ input d, clk, clrn, prn, ena,
+ input asdata, aload, sclr, sload);
+
+ // Timing simulation is not covered
+ parameter power_up="dontcare";
+ parameter is_wysiwyg="false";
+
+ reg q_tmp;
+ wire reset;
+ reg [7:0] debug_net;
+
+ assign reset = (prn && sclr && ~clrn && ena);
+ assign q = q_tmp & 1'b1;
+
+ always @(posedge clk, posedge aload) begin
+ if(reset) q_tmp <= 0;
+ else q_tmp <= d;
+ end
+ assign q = q_tmp;
+
+endmodule // dffeas
diff --git a/techlibs/intel/max10/cells_arith.v b/techlibs/intel/max10/cells_arith.v
new file mode 100644
index 00000000..e2194cbd
--- /dev/null
+++ b/techlibs/intel/max10/cells_arith.v
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ */
+
+// NOTE: This is still WIP.
+(* techmap_celltype = "$alu" *)
+module _80_altera_max10_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;
+ output CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$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:0] C = {CO, CI};
+ wire [Y_WIDTH+1:0] COx;
+ wire [Y_WIDTH+1:0] C = {COx, CI};
+
+ /* Start implementation */
+ (* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b0000_0000_1010_1010), .sum_lutc_input("cin")) carry_start (.cout(COx[0]), .dataa(C[0]), .datab(1'b1), .datac(1'b1), .datad(1'b1));
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
+ if(i==Y_WIDTH-1) begin
+ (* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b1111_0000_1110_0000), .sum_lutc_input("cin")) carry_end (.combout(COx[Y_WIDTH]), .dataa(1'b1), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[Y_WIDTH]));
+ assign CO = COx[Y_WIDTH];
+ end
+ else
+ fiftyfivenm_lcell_comb #(.lut_mask(16'b1001_0110_1110_1000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(COx[i+1]), .dataa(AA[i]), .datab(BB[i]), .datac(1'b1), .datad(1'b1), .cin(C[i+1]));
+ end: slice
+ endgenerate
+ /* End implementation */
+ assign X = AA ^ BB;
+
+endmodule
diff --git a/techlibs/intel/max10/cells_map.v b/techlibs/intel/max10/cells_map.v
new file mode 100644
index 00000000..6d604e07
--- /dev/null
+++ b/techlibs/intel/max10/cells_map.v
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ *
+ */
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+
+// Normal mode DFF negedge clk, negedge reset
+module \$_DFF_N_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Normal mode DFF
+module \$_DFF_P_ (input D, C, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+// Async Active Low Reset DFF
+module \$_DFF_PN0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+// Async Active High Reset DFF
+module \$_DFF_PP0_ (input D, C, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire R_i = ~ R;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+endmodule
+
+module \$__DFFE_PP0 (input D, C, E, R, output Q);
+ parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
+ wire E_i = ~ E;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+endmodule
+
+// Input buffer map
+module \$__inpad (input I, output O);
+ fiftyfivenm_io_ibuf _TECHMAP_REPLACE_ (.o(O), .i(I), .ibar(1'b0));
+endmodule
+
+// Output buffer map
+module \$__outpad (input I, output O);
+ fiftyfivenm_io_obuf _TECHMAP_REPLACE_ (.o(O), .i(I), .oe(1'b1));
+endmodule
+
+// LUT Map
+/* 0 -> datac
+ 1 -> cin */
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+ input [WIDTH-1:0] A;
+ output Y;
+ generate
+ if (WIDTH == 1) begin
+ assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
+ end else
+ if (WIDTH == 2) begin
+ fiftyfivenm_lcell_comb #(.lut_mask({4{LUT}}), .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y), .dataa(A[0]), .datab(A[1]), .datac(1'b1),.datad(1'b1));
+ end else
+ if(WIDTH == 3) begin
+ fiftyfivenm_lcell_comb #(.lut_mask({2{LUT}}), .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y), .dataa(A[0]), .datab(A[1]), .datac(A[2]),.datad(1'b1));
+ end else
+ if(WIDTH == 4) begin
+ fiftyfivenm_lcell_comb #(.lut_mask(LUT), .sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.combout(Y), .dataa(A[0]), .datab(A[1]), .datac(A[2]),.datad(A[3]));
+ end else
+ wire _TECHMAP_FAIL_ = 1;
+ endgenerate
+endmodule //
+
+
diff --git a/techlibs/intel/max10/cells_sim.v b/techlibs/intel/max10/cells_sim.v
new file mode 100644
index 00000000..98673596
--- /dev/null
+++ b/techlibs/intel/max10/cells_sim.v
@@ -0,0 +1,292 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+module VCC (output V);
+ assign V = 1'b1;
+endmodule // VCC
+
+module GND (output G);
+ assign G = 1'b0;
+endmodule // GND
+
+/* Altera MAX10 devices Input Buffer Primitive */
+module fiftyfivenm_io_ibuf
+ (output o, input i, input ibar);
+ assign ibar = ibar;
+ assign o = i;
+endmodule // fiftyfivenm_io_ibuf
+
+/* Altera MAX10 devices Output Buffer Primitive */
+module fiftyfivenm_io_obuf
+ (output o, input i, input oe);
+ assign o = i;
+ assign oe = oe;
+endmodule // fiftyfivenm_io_obuf
+
+/* Altera MAX10 4-input non-fracturable LUT Primitive */
+module fiftyfivenm_lcell_comb
+ (output combout, cout,
+ input dataa, datab, datac, datad, cin);
+
+ /* Internal parameters which define the behaviour
+ of the LUT primitive.
+ lut_mask define the lut function, can be expressed in 16-digit bin or hex.
+ sum_lutc_input define the type of LUT (combinational | arithmetic).
+ dont_touch for retiming || carry options.
+ lpm_type for WYSIWYG */
+
+ parameter lut_mask = 16'hFFFF;
+ parameter dont_touch = "off";
+ parameter lpm_type = "fiftyfivenm_lcell_comb";
+ parameter sum_lutc_input = "datac";
+
+ reg [1:0] lut_type;
+ reg cout_rt;
+ reg combout_rt;
+ wire dataa_w;
+ wire datab_w;
+ wire datac_w;
+ wire datad_w;
+ wire cin_w;
+
+ assign dataa_w = dataa;
+ assign datab_w = datab;
+ assign datac_w = datac;
+ assign datad_w = datad;
+
+ function lut_data;
+ input [15:0] mask;
+ input dataa, datab, datac, datad;
+ reg [7:0] s3;
+ reg [3:0] s2;
+ reg [1:0] s1;
+ begin
+ s3 = datad ? mask[15:8] : mask[7:0];
+ s2 = datac ? s3[7:4] : s3[3:0];
+ s1 = datab ? s2[3:2] : s2[1:0];
+ lut_data = dataa ? s1[1] : s1[0];
+ end
+
+ endfunction
+
+ initial begin
+ if (sum_lutc_input == "datac") lut_type = 0;
+ else
+ if (sum_lutc_input == "cin") lut_type = 1;
+ else begin
+ $error("Error in sum_lutc_input. Parameter %s is not a valid value.\n", sum_lutc_input);
+ $finish();
+ end
+ end
+
+ always @(dataa_w or datab_w or datac_w or datad_w or cin_w) begin
+ if (lut_type == 0) begin // logic function
+ combout_rt = lut_data(lut_mask, dataa_w, datab_w,
+ datac_w, datad_w);
+ end
+ else if (lut_type == 1) begin // arithmetic function
+ combout_rt = lut_data(lut_mask, dataa_w, datab_w,
+ cin_w, datad_w);
+ end
+ cout_rt = lut_data(lut_mask, dataa_w, datab_w, cin_w, 'b0);
+ end
+
+ assign combout = combout_rt & 1'b1;
+ assign cout = cout_rt & 1'b1;
+
+endmodule // fiftyfivenm_lcell_comb
+
+/* Altera D Flip-Flop Primitive */
+module dffeas
+ (output q,
+ input d, clk, clrn, prn, ena,
+ input asdata, aload, sclr, sload);
+
+ // Timing simulation is not covered
+ parameter power_up="dontcare";
+ parameter is_wysiwyg="false";
+
+ reg q_tmp;
+ wire reset;
+ reg [7:0] debug_net;
+
+ assign reset = (prn && sclr && ~clrn && ena);
+ assign q = q_tmp & 1'b1;
+
+ always @(posedge clk, posedge aload) begin
+ if(reset) q_tmp <= 0;
+ else q_tmp <= d;
+ end
+ assign q = q_tmp;
+
+endmodule // dffeas
+
+/* MAX10 altpll clearbox model */
+(* blackbox *)
+module fiftyfivenm_pll
+ (inclk,
+ fbin,
+ fbout,
+ clkswitch,
+ areset,
+ pfdena,
+ scanclk,
+ scandata,
+ scanclkena,
+ configupdate,
+ clk,
+ phasecounterselect,
+ phaseupdown,
+ phasestep,
+ clkbad,
+ activeclock,
+ locked,
+ scandataout,
+ scandone,
+ phasedone,
+ vcooverrange,
+ vcounderrange);
+
+ parameter operation_mode = "normal";
+ parameter pll_type = "auto";
+ parameter compensate_clock = "clock0";
+ parameter inclk0_input_frequency = 0;
+ parameter inclk1_input_frequency = 0;
+ parameter self_reset_on_loss_lock = "off";
+ parameter switch_over_type = "auto";
+ parameter switch_over_counter = 1;
+ parameter enable_switch_over_counter = "off";
+ parameter bandwidth = 0;
+ parameter bandwidth_type = "auto";
+ parameter use_dc_coupling = "false";
+ parameter lock_high = 0;
+ parameter lock_low = 0;
+ parameter lock_window_ui = "0.05";
+ parameter test_bypass_lock_detect = "off";
+ parameter clk0_output_frequency = 0;
+ parameter clk0_multiply_by = 0;
+ parameter clk0_divide_by = 0;
+ parameter clk0_phase_shift = "0";
+ parameter clk0_duty_cycle = 50;
+ parameter clk1_output_frequency = 0;
+ parameter clk1_multiply_by = 0;
+ parameter clk1_divide_by = 0;
+ parameter clk1_phase_shift = "0";
+ parameter clk1_duty_cycle = 50;
+ parameter clk2_output_frequency = 0;
+ parameter clk2_multiply_by = 0;
+ parameter clk2_divide_by = 0;
+ parameter clk2_phase_shift = "0";
+ parameter clk2_duty_cycle = 50;
+ parameter clk3_output_frequency = 0;
+ parameter clk3_multiply_by = 0;
+ parameter clk3_divide_by = 0;
+ parameter clk3_phase_shift = "0";
+ parameter clk3_duty_cycle = 50;
+ parameter clk4_output_frequency = 0;
+ parameter clk4_multiply_by = 0;
+ parameter clk4_divide_by = 0;
+ parameter clk4_phase_shift = "0";
+ parameter clk4_duty_cycle = 50;
+ parameter pfd_min = 0;
+ parameter pfd_max = 0;
+ parameter vco_min = 0;
+ parameter vco_max = 0;
+ parameter vco_center = 0;
+ // Advanced user parameters
+ parameter m_initial = 1;
+ parameter m = 0;
+ parameter n = 1;
+ parameter c0_high = 1;
+ parameter c0_low = 1;
+ parameter c0_initial = 1;
+ parameter c0_mode = "bypass";
+ parameter c0_ph = 0;
+ parameter c1_high = 1;
+ parameter c1_low = 1;
+ parameter c1_initial = 1;
+ parameter c1_mode = "bypass";
+ parameter c1_ph = 0;
+ parameter c2_high = 1;
+ parameter c2_low = 1;
+ parameter c2_initial = 1;
+ parameter c2_mode = "bypass";
+ parameter c2_ph = 0;
+ parameter c3_high = 1;
+ parameter c3_low = 1;
+ parameter c3_initial = 1;
+ parameter c3_mode = "bypass";
+ parameter c3_ph = 0;
+ parameter c4_high = 1;
+ parameter c4_low = 1;
+ parameter c4_initial = 1;
+ parameter c4_mode = "bypass";
+ parameter c4_ph = 0;
+ parameter m_ph = 0;
+ parameter clk0_counter = "unused";
+ parameter clk1_counter = "unused";
+ parameter clk2_counter = "unused";
+ parameter clk3_counter = "unused";
+ parameter clk4_counter = "unused";
+ parameter c1_use_casc_in = "off";
+ parameter c2_use_casc_in = "off";
+ parameter c3_use_casc_in = "off";
+ parameter c4_use_casc_in = "off";
+ parameter m_test_source = -1;
+ parameter c0_test_source = -1;
+ parameter c1_test_source = -1;
+ parameter c2_test_source = -1;
+ parameter c3_test_source = -1;
+ parameter c4_test_source = -1;
+ parameter vco_multiply_by = 0;
+ parameter vco_divide_by = 0;
+ parameter vco_post_scale = 1;
+ parameter vco_frequency_control = "auto";
+ parameter vco_phase_shift_step = 0;
+ parameter charge_pump_current = 10;
+ parameter loop_filter_r = "1.0";
+ parameter loop_filter_c = 0;
+ parameter pll_compensation_delay = 0;
+ parameter lpm_type = "fiftyfivenm_pll";
+ parameter phase_counter_select_width = 3;
+
+ input [1:0] inclk;
+ input fbin;
+ input clkswitch;
+ input areset;
+ input pfdena;
+ input [phase_counter_select_width - 1:0] phasecounterselect;
+ input phaseupdown;
+ input phasestep;
+ input scanclk;
+ input scanclkena;
+ input scandata;
+ input configupdate;
+ output [4:0] clk;
+ output [1:0] clkbad;
+ output activeclock;
+ output locked;
+ output scandataout;
+ output scandone;
+ output fbout;
+ output phasedone;
+ output vcooverrange;
+ output vcounderrange;
+
+endmodule // cycloneive_pll
diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc
new file mode 100644
index 00000000..d74f295e
--- /dev/null
+++ b/techlibs/intel/synth_intel.cc
@@ -0,0 +1,270 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SynthIntelPass : public ScriptPass {
+ SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") { }
+
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_intel [options]\n");
+ log("\n");
+ log("This command runs synthesis for Intel FPGAs.\n");
+ log("\n");
+ log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
+ log(" generate the synthesis netlist for the specified family.\n");
+ log(" MAX10 is the default target if not family argument specified.\n");
+ log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
+ log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module (default='top')\n");
+ log("\n");
+ log(" -vqm <file>\n");
+ log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
+ log(" output file is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -vpr <file>\n");
+ log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
+ log(" compatible with the Quartus flow. Writing of an\n");
+ log(" output file is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -noiopads\n");
+ log(" do not use altsyncram cells in output netlist\n");
+ log("\n");
+ log(" -nobram\n");
+ log(" do not use altsyncram cells in output netlist\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log(" -retime\n");
+ log(" run 'abc' with -dff option\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
+
+ string top_opt, family_opt, vout_file, blif_file;
+ bool retime, flatten, nobram, noiopads;
+
+ void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ family_opt = "max10";
+ vout_file = "";
+ blif_file = "";
+ retime = false;
+ flatten = true;
+ nobram = false;
+ noiopads = false;
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-family" && argidx+1 < args.size()) {
+ family_opt = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_opt = "-top " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-vqm" && argidx+1 < args.size()) {
+ vout_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-vpr" && argidx+1 < args.size()) {
+ blif_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
+ if (args[argidx] == "-noiopads") {
+ noiopads = true;
+ continue;
+ }
+ if (args[argidx] == "-nobram") {
+ nobram = true;
+ continue;
+ }
+ if (args[argidx] == "-flatten") {
+ flatten = true;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This command only operates on fully selected designs!\n");
+ if (family_opt != "max10" && family_opt !="a10gx" && family_opt != "cyclonev" && family_opt !="cycloneiv" && family_opt !="cycloneive" && family_opt != "cyclone10")
+ log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());
+
+ log_header(design, "Executing SYNTH_INTEL pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ void script() YS_OVERRIDE
+ {
+ if (check_label("begin"))
+ {
+ if(check_label("family") && family_opt=="max10")
+ run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
+ else if(check_label("family") && family_opt=="a10gx")
+ run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
+ else if(check_label("family") && family_opt=="cyclonev")
+ run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
+ else if(check_label("family") && family_opt=="cyclone10")
+ run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
+ else if(check_label("family") && family_opt=="cycloneiv")
+ run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
+ else
+ run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
+ // Misc and common cells
+ run("read_verilog -sv -lib +/intel/common/m9k_bb.v");
+ run("read_verilog -sv -lib +/intel/common/altpll_bb.v");
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
+
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
+ {
+ run("proc");
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
+ }
+
+ if (check_label("coarse"))
+ {
+ run("synth -run coarse");
+ }
+
+ if (!nobram && check_label("bram", "(skip if -nobram)"))
+ {
+ run("memory_bram -rules +/intel/common/brams.txt");
+ run("techmap -map +/intel/common/brams_map.v");
+ }
+
+ if (check_label("fine"))
+ {
+ run("opt -fast -mux_undef -undriven -fine -full");
+ run("memory_map");
+ run("opt -undriven -fine");
+ run("dffsr2dff");
+ run("dff2dffe -direct-match $_DFF_*");
+ run("opt -fine");
+ run("techmap -map +/techmap.v");
+ run("opt -full");
+ run("clean -purge");
+ run("setundef -undriven -zero");
+ if (retime || help_mode)
+ run("abc -markgroups -dff", "(only if -retime)");
+ }
+
+ if (check_label("map_luts"))
+ {
+ if(family_opt=="a10gx" || family_opt=="cyclonev")
+ run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
+ else
+ run("abc -lut 4" + string(retime ? " -dff" : ""));
+ run("clean");
+ }
+
+ if (check_label("map_cells"))
+ {
+ if (!noiopads)
+ run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
+ if(family_opt=="max10")
+ run("techmap -map +/intel/max10/cells_map.v");
+ else if(family_opt=="a10gx")
+ run("techmap -map +/intel/a10gx/cells_map.v");
+ else if(family_opt=="cyclonev")
+ run("techmap -map +/intel/cyclonev/cells_map.v");
+ else if(family_opt=="cyclone10")
+ run("techmap -map +/intel/cyclone10/cells_map.v");
+ else if(family_opt=="cycloneiv")
+ run("techmap -map +/intel/cycloneiv/cells_map.v");
+ else
+ run("techmap -map +/intel/cycloneive/cells_map.v");
+ run("dffinit -highlow -ff dffeas q power_up");
+ run("clean -purge");
+ }
+
+ if (check_label("check"))
+ {
+ run("hierarchy -check");
+ run("stat");
+ run("check -noinit");
+ }
+
+ if (check_label("vqm"))
+ {
+ if (!vout_file.empty() || help_mode)
+ run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
+ help_mode ? "<file-name>" : vout_file.c_str()));
+ }
+
+ if (check_label("vpr"))
+ {
+ if (!blif_file.empty() || help_mode)
+ {
+ run(stringf("opt_clean -purge"));
+ run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
+ }
+ }
+ }
+} SynthIntelPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 5f09ffb0..887ea27d 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -27,8 +27,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_bb.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut2lut.v))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
diff --git a/techlibs/xilinx/brams_init.py b/techlibs/xilinx/brams_init.py
index e787b1f7..d46a2b4f 100644
--- a/techlibs/xilinx/brams_init.py
+++ b/techlibs/xilinx/brams_init.py
@@ -2,27 +2,27 @@
with open("techlibs/xilinx/brams_init_18.vh", "w") as f:
for i in range(8):
- init_snippets = ["INIT[%3d*9+8]" % (k+256*i,) for k in range(255, -1, -1)]
+ init_snippets = [" INIT[%3d*9+8]" % (k+256*i,) for k in range(255, -1, -1)]
for k in range(4, 256, 4):
init_snippets[k] = "\n " + init_snippets[k]
- print(".INITP_%02X({%s})," % (i, ", ".join(init_snippets)), file=f)
+ print(".INITP_%02X({%s})," % (i, ",".join(init_snippets)), file=f)
for i in range(64):
- init_snippets = ["INIT[%3d*9 +: 8]" % (k+32*i,) for k in range(31, -1, -1)]
+ init_snippets = [" INIT[%3d*9 +: 8]" % (k+32*i,) for k in range(31, -1, -1)]
for k in range(4, 32, 4):
init_snippets[k] = "\n " + init_snippets[k]
- print(".INIT_%02X({%s})," % (i, ", ".join(init_snippets)), file=f)
+ print(".INIT_%02X({%s})," % (i, ",".join(init_snippets)), file=f)
with open("techlibs/xilinx/brams_init_36.vh", "w") as f:
for i in range(16):
- init_snippets = ["INIT[%3d*9+8]" % (k+256*i,) for k in range(255, -1, -1)]
+ init_snippets = [" INIT[%3d*9+8]" % (k+256*i,) for k in range(255, -1, -1)]
for k in range(4, 256, 4):
init_snippets[k] = "\n " + init_snippets[k]
- print(".INITP_%02X({%s})," % (i, ", ".join(init_snippets)), file=f)
+ print(".INITP_%02X({%s})," % (i, ",".join(init_snippets)), file=f)
for i in range(128):
- init_snippets = ["INIT[%3d*9 +: 8]" % (k+32*i,) for k in range(31, -1, -1)]
+ init_snippets = [" INIT[%3d*9 +: 8]" % (k+32*i,) for k in range(31, -1, -1)]
for k in range(4, 32, 4):
init_snippets[k] = "\n " + init_snippets[k]
- print(".INIT_%02X({%s})," % (i, ", ".join(init_snippets)), file=f)
+ print(".INIT_%02X({%s})," % (i, ",".join(init_snippets)), file=f)
with open("techlibs/xilinx/brams_init_16.vh", "w") as f:
for i in range(64):
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index 8e5a83ce..0771be0b 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -15,6 +15,7 @@ module \$_DFF_NP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(
module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
+`ifndef NO_LUT
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
@@ -82,3 +83,4 @@ module \$lut (A, Y);
end
endgenerate
endmodule
+`endif
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index 1f114a22..eba17ac9 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -156,3 +156,33 @@ module FDPE (output reg Q, input C, CE, D, PRE);
endcase endgenerate
endmodule
+module RAM64X1D (
+ output DPO, SPO,
+ input D, WCLK, WE,
+ input A0, A1, A2, A3, A4, A5,
+ input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
+);
+ parameter INIT = 64'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+ wire [5:0] a = {A5, A4, A3, A2, A1, A0};
+ wire [5:0] dpra = {DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0};
+ reg [63:0] mem = INIT;
+ assign SPO = mem[a];
+ assign DPO = mem[dpra];
+ wire clk = WCLK ^ IS_WCLK_INVERTED;
+ always @(posedge clk) if (WE) mem[a] <= D;
+endmodule
+
+module RAM128X1D (
+ output DPO, SPO,
+ input D, WCLK, WE,
+ input [6:0] A, DPRA
+);
+ parameter INIT = 128'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+ reg [127:0] mem = INIT;
+ assign SPO = mem[A];
+ assign DPO = mem[DPRA];
+ wire clk = WCLK ^ IS_WCLK_INVERTED;
+ always @(posedge clk) if (WE) mem[A] <= D;
+endmodule
diff --git a/techlibs/xilinx/drams_bb.v b/techlibs/xilinx/drams_bb.v
deleted file mode 100644
index 11168fe1..00000000
--- a/techlibs/xilinx/drams_bb.v
+++ /dev/null
@@ -1,20 +0,0 @@
-
-module RAM64X1D (
- output DPO, SPO,
- input D, WCLK, WE,
- input A0, A1, A2, A3, A4, A5,
- input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
-);
- parameter INIT = 64'h0;
- parameter IS_WCLK_INVERTED = 1'b0;
-endmodule
-
-module RAM128X1D (
- output DPO, SPO,
- input D, WCLK, WE,
- input [6:0] A, DPRA
-);
- parameter INIT = 128'h0;
- parameter IS_WCLK_INVERTED = 1'b0;
-endmodule
-
diff --git a/techlibs/xilinx/lut2lut.v b/techlibs/xilinx/lut2lut.v
new file mode 100644
index 00000000..061ad204
--- /dev/null
+++ b/techlibs/xilinx/lut2lut.v
@@ -0,0 +1,65 @@
+module LUT1(output O, input I0);
+ parameter [1:0] INIT = 0;
+ \$lut #(
+ .WIDTH(1),
+ .LUT(INIT)
+ ) _TECHMAP_REPLACE_ (
+ .A(I0),
+ .Y(O)
+ );
+endmodule
+
+module LUT2(output O, input I0, I1);
+ parameter [3:0] INIT = 0;
+ \$lut #(
+ .WIDTH(2),
+ .LUT(INIT)
+ ) _TECHMAP_REPLACE_ (
+ .A({I1, I0}),
+ .Y(O)
+ );
+endmodule
+
+module LUT3(output O, input I0, I1, I2);
+ parameter [7:0] INIT = 0;
+ \$lut #(
+ .WIDTH(3),
+ .LUT(INIT)
+ ) _TECHMAP_REPLACE_ (
+ .A({I2, I1, I0}),
+ .Y(O)
+ );
+endmodule
+
+module LUT4(output O, input I0, I1, I2, I3);
+ parameter [15:0] INIT = 0;
+ \$lut #(
+ .WIDTH(4),
+ .LUT(INIT)
+ ) _TECHMAP_REPLACE_ (
+ .A({I3, I2, I1, I0}),
+ .Y(O)
+ );
+endmodule
+
+module LUT5(output O, input I0, I1, I2, I3, I4);
+ parameter [31:0] INIT = 0;
+ \$lut #(
+ .WIDTH(5),
+ .LUT(INIT)
+ ) _TECHMAP_REPLACE_ (
+ .A({I4, I3, I2, I1, I0}),
+ .Y(O)
+ );
+endmodule
+
+module LUT6(output O, input I0, I1, I2, I3, I4, I5);
+ parameter [63:0] INIT = 0;
+ \$lut #(
+ .WIDTH(6),
+ .LUT(INIT)
+ ) _TECHMAP_REPLACE_ (
+ .A({I5, I4, I3, I2, I1, I0}),
+ .Y(O)
+ );
+endmodule
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index e7ec1e6e..590fe61d 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -34,9 +34,11 @@ bool check_label(bool &active, std::string run_from, std::string run_to, std::st
return active;
}
-struct SynthXilinxPass : public Pass {
+struct SynthXilinxPass : public Pass
+{
SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
- virtual void help()
+
+ void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
@@ -53,6 +55,14 @@ struct SynthXilinxPass : public Pass {
log(" write the design to the specified edif file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
+ log(" -blif <file>\n");
+ log(" write the design to the specified BLIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -vpr\n");
+ log(" generate an output netlist (and BLIF file) suitable for VPR\n");
+ log(" (this feature is experimental and incomplete)\n");
+ 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");
@@ -71,7 +81,6 @@ struct SynthXilinxPass : public Pass {
log(" read_verilog -lib +/xilinx/cells_sim.v\n");
log(" read_verilog -lib +/xilinx/cells_xtra.v\n");
log(" read_verilog -lib +/xilinx/brams_bb.v\n");
- log(" read_verilog -lib +/xilinx/drams_bb.v\n");
log(" hierarchy -check -top <top>\n");
log("\n");
log(" flatten: (only if -flatten)\n");
@@ -103,7 +112,7 @@ struct SynthXilinxPass : public Pass {
log(" clean\n");
log("\n");
log(" map_cells:\n");
- log(" techmap -map +/xilinx/cells_map.v\n");
+ log(" techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode)\n");
log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT\n");
log(" clean\n");
log("\n");
@@ -115,14 +124,19 @@ struct SynthXilinxPass : public Pass {
log(" edif: (only if -edif)\n");
log(" write_edif <file-name>\n");
log("\n");
+ log(" blif: (only if -blif)\n");
+ log(" write_blif <file-name>\n");
+ log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string top_opt = "-auto-top";
std::string edif_file;
+ std::string blif_file;
std::string run_from, run_to;
bool flatten = false;
bool retime = false;
+ bool vpr = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -135,6 +149,10 @@ struct SynthXilinxPass : public Pass {
edif_file = args[++argidx];
continue;
}
+ if (args[argidx] == "-blif" && argidx+1 < args.size()) {
+ blif_file = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-run" && argidx+1 < args.size()) {
size_t pos = args[argidx+1].find(':');
if (pos == std::string::npos)
@@ -151,6 +169,10 @@ struct SynthXilinxPass : public Pass {
retime = true;
continue;
}
+ if (args[argidx] == "-vpr") {
+ vpr = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -168,7 +190,6 @@ struct SynthXilinxPass : public Pass {
Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v");
Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v");
Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v");
- Pass::call(design, "read_verilog -lib +/xilinx/drams_bb.v");
Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
}
@@ -214,7 +235,10 @@ struct SynthXilinxPass : public Pass {
if (check_label(active, run_from, run_to, "map_cells"))
{
- Pass::call(design, "techmap -map +/xilinx/cells_map.v");
+ if (vpr)
+ Pass::call(design, "techmap -D NO_LUT -map +/xilinx/cells_map.v");
+ else
+ Pass::call(design, "techmap -map +/xilinx/cells_map.v");
Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT");
Pass::call(design, "clean");
}
@@ -231,6 +255,11 @@ struct SynthXilinxPass : public Pass {
if (!edif_file.empty())
Pass::call(design, stringf("write_edif %s", edif_file.c_str()));
}
+ if (check_label(active, run_from, run_to, "blif"))
+ {
+ if (!blif_file.empty())
+ Pass::call(design, stringf("write_blif %s", edif_file.c_str()));
+ }
log_pop();
}
diff --git a/tests/sat/sizebits.sv b/tests/sat/sizebits.sv
new file mode 100644
index 00000000..d7ce2326
--- /dev/null
+++ b/tests/sat/sizebits.sv
@@ -0,0 +1,32 @@
+module functions01;
+
+wire [5:2]x;
+wire [3:0]y[2:7];
+wire [3:0]z[7:2][2:9];
+
+//wire [$size(x)-1:0]x_size;
+//wire [$size({x, x})-1:0]xx_size;
+//wire [$size(y)-1:0]y_size;
+//wire [$size(z)-1:0]z_size;
+
+assert property ($size(x) == 4);
+assert property ($size({3{x}}) == 3*4);
+assert property ($size(y) == 6);
+assert property ($size(y, 1) == 6);
+assert property ($size(y, (1+1)) == 4);
+
+assert property ($size(z) == 6);
+assert property ($size(z, 1) == 6);
+assert property ($size(z, 2) == 8);
+assert property ($size(z, 3) == 4);
+// This should trigger an error if enabled (it does).
+//assert property ($size(z, 4) == 4);
+
+//wire [$bits(x)-1:0]x_bits;
+//wire [$bits({x, x})-1:0]xx_bits;
+
+assert property ($bits(x) == 4);
+assert property ($bits(y) == 4*6);
+assert property ($bits(z) == 4*6*8);
+
+endmodule
diff --git a/tests/sat/sizebits.ys b/tests/sat/sizebits.ys
new file mode 100644
index 00000000..689227a4
--- /dev/null
+++ b/tests/sat/sizebits.ys
@@ -0,0 +1,2 @@
+read_verilog -sv sizebits.sv
+prep; sat -verify -prove-asserts
diff --git a/tests/simple/arraycells.v b/tests/simple/arraycells.v
index 704ca3fd..fd85a119 100644
--- a/tests/simple/arraycells.v
+++ b/tests/simple/arraycells.v
@@ -2,7 +2,7 @@
module array_test001(a, b, c, y);
input a;
input [31:0] b, c;
- input [31:0] y;
+ output [31:0] y;
aoi12 p [31:0] (a, b, c, y);
endmodule
diff --git a/tests/simple/graphtest.v b/tests/simple/graphtest.v
index 74788dbb..9b16b61c 100644
--- a/tests/simple/graphtest.v
+++ b/tests/simple/graphtest.v
@@ -25,7 +25,7 @@ assign Z[7:4] = {1'b0, B[2:0]}; // Concat of CV and PI connect to PO
always @* begin
if (A == 4'b1111) begin // All-Const at port (eq)
X = B;
- end
+ end
else begin
X = 4'b0000; // All-Const at port (mux)
end
diff --git a/tests/simple/hierdefparam.v b/tests/simple/hierdefparam.v
new file mode 100644
index 00000000..ff92c38b
--- /dev/null
+++ b/tests/simple/hierdefparam.v
@@ -0,0 +1,23 @@
+module hierdefparam_top(input [7:0] A, output [7:0] Y);
+ generate begin:foo
+ hierdefparam_a mod_a(.A(A), .Y(Y));
+ end endgenerate
+ defparam foo.mod_a.bar[0].mod_b.addvalue = 42;
+ defparam foo.mod_a.bar[1].mod_b.addvalue = 43;
+endmodule
+
+module hierdefparam_a(input [7:0] A, output [7:0] Y);
+ genvar i;
+ generate
+ for (i = 0; i < 2; i=i+1) begin:bar
+ wire [7:0] a, y;
+ hierdefparam_b mod_b(.A(a), .Y(y));
+ end
+ endgenerate
+ assign bar[0].a = A, bar[1].a = bar[0].y, Y = bar[1].y;
+endmodule
+
+module hierdefparam_b(input [7:0] A, output [7:0] Y);
+ parameter [7:0] addvalue = 44;
+ assign Y = A + addvalue;
+endmodule
diff --git a/tests/simple/specify.v b/tests/simple/specify.v
new file mode 100644
index 00000000..f19418d9
--- /dev/null
+++ b/tests/simple/specify.v
@@ -0,0 +1,31 @@
+module test_specify;
+
+specparam a=1;
+
+specify
+endspecify
+
+specify
+(A => B) = ( 1 ) ;
+(A- => B) = ( 1,2 ) ;
+(A+ => B) = ( 1,2,3 ) ;
+(A => B) = (
+ 1.1, 2, 3,
+ 4, 5.5, 6.6
+) ;
+(A => B) = (
+ 1.1, 2, 3,
+ 4, 5.5, 6.6 ,
+ 7.7, 8.8, 9,
+ 10.1, 11, 12
+) ;
+specparam b=1;
+specparam [1:2] asasa=1;
+endspecify
+
+specify
+specparam c=1:2:3;
+endspecify
+
+endmodule
+
diff --git a/tests/sva/.gitignore b/tests/sva/.gitignore
new file mode 100644
index 00000000..cc254049
--- /dev/null
+++ b/tests/sva/.gitignore
@@ -0,0 +1,7 @@
+/*_pass.sby
+/*_fail.sby
+/*_pass
+/*_fail
+/*.ok
+/vhdlpsl[0-9][0-9]
+/vhdlpsl[0-9][0-9].sby
diff --git a/tests/sva/Makefile b/tests/sva/Makefile
new file mode 100644
index 00000000..1b217f74
--- /dev/null
+++ b/tests/sva/Makefile
@@ -0,0 +1,13 @@
+
+TESTS = $(sort $(basename $(wildcard *.sv)) $(basename $(wildcard *.vhd)))
+
+all: $(addsuffix .ok,$(TESTS))
+
+%.ok:
+ bash runtest.sh $@
+
+clean:
+ rm -rf $(addsuffix .ok,$(TESTS)) $(addsuffix .sby,$(TESTS)) $(TESTS)
+ rm -rf $(addsuffix _pass.sby,$(TESTS)) $(addsuffix _pass,$(TESTS))
+ rm -rf $(addsuffix _fail.sby,$(TESTS)) $(addsuffix _fail,$(TESTS))
+
diff --git a/tests/sva/basic00.sv b/tests/sva/basic00.sv
new file mode 100644
index 00000000..30c37f5f
--- /dev/null
+++ b/tests/sva/basic00.sv
@@ -0,0 +1,12 @@
+module top (input clk, reset, antecedent, output reg consequent);
+ always @(posedge clk)
+ consequent <= reset ? 0 : antecedent;
+
+`ifdef FAIL
+ test_assert: assert property ( @(posedge clk) disable iff (reset) antecedent |-> consequent )
+ else $error("Failed with consequent = ", $sampled(consequent));
+`else
+ test_assert: assert property ( @(posedge clk) disable iff (reset) antecedent |=> consequent )
+ else $error("Failed with consequent = ", $sampled(consequent));
+`endif
+endmodule
diff --git a/tests/sva/basic01.sv b/tests/sva/basic01.sv
new file mode 100644
index 00000000..74ab9343
--- /dev/null
+++ b/tests/sva/basic01.sv
@@ -0,0 +1,16 @@
+module top (input logic clock, ctrl);
+ logic read = 0, write = 0, ready = 0;
+
+ always @(posedge clock) begin
+ read <= !ctrl;
+ write <= ctrl;
+ ready <= write;
+ end
+
+ a_rw: assert property ( @(posedge clock) !(read && write) );
+`ifdef FAIL
+ a_wr: assert property ( @(posedge clock) write |-> ready );
+`else
+ a_wr: assert property ( @(posedge clock) write |=> ready );
+`endif
+endmodule
diff --git a/tests/sva/basic02.sv b/tests/sva/basic02.sv
new file mode 100644
index 00000000..b34f3aff
--- /dev/null
+++ b/tests/sva/basic02.sv
@@ -0,0 +1,20 @@
+module top (input logic clock, ctrl);
+ logic read = 0, write = 0, ready = 0;
+
+ always @(posedge clock) begin
+ read <= !ctrl;
+ write <= ctrl;
+ ready <= write;
+ end
+endmodule
+
+module top_properties (input logic clock, read, write, ready);
+ a_rw: assert property ( @(posedge clock) !(read && write) );
+`ifdef FAIL
+ a_wr: assert property ( @(posedge clock) write |-> ready );
+`else
+ a_wr: assert property ( @(posedge clock) write |=> ready );
+`endif
+endmodule
+
+bind top top_properties properties_inst (.*);
diff --git a/tests/sva/basic03.sv b/tests/sva/basic03.sv
new file mode 100644
index 00000000..8018de4c
--- /dev/null
+++ b/tests/sva/basic03.sv
@@ -0,0 +1,12 @@
+module top (input logic clk, input logic selA, selB, QA, QB, output logic Q);
+ always @(posedge clk) begin
+ if (selA) Q <= QA;
+ if (selB) Q <= QB;
+ end
+
+ check_selA: assert property ( @(posedge clk) selA |=> Q == $past(QA) );
+ check_selB: assert property ( @(posedge clk) selB |=> Q == $past(QB) );
+`ifndef FAIL
+ assume_not_11: assume property ( @(posedge clk) !(selA & selB) );
+`endif
+endmodule
diff --git a/tests/sva/basic04.sv b/tests/sva/basic04.sv
new file mode 100644
index 00000000..bc46be9f
--- /dev/null
+++ b/tests/sva/basic04.sv
@@ -0,0 +1,10 @@
+module top_properties (input logic clock, read, write, ready);
+ a_rw: assert property ( @(posedge clock) !(read && write) );
+`ifdef FAIL
+ a_wr: assert property ( @(posedge clock) write |-> ready );
+`else
+ a_wr: assert property ( @(posedge clock) write |=> ready );
+`endif
+endmodule
+
+bind top top_properties properties_inst (.*);
diff --git a/tests/sva/basic04.vhd b/tests/sva/basic04.vhd
new file mode 100644
index 00000000..f2ec305e
--- /dev/null
+++ b/tests/sva/basic04.vhd
@@ -0,0 +1,26 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity top is
+ port (
+ clock : in std_logic;
+ ctrl : in std_logic;
+ x : out std_logic
+ );
+end entity;
+
+architecture rtl of top is
+ signal read : std_logic := '0';
+ signal write : std_logic := '0';
+ signal ready : std_logic := '0';
+begin
+ process (clock) begin
+ if (rising_edge(clock)) then
+ read <= not ctrl;
+ write <= ctrl;
+ ready <= write;
+ end if;
+ end process;
+
+ x <= read xor write xor ready;
+end architecture;
diff --git a/tests/sva/basic05.sv b/tests/sva/basic05.sv
new file mode 100644
index 00000000..816ee1da
--- /dev/null
+++ b/tests/sva/basic05.sv
@@ -0,0 +1,19 @@
+module top (input logic clock, ctrl);
+ logic read, write, ready;
+
+ demo uut (
+ .clock(clock),
+ .ctrl(ctrl)
+ );
+
+ assign read = uut.read;
+ assign write = uut.write;
+ assign ready = uut.ready;
+
+ a_rw: assert property ( @(posedge clock) !(read && write) );
+`ifdef FAIL
+ a_wr: assert property ( @(posedge clock) write |-> ready );
+`else
+ a_wr: assert property ( @(posedge clock) write |=> ready );
+`endif
+endmodule
diff --git a/tests/sva/basic05.vhd b/tests/sva/basic05.vhd
new file mode 100644
index 00000000..8d42f71e
--- /dev/null
+++ b/tests/sva/basic05.vhd
@@ -0,0 +1,26 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity demo is
+ port (
+ clock : in std_logic;
+ ctrl : in std_logic;
+ x : out std_logic
+ );
+end entity;
+
+architecture rtl of demo is
+ signal read : std_logic := '0';
+ signal write : std_logic := '0';
+ signal ready : std_logic := '0';
+begin
+ process (clock) begin
+ if (rising_edge(clock)) then
+ read <= not ctrl;
+ write <= ctrl;
+ ready <= write;
+ end if;
+ end process;
+
+ x <= read xor write xor ready;
+end architecture;
diff --git a/tests/sva/counter.sv b/tests/sva/counter.sv
new file mode 100644
index 00000000..4f949115
--- /dev/null
+++ b/tests/sva/counter.sv
@@ -0,0 +1,30 @@
+module top (input clk, reset, up, down, output reg [7:0] cnt);
+ always @(posedge clk) begin
+ if (reset)
+ cnt <= 0;
+ else if (up)
+ cnt <= cnt + 1;
+ else if (down)
+ cnt <= cnt - 1;
+ end
+
+ default clocking @(posedge clk); endclocking
+ default disable iff (reset);
+
+ assert property (up |=> cnt == $past(cnt) + 8'd 1);
+ assert property (up [*2] |=> cnt == $past(cnt, 2) + 8'd 2);
+ assert property (up ##1 up |=> cnt == $past(cnt, 2) + 8'd 2);
+
+`ifndef FAIL
+ assume property (down |-> !up);
+`endif
+ assert property (up ##1 down |=> cnt == $past(cnt, 2));
+ assert property (down |=> cnt == $past(cnt) - 8'd 1);
+
+ property down_n(n);
+ down [*n] |=> cnt == $past(cnt, n) - n;
+ endproperty
+
+ assert property (down_n(8'd 3));
+ assert property (down_n(8'd 5));
+endmodule
diff --git a/tests/sva/runtest.sh b/tests/sva/runtest.sh
new file mode 100644
index 00000000..1b65ca9c
--- /dev/null
+++ b/tests/sva/runtest.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+set -ex
+
+prefix=${1%.ok}
+prefix=${prefix%.sv}
+prefix=${prefix%.vhd}
+test -f $prefix.sv -o -f $prefix.vhd
+
+generate_sby() {
+ cat <<- EOT
+ [options]
+ mode bmc
+ depth 10
+ expect $1
+
+ [engines]
+ smtbmc yices
+
+ [script]
+ EOT
+
+ if [ -f $prefix.sv ]; then
+ if [ "$1" = "fail" ]; then
+ echo "verific -sv ${prefix}_fail.sv"
+ else
+ echo "verific -sv $prefix.sv"
+ fi
+ fi
+
+ if [ -f $prefix.vhd ]; then
+ echo "verific -vhdl $prefix.vhd"
+ fi
+
+ cat <<- EOT
+ verific -import -extnets -all top
+ prep -top top
+ chformal -early -assume
+
+ [files]
+ EOT
+
+ if [ -f $prefix.sv ]; then
+ echo "$prefix.sv"
+ fi
+
+ if [ -f $prefix.vhd ]; then
+ echo "$prefix.vhd"
+ fi
+
+ if [ "$1" = "fail" ]; then
+ cat <<- EOT
+
+ [file ${prefix}_fail.sv]
+ \`define FAIL
+ \`include "$prefix.sv"
+ EOT
+ fi
+}
+
+if [ -f $prefix.sv ]; then
+ generate_sby pass > ${prefix}_pass.sby
+ generate_sby fail > ${prefix}_fail.sby
+ sby --yosys $PWD/../../yosys -f ${prefix}_pass.sby
+ sby --yosys $PWD/../../yosys -f ${prefix}_fail.sby
+else
+ generate_sby pass > ${prefix}.sby
+ sby --yosys $PWD/../../yosys -f ${prefix}.sby
+fi
+
+touch $prefix.ok
+
diff --git a/tests/sva/sva_not.sv b/tests/sva/sva_not.sv
new file mode 100644
index 00000000..d81a4865
--- /dev/null
+++ b/tests/sva/sva_not.sv
@@ -0,0 +1,34 @@
+module top (
+ input clk,
+ input reset,
+ input ping,
+ input [1:0] cfg,
+ output reg pong
+);
+ reg [2:0] cnt;
+ localparam integer maxdelay = 8;
+
+ always @(posedge clk) begin
+ if (reset) begin
+ cnt <= 0;
+ pong <= 0;
+ end else begin
+ cnt <= cnt - |cnt;
+ pong <= cnt == 1;
+ if (ping) cnt <= 4 + cfg;
+ end
+ end
+
+ assert property (
+ @(posedge clk)
+ disable iff (reset)
+ not (ping ##1 !pong [*maxdelay])
+ );
+
+`ifndef FAIL
+ assume property (
+ @(posedge clk)
+ not (cnt && ping)
+ );
+`endif
+endmodule
diff --git a/tests/sva/sva_range.sv b/tests/sva/sva_range.sv
new file mode 100644
index 00000000..d1569fc8
--- /dev/null
+++ b/tests/sva/sva_range.sv
@@ -0,0 +1,19 @@
+module top (
+ input clk,
+ input a, b, c, d
+);
+ default clocking @(posedge clk); endclocking
+
+ assert property (
+ a ##[*] b |=> c until d
+ );
+
+`ifndef FAIL
+ assume property (
+ b |=> ##5 d
+ );
+ assume property (
+ b || (c && !d) |=> c
+ );
+`endif
+endmodule
diff --git a/tests/sva/sva_throughout.sv b/tests/sva/sva_throughout.sv
new file mode 100644
index 00000000..7e036a06
--- /dev/null
+++ b/tests/sva/sva_throughout.sv
@@ -0,0 +1,19 @@
+module top (
+ input clk,
+ input a, b, c, d
+);
+ default clocking @(posedge clk); endclocking
+
+ assert property (
+ a |=> b throughout (c ##1 d)
+ );
+
+`ifndef FAIL
+ assume property (
+ a |=> b && c
+ );
+ assume property (
+ b && c |=> b && d
+ );
+`endif
+endmodule
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index d0b0a89d..d6216244 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
libs=""
genvcd=false
@@ -100,7 +100,7 @@ do
echo -n "Test: $bn "
fi
- rm -f ${bn}.{err,log,sikp}
+ rm -f ${bn}.{err,log,skip}
mkdir -p ${bn}.out
rm -rf ${bn}.out/*
diff --git a/tests/unit/Makefile b/tests/unit/Makefile
new file mode 100644
index 00000000..9f1e5c99
--- /dev/null
+++ b/tests/unit/Makefile
@@ -0,0 +1,35 @@
+GTESTFLAG := -lgtest -lgtest_main
+RPATH := -Wl,-rpath
+EXTRAFLAGS := -lyosys -pthreads
+
+OBJTEST := objtest
+BINTEST := bintest
+
+ALLTESTFILE := $(shell find -name '*Test.cc' -printf '%P ')
+TESTDIRS := $(sort $(dir $(ALLTESTFILE)))
+TESTS := $(addprefix $(BINTEST)/, $(basename $(ALLTESTFILE:%Test.cc=%Test.o)))
+
+# Prevent make from removing our .o files
+.SECONDARY:
+
+all: prepare $(TESTS) run-tests
+
+$(BINTEST)/%: $(OBJTEST)/%.o
+ $(CXX) -L$(ROOTPATH) $(RPATH)=$(ROOTPATH) -o $@ $^ $(LDLIBS) \
+ $(GTESTFLAG) $(EXTRAFLAGS)
+
+$(OBJTEST)/%.o: $(basename $(subst $(OBJTEST),.,%)).cc
+ $(CXX) -o $@ -c -I$(ROOTPATH) $(CPPFLAGS) $(CXXFLAGS) $^
+
+.PHONY: prepare run-tests clean
+
+run-tests: $(TESTS)
+ $(subst Test ,Test; ,$^)
+
+prepare:
+ mkdir -p $(addprefix $(BINTEST)/,$(TESTDIRS))
+ mkdir -p $(addprefix $(OBJTEST)/,$(TESTDIRS))
+
+clean:
+ rm -rf $(OBJTEST)
+ rm -rf $(BINTEST)
diff --git a/tests/unit/kernel/logTest.cc b/tests/unit/kernel/logTest.cc
new file mode 100644
index 00000000..62b4f3b9
--- /dev/null
+++ b/tests/unit/kernel/logTest.cc
@@ -0,0 +1,14 @@
+#include <gtest/gtest.h>
+
+#include "kernel/yosys.h"
+#include "kernel/log.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+TEST(KernelLogTest, logvValidValues)
+{
+ //TODO: Implement log test
+ EXPECT_EQ(7, 7);
+}
+
+YOSYS_NAMESPACE_END
diff --git a/tests/unit/kernel/rtlilTest.cc b/tests/unit/kernel/rtlilTest.cc
new file mode 100644
index 00000000..d9eeed55
--- /dev/null
+++ b/tests/unit/kernel/rtlilTest.cc
@@ -0,0 +1,14 @@
+#include <gtest/gtest.h>
+
+#include "kernel/yosys.h"
+#include "kernel/rtlil.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+TEST(KernelRtlilTest, getReferenceValid)
+{
+ //TODO: Implement rtlil test
+ EXPECT_EQ(33, 33);
+}
+
+YOSYS_NAMESPACE_END
diff --git a/tests/various/reg_wire_error.sv b/tests/various/reg_wire_error.sv
new file mode 100644
index 00000000..fe5ff3ab
--- /dev/null
+++ b/tests/various/reg_wire_error.sv
@@ -0,0 +1,74 @@
+module sub_mod(input i_in, output o_out);
+assign o_out = i_in;
+endmodule
+
+module test(i_clk, i, i_reg, o_reg, o_wire, o_mr, o_mw, o_ml);
+input i_clk;
+input i;
+input i_reg;
+output o_reg;
+output o_wire;
+output o_mr, o_mw, o_ml;
+
+// Enable this to see how it doesn't fail on yosys although it should
+//reg o_wire;
+// Enable this instead of the above to see how logic can be mapped to a wire
+logic o_wire;
+// Enable this to see how it doesn't fail on yosys although it should
+//reg i_reg;
+// Disable this to see how it doesn't fail on yosys although it should
+//reg o_reg;
+
+logic l_reg;
+
+// Enable this to tst if logic-turne-reg will catch assignments even if done before it turned into a reg
+assign l_reg = !o_reg;
+initial o_reg = 1'b0;
+always @(posedge i_clk)
+begin
+ o_reg <= !o_reg;
+ l_reg <= !o_reg;
+end
+
+assign o_wire = !o_reg;
+// Uncomment this to see how a logic already turned intoa reg can be freely assigned on yosys
+assign l_reg = !o_reg;
+
+sub_mod sm_inst (
+ .i_in(1'b1),
+ .o_out(o_reg)
+);
+
+wire mw1[0:1];
+wire mw2[0:1];
+wire mw3[0:1];
+reg mr1[0:1];
+reg mr2[0:1];
+reg mr3[0:1];
+logic ml1[0:1];
+logic ml2[0:1];
+logic ml3[0:1];
+
+assign o_mw = mw1[i];
+assign o_mr = mr1[i];
+assign o_ml = ml1[i];
+
+assign mw1[1] = 1'b1;
+//assign mr1[1] = 1'b1;
+assign ml1[1] = 1'b1;
+always @(posedge i_clk)
+begin
+ mr2[0] = 1'b0;
+ mw2[0] = 1'b0;
+ ml2[0] = 1'b0;
+end
+
+always @(posedge i_clk)
+begin
+ mr3[0] <= 1'b0;
+ mw3[0] <= 1'b0;
+ ml3[0] <= 1'b0;
+end
+
+endmodule
+
diff --git a/tests/various/reg_wire_error.ys b/tests/various/reg_wire_error.ys
new file mode 100644
index 00000000..b9d03155
--- /dev/null
+++ b/tests/various/reg_wire_error.ys
@@ -0,0 +1 @@
+read_verilog -sv reg_wire_error.sv